Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

q35: add virtio-mmio slots #13

Draft
wants to merge 82 commits into
base: svsm-igvm
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
1c95816
i386/pc: Drop pc_machine_kvm_type()
calmisi Jul 20, 2023
eccfb38
i386/cpuid: Decrease cpuid_i when skipping CPUID leaf 1F
calmisi Jul 11, 2022
83066e8
i386/cpuid: Remove subleaf constraint on CPUID leaf 1F
calmisi Jul 11, 2022
6f0194e
trace/kvm: Split address space and slot id in trace_kvm_set_user_memo…
calmisi Apr 23, 2021
a4ef508
*** HACK *** linux-headers: Update headers to pull in gmem APIs
calmisi Jul 20, 2023
a3b4f68
RAMBlock: Add support of KVM private guest memfd
calmisi Sep 22, 2023
9c9149c
RAMBlock/guest_memfd: Enable KVM_GUEST_MEMFD_ALLOW_HUGEPAGE
calmisi Nov 13, 2023
e3fbcaf
HostMem: Add mechanism to opt in kvm guest memfd via MachineState
calmisi Jun 3, 2023
ab6b5c6
kvm: Enable KVM_SET_USER_MEMORY_REGION2 for memslot
chao-p Jun 3, 2023
86063d6
kvm: Introduce support for memory_attributes
calmisi Jul 31, 2023
e1f111b
physmem: Relax the alignment check of host_startaddr in ram_block_dis…
calmisi Oct 26, 2023
132e2eb
physmem: replace function name with __func__ in ram_block_discard_ran…
calmisi Dec 22, 2022
2b6dde8
physmem: Introduce ram_block_convert_range() for page conversion
calmisi Aug 1, 2023
3d6f437
kvm: handle KVM_EXIT_MEMORY_FAULT
chao-p Nov 24, 2021
e807937
trace/kvm: Add trace for page convertion between shared and private
yamahata Aug 16, 2022
89836cb
target/i386: Implement mc->kvm_type() to get VM type
calmisi Dec 7, 2021
1767802
target/i386: Parse TDX vm type
calmisi Dec 7, 2021
930792f
target/i386: Introduce kvm_confidential_guest_init()
calmisi Dec 7, 2021
3c1892e
kvm/memory: Introduce the infrastructure to set the default shared/pr…
calmisi Jul 31, 2023
bbbd176
memory: Introduce memory_region_init_ram_guest_memfd()
calmisi Jun 3, 2023
1233d0f
pci-host/q35: Move PAM initialization above SMRAM initialization
yamahata Jul 7, 2021
1fc2d77
q35: Introduce smm_ranges property for q35-pci-host
Jul 27, 2020
48cd1d2
Revert "target/i386: Parse TDX vm type"
mdroth Nov 16, 2023
0591737
*kvm: Use new KVM_MEM_GUEST_MEMFD flag instead of KVM_MEM_PRIVATE
mdroth Nov 17, 2023
c2dee38
Update kernel headers for snp-host-v11
mdroth Nov 17, 2023
187dce4
i386/sev: Introduce "sev-common" type to encapsulate common SEV state
mdroth Aug 9, 2021
223c02e
i386/sev: Introduce 'sev-snp-guest' object
codomania Jul 7, 2021
1d94d23
i386/sev: Initialize SNP context
codomania Jul 8, 2021
065a76e
i386/sev: Add the SNP launch start context
codomania Jul 9, 2021
180c48d
i386/sev: Add support to encrypt BIOS when SEV-SNP is enabled
codomania Jul 9, 2021
56b0162
hw/i386: Add function to get SEV metadata from ovmf header
codomania Oct 23, 2021
737c833
i386/sev: Populate secrets and cpuid page and finalize the SNP launch
codomania Oct 23, 2021
df851cb
target/i386: Set SEV-SNP CPUID bit when SNP enabled
mdroth Aug 26, 2021
3d94be6
i386/sev: Add support for SNP CPUID validation
mdroth Aug 5, 2021
7203d7c
i386/sev: Update query-sev QAPI format to handle SEV-SNP
mdroth Aug 26, 2021
6f4cd86
*i386/sev: Don't return launch measurements for SEV-SNP guests
mdroth Dec 23, 2021
39ac214
qapi, i386: Move kernel-hashes to SevCommonProperties
dubek Mar 2, 2023
0286165
i386/sev: Extract build_kernel_loader_hashes
dubek Mar 2, 2023
d2a2270
i386/sev: Reorder struct declarations
dubek Mar 2, 2023
58593e8
i386/sev: Allow measured direct kernel boot on SNP
dubek Mar 2, 2023
057e559
*i386/sev: Queue up the SNP launch updates to perform at launch finish
tlendacky Feb 28, 2023
ca5526e
*kvm: Make kvm_convert_memory() non-static
mdroth Dec 5, 2023
3adccf1
*squash: snp_launch_update: convert initial payload to private
mdroth Dec 5, 2023
9b22c80
*add memory_region_init_rom_device_private
mdroth Dec 5, 2023
4b31da6
*update sev_kvm_init to set require_guest_memfd for SNP
mdroth Dec 5, 2023
1624017
*set KVM_X86_SNP_VM when creating SNP KVM instance
mdroth Dec 5, 2023
5900948
*kvm: Add kvm_has_restricted_memory() helper
mdroth Mar 6, 2023
799a6f8
*disable SMM and set ms->require_guest_memfd for SNP
mdroth Dec 6, 2023
8be7917
*automatically use guest_memfd for ROM regions
mdroth Dec 6, 2023
aded48f
*also call sev_kvm_init() for sev-snp-guest CGS object init
mdroth Dec 6, 2023
616be1e
*i386/sev: Add handling for KVM_EXIT_VMGEXIT
mdroth Apr 19, 2022
ad64c3f
*sev: combine contiguous memory attr updates
mdroth Nov 9, 2023
2702c9c
*memory fault debug
mdroth Dec 1, 2023
b8bedfd
*fix up and rework error/return code handling for PSCs
mdroth Jun 6, 2023
4297af7
*use guest_memfd for legacy ROMs
mdroth Dec 4, 2023
86dfb3a
*update headers for SNP hypervisor v11
mdroth Dec 25, 2023
3e81f8b
*drop use of KVM_GUEST_MEMFD_ALLOW_HUGEPAGE flag
mdroth Dec 30, 2023
73a0ccc
*use new VMGEXIT handling for page-state changes
mdroth Dec 30, 2023
8cbbc77
*initial support for supplying certs for extended requests
mdroth Dec 30, 2023
798d394
*fix non-SNP handling for memory regions
mdroth Jan 10, 2024
b6ee121
*skip RAMBlock notifiers for SNP
mdroth Jan 11, 2024
049f963
meson: Add optional dependency on IGVM library
roy-hopkins Jan 5, 2024
b2c88ed
backends/confidential-guest-support: Add IGVM file parameter
roy-hopkins Jan 5, 2024
623899a
backends/confidential-guest-support: Add functions to support IGVM
roy-hopkins Jan 5, 2024
929b05c
backends/igvm: Implement parsing and processing of IGVM files
roy-hopkins Jan 5, 2024
2dc62cc
i386/pc: Process IGVM file during PC initialization if present
roy-hopkins Jan 8, 2024
dab862a
i386/pc_sysfw: Ensure sysfw flash configuration does not conflict wit…
roy-hopkins Jan 8, 2024
7534bc4
i386/cpu: Fix handling of LDTR an TR in cpu_x86_load_seg_cache()
roy-hopkins Apr 2, 2024
6603801
i386/sev: Refactor setting of reset vector and initial CPU state
roy-hopkins Jan 8, 2024
251dab3
i386/sev: Implement ConfidentialGuestSupport functions for SEV
roy-hopkins Jan 8, 2024
9fc7c34
docs/system: Add documentation on support for IGVM
roy-hopkins Feb 23, 2024
896d803
i386/sev: Fix error handling in sev_get_capabilities()
roy-hopkins Apr 2, 2024
5785124
backends/confidential-guest-support: Add set_guest_policy() function
roy-hopkins Apr 2, 2024
b6fb543
backends/igvm: Process initialization sections in IGVM file
roy-hopkins Apr 2, 2024
ff68d54
backends/igvm: Handle policy for SEV guests
roy-hopkins Apr 2, 2024
0fd5b1f
i386/sev: Add implementation of CGS set_guest_policy()
roy-hopkins Apr 2, 2024
e0eece1
i386/sev: Fix error handling in sev_snp_launch_finish()
roy-hopkins Apr 2, 2024
7910d8b
i386/sev: Sync additional VMSA segment registers
roy-hopkins Apr 8, 2024
72da3a9
backends/igvm: Fix compile error when built without `--enable-igvm`
vijaydhanraj Apr 11, 2024
026267e
Merge pull request #9 from vijaydhanraj/svsm-igvm
joergroedel Apr 12, 2024
260df2b
Merge pull request #7 from roy-hopkins/snp-v3-wip-igvm_v2_idblock
joergroedel Apr 12, 2024
e2efb6f
q35: add virtio-mmio slots
kraxel Mar 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
219 changes: 200 additions & 19 deletions accel/kvm/kvm-all.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ bool kvm_msi_use_devid;
bool kvm_has_guest_debug;
static int kvm_sstep_flags;
static bool kvm_immediate_exit;
static bool kvm_guest_memfd_supported;
static uint64_t kvm_supported_memory_attributes;
static hwaddr kvm_max_slot_size = ~0;

static const KVMCapabilityInfo kvm_required_capabilites[] = {
Expand Down Expand Up @@ -292,34 +294,69 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram,
static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, bool new)
{
KVMState *s = kvm_state;
struct kvm_userspace_memory_region mem;
struct kvm_userspace_memory_region2 mem;
static int cap_user_memory2 = -1;
int ret;

if (cap_user_memory2 == -1) {
cap_user_memory2 = kvm_check_extension(s, KVM_CAP_USER_MEMORY2);
}

if (!cap_user_memory2 && slot->guest_memfd >= 0) {
error_report("%s, KVM doesn't support KVM_CAP_USER_MEMORY2,"
" which is required by guest memfd!", __func__);
exit(1);
}

mem.slot = slot->slot | (kml->as_id << 16);
mem.guest_phys_addr = slot->start_addr;
mem.userspace_addr = (unsigned long)slot->ram;
mem.flags = slot->flags;
mem.guest_memfd = slot->guest_memfd;
mem.guest_memfd_offset = slot->guest_memfd_offset;

if (slot->memory_size && !new && (mem.flags ^ slot->old_flags) & KVM_MEM_READONLY) {
/* Set the slot size to 0 before setting the slot to the desired
* value. This is needed based on KVM commit 75d61fbc. */
mem.memory_size = 0;
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);

if (cap_user_memory2) {
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION2, &mem);
} else {
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
}
if (ret < 0) {
goto err;
}
}
mem.memory_size = slot->memory_size;
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
if (cap_user_memory2) {
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION2, &mem);
} else {
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
}
slot->old_flags = mem.flags;
err:
trace_kvm_set_user_memory(mem.slot, mem.flags, mem.guest_phys_addr,
mem.memory_size, mem.userspace_addr, ret);
trace_kvm_set_user_memory(mem.slot >> 16, (uint16_t)mem.slot, mem.flags,
mem.guest_phys_addr, mem.memory_size,
mem.userspace_addr, mem.guest_memfd,
mem.guest_memfd_offset, ret);
if (ret < 0) {
error_report("%s: KVM_SET_USER_MEMORY_REGION failed, slot=%d,"
" start=0x%" PRIx64 ", size=0x%" PRIx64 ": %s",
__func__, mem.slot, slot->start_addr,
(uint64_t)mem.memory_size, strerror(errno));
if (cap_user_memory2) {
error_report("%s: KVM_SET_USER_MEMORY_REGION2 failed, slot=%d,"
" start=0x%" PRIx64 ", size=0x%" PRIx64 ","
" flags=0x%" PRIx32 ", guest_memfd=%" PRId32 ","
" guest_memfd_offset=0x%" PRIx64 ": %s",
__func__, mem.slot, slot->start_addr,
(uint64_t)mem.memory_size, mem.flags,
mem.guest_memfd, (uint64_t)mem.guest_memfd_offset,
strerror(errno));
} else {
error_report("%s: KVM_SET_USER_MEMORY_REGION failed, slot=%d,"
" start=0x%" PRIx64 ", size=0x%" PRIx64 ": %s",
__func__, mem.slot, slot->start_addr,
(uint64_t)mem.memory_size, strerror(errno));
}
}
return ret;
}
Expand Down Expand Up @@ -475,6 +512,9 @@ static int kvm_mem_flags(MemoryRegion *mr)
if (readonly && kvm_readonly_mem_allowed) {
flags |= KVM_MEM_READONLY;
}
if (memory_region_has_guest_memfd(mr)) {
flags |= KVM_MEM_GUEST_MEMFD;
}
return flags;
}

Expand Down Expand Up @@ -1266,6 +1306,44 @@ void kvm_set_max_memslot_size(hwaddr max_slot_size)
kvm_max_slot_size = max_slot_size;
}

static int kvm_set_memory_attributes(hwaddr start, hwaddr size, uint64_t attr)
{
struct kvm_memory_attributes attrs;
int r;

attrs.attributes = attr;
attrs.address = start;
attrs.size = size;
attrs.flags = 0;

r = kvm_vm_ioctl(kvm_state, KVM_SET_MEMORY_ATTRIBUTES, &attrs);
if (r) {
warn_report("%s: failed to set memory (0x%lx+%#zx) with attr 0x%lx error '%s'",
__func__, start, size, attr, strerror(errno));
}
return r;
}

int kvm_set_memory_attributes_private(hwaddr start, hwaddr size)
{
if (!(kvm_supported_memory_attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE)) {
error_report("KVM doesn't support PRIVATE memory attribute\n");
return -EINVAL;
}

return kvm_set_memory_attributes(start, size, KVM_MEMORY_ATTRIBUTE_PRIVATE);
}

int kvm_set_memory_attributes_shared(hwaddr start, hwaddr size)
{
if (!(kvm_supported_memory_attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE)) {
error_report("KVM doesn't support PRIVATE memory attribute\n");
return -EINVAL;
}

return kvm_set_memory_attributes(start, size, 0);
}

/* Called with KVMMemoryListener.slots_lock held */
static void kvm_set_phys_mem(KVMMemoryListener *kml,
MemoryRegionSection *section, bool add)
Expand Down Expand Up @@ -1362,13 +1440,26 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
mem->ram_start_offset = ram_start_offset;
mem->ram = ram;
mem->flags = kvm_mem_flags(mr);
mem->guest_memfd = mr->ram_block->guest_memfd;
mem->guest_memfd_offset = (uint8_t*)ram - mr->ram_block->host;

kvm_slot_init_dirty_bitmap(mem);
err = kvm_set_user_memory_region(kml, mem, true);
if (err) {
fprintf(stderr, "%s: error registering slot: %s\n", __func__,
strerror(-err));
abort();
}

if (memory_region_is_default_private(mr)) {
err = kvm_set_memory_attributes_private(start_addr, slot_size);
if (err) {
error_report("%s: failed to set memory attribute private: %s\n",
__func__, strerror(-err));
exit(1);
}
}

start_addr += slot_size;
ram_start_offset += slot_size;
ram += slot_size;
Expand Down Expand Up @@ -2396,6 +2487,11 @@ static int kvm_init(MachineState *ms)
}
s->as = g_new0(struct KVMAs, s->nr_as);

kvm_guest_memfd_supported = kvm_check_extension(s, KVM_CAP_GUEST_MEMFD);

ret = kvm_check_extension(s, KVM_CAP_MEMORY_ATTRIBUTES);
kvm_supported_memory_attributes = ret > 0 ? ret : 0;

if (object_property_find(OBJECT(current_machine), "kvm-type")) {
g_autofree char *kvm_type = object_property_get_str(OBJECT(current_machine),
"kvm-type",
Expand Down Expand Up @@ -2816,6 +2912,51 @@ static void kvm_eat_signals(CPUState *cpu)
} while (sigismember(&chkset, SIG_IPI));
}

int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
{
MemoryRegionSection section;
ram_addr_t offset;
RAMBlock *rb;
void *addr;
int ret = -1;

trace_kvm_convert_memory(start, size, to_private ? "shared_to_private" : "private_to_shared");
section = memory_region_find(get_system_memory(), start, size);
if (!section.mr) {
return ret;
}

if (memory_region_has_guest_memfd(section.mr)) {
if (to_private) {
ret = kvm_set_memory_attributes_private(start, size);
} else {
ret = kvm_set_memory_attributes_shared(start, size);
}

if (ret) {
memory_region_unref(section.mr);
return ret;
}

addr = memory_region_get_ram_ptr(section.mr) +
section.offset_within_region;
rb = qemu_ram_block_from_host(addr, false, &offset);
/*
* With KVM_SET_MEMORY_ATTRIBUTES by kvm_set_memory_attributes(),
* operation on underlying file descriptor is only for releasing
* unnecessary pages.
*/
ram_block_convert_range(rb, offset, size, to_private);
} else {
warn_report("Convert non guest_memfd backed memory region "
"(0x%"HWADDR_PRIx" ,+ 0x%"HWADDR_PRIx") to %s",
start, size, to_private ? "private" : "shared");
}

memory_region_unref(section.mr);
return ret;
}

int kvm_cpu_exec(CPUState *cpu)
{
struct kvm_run *run = cpu->kvm_run;
Expand Down Expand Up @@ -2883,18 +3024,20 @@ int kvm_cpu_exec(CPUState *cpu)
ret = EXCP_INTERRUPT;
break;
}
fprintf(stderr, "error: kvm run failed %s\n",
strerror(-run_ret));
if (!(run_ret == -EFAULT && run->exit_reason == KVM_EXIT_MEMORY_FAULT)) {
fprintf(stderr, "error: kvm run failed %s\n",
strerror(-run_ret));
#ifdef TARGET_PPC
if (run_ret == -EBUSY) {
fprintf(stderr,
"This is probably because your SMT is enabled.\n"
"VCPU can only run on primary threads with all "
"secondary threads offline.\n");
}
if (run_ret == -EBUSY) {
fprintf(stderr,
"This is probably because your SMT is enabled.\n"
"VCPU can only run on primary threads with all "
"secondary threads offline.\n");
}
#endif
ret = -1;
break;
ret = -1;
break;
}
}

trace_kvm_run_exit(cpu->cpu_index, run->exit_reason);
Expand Down Expand Up @@ -2981,6 +3124,18 @@ int kvm_cpu_exec(CPUState *cpu)
break;
}
break;
case KVM_EXIT_MEMORY_FAULT:
g_warning("memory fault: GPA 0x%llx size 0x%llx flags 0x%llx",
run->memory_fault.gpa, run->memory_fault.size, run->memory_fault.flags);
if (run->memory_fault.flags & ~KVM_MEMORY_EXIT_FLAG_PRIVATE) {
error_report("KVM_EXIT_MEMORY_FAULT: Unknown flag 0x%" PRIx64,
(uint64_t)run->memory_fault.flags);
ret = -1;
break;
}
ret = kvm_convert_memory(run->memory_fault.gpa, run->memory_fault.size,
run->memory_fault.flags & KVM_MEMORY_EXIT_FLAG_PRIVATE);
break;
default:
DPRINTF("kvm_arch_handle_exit\n");
ret = kvm_arch_handle_exit(cpu, run);
Expand Down Expand Up @@ -4077,3 +4232,29 @@ void query_stats_schemas_cb(StatsSchemaList **result, Error **errp)
query_stats_schema_vcpu(first_cpu, &stats_args);
}
}

int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
{
int fd;
struct kvm_create_guest_memfd guest_memfd = {
.size = size,
.flags = flags,
};

if (!kvm_guest_memfd_supported) {
error_setg(errp, "KVM doesn't support guest memfd\n");
return -EOPNOTSUPP;
}

fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_GUEST_MEMFD, &guest_memfd);
if (fd < 0) {
error_setg_errno(errp, errno, "%s: error creating kvm guest memfd\n", __func__);
}

return fd;
}

bool kvm_has_restricted_memory(void)
{
return current_machine->require_guest_memfd;
}
4 changes: 2 additions & 2 deletions accel/kvm/trace-events
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d"
kvm_irqchip_release_virq(int virq) "virq %d"
kvm_set_ioeventfd_mmio(int fd, uint64_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%" PRIx64 " val=0x%x assign: %d size: %d match: %d"
kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%x val=0x%x assign: %d size: %d match: %d"
kvm_set_user_memory(uint32_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d"
kvm_set_user_memory(uint16_t as, uint16_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, uint32_t fd, uint64_t fd_offset, int ret) "AddrSpace#%d Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " guest_memfd=%d" " guest_memfd_offset=0x%" PRIx64 " ret=%d"
kvm_clear_dirty_log(uint32_t slot, uint64_t start, uint32_t size) "slot#%"PRId32" start 0x%"PRIx64" size 0x%"PRIx32
kvm_resample_fd_notify(int gsi) "gsi %d"
kvm_dirty_ring_full(int id) "vcpu %d"
Expand All @@ -25,4 +25,4 @@ kvm_dirty_ring_reaper(const char *s) "%s"
kvm_dirty_ring_reap(uint64_t count, int64_t t) "reaped %"PRIu64" pages (took %"PRIi64" us)"
kvm_dirty_ring_reaper_kick(const char *reason) "%s"
kvm_dirty_ring_flush(int finished) "%d"

kvm_convert_memory(uint64_t start, uint64_t size, const char *msg) "start 0x%" PRIx64 " size 0x%" PRIx64 " %s"
5 changes: 5 additions & 0 deletions accel/stubs/kvm-stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,8 @@ uint32_t kvm_dirty_ring_size(void)
{
return 0;
}

bool kvm_has_restricted_memory(void)
{
return false;
}
Loading