summary refs log tree commit diff stats
path: root/system/physmem.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2024-04-23 17:35:57 -0700
committerRichard Henderson <richard.henderson@linaro.org>2024-04-23 17:35:57 -0700
commit13b1e9667737132440f4d500c31cb69320c6b15a (patch)
treec598a1b459bdb3fceabc97393178d34497f65e4a /system/physmem.c
parent1a6f53953df65f31e922f8a1763dac9f10adc81b (diff)
parent7653b44534d3267fa63ebc9d7221eaa7b48bf5ae (diff)
downloadfocaccia-qemu-13b1e9667737132440f4d500c31cb69320c6b15a.tar.gz
focaccia-qemu-13b1e9667737132440f4d500c31cb69320c6b15a.zip
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* cleanups for stubs
* do not link pixman automatically into all targets
* optimize computation of VGA dirty memory region
* kvm: use configs/ definition to conditionalize debug support
* hw: Add compat machines for 9.1
* target/i386: add guest-phys-bits cpu property
* target/i386: Introduce Icelake-Server-v7 and SierraForest models
* target/i386: Export RFDS bit to guests
* q35: SMM ranges cleanups
* target/i386: basic support for confidential guests
* linux-headers: update headers
* target/i386: SEV: use KVM_SEV_INIT2 if possible
* kvm: Introduce support for memory_attributes
* RAMBlock: Add support of KVM private guest memfd
* Consolidate use of warn_report_once()
* pythondeps.toml: warn about updates needed to docs/requirements.txt
* target/i386: always write 32-bits for SGDT and SIDT

# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmYn1UkUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroO1nwgAhRQhkYcdtFc649WJWTNvJCNzmek0
# Sg7trH2NKlwA75zG8Qv4TR3E71UrXoY9oItwYstc4Erz+tdf73WyaHMF3cEk1p82
# xx3LcBYhP7jGSjabxTkZsFU8+MM1raOjRN/tHvfcjYLaJOqJZplnkaVhMbNPsVuM
# IPJ5bVQohxpmHKPbeFNpF4QJ9wGyZAYOfJOFCk09xQtHnA8CtFjS9to33QPAR/Se
# OVZwRCigVjf0KNmCnHC8tJHoW8pG/cdQAr3qqd397XbM1vVELv9fiXiMoGF78UsY
# trO4K2yg6N5Sly4Qv/++zZ0OZNkL3BREGp3wf4eTSvLXxqSGvfi8iLpFGA==
# =lwSL
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 23 Apr 2024 08:35:37 AM PDT
# gpg:                using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg:                issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [undefined]
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (63 commits)
  target/i386/translate.c: always write 32-bits for SGDT and SIDT
  pythondeps.toml: warn about updates needed to docs/requirements.txt
  accel/tcg/icount-common: Consolidate the use of warn_report_once()
  target/i386/cpu: Merge the warning and error messages for AMD HT check
  target/i386/cpu: Consolidate the use of warn_report_once()
  target/i386/host-cpu: Consolidate the use of warn_report_once()
  kvm/tdx: Ignore memory conversion to shared of unassigned region
  kvm/tdx: Don't complain when converting vMMIO region to shared
  kvm: handle KVM_EXIT_MEMORY_FAULT
  physmem: Introduce ram_block_discard_guest_memfd_range()
  RAMBlock: make guest_memfd require uncoordinated discard
  HostMem: Add mechanism to opt in kvm guest memfd via MachineState
  kvm/memory: Make memory type private by default if it has guest memfd backend
  kvm: Enable KVM_SET_USER_MEMORY_REGION2 for memslot
  RAMBlock: Add support of KVM private guest memfd
  kvm: Introduce support for memory_attributes
  trace/kvm: Split address space and slot id in trace_kvm_set_user_memory()
  hw/i386/sev: Use legacy SEV VM types for older machine types
  i386/sev: Add 'legacy-vm-type' parameter for SEV guest objects
  target/i386: SEV: use KVM_SEV_INIT2 if possible
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'system/physmem.c')
-rw-r--r--system/physmem.c65
1 files changed, 62 insertions, 3 deletions
diff --git a/system/physmem.c b/system/physmem.c
index a4fe3d2bf8..c3d04ca921 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -1808,6 +1808,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
     const bool shared = qemu_ram_is_shared(new_block);
     RAMBlock *block;
     RAMBlock *last_block = NULL;
+    bool free_on_error = false;
     ram_addr_t old_ram_size, new_ram_size;
     Error *err = NULL;
 
@@ -1837,6 +1838,26 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
                 return;
             }
             memory_try_enable_merging(new_block->host, new_block->max_length);
+            free_on_error = true;
+        }
+    }
+
+    if (new_block->flags & RAM_GUEST_MEMFD) {
+        assert(kvm_enabled());
+        assert(new_block->guest_memfd < 0);
+
+        if (ram_block_discard_require(true) < 0) {
+            error_setg_errno(errp, errno,
+                             "cannot set up private guest memory: discard currently blocked");
+            error_append_hint(errp, "Are you using assigned devices?\n");
+            goto out_free;
+        }
+
+        new_block->guest_memfd = kvm_create_guest_memfd(new_block->max_length,
+                                                        0, errp);
+        if (new_block->guest_memfd < 0) {
+            qemu_mutex_unlock_ramlist();
+            goto out_free;
         }
     }
 
@@ -1888,6 +1909,13 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
         ram_block_notify_add(new_block->host, new_block->used_length,
                              new_block->max_length);
     }
+    return;
+
+out_free:
+    if (free_on_error) {
+        qemu_anon_ram_free(new_block->host, new_block->max_length);
+        new_block->host = NULL;
+    }
 }
 
 #ifdef CONFIG_POSIX
@@ -1902,7 +1930,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
     /* Just support these ram flags by now. */
     assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE |
                           RAM_PROTECTED | RAM_NAMED_FILE | RAM_READONLY |
-                          RAM_READONLY_FD)) == 0);
+                          RAM_READONLY_FD | RAM_GUEST_MEMFD)) == 0);
 
     if (xen_enabled()) {
         error_setg(errp, "-mem-path not supported with Xen");
@@ -1939,6 +1967,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
     new_block->used_length = size;
     new_block->max_length = size;
     new_block->flags = ram_flags;
+    new_block->guest_memfd = -1;
     new_block->host = file_ram_alloc(new_block, size, fd, !file_size, offset,
                                      errp);
     if (!new_block->host) {
@@ -2018,7 +2047,7 @@ RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
     int align;
 
     assert((ram_flags & ~(RAM_SHARED | RAM_RESIZEABLE | RAM_PREALLOC |
-                          RAM_NORESERVE)) == 0);
+                          RAM_NORESERVE | RAM_GUEST_MEMFD)) == 0);
     assert(!host ^ (ram_flags & RAM_PREALLOC));
 
     align = qemu_real_host_page_size();
@@ -2033,6 +2062,7 @@ RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
     new_block->max_length = max_size;
     assert(max_size >= size);
     new_block->fd = -1;
+    new_block->guest_memfd = -1;
     new_block->page_size = qemu_real_host_page_size();
     new_block->host = host;
     new_block->flags = ram_flags;
@@ -2055,7 +2085,7 @@ RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
 RAMBlock *qemu_ram_alloc(ram_addr_t size, uint32_t ram_flags,
                          MemoryRegion *mr, Error **errp)
 {
-    assert((ram_flags & ~(RAM_SHARED | RAM_NORESERVE)) == 0);
+    assert((ram_flags & ~(RAM_SHARED | RAM_NORESERVE | RAM_GUEST_MEMFD)) == 0);
     return qemu_ram_alloc_internal(size, size, NULL, NULL, ram_flags, mr, errp);
 }
 
@@ -2083,6 +2113,12 @@ static void reclaim_ramblock(RAMBlock *block)
     } else {
         qemu_anon_ram_free(block->host, block->max_length);
     }
+
+    if (block->guest_memfd >= 0) {
+        close(block->guest_memfd);
+        ram_block_discard_require(false);
+    }
+
     g_free(block);
 }
 
@@ -3685,6 +3721,29 @@ err:
     return ret;
 }
 
+int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t start,
+                                        size_t length)
+{
+    int ret = -1;
+
+#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
+    ret = fallocate(rb->guest_memfd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+                    start, length);
+
+    if (ret) {
+        ret = -errno;
+        error_report("%s: Failed to fallocate %s:%" PRIx64 " +%zx (%d)",
+                     __func__, rb->idstr, start, length, ret);
+    }
+#else
+    ret = -ENOSYS;
+    error_report("%s: fallocate not available %s:%" PRIx64 " +%zx (%d)",
+                 __func__, rb->idstr, start, length, ret);
+#endif
+
+    return ret;
+}
+
 bool ramblock_is_pmem(RAMBlock *rb)
 {
     return rb->flags & RAM_PMEM;