Merge tag 'housekeeping-20240424' of https://github.com/philmd/qemu into staging
Removal of deprecated code
- Remove the Nios II target and hardware
- Remove pvrdma device and rdmacm-mux helper
- Remove GlusterFS RDMA protocol handling
- Update Sriram Yagnaraman mail address
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmYpE0YACgkQ4+MsLN6t
# wN5PIA//egomANjRHAUAf9tdjljgT/JR49ejM7iInyxspR/xaiq0TlP2kP6aDNps
# y1HAWBwfj5lGxeMgQ1mSKJGka3v2AIPWb7RbNT+9AaiWHv+sx5OrEytozUsFHLo8
# gSgRQocq0NY2a9dPbtkDqfbmq/rkCC7wgZzwroHsyOdiqYsWDKPJFleBDMjGmEaf
# colhiDmhUPgvE3NNpwfEVNh/2SzxUxY8k5FHal6qij5z56ZqBglgnziDZEvGVCZ1
# uF4Hca/kh7TV2MVsdStPbGWZYDhJ/Np/2FnRoThD1Hc4qq8d/SH997m2F94tSOud
# YeH54Vp5lmCeYgba5y8VP0ZPx/b9XnTtLvKggNdoqB+T2LBWPRt8kehqoaxvammF
# ALzbY/t2vUxL6nIVbosOaTyqVOXvynk3/Js5S0jbnlu+vP2WvvFEzfYKIs2DIA8w
# z56o/rG4KfyxF0aDB+CvLNwtJS8THqeivPqmYoKTdN9FPpN2RyBNLITrKo389ygF
# 3oWy3+xsKGIPdNFY0a4l25xntqWNhND89ejzyL9M6G1cQ9RdEmTIUGTrinPQQmfP
# oHIJMBeTdj7EqPL4LB3BR/htw9U5PobeMNYKFsRkS39PjGDqba5wbIdk3w5/Rcxa
# s/PKdspDKWPwZ5jhcLD0qxAGJFnqM2UFjPo+U8qyI3RXKXFAn0E=
# =c8Aj
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 24 Apr 2024 07:12:22 AM PDT
# gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE
# gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full]
* tag 'housekeeping-20240424' of https://github.com/philmd/qemu:
block/gluster: Remove deprecated RDMA protocol handling
hw/rdma: Remove deprecated pvrdma device and rdmacm-mux helper
hw/timer: Remove the ALTERA_TIMER model
target/nios2: Remove the deprecated Nios II target
MAINTAINERS: Update Sriram Yagnaraman mail address
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c
index b3c946d..94c828a 100644
--- a/accel/kvm/kvm-accel-ops.c
+++ b/accel/kvm/kvm-accel-ops.c
@@ -82,10 +82,10 @@
static bool kvm_cpus_are_resettable(void)
{
- return !kvm_enabled() || kvm_cpu_check_are_resettable();
+ return !kvm_enabled() || !kvm_state->guest_state_protected;
}
-#ifdef KVM_CAP_SET_GUEST_DEBUG
+#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
static int kvm_update_guest_debug_ops(CPUState *cpu)
{
return kvm_update_guest_debug(cpu, 0);
@@ -104,7 +104,7 @@
ops->synchronize_state = kvm_cpu_synchronize_state;
ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm;
-#ifdef KVM_CAP_SET_GUEST_DEBUG
+#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
ops->update_guest_debug = kvm_update_guest_debug_ops;
ops->supports_guest_debug = kvm_supports_guest_debug;
ops->insert_breakpoint = kvm_insert_breakpoint;
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 931f742..d7281b9 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -91,6 +91,8 @@
static bool kvm_has_guest_debug;
static int kvm_sstep_flags;
static bool kvm_immediate_exit;
+static uint64_t kvm_supported_memory_attributes;
+static bool kvm_guest_memfd_supported;
static hwaddr kvm_max_slot_size = ~0;
static const KVMCapabilityInfo kvm_required_capabilites[] = {
@@ -282,34 +284,58 @@
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;
int ret;
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 (kvm_guest_memfd_supported) {
+ 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 (kvm_guest_memfd_supported) {
+ 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 (kvm_guest_memfd_supported) {
+ 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;
}
@@ -464,6 +490,10 @@
if (readonly && kvm_readonly_mem_allowed) {
flags |= KVM_MEM_READONLY;
}
+ if (memory_region_has_guest_memfd(mr)) {
+ assert(kvm_guest_memfd_supported);
+ flags |= KVM_MEM_GUEST_MEMFD;
+ }
return flags;
}
@@ -1265,6 +1295,36 @@
kvm_max_slot_size = max_slot_size;
}
+static int kvm_set_memory_attributes(hwaddr start, uint64_t size, uint64_t attr)
+{
+ struct kvm_memory_attributes attrs;
+ int r;
+
+ assert((attr & kvm_supported_memory_attributes) == attr);
+ 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) {
+ error_report("failed to set memory (0x%" HWADDR_PRIx "+0x%" PRIx64 ") "
+ "with attr 0x%" PRIx64 " error '%s'",
+ start, size, attr, strerror(errno));
+ }
+ return r;
+}
+
+int kvm_set_memory_attributes_private(hwaddr start, uint64_t size)
+{
+ return kvm_set_memory_attributes(start, size, KVM_MEMORY_ATTRIBUTE_PRIVATE);
+}
+
+int kvm_set_memory_attributes_shared(hwaddr start, uint64_t size)
+{
+ 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)
@@ -1361,6 +1421,9 @@
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) {
@@ -1368,6 +1431,16 @@
strerror(-err));
abort();
}
+
+ if (memory_region_has_guest_memfd(mr)) {
+ err = kvm_set_memory_attributes_private(start_addr, slot_size);
+ if (err) {
+ error_report("%s: failed to set memory attribute private: %s",
+ __func__, strerror(-err));
+ exit(1);
+ }
+ }
+
start_addr += slot_size;
ram_start_offset += slot_size;
ram += slot_size;
@@ -2360,7 +2433,7 @@
s->sigmask_len = 8;
accel_blocker_init();
-#ifdef KVM_CAP_SET_GUEST_DEBUG
+#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
QTAILQ_INIT(&s->kvm_sw_breakpoints);
#endif
QLIST_INIT(&s->kvm_parked_vcpus);
@@ -2386,6 +2459,12 @@
goto err;
}
+ kvm_supported_memory_attributes = kvm_check_extension(s, KVM_CAP_MEMORY_ATTRIBUTES);
+ kvm_guest_memfd_supported =
+ kvm_check_extension(s, KVM_CAP_GUEST_MEMFD) &&
+ kvm_check_extension(s, KVM_CAP_USER_MEMORY2) &&
+ (kvm_supported_memory_attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE);
+
kvm_immediate_exit = kvm_check_extension(s, KVM_CAP_IMMEDIATE_EXIT);
s->nr_slots = kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS);
@@ -2544,7 +2623,7 @@
kvm_vm_attributes_allowed =
(kvm_check_extension(s, KVM_CAP_VM_ATTRIBUTES) > 0);
-#ifdef KVM_CAP_SET_GUEST_DEBUG
+#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
kvm_has_guest_debug =
(kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG) > 0);
#endif
@@ -2553,7 +2632,7 @@
if (kvm_has_guest_debug) {
kvm_sstep_flags = SSTEP_ENABLE;
-#if defined KVM_CAP_SET_GUEST_DEBUG2
+#if defined TARGET_KVM_HAVE_GUEST_DEBUG
int guest_debug_flags =
kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG2);
@@ -2696,14 +2775,9 @@
s->coalesced_flush_in_progress = false;
}
-bool kvm_cpu_check_are_resettable(void)
-{
- return kvm_arch_cpu_check_are_resettable();
-}
-
static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
{
- if (!cpu->vcpu_dirty) {
+ if (!cpu->vcpu_dirty && !kvm_state->guest_state_protected) {
int ret = kvm_arch_get_registers(cpu);
if (ret) {
error_report("Failed to get registers: %s", strerror(-ret));
@@ -2717,7 +2791,7 @@
void kvm_cpu_synchronize_state(CPUState *cpu)
{
- if (!cpu->vcpu_dirty) {
+ if (!cpu->vcpu_dirty && !kvm_state->guest_state_protected) {
run_on_cpu(cpu, do_kvm_cpu_synchronize_state, RUN_ON_CPU_NULL);
}
}
@@ -2752,7 +2826,13 @@
void kvm_cpu_synchronize_post_init(CPUState *cpu)
{
- run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
+ if (!kvm_state->guest_state_protected) {
+ /*
+ * This runs before the machine_init_done notifiers, and is the last
+ * opportunity to synchronize the state of confidential guests.
+ */
+ run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
+ }
}
static void do_kvm_cpu_synchronize_pre_loadvm(CPUState *cpu, run_on_cpu_data arg)
@@ -2820,6 +2900,94 @@
} while (sigismember(&chkset, SIG_IPI));
}
+int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
+{
+ MemoryRegionSection section;
+ ram_addr_t offset;
+ MemoryRegion *mr;
+ RAMBlock *rb;
+ void *addr;
+ int ret = -1;
+
+ trace_kvm_convert_memory(start, size, to_private ? "shared_to_private" : "private_to_shared");
+
+ if (!QEMU_PTR_IS_ALIGNED(start, qemu_real_host_page_size()) ||
+ !QEMU_PTR_IS_ALIGNED(size, qemu_real_host_page_size())) {
+ return -1;
+ }
+
+ if (!size) {
+ return -1;
+ }
+
+ section = memory_region_find(get_system_memory(), start, size);
+ mr = section.mr;
+ if (!mr) {
+ /*
+ * Ignore converting non-assigned region to shared.
+ *
+ * TDX requires vMMIO region to be shared to inject #VE to guest.
+ * OVMF issues conservatively MapGPA(shared) on 32bit PCI MMIO region,
+ * and vIO-APIC 0xFEC00000 4K page.
+ * OVMF assigns 32bit PCI MMIO region to
+ * [top of low memory: typically 2GB=0xC000000, 0xFC00000)
+ */
+ if (!to_private) {
+ return 0;
+ }
+ return -1;
+ }
+
+ if (!memory_region_has_guest_memfd(mr)) {
+ /*
+ * Because vMMIO region must be shared, guest TD may convert vMMIO
+ * region to shared explicitly. Don't complain such case. See
+ * memory_region_type() for checking if the region is MMIO region.
+ */
+ if (!to_private &&
+ !memory_region_is_ram(mr) &&
+ !memory_region_is_ram_device(mr) &&
+ !memory_region_is_rom(mr) &&
+ !memory_region_is_romd(mr)) {
+ ret = 0;
+ } else {
+ error_report("Convert non guest_memfd backed memory region "
+ "(0x%"HWADDR_PRIx" ,+ 0x%"HWADDR_PRIx") to %s",
+ start, size, to_private ? "private" : "shared");
+ }
+ goto out_unref;
+ }
+
+ if (to_private) {
+ ret = kvm_set_memory_attributes_private(start, size);
+ } else {
+ ret = kvm_set_memory_attributes_shared(start, size);
+ }
+ if (ret) {
+ goto out_unref;
+ }
+
+ addr = memory_region_get_ram_ptr(mr) + section.offset_within_region;
+ rb = qemu_ram_block_from_host(addr, false, &offset);
+
+ if (to_private) {
+ if (rb->page_size != qemu_real_host_page_size()) {
+ /*
+ * shared memory is backed by hugetlb, which is supposed to be
+ * pre-allocated and doesn't need to be discarded
+ */
+ goto out_unref;
+ }
+ ret = ram_block_discard_range(rb, offset, size);
+ } else {
+ ret = ram_block_discard_guest_memfd_range(rb, offset, size);
+ }
+
+out_unref:
+ memory_region_unref(mr);
+ return ret;
+}
+
int kvm_cpu_exec(CPUState *cpu)
{
struct kvm_run *run = cpu->kvm_run;
@@ -2887,18 +3055,20 @@
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);
@@ -2981,6 +3151,19 @@
break;
}
break;
+ case KVM_EXIT_MEMORY_FAULT:
+ trace_kvm_memory_fault(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:
ret = kvm_arch_handle_exit(cpu, run);
break;
@@ -3157,7 +3340,7 @@
return kvm_check_extension(kvm_state, KVM_CAP_ARM_USER_IRQ);
}
-#ifdef KVM_CAP_SET_GUEST_DEBUG
+#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, vaddr pc)
{
struct kvm_sw_breakpoint *bp;
@@ -3317,7 +3500,7 @@
}
}
-#endif /* !KVM_CAP_SET_GUEST_DEBUG */
+#endif /* !TARGET_KVM_HAVE_GUEST_DEBUG */
static int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset)
{
@@ -4099,3 +4282,30 @@
query_stats_schema_vcpu(first_cpu, &stats_args);
}
}
+
+void kvm_mark_guest_state_protected(void)
+{
+ kvm_state->guest_state_protected = true;
+}
+
+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 does not support guest_memfd");
+ return -1;
+ }
+
+ fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_GUEST_MEMFD, &guest_memfd);
+ if (fd < 0) {
+ error_setg_errno(errp, errno, "Error creating KVM guest_memfd");
+ return -1;
+ }
+
+ return fd;
+}
diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events
index a259025..681ccb6 100644
--- a/accel/kvm/trace-events
+++ b/accel/kvm/trace-events
@@ -15,7 +15,7 @@
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"
@@ -31,3 +31,5 @@
kvm_interrupt_exit_request(void) ""
kvm_io_window_exit(void) ""
kvm_run_exit_system_event(int cpu_index, uint32_t event_type) "cpu_index %d, system_even_type %"PRIu32
+kvm_convert_memory(uint64_t start, uint64_t size, const char *msg) "start 0x%" PRIx64 " size 0x%" PRIx64 " %s"
+kvm_memory_fault(uint64_t start, uint64_t size, uint64_t flags) "start 0x%" PRIx64 " size 0x%" PRIx64 " flags 0x%" PRIx64
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index ca38172..8e0eb22 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -129,3 +129,8 @@
{
return false;
}
+
+int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
+{
+ return -ENOSYS;
+}
diff --git a/accel/tcg/icount-common.c b/accel/tcg/icount-common.c
index a4a747d..8d3d3a7 100644
--- a/accel/tcg/icount-common.c
+++ b/accel/tcg/icount-common.c
@@ -336,10 +336,8 @@
deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL,
~QEMU_TIMER_ATTR_EXTERNAL);
if (deadline < 0) {
- static bool notified;
- if (!icount_sleep && !notified) {
- warn_report("icount sleep disabled and no active timers");
- notified = true;
+ if (!icount_sleep) {
+ warn_report_once("icount sleep disabled and no active timers");
}
return;
}
diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c
index ac3e433..3c69db7 100644
--- a/backends/hostmem-file.c
+++ b/backends/hostmem-file.c
@@ -85,6 +85,7 @@
ram_flags |= fb->readonly ? RAM_READONLY_FD : 0;
ram_flags |= fb->rom == ON_OFF_AUTO_ON ? RAM_READONLY : 0;
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
+ ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0;
ram_flags |= fb->is_pmem ? RAM_PMEM : 0;
ram_flags |= RAM_NAMED_FILE;
return memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name,
diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
index 3923ea9..745ead0 100644
--- a/backends/hostmem-memfd.c
+++ b/backends/hostmem-memfd.c
@@ -55,6 +55,7 @@
name = host_memory_backend_get_name(backend);
ram_flags = backend->share ? RAM_SHARED : 0;
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
+ ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0;
return memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name,
backend->size, ram_flags, fd, 0, errp);
}
diff --git a/backends/hostmem-ram.c b/backends/hostmem-ram.c
index d121249..f7d81af 100644
--- a/backends/hostmem-ram.c
+++ b/backends/hostmem-ram.c
@@ -30,6 +30,7 @@
name = host_memory_backend_get_name(backend);
ram_flags = backend->share ? RAM_SHARED : 0;
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
+ ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0;
return memory_region_init_ram_flags_nomigrate(&backend->mr, OBJECT(backend),
name, backend->size,
ram_flags, errp);
diff --git a/backends/hostmem.c b/backends/hostmem.c
index 81a72ce..eb9682b 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -277,6 +277,7 @@
/* TODO: convert access to globals to compat properties */
backend->merge = machine_mem_merge(machine);
backend->dump = machine_dump_guest_core(machine);
+ backend->guest_memfd = machine_require_guest_memfd(machine);
backend->reserve = true;
backend->prealloc_threads = machine->smp.cpus;
}
diff --git a/backends/iommufd.c b/backends/iommufd.c
index 62a79fa..76a0204 100644
--- a/backends/iommufd.c
+++ b/backends/iommufd.c
@@ -13,7 +13,6 @@
#include "qemu/osdep.h"
#include "sysemu/iommufd.h"
#include "qapi/error.h"
-#include "qapi/qmp/qerror.h"
#include "qemu/module.h"
#include "qom/object_interfaces.h"
#include "qemu/error-report.h"
diff --git a/block/snapshot.c b/block/snapshot.c
index 8242b4a..8fd1756 100644
--- a/block/snapshot.c
+++ b/block/snapshot.c
@@ -28,7 +28,6 @@
#include "block/qdict.h"
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qerror.h"
#include "qapi/qmp/qstring.h"
#include "qemu/option.h"
#include "sysemu/block-backend.h"
@@ -359,7 +358,8 @@
GLOBAL_STATE_CODE();
if (!drv) {
- error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
+ error_setg(errp, "Device '%s' has no medium",
+ bdrv_get_device_name(bs));
return -ENOMEDIUM;
}
if (!snapshot_id && !name) {
@@ -437,7 +437,8 @@
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!drv) {
- error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
+ error_setg(errp, "Device '%s' has no medium",
+ bdrv_get_device_name(bs));
return -ENOMEDIUM;
}
if (!snapshot_id && !name) {
diff --git a/blockdev.c b/blockdev.c
index 057601d..08eccc9 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1395,7 +1395,7 @@
bdrv_drained_begin(state->old_bs);
if (!bdrv_is_inserted(state->old_bs)) {
- error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM,
+ error_setg(errp, "Device '%s' has no medium",
bdrv_get_device_or_node_name(state->old_bs));
return;
}
diff --git a/chardev/char-fe.c b/chardev/char-fe.c
index 66cee84..b214ba3 100644
--- a/chardev/char-fe.c
+++ b/chardev/char-fe.c
@@ -24,7 +24,6 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
-#include "qapi/qmp/qerror.h"
#include "sysemu/replay.h"
#include "chardev/char-fe.h"
diff --git a/configs/targets/aarch64-softmmu.mak b/configs/targets/aarch64-softmmu.mak
index b4338e9..83c2239 100644
--- a/configs/targets/aarch64-softmmu.mak
+++ b/configs/targets/aarch64-softmmu.mak
@@ -1,5 +1,6 @@
TARGET_ARCH=aarch64
TARGET_BASE_ARCH=arm
TARGET_SUPPORTS_MTTCG=y
+TARGET_KVM_HAVE_GUEST_DEBUG=y
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml gdb-xml/aarch64-pauth.xml
TARGET_NEED_FDT=y
diff --git a/configs/targets/i386-softmmu.mak b/configs/targets/i386-softmmu.mak
index 6b3c99f..d61b507 100644
--- a/configs/targets/i386-softmmu.mak
+++ b/configs/targets/i386-softmmu.mak
@@ -1,4 +1,5 @@
TARGET_ARCH=i386
TARGET_SUPPORTS_MTTCG=y
TARGET_NEED_FDT=y
+TARGET_KVM_HAVE_GUEST_DEBUG=y
TARGET_XML_FILES= gdb-xml/i386-32bit.xml
diff --git a/configs/targets/ppc-softmmu.mak b/configs/targets/ppc-softmmu.mak
index 7744401..f3ea9c9 100644
--- a/configs/targets/ppc-softmmu.mak
+++ b/configs/targets/ppc-softmmu.mak
@@ -1,4 +1,5 @@
TARGET_ARCH=ppc
TARGET_BIG_ENDIAN=y
+TARGET_KVM_HAVE_GUEST_DEBUG=y
TARGET_XML_FILES= gdb-xml/power-core.xml gdb-xml/power-fpu.xml gdb-xml/power-altivec.xml gdb-xml/power-spe.xml
TARGET_NEED_FDT=y
diff --git a/configs/targets/ppc64-softmmu.mak b/configs/targets/ppc64-softmmu.mak
index ddf0c39..1db8d83 100644
--- a/configs/targets/ppc64-softmmu.mak
+++ b/configs/targets/ppc64-softmmu.mak
@@ -2,5 +2,6 @@
TARGET_BASE_ARCH=ppc
TARGET_BIG_ENDIAN=y
TARGET_SUPPORTS_MTTCG=y
+TARGET_KVM_HAVE_GUEST_DEBUG=y
TARGET_XML_FILES= gdb-xml/power64-core.xml gdb-xml/power-fpu.xml gdb-xml/power-altivec.xml gdb-xml/power-spe.xml gdb-xml/power-vsx.xml
TARGET_NEED_FDT=y
diff --git a/configs/targets/s390x-softmmu.mak b/configs/targets/s390x-softmmu.mak
index 70d2f9f..b22218a 100644
--- a/configs/targets/s390x-softmmu.mak
+++ b/configs/targets/s390x-softmmu.mak
@@ -1,4 +1,5 @@
TARGET_ARCH=s390x
TARGET_BIG_ENDIAN=y
TARGET_SUPPORTS_MTTCG=y
+TARGET_KVM_HAVE_GUEST_DEBUG=y
TARGET_XML_FILES= gdb-xml/s390x-core64.xml gdb-xml/s390-acr.xml gdb-xml/s390-fpr.xml gdb-xml/s390-vx.xml gdb-xml/s390-cr.xml gdb-xml/s390-virt.xml gdb-xml/s390-virt-kvm.xml gdb-xml/s390-gs.xml
diff --git a/configs/targets/x86_64-softmmu.mak b/configs/targets/x86_64-softmmu.mak
index 197817c..c5f882e 100644
--- a/configs/targets/x86_64-softmmu.mak
+++ b/configs/targets/x86_64-softmmu.mak
@@ -2,4 +2,5 @@
TARGET_BASE_ARCH=i386
TARGET_SUPPORTS_MTTCG=y
TARGET_NEED_FDT=y
+TARGET_KVM_HAVE_GUEST_DEBUG=y
TARGET_XML_FILES= gdb-xml/i386-64bit.xml
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 691e521..02583f2 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,2 +1,5 @@
+# Used by readthedocs.io
+# Should be in sync with the "installed" key of pythondeps.toml
+
sphinx==5.3.0
sphinx_rtd_theme==1.1.1
diff --git a/ebpf/meson.build b/ebpf/meson.build
index c5bf929..bff6156 100644
--- a/ebpf/meson.build
+++ b/ebpf/meson.build
@@ -1 +1 @@
-common_ss.add(when: libbpf, if_true: files('ebpf.c', 'ebpf_rss.c'), if_false: files('ebpf_rss-stub.c'))
+system_ss.add(when: libbpf, if_true: files('ebpf.c', 'ebpf_rss.c'), if_false: files('ebpf_rss-stub.c'))
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index a9a913a..c9119ef 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3223,10 +3223,17 @@
}
type_init(machvirt_machine_init);
-static void virt_machine_9_0_options(MachineClass *mc)
+static void virt_machine_9_1_options(MachineClass *mc)
{
}
-DEFINE_VIRT_MACHINE_AS_LATEST(9, 0)
+DEFINE_VIRT_MACHINE_AS_LATEST(9, 1)
+
+static void virt_machine_9_0_options(MachineClass *mc)
+{
+ virt_machine_9_1_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_0, hw_compat_9_0_len);
+}
+DEFINE_VIRT_MACHINE(9, 0)
static void virt_machine_8_2_options(MachineClass *mc)
{
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 37ede0e..582c2df 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -33,6 +33,9 @@
#include "hw/virtio/virtio-iommu.h"
#include "audio/audio.h"
+GlobalProperty hw_compat_9_0[] = {};
+const size_t hw_compat_9_0_len = G_N_ELEMENTS(hw_compat_9_0);
+
GlobalProperty hw_compat_8_2[] = {
{ "migration", "zero-page-detection", "legacy"},
{ TYPE_VIRTIO_IOMMU_PCI, "granule", "4k" },
@@ -1198,6 +1201,11 @@
return machine->mem_merge;
}
+bool machine_require_guest_memfd(MachineState *machine)
+{
+ return machine->require_guest_memfd;
+}
+
static char *cpu_slot_to_string(const CPUArchId *cpu)
{
GString *s = g_string_new(NULL);
diff --git a/hw/core/meson.build b/hw/core/meson.build
index e26f2e0..f20d414 100644
--- a/hw/core/meson.build
+++ b/hw/core/meson.build
@@ -3,7 +3,6 @@
'bus.c',
'qdev-properties.c',
'qdev.c',
- 'reset.c',
'resetcontainer.c',
'resettable.c',
'vmstate-if.c',
@@ -12,16 +11,6 @@
'clock.c',
'qdev-clock.c',
))
-if have_system
- hwcore_ss.add(files(
- 'hotplug.c',
- 'qdev-hotplug.c',
- ))
-else
- hwcore_ss.add(files(
- 'hotplug-stubs.c',
- ))
-endif
common_ss.add(files('cpu-common.c'))
common_ss.add(files('machine-smp.c'))
@@ -40,6 +29,7 @@
'cpu-sysemu.c',
'fw-path-provider.c',
'gpio.c',
+ 'hotplug.c',
'loader.c',
'machine-hmp-cmds.c',
'machine-qmp-cmds.c',
@@ -48,7 +38,9 @@
'null-machine.c',
'numa.c',
'qdev-fw.c',
+ 'qdev-hotplug.c',
'qdev-properties-system.c',
+ 'reset.c',
'sysbus.c',
'vm-change-state-handler.c',
'clock-vmstate.c',
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 7d6fa72..86a5835 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -2,7 +2,6 @@
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qapi/qapi-types-misc.h"
-#include "qapi/qmp/qerror.h"
#include "qapi/qmp/qlist.h"
#include "qemu/ctype.h"
#include "qemu/error-report.h"
@@ -792,7 +791,7 @@
break;
default:
case -EINVAL:
- error_setg(errp, QERR_PROPERTY_VALUE_BAD,
+ error_setg(errp, "Property '%s.%s' doesn't take value '%s'",
object_get_typename(obj), name, value);
break;
case -ENOENT:
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index c68d0f7..00efaf1 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -29,7 +29,6 @@
#include "qapi/error.h"
#include "qapi/qapi-events-qdev.h"
#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qerror.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
@@ -479,7 +478,8 @@
static int unattached_count;
if (dev->hotplugged && !dc->hotpluggable) {
- error_setg(errp, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj));
+ error_setg(errp, "Device '%s' does not support hotplugging",
+ object_get_typename(obj));
return;
}
diff --git a/hw/display/meson.build b/hw/display/meson.build
index f93a69f..4751aab 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -3,7 +3,7 @@
system_ss.add(when: 'CONFIG_DDC', if_true: files('i2c-ddc.c'))
system_ss.add(when: 'CONFIG_EDID', if_true: files('edid-generate.c', 'edid-region.c'))
-system_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('ramfb.c'))
+system_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('ramfb.c'), if_false: files('ramfb-stubs.c'))
system_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('ramfb-standalone.c'))
system_ss.add(when: 'CONFIG_VGA_CIRRUS', if_true: files('cirrus_vga.c'))
diff --git a/stubs/ramfb.c b/hw/display/ramfb-stubs.c
similarity index 100%
rename from stubs/ramfb.c
rename to hw/display/ramfb-stubs.c
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 77f59e8..e91a76b 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1574,22 +1574,16 @@
/* Horizontal pel panning bit 3 is only used in text mode. */
hpel = bits <= 8 ? s->params.hpel & 7 : 0;
+ bwidth = DIV_ROUND_UP(width * bits, 8); /* scanline length */
+ if (hpel) {
+ bwidth += 4;
+ }
region_start = (s->params.start_addr * 4);
- region_end = region_start + (ram_addr_t)s->params.line_offset * height;
- region_end += width * depth / 8; /* scanline length */
- region_end -= s->params.line_offset;
- if (hpel) {
- region_end += 4;
- }
- if (region_end > s->vbe_size || depth == 0 || depth == 15) {
+ region_end = region_start + (ram_addr_t)s->params.line_offset * (height - 1) + bwidth;
+ if (region_end > s->vbe_size) {
/*
- * We land here on:
- * - wraps around (can happen with cirrus vbe modes)
- * - depth == 0 (256 color palette video mode)
- * - depth == 15
- *
- * Take the safe and slow route:
+ * On wrap around take the safe and slow route:
* - create a dirty bitmap snapshot for all vga memory.
* - force shadowing (so all vga memory access goes
* through vga_read_*() helpers).
@@ -1602,6 +1596,10 @@
region_end = s->vbe_size;
force_shadow = true;
}
+ if (s->params.line_compare < height) {
+ /* split screen mode */
+ region_start = 0;
+ }
/*
* Check whether we can share the surface with the backend
@@ -1667,20 +1665,12 @@
s->params.line_compare, sr(s, VGA_SEQ_CLOCK_MODE));
#endif
addr1 = (s->params.start_addr * 4);
- bwidth = DIV_ROUND_UP(width * bits, 8);
- if (hpel) {
- bwidth += 4;
- }
y_start = -1;
d = surface_data(surface);
linesize = surface_stride(surface);
y1 = 0;
if (!full_update) {
- if (s->params.line_compare < height) {
- /* split screen mode */
- region_start = 0;
- }
snap = memory_region_snapshot_and_clear_dirty(&s->vram, region_start,
region_end - region_start,
DIRTY_MEMORY_VGA);
diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c
index 20f1926..0cc2919 100644
--- a/hw/i386/acpi-common.c
+++ b/hw/i386/acpi-common.c
@@ -107,7 +107,9 @@
acpi_table_begin(&table, table_data);
/* Local APIC Address */
build_append_int_noprefix(table_data, APIC_DEFAULT_ADDRESS, 4);
- build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */
+ /* Flags. bit 0: PCAT_COMPAT */
+ build_append_int_noprefix(table_data,
+ x86ms->pic != ON_OFF_AUTO_OFF ? 1 : 0 , 4);
for (i = 0; i < apic_ids->len; i++) {
pc_madt_cpu_entry(i, apic_ids, table_data, false);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 5c21b0c..08c7de4 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -78,6 +78,12 @@
{ "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
{ "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },
+GlobalProperty pc_compat_9_0[] = {
+ { TYPE_X86_CPU, "guest-phys-bits", "0" },
+ { "sev-guest", "legacy-vm-type", "true" },
+};
+const size_t pc_compat_9_0_len = G_N_ELEMENTS(pc_compat_9_0);
+
GlobalProperty pc_compat_8_2[] = {};
const size_t pc_compat_8_2_len = G_N_ELEMENTS(pc_compat_8_2);
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 18ba076..8850c49 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -513,13 +513,26 @@
"Use a different south bridge than PIIX3");
}
-static void pc_i440fx_9_0_machine_options(MachineClass *m)
+static void pc_i440fx_9_1_machine_options(MachineClass *m)
{
pc_i440fx_machine_options(m);
m->alias = "pc";
m->is_default = true;
}
+DEFINE_I440FX_MACHINE(v9_1, "pc-i440fx-9.1", NULL,
+ pc_i440fx_9_1_machine_options);
+
+static void pc_i440fx_9_0_machine_options(MachineClass *m)
+{
+ pc_i440fx_9_1_machine_options(m);
+ m->alias = NULL;
+ m->is_default = false;
+
+ compat_props_add(m->compat_props, hw_compat_9_0, hw_compat_9_0_len);
+ compat_props_add(m->compat_props, pc_compat_9_0, pc_compat_9_0_len);
+}
+
DEFINE_I440FX_MACHINE(v9_0, "pc-i440fx-9.0", NULL,
pc_i440fx_9_0_machine_options);
@@ -528,8 +541,6 @@
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_9_0_machine_options(m);
- m->alias = NULL;
- m->is_default = false;
compat_props_add(m->compat_props, hw_compat_8_2, hw_compat_8_2_len);
compat_props_add(m->compat_props, pc_compat_8_2, pc_compat_8_2_len);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index c7bc8a2..bb53a51 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -219,6 +219,8 @@
x86ms->above_4g_mem_size, NULL);
object_property_set_bool(phb, PCI_HOST_BYPASS_IOMMU,
pcms->default_bus_bypass_iommu, NULL);
+ object_property_set_bool(phb, PCI_HOST_PROP_SMM_RANGES,
+ x86_machine_is_smm_enabled(x86ms), NULL);
sysbus_realize_and_unref(SYS_BUS_DEVICE(phb), &error_fatal);
/* pci */
@@ -365,12 +367,23 @@
pc_q35_compat_defaults, pc_q35_compat_defaults_len);
}
-static void pc_q35_9_0_machine_options(MachineClass *m)
+static void pc_q35_9_1_machine_options(MachineClass *m)
{
pc_q35_machine_options(m);
m->alias = "q35";
}
+DEFINE_Q35_MACHINE(v9_1, "pc-q35-9.1", NULL,
+ pc_q35_9_1_machine_options);
+
+static void pc_q35_9_0_machine_options(MachineClass *m)
+{
+ pc_q35_9_1_machine_options(m);
+ m->alias = NULL;
+ compat_props_add(m->compat_props, hw_compat_9_0, hw_compat_9_0_len);
+ compat_props_add(m->compat_props, pc_compat_9_0, pc_compat_9_0_len);
+}
+
DEFINE_Q35_MACHINE(v9_0, "pc-q35-9.0", NULL,
pc_q35_9_0_machine_options);
@@ -378,7 +391,6 @@
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_9_0_machine_options(m);
- m->alias = NULL;
m->max_cpus = 1024;
compat_props_add(m->compat_props, hw_compat_8_2, hw_compat_8_2_len);
compat_props_add(m->compat_props, pc_compat_8_2, pc_compat_8_2_len);
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index ffbda48..3d5b51e 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -679,14 +679,6 @@
return dev;
}
-struct setup_data {
- uint64_t next;
- uint32_t type;
- uint32_t len;
- uint8_t data[];
-} __attribute__((packed));
-
-
/*
* The entry point into the kernel for PVH boot is different from
* the native entry point. The PVH entry is defined by the x86/HVM
@@ -1389,6 +1381,16 @@
qapi_free_SgxEPCList(list);
}
+static int x86_kvm_type(MachineState *ms, const char *vm_type)
+{
+ /*
+ * No x86 machine has a kvm-type property. If one is added that has
+ * it, it should call kvm_get_vm_type() directly or not use it at all.
+ */
+ assert(vm_type == NULL);
+ return kvm_enabled() ? kvm_get_vm_type(ms) : 0;
+}
+
static void x86_machine_initfn(Object *obj)
{
X86MachineState *x86ms = X86_MACHINE(obj);
@@ -1413,6 +1415,7 @@
mc->cpu_index_to_instance_props = x86_cpu_index_to_props;
mc->get_default_cpu_node_id = x86_get_default_cpu_node_id;
mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids;
+ mc->kvm_type = x86_kvm_type;
x86mc->save_tsc_khz = true;
x86mc->fwcfg_dma_enabled = true;
nc->nmi_monitor_handler = x86_nmi;
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index 7745cb3..006d219 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -457,11 +457,12 @@
int128_get64(section->size));
}
-static void xen_log_global_start(MemoryListener *listener)
+static bool xen_log_global_start(MemoryListener *listener, Error **errp)
{
if (xen_enabled()) {
xen_in_migration = true;
}
+ return true;
}
static void xen_log_global_stop(MemoryListener *listener)
@@ -668,7 +669,7 @@
void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
{
if (enable) {
- memory_global_dirty_log_start(GLOBAL_DIRTY_MIGRATION);
+ memory_global_dirty_log_start(GLOBAL_DIRTY_MIGRATION, errp);
} else {
memory_global_dirty_log_stop(GLOBAL_DIRTY_MIGRATION);
}
diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c
index b8e5e10..09bc9bd 100644
--- a/hw/m68k/virt.c
+++ b/hw/m68k/virt.c
@@ -357,10 +357,17 @@
} \
type_init(machvirt_machine_##major##_##minor##_init);
-static void virt_machine_9_0_options(MachineClass *mc)
+static void virt_machine_9_1_options(MachineClass *mc)
{
}
-DEFINE_VIRT_MACHINE(9, 0, true)
+DEFINE_VIRT_MACHINE(9, 1, true)
+
+static void virt_machine_9_0_options(MachineClass *mc)
+{
+ virt_machine_9_1_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_0, hw_compat_9_0_len);
+}
+DEFINE_VIRT_MACHINE(9, 0, false)
static void virt_machine_8_2_options(MachineClass *mc)
{
diff --git a/stubs/memory_device.c b/hw/mem/memory-device-stubs.c
similarity index 100%
rename from stubs/memory_device.c
rename to hw/mem/memory-device-stubs.c
diff --git a/hw/mem/meson.build b/hw/mem/meson.build
index faee1fe..1c1c6da 100644
--- a/hw/mem/meson.build
+++ b/hw/mem/meson.build
@@ -6,6 +6,7 @@
mem_ss.add(when: 'CONFIG_CXL_MEM_DEVICE', if_true: files('cxl_type3.c'))
system_ss.add(when: 'CONFIG_CXL_MEM_DEVICE', if_false: files('cxl_type3_stubs.c'))
+system_ss.add(when: 'CONFIG_MEM_DEVICE', if_false: files('memory-device-stubs.c'))
system_ss.add_all(when: 'CONFIG_MEM_DEVICE', if_true: mem_ss)
system_ss.add(when: 'CONFIG_SPARSE_MEM', if_true: files('sparse-mem.c'))
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 0d7d4e3..0b6cbae 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -179,6 +179,8 @@
mch.below_4g_mem_size, 0),
DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MEM_SIZE, Q35PCIHost,
mch.above_4g_mem_size, 0),
+ DEFINE_PROP_BOOL(PCI_HOST_PROP_SMM_RANGES, Q35PCIHost,
+ mch.has_smm_ranges, true),
DEFINE_PROP_BOOL("x-pci-hole64-fix", Q35PCIHost, pci_hole64_fix, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -214,6 +216,7 @@
/* mch's object_initialize resets the default value, set it again */
qdev_prop_set_uint64(DEVICE(s), PCI_HOST_PROP_PCI_HOLE64_SIZE,
Q35_PCI_HOST_HOLE64_SIZE_DEFAULT);
+
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "uint32",
q35_host_get_pci_hole_start,
NULL, NULL, NULL);
@@ -476,6 +479,10 @@
mch_update_pciexbar(mch);
}
+ if (!mch->has_smm_ranges) {
+ return;
+ }
+
if (ranges_overlap(address, len, MCH_HOST_BRIDGE_SMRAM,
MCH_HOST_BRIDGE_SMRAM_SIZE)) {
mch_update_smram(mch);
@@ -494,10 +501,13 @@
static void mch_update(MCHPCIState *mch)
{
mch_update_pciexbar(mch);
+
mch_update_pam(mch);
- mch_update_smram(mch);
- mch_update_ext_tseg_mbytes(mch);
- mch_update_smbase_smram(mch);
+ if (mch->has_smm_ranges) {
+ mch_update_smram(mch);
+ mch_update_ext_tseg_mbytes(mch);
+ mch_update_smbase_smram(mch);
+ }
/*
* pci hole goes from end-of-low-ram to io-apic.
@@ -538,19 +548,21 @@
pci_set_quad(d->config + MCH_HOST_BRIDGE_PCIEXBAR,
MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT);
- d->config[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT;
- d->config[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_DEFAULT;
- d->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK;
- d->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK;
+ if (mch->has_smm_ranges) {
+ d->config[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT;
+ d->config[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_DEFAULT;
+ d->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK;
+ d->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK;
- if (mch->ext_tseg_mbytes > 0) {
- pci_set_word(d->config + MCH_HOST_BRIDGE_EXT_TSEG_MBYTES,
- MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_QUERY);
+ if (mch->ext_tseg_mbytes > 0) {
+ pci_set_word(d->config + MCH_HOST_BRIDGE_EXT_TSEG_MBYTES,
+ MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_QUERY);
+ }
+
+ d->config[MCH_HOST_BRIDGE_F_SMBASE] = 0;
+ d->wmask[MCH_HOST_BRIDGE_F_SMBASE] = 0xff;
}
- d->config[MCH_HOST_BRIDGE_F_SMBASE] = 0;
- d->wmask[MCH_HOST_BRIDGE_F_SMBASE] = 0xff;
-
mch_update(mch);
}
@@ -568,6 +580,20 @@
/* setup pci memory mapping */
pc_pci_as_mapping_init(mch->system_memory, mch->pci_address_space);
+ /* PAM */
+ init_pam(&mch->pam_regions[0], OBJECT(mch), mch->ram_memory,
+ mch->system_memory, mch->pci_address_space,
+ PAM_BIOS_BASE, PAM_BIOS_SIZE);
+ for (i = 0; i < ARRAY_SIZE(mch->pam_regions) - 1; ++i) {
+ init_pam(&mch->pam_regions[i + 1], OBJECT(mch), mch->ram_memory,
+ mch->system_memory, mch->pci_address_space,
+ PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
+ }
+
+ if (!mch->has_smm_ranges) {
+ return;
+ }
+
/* if *disabled* show SMRAM to all CPUs */
memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region",
mch->pci_address_space, MCH_HOST_BRIDGE_SMRAM_C_BASE,
@@ -634,15 +660,6 @@
object_property_add_const_link(qdev_get_machine(), "smram",
OBJECT(&mch->smram));
-
- init_pam(&mch->pam_regions[0], OBJECT(mch), mch->ram_memory,
- mch->system_memory, mch->pci_address_space,
- PAM_BIOS_BASE, PAM_BIOS_SIZE);
- for (i = 0; i < ARRAY_SIZE(mch->pam_regions) - 1; ++i) {
- init_pam(&mch->pam_regions[i + 1], OBJECT(mch), mch->ram_memory,
- mch->system_memory, mch->pci_address_space,
- PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
- }
}
uint64_t mch_mcfg_base(void)
diff --git a/hw/ppc/pef.c b/hw/ppc/pef.c
index d28ed3b..4755334 100644
--- a/hw/ppc/pef.c
+++ b/hw/ppc/pef.c
@@ -15,7 +15,6 @@
#include "sysemu/kvm.h"
#include "migration/blocker.h"
#include "exec/confidential-guest-support.h"
-#include "hw/ppc/pef.h"
#define TYPE_PEF_GUEST "pef-guest"
OBJECT_DECLARE_SIMPLE_TYPE(PefGuest, PEF_GUEST)
@@ -93,7 +92,7 @@
#endif
}
-int pef_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
+static int pef_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
{
if (!object_dynamic_cast(OBJECT(cgs), TYPE_PEF_GUEST)) {
return 0;
@@ -107,7 +106,7 @@
return kvmppc_svm_init(cgs, errp);
}
-int pef_kvm_reset(ConfidentialGuestSupport *cgs, Error **errp)
+static int pef_kvm_reset(ConfidentialGuestSupport *cgs, Error **errp)
{
if (!object_dynamic_cast(OBJECT(cgs), TYPE_PEF_GUEST)) {
return 0;
@@ -131,6 +130,10 @@
static void pef_guest_class_init(ObjectClass *oc, void *data)
{
+ ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
+
+ klass->kvm_init = pef_kvm_init;
+ klass->kvm_reset = pef_kvm_reset;
}
static void pef_guest_init(Object *obj)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index e9bc97f..d2d1e31 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -75,6 +75,7 @@
#include "hw/virtio/vhost-scsi-common.h"
#include "exec/ram_addr.h"
+#include "exec/confidential-guest-support.h"
#include "hw/usb.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
@@ -87,7 +88,6 @@
#include "hw/ppc/spapr_tpm_proxy.h"
#include "hw/ppc/spapr_nvdimm.h"
#include "hw/ppc/spapr_numa.h"
-#include "hw/ppc/pef.h"
#include "monitor/monitor.h"
@@ -1715,7 +1715,9 @@
qemu_guest_getrandom_nofail(spapr->fdt_rng_seed, 32);
}
- pef_kvm_reset(machine->cgs, &error_fatal);
+ if (machine->cgs) {
+ confidential_guest_kvm_reset(machine->cgs, &error_fatal);
+ }
spapr_caps_apply(spapr);
spapr_nested_reset(spapr);
@@ -2172,7 +2174,7 @@
}
};
-static int htab_save_setup(QEMUFile *f, void *opaque)
+static int htab_save_setup(QEMUFile *f, void *opaque, Error **errp)
{
SpaprMachineState *spapr = opaque;
@@ -2841,7 +2843,9 @@
/*
* if Secure VM (PEF) support is configured, then initialize it
*/
- pef_kvm_init(machine->cgs, &error_fatal);
+ if (machine->cgs) {
+ confidential_guest_kvm_init(machine->cgs, &error_fatal);
+ }
msi_nonbroken = true;
@@ -4806,14 +4810,25 @@
type_init(spapr_machine_register_##suffix)
/*
- * pseries-9.0
+ * pseries-9.1
*/
-static void spapr_machine_9_0_class_options(MachineClass *mc)
+static void spapr_machine_9_1_class_options(MachineClass *mc)
{
/* Defaults for the latest behaviour inherited from the base class */
}
-DEFINE_SPAPR_MACHINE(9_0, "9.0", true);
+DEFINE_SPAPR_MACHINE(9_1, "9.1", true);
+
+/*
+ * pseries-9.0
+ */
+static void spapr_machine_9_0_class_options(MachineClass *mc)
+{
+ spapr_machine_9_1_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_0, hw_compat_9_0_len);
+}
+
+DEFINE_SPAPR_MACHINE(9_0, "9.0", false);
/*
* pseries-8.2
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 25e0295..72cfba4 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -39,7 +39,6 @@
#include "trace.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
-#include "qapi/qmp/qerror.h"
#include "hw/ppc/fdt.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_bus.h"
@@ -1554,7 +1553,7 @@
* we need to let them know it's not enabled
*/
if (plugged_dev->hotplugged) {
- error_setg(errp, QERR_BUS_NO_HOTPLUG,
+ error_setg(errp, "Bus '%s' does not support hotplugging",
phb->parent_obj.bus->qbus.name);
return;
}
@@ -1675,7 +1674,7 @@
SpaprDrc *drc = drc_from_dev(phb, pdev);
if (!phb->dr_enabled) {
- error_setg(errp, QERR_BUS_NO_HOTPLUG,
+ error_setg(errp, "Bus '%s' does not support hotplugging",
phb->parent_obj.bus->qbus.name);
return;
}
diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c
index 24cd013..eeaa811 100644
--- a/hw/s390x/s390-stattrib-kvm.c
+++ b/hw/s390x/s390-stattrib-kvm.c
@@ -17,6 +17,7 @@
#include "sysemu/kvm.h"
#include "exec/ram_addr.h"
#include "kvm/kvm_s390x.h"
+#include "qapi/error.h"
Object *kvm_s390_stattrib_create(void)
{
@@ -137,14 +138,21 @@
}
}
-static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val)
+static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val,
+ Error **errp)
{
struct kvm_device_attr attr = {
.group = KVM_S390_VM_MIGRATION,
.attr = val,
.addr = 0,
};
- return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+ int r;
+
+ r = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+ if (r) {
+ error_setg_errno(errp, -r, "setting KVM_S390_VM_MIGRATION failed");
+ }
+ return r;
}
static long long kvm_s390_stattrib_get_dirtycount(S390StAttribState *sa)
diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c
index c483b62..bc04187 100644
--- a/hw/s390x/s390-stattrib.c
+++ b/hw/s390x/s390-stattrib.c
@@ -60,11 +60,13 @@
S390StAttribState *sas = s390_get_stattrib_device();
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
uint64_t what = qdict_get_int(qdict, "mode");
+ Error *local_err = NULL;
int r;
- r = sac->set_migrationmode(sas, what);
+ r = sac->set_migrationmode(sas, what, &local_err);
if (r < 0) {
- monitor_printf(mon, "Error: %s", strerror(-r));
+ monitor_printf(mon, "Error: %s", error_get_pretty(local_err));
+ error_free(local_err);
}
}
@@ -166,7 +168,7 @@
return ret;
}
-static int cmma_save_setup(QEMUFile *f, void *opaque)
+static int cmma_save_setup(QEMUFile *f, void *opaque, Error **errp)
{
S390StAttribState *sas = S390_STATTRIB(opaque);
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
@@ -175,7 +177,7 @@
* Signal that we want to start a migration, thus needing PGSTE dirty
* tracking.
*/
- res = sac->set_migrationmode(sas, 1);
+ res = sac->set_migrationmode(sas, true, errp);
if (res) {
return res;
}
@@ -260,7 +262,7 @@
{
S390StAttribState *sas = S390_STATTRIB(opaque);
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
- sac->set_migrationmode(sas, 0);
+ sac->set_migrationmode(sas, false, NULL);
}
static bool cmma_active(void *opaque)
@@ -293,7 +295,8 @@
{
return 0;
}
-static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value)
+static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value,
+ Error **errp)
{
return 0;
}
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index b1dcb38..4dcc213 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -14,6 +14,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "exec/ram_addr.h"
+#include "exec/confidential-guest-support.h"
#include "hw/s390x/s390-virtio-hcall.h"
#include "hw/s390x/sclp.h"
#include "hw/s390x/s390_flic.h"
@@ -260,7 +261,9 @@
s390_init_cpus(machine);
/* Need CPU model to be determined before we can set up PV */
- s390_pv_init(machine->cgs, &error_fatal);
+ if (machine->cgs) {
+ confidential_guest_kvm_init(machine->cgs, &error_fatal);
+ }
s390_flic_init();
@@ -859,14 +862,26 @@
} \
type_init(ccw_machine_register_##suffix)
+static void ccw_machine_9_1_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_9_1_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE(9_1, "9.1", true);
+
static void ccw_machine_9_0_instance_options(MachineState *machine)
{
+ ccw_machine_9_1_instance_options(machine);
}
static void ccw_machine_9_0_class_options(MachineClass *mc)
{
+ ccw_machine_9_1_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_0, hw_compat_9_0_len);
}
-DEFINE_CCW_MACHINE(9_0, "9.0", true);
+DEFINE_CCW_MACHINE(9_0, "9.0", false);
static void ccw_machine_8_2_instance_options(MachineState *machine)
{
diff --git a/stubs/usb-dev-stub.c b/hw/usb/bus-stub.c
similarity index 82%
rename from stubs/usb-dev-stub.c
rename to hw/usb/bus-stub.c
index aa55769..fcabe84 100644
--- a/stubs/usb-dev-stub.c
+++ b/hw/usb/bus-stub.c
@@ -26,8 +26,3 @@
error_setg(errp, "Support for USB devices not built-in");
return NULL;
}
-
-void hmp_info_usb(Monitor *mon, const QDict *qdict)
-{
- monitor_printf(mon, "Support for USB devices not built-in\n");
-}
diff --git a/hw/usb/meson.build b/hw/usb/meson.build
index aac3bb3..23f7f7a 100644
--- a/hw/usb/meson.build
+++ b/hw/usb/meson.build
@@ -9,7 +9,7 @@
'desc-msos.c',
'libhw.c',
'pcap.c',
-))
+), if_false: files('bus-stub.c'))
# usb host adapters
system_ss.add(when: 'CONFIG_USB_UHCI', if_true: files('hcd-uhci.c'))
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 011ceaa..8f9cbdc 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -1066,7 +1066,8 @@
return ret;
}
-static void vfio_listener_log_global_start(MemoryListener *listener)
+static bool vfio_listener_log_global_start(MemoryListener *listener,
+ Error **errp)
{
VFIOContainerBase *bcontainer = container_of(listener, VFIOContainerBase,
listener);
@@ -1083,6 +1084,7 @@
ret, strerror(-ret));
vfio_set_migration_error(ret);
}
+ return !ret;
}
static void vfio_listener_log_global_stop(MemoryListener *listener)
diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
index 1149c6b..06ae409 100644
--- a/hw/vfio/migration.c
+++ b/hw/vfio/migration.c
@@ -376,11 +376,12 @@
return 0;
}
-static int vfio_save_setup(QEMUFile *f, void *opaque)
+static int vfio_save_setup(QEMUFile *f, void *opaque, Error **errp)
{
VFIODevice *vbasedev = opaque;
VFIOMigration *migration = vbasedev->migration;
uint64_t stop_copy_size = VFIO_MIG_DEFAULT_DATA_BUFFER_SIZE;
+ int ret;
qemu_put_be64(f, VFIO_MIG_FLAG_DEV_SETUP_STATE);
@@ -389,19 +390,19 @@
stop_copy_size);
migration->data_buffer = g_try_malloc0(migration->data_buffer_size);
if (!migration->data_buffer) {
- error_report("%s: Failed to allocate migration data buffer",
- vbasedev->name);
+ error_setg(errp, "%s: Failed to allocate migration data buffer",
+ vbasedev->name);
return -ENOMEM;
}
if (vfio_precopy_supported(vbasedev)) {
- int ret;
-
switch (migration->device_state) {
case VFIO_DEVICE_STATE_RUNNING:
ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_PRE_COPY,
VFIO_DEVICE_STATE_RUNNING);
if (ret) {
+ error_setg(errp, "%s: Failed to set new PRE_COPY state",
+ vbasedev->name);
return ret;
}
@@ -412,6 +413,8 @@
/* vfio_save_complete_precopy() will go to STOP_COPY */
break;
default:
+ error_setg(errp, "%s: Invalid device state %d", vbasedev->name,
+ migration->device_state);
return -EINVAL;
}
}
@@ -420,7 +423,12 @@
qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE);
- return qemu_file_get_error(f);
+ ret = qemu_file_get_error(f);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "%s: save setup failed", vbasedev->name);
+ }
+
+ return ret;
}
static void vfio_save_cleanup(void *opaque)
@@ -580,12 +588,17 @@
}
}
-static int vfio_load_setup(QEMUFile *f, void *opaque)
+static int vfio_load_setup(QEMUFile *f, void *opaque, Error **errp)
{
VFIODevice *vbasedev = opaque;
+ int ret;
- return vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_RESUMING,
+ ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_RESUMING,
vbasedev->migration->device_state);
+ if (ret) {
+ error_setg(errp, "%s: Failed to set RESUMING state", vbasedev->name);
+ }
+ return ret;
}
static int vfio_load_cleanup(void *opaque)
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index d7f18c9..621fc65 100644
--- a/hw/virtio/meson.build
+++ b/hw/virtio/meson.build
@@ -87,6 +87,8 @@
system_ss.add_all(when: 'CONFIG_VIRTIO', if_true: system_virtio_ss)
system_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c'))
system_ss.add(when: 'CONFIG_VIRTIO', if_false: files('virtio-stub.c'))
+system_ss.add(when: 'CONFIG_VIRTIO_MD', if_false: files('virtio-md-stubs.c'))
+
system_ss.add(files('virtio-hmp-cmds.c'))
specific_ss.add_all(when: 'CONFIG_VIRTIO', if_true: specific_virtio_ss)
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index f50180e..4acd77e 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1044,7 +1044,7 @@
return r;
}
-static void vhost_log_global_start(MemoryListener *listener)
+static bool vhost_log_global_start(MemoryListener *listener, Error **errp)
{
int r;
@@ -1052,6 +1052,7 @@
if (r < 0) {
abort();
}
+ return true;
}
static void vhost_log_global_stop(MemoryListener *listener)
diff --git a/stubs/virtio-md-pci.c b/hw/virtio/virtio-md-stubs.c
similarity index 100%
rename from stubs/virtio-md-pci.c
rename to hw/virtio/virtio-md-stubs.c
diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h
index ba2dd4b..e5b188c 100644
--- a/include/exec/confidential-guest-support.h
+++ b/include/exec/confidential-guest-support.h
@@ -23,7 +23,10 @@
#include "qom/object.h"
#define TYPE_CONFIDENTIAL_GUEST_SUPPORT "confidential-guest-support"
-OBJECT_DECLARE_SIMPLE_TYPE(ConfidentialGuestSupport, CONFIDENTIAL_GUEST_SUPPORT)
+OBJECT_DECLARE_TYPE(ConfidentialGuestSupport,
+ ConfidentialGuestSupportClass,
+ CONFIDENTIAL_GUEST_SUPPORT)
+
struct ConfidentialGuestSupport {
Object parent;
@@ -55,8 +58,37 @@
typedef struct ConfidentialGuestSupportClass {
ObjectClass parent;
+
+ int (*kvm_init)(ConfidentialGuestSupport *cgs, Error **errp);
+ int (*kvm_reset)(ConfidentialGuestSupport *cgs, Error **errp);
} ConfidentialGuestSupportClass;
+static inline int confidential_guest_kvm_init(ConfidentialGuestSupport *cgs,
+ Error **errp)
+{
+ ConfidentialGuestSupportClass *klass;
+
+ klass = CONFIDENTIAL_GUEST_SUPPORT_GET_CLASS(cgs);
+ if (klass->kvm_init) {
+ return klass->kvm_init(cgs, errp);
+ }
+
+ return 0;
+}
+
+static inline int confidential_guest_kvm_reset(ConfidentialGuestSupport *cgs,
+ Error **errp)
+{
+ ConfidentialGuestSupportClass *klass;
+
+ klass = CONFIDENTIAL_GUEST_SUPPORT_GET_CLASS(cgs);
+ if (klass->kvm_reset) {
+ return klass->kvm_reset(cgs, errp);
+ }
+
+ return 0;
+}
+
#endif /* !CONFIG_USER_ONLY */
#endif /* QEMU_CONFIDENTIAL_GUEST_SUPPORT_H */
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 6346df1..6d53188 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -159,6 +159,8 @@
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque);
int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length);
+int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t start,
+ size_t length);
#endif
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 8626a35..dbb1bad 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -243,6 +243,9 @@
/* RAM FD is opened read-only */
#define RAM_READONLY_FD (1 << 11)
+/* RAM can be private that has kvm guest memfd backend */
+#define RAM_GUEST_MEMFD (1 << 12)
+
static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn,
IOMMUNotifierFlag flags,
hwaddr start, hwaddr end,
@@ -998,8 +1001,11 @@
* active at that time.
*
* @listener: The #MemoryListener.
+ * @errp: pointer to Error*, to store an error if it happens.
+ *
+ * Return: true on success, else false setting @errp with error.
*/
- void (*log_global_start)(MemoryListener *listener);
+ bool (*log_global_start)(MemoryListener *listener, Error **errp);
/**
* @log_global_stop:
@@ -1307,7 +1313,8 @@
* @name: Region name, becomes part of RAMBlock name used in migration stream
* must be unique within any device
* @size: size of the region.
- * @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_NORESERVE.
+ * @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_NORESERVE,
+ * RAM_GUEST_MEMFD.
* @errp: pointer to Error*, to store an error if it happens.
*
* Note that this function does not do anything to cause the data in the
@@ -1369,7 +1376,7 @@
* (getpagesize()) will be used.
* @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM,
* RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY,
- * RAM_READONLY_FD
+ * RAM_READONLY_FD, RAM_GUEST_MEMFD
* @path: the path in which to allocate the RAM.
* @offset: offset within the file referenced by path
* @errp: pointer to Error*, to store an error if it happens.
@@ -1399,7 +1406,7 @@
* @size: size of the region.
* @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM,
* RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY,
- * RAM_READONLY_FD
+ * RAM_READONLY_FD, RAM_GUEST_MEMFD
* @fd: the fd to mmap.
* @offset: offset within the file referenced by fd
* @errp: pointer to Error*, to store an error if it happens.
@@ -1723,6 +1730,16 @@
bool memory_region_is_protected(MemoryRegion *mr);
/**
+ * memory_region_has_guest_memfd: check whether a memory region has guest_memfd
+ * associated
+ *
+ * Returns %true if a memory region's ram_block has valid guest_memfd assigned.
+ *
+ * @mr: the memory region being queried
+ */
+bool memory_region_has_guest_memfd(MemoryRegion *mr);
+
+/**
* memory_region_get_iommu: check whether a memory region is an iommu
*
* Returns pointer to IOMMUMemoryRegion if a memory region is an iommu,
@@ -2567,8 +2584,11 @@
* memory_global_dirty_log_start: begin dirty logging for all regions
*
* @flags: purpose of starting dirty log, migration or dirty rate
+ * @errp: pointer to Error*, to store an error if it happens.
+ *
+ * Return: true on success, else false setting @errp with error.
*/
-void memory_global_dirty_log_start(unsigned int flags);
+bool memory_global_dirty_log_start(unsigned int flags, Error **errp);
/**
* memory_global_dirty_log_stop: end dirty logging for all regions
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index de45ba7..07c8f86 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -110,7 +110,7 @@
* @mr: the memory region where the ram block is
* @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM,
* RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY,
- * RAM_READONLY_FD
+ * RAM_READONLY_FD, RAM_GUEST_MEMFD
* @mem_path or @fd: specify the backing file or device
* @offset: Offset into target file
* @errp: pointer to Error*, to store an error if it happens
diff --git a/include/exec/ramblock.h b/include/exec/ramblock.h
index 848915e..0babd10 100644
--- a/include/exec/ramblock.h
+++ b/include/exec/ramblock.h
@@ -41,6 +41,7 @@
QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers;
int fd;
uint64_t fd_offset;
+ int guest_memfd;
size_t page_size;
/* dirty bitmap used during migration */
unsigned long *bmap;
@@ -57,7 +58,7 @@
off_t bitmap_offset;
uint64_t pages_offset;
- /* bitmap of already received pages in postcopy */
+ /* Bitmap of already received pages. Only used on destination side. */
unsigned long *receivedmap;
/*
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 8b8f6d5..69c1ba4 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -36,6 +36,7 @@
int machine_phandle_start(MachineState *machine);
bool machine_dump_guest_core(MachineState *machine);
bool machine_mem_merge(MachineState *machine);
+bool machine_require_guest_memfd(MachineState *machine);
HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine);
void machine_set_cpu_numa_node(MachineState *machine,
const CpuInstanceProperties *props,
@@ -370,6 +371,7 @@
char *dt_compatible;
bool dump_guest_core;
bool mem_merge;
+ bool require_guest_memfd;
bool usb;
bool usb_disabled;
char *firmware;
@@ -425,6 +427,9 @@
} \
type_init(machine_initfn##_register_types)
+extern GlobalProperty hw_compat_9_0[];
+extern const size_t hw_compat_9_0_len;
+
extern GlobalProperty hw_compat_8_2[];
extern const size_t hw_compat_8_2_len;
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 27a6807..e522909 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -161,6 +161,7 @@
#define PCI_HOST_PROP_PCI_HOLE64_SIZE "pci-hole64-size"
#define PCI_HOST_BELOW_4G_MEM_SIZE "below-4g-mem-size"
#define PCI_HOST_ABOVE_4G_MEM_SIZE "above-4g-mem-size"
+#define PCI_HOST_PROP_SMM_RANGES "smm-ranges"
void pc_pci_as_mapping_init(MemoryRegion *system_memory,
@@ -198,6 +199,9 @@
/* sgx.c */
void pc_machine_init_sgx_epc(PCMachineState *pcms);
+extern GlobalProperty pc_compat_9_0[];
+extern const size_t pc_compat_9_0_len;
+
extern GlobalProperty pc_compat_8_2[];
extern const size_t pc_compat_8_2_len;
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
index bafcbe6..22fadfa 100644
--- a/include/hw/pci-host/q35.h
+++ b/include/hw/pci-host/q35.h
@@ -50,6 +50,7 @@
MemoryRegion tseg_blackhole, tseg_window;
MemoryRegion smbase_blackhole, smbase_window;
bool has_smram_at_smbase;
+ bool has_smm_ranges;
Range pci_hole;
uint64_t below_4g_mem_size;
uint64_t above_4g_mem_size;
diff --git a/include/hw/ppc/pef.h b/include/hw/ppc/pef.h
deleted file mode 100644
index 707dbe5..0000000
--- a/include/hw/ppc/pef.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * PEF (Protected Execution Facility) for POWER support
- *
- * Copyright Red Hat.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef HW_PPC_PEF_H
-#define HW_PPC_PEF_H
-
-int pef_kvm_init(ConfidentialGuestSupport *cgs, Error **errp);
-int pef_kvm_reset(ConfidentialGuestSupport *cgs, Error **errp);
-
-#endif /* HW_PPC_PEF_H */
diff --git a/include/hw/s390x/storage-attributes.h b/include/hw/s390x/storage-attributes.h
index 5239eb5..8921a04 100644
--- a/include/hw/s390x/storage-attributes.h
+++ b/include/hw/s390x/storage-attributes.h
@@ -39,7 +39,7 @@
int (*set_stattr)(S390StAttribState *sa, uint64_t start_gfn,
uint32_t count, uint8_t *values);
void (*synchronize)(S390StAttribState *sa);
- int (*set_migrationmode)(S390StAttribState *sa, bool value);
+ int (*set_migrationmode)(S390StAttribState *sa, bool value, Error **errp);
int (*get_active)(S390StAttribState *sa);
long long (*get_dirtycount)(S390StAttribState *sa);
};
diff --git a/include/migration/register.h b/include/migration/register.h
index d7b70a8..f60e797 100644
--- a/include/migration/register.h
+++ b/include/migration/register.h
@@ -60,10 +60,11 @@
*
* @f: QEMUFile where to send the data
* @opaque: data pointer passed to register_savevm_live()
+ * @errp: pointer to Error*, to store an error if it happens.
*
* Returns zero to indicate success and negative for error
*/
- int (*save_setup)(QEMUFile *f, void *opaque);
+ int (*save_setup)(QEMUFile *f, void *opaque, Error **errp);
/**
* @save_cleanup
@@ -233,10 +234,11 @@
*
* @f: QEMUFile where to receive the data
* @opaque: data pointer passed to register_savevm_live()
+ * @errp: pointer to Error*, to store an error if it happens.
*
* Returns zero to indicate success and negative for error
*/
- int (*load_setup)(QEMUFile *f, void *opaque);
+ int (*load_setup)(QEMUFile *f, void *opaque, Error **errp);
/**
* @load_cleanup
diff --git a/include/qapi/qmp/qerror.h b/include/qapi/qmp/qerror.h
index 0c2689c..00b18e9 100644
--- a/include/qapi/qmp/qerror.h
+++ b/include/qapi/qmp/qerror.h
@@ -17,36 +17,15 @@
* add new ones!
*/
-#define QERR_BUS_NO_HOTPLUG \
- "Bus '%s' does not support hotplugging"
-
-#define QERR_DEVICE_HAS_NO_MEDIUM \
- "Device '%s' has no medium"
-
-#define QERR_DEVICE_NO_HOTPLUG \
- "Device '%s' does not support hotplugging"
-
-#define QERR_INVALID_PARAMETER \
- "Invalid parameter '%s'"
-
-#define QERR_INVALID_PARAMETER_TYPE \
- "Invalid parameter type for '%s', expected: %s"
-
#define QERR_INVALID_PARAMETER_VALUE \
"Parameter '%s' expects %s"
#define QERR_IO_ERROR \
"An IO error has occurred"
-#define QERR_MIGRATION_ACTIVE \
- "There's a migration process in progress"
-
#define QERR_MISSING_PARAMETER \
"Parameter '%s' is missing"
-#define QERR_PROPERTY_VALUE_BAD \
- "Property '%s.%s' doesn't take value '%s'"
-
#define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
"Property %s.%s doesn't take value %" PRId64 " (minimum: %" PRId64 ", maximum: %" PRId64 ")"
diff --git a/include/qemu/config-file.h b/include/qemu/config-file.h
index b82a778..51b310f 100644
--- a/include/qemu/config-file.h
+++ b/include/qemu/config-file.h
@@ -8,6 +8,9 @@
QemuOptsList *qemu_find_opts_err(const char *group, Error **errp);
QemuOpts *qemu_find_opts_singleton(const char *group);
+extern QemuOptsList *vm_config_groups[];
+extern QemuOptsList *drive_config_groups[];
+
void qemu_add_opts(QemuOptsList *list);
void qemu_add_drive_opts(QemuOptsList *list);
int qemu_global_option(const char *str);
diff --git a/include/standard-headers/asm-x86/bootparam.h b/include/standard-headers/asm-x86/bootparam.h
index 0b06d2b..b582a10 100644
--- a/include/standard-headers/asm-x86/bootparam.h
+++ b/include/standard-headers/asm-x86/bootparam.h
@@ -2,21 +2,7 @@
#ifndef _ASM_X86_BOOTPARAM_H
#define _ASM_X86_BOOTPARAM_H
-/* setup_data/setup_indirect types */
-#define SETUP_NONE 0
-#define SETUP_E820_EXT 1
-#define SETUP_DTB 2
-#define SETUP_PCI 3
-#define SETUP_EFI 4
-#define SETUP_APPLE_PROPERTIES 5
-#define SETUP_JAILHOUSE 6
-#define SETUP_CC_BLOB 7
-#define SETUP_IMA 8
-#define SETUP_RNG_SEED 9
-#define SETUP_ENUM_MAX SETUP_RNG_SEED
-
-#define SETUP_INDIRECT (1<<31)
-#define SETUP_TYPE_MAX (SETUP_ENUM_MAX | SETUP_INDIRECT)
+#include "standard-headers/asm-x86/setup_data.h"
/* ram_size flags */
#define RAMDISK_IMAGE_START_MASK 0x07FF
@@ -38,6 +24,7 @@
#define XLF_EFI_KEXEC (1<<4)
#define XLF_5LEVEL (1<<5)
#define XLF_5LEVEL_ENABLED (1<<6)
+#define XLF_MEM_ENCRYPTION (1<<7)
#endif /* _ASM_X86_BOOTPARAM_H */
diff --git a/include/standard-headers/asm-x86/kvm_para.h b/include/standard-headers/asm-x86/kvm_para.h
index f0235e5..9a011d2 100644
--- a/include/standard-headers/asm-x86/kvm_para.h
+++ b/include/standard-headers/asm-x86/kvm_para.h
@@ -92,7 +92,7 @@
#define KVM_ASYNC_PF_DELIVERY_AS_INT (1 << 3)
/* MSR_KVM_ASYNC_PF_INT */
-#define KVM_ASYNC_PF_VEC_MASK GENMASK(7, 0)
+#define KVM_ASYNC_PF_VEC_MASK __GENMASK(7, 0)
/* MSR_KVM_MIGRATION_CONTROL */
#define KVM_MIGRATION_READY (1 << 0)
@@ -142,7 +142,6 @@
uint32_t token;
uint8_t pad[56];
- uint32_t enabled;
};
#define KVM_PV_EOI_BIT 0
diff --git a/include/standard-headers/asm-x86/setup_data.h b/include/standard-headers/asm-x86/setup_data.h
new file mode 100644
index 0000000..09355f5
--- /dev/null
+++ b/include/standard-headers/asm-x86/setup_data.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _ASM_X86_SETUP_DATA_H
+#define _ASM_X86_SETUP_DATA_H
+
+/* setup_data/setup_indirect types */
+#define SETUP_NONE 0
+#define SETUP_E820_EXT 1
+#define SETUP_DTB 2
+#define SETUP_PCI 3
+#define SETUP_EFI 4
+#define SETUP_APPLE_PROPERTIES 5
+#define SETUP_JAILHOUSE 6
+#define SETUP_CC_BLOB 7
+#define SETUP_IMA 8
+#define SETUP_RNG_SEED 9
+#define SETUP_ENUM_MAX SETUP_RNG_SEED
+
+#define SETUP_INDIRECT (1<<31)
+#define SETUP_TYPE_MAX (SETUP_ENUM_MAX | SETUP_INDIRECT)
+
+#ifndef __ASSEMBLY__
+
+#include "standard-headers/linux/types.h"
+
+/* extensible setup data list node */
+struct setup_data {
+ uint64_t next;
+ uint32_t type;
+ uint32_t len;
+ uint8_t data[];
+};
+
+/* extensible setup indirect data node */
+struct setup_indirect {
+ uint32_t type;
+ uint32_t reserved; /* Reserved, must be set to zero. */
+ uint64_t len;
+ uint64_t addr;
+};
+
+/*
+ * The E820 memory region entry of the boot protocol ABI:
+ */
+struct boot_e820_entry {
+ uint64_t addr;
+ uint64_t size;
+ uint32_t type;
+} QEMU_PACKED;
+
+/*
+ * The boot loader is passing platform information via this Jailhouse-specific
+ * setup data structure.
+ */
+struct jailhouse_setup_data {
+ struct {
+ uint16_t version;
+ uint16_t compatible_version;
+ } QEMU_PACKED hdr;
+ struct {
+ uint16_t pm_timer_address;
+ uint16_t num_cpus;
+ uint64_t pci_mmconfig_base;
+ uint32_t tsc_khz;
+ uint32_t apic_khz;
+ uint8_t standard_ioapic;
+ uint8_t cpu_ids[255];
+ } QEMU_PACKED v1;
+ struct {
+ uint32_t flags;
+ } QEMU_PACKED v2;
+} QEMU_PACKED;
+
+/*
+ * IMA buffer setup data information from the previous kernel during kexec
+ */
+struct ima_setup_data {
+ uint64_t addr;
+ uint64_t size;
+} QEMU_PACKED;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_X86_SETUP_DATA_H */
diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h
index dfb54ef..0150378 100644
--- a/include/standard-headers/linux/ethtool.h
+++ b/include/standard-headers/linux/ethtool.h
@@ -2023,6 +2023,53 @@
#define IPV4_FLOW 0x10 /* hash only */
#define IPV6_FLOW 0x11 /* hash only */
#define ETHER_FLOW 0x12 /* spec only (ether_spec) */
+
+/* Used for GTP-U IPv4 and IPv6.
+ * The format of GTP packets only includes
+ * elements such as TEID and GTP version.
+ * It is primarily intended for data communication of the UE.
+ */
+#define GTPU_V4_FLOW 0x13 /* hash only */
+#define GTPU_V6_FLOW 0x14 /* hash only */
+
+/* Use for GTP-C IPv4 and v6.
+ * The format of these GTP packets does not include TEID.
+ * Primarily expected to be used for communication
+ * to create sessions for UE data communication,
+ * commonly referred to as CSR (Create Session Request).
+ */
+#define GTPC_V4_FLOW 0x15 /* hash only */
+#define GTPC_V6_FLOW 0x16 /* hash only */
+
+/* Use for GTP-C IPv4 and v6.
+ * Unlike GTPC_V4_FLOW, the format of these GTP packets includes TEID.
+ * After session creation, it becomes this packet.
+ * This is mainly used for requests to realize UE handover.
+ */
+#define GTPC_TEID_V4_FLOW 0x17 /* hash only */
+#define GTPC_TEID_V6_FLOW 0x18 /* hash only */
+
+/* Use for GTP-U and extended headers for the PSC (PDU Session Container).
+ * The format of these GTP packets includes TEID and QFI.
+ * In 5G communication using UPF (User Plane Function),
+ * data communication with this extended header is performed.
+ */
+#define GTPU_EH_V4_FLOW 0x19 /* hash only */
+#define GTPU_EH_V6_FLOW 0x1a /* hash only */
+
+/* Use for GTP-U IPv4 and v6 PSC (PDU Session Container) extended headers.
+ * This differs from GTPU_EH_V(4|6)_FLOW in that it is distinguished by
+ * UL/DL included in the PSC.
+ * There are differences in the data included based on Downlink/Uplink,
+ * and can be used to distinguish packets.
+ * The functions described so far are useful when you want to
+ * handle communication from the mobile network in UPF, PGW, etc.
+ */
+#define GTPU_UL_V4_FLOW 0x1b /* hash only */
+#define GTPU_UL_V6_FLOW 0x1c /* hash only */
+#define GTPU_DL_V4_FLOW 0x1d /* hash only */
+#define GTPU_DL_V6_FLOW 0x1e /* hash only */
+
/* Flag to enable additional fields in struct ethtool_rx_flow_spec */
#define FLOW_EXT 0x80000000
#define FLOW_MAC_EXT 0x40000000
@@ -2037,6 +2084,7 @@
#define RXH_IP_DST (1 << 5)
#define RXH_L4_B_0_1 (1 << 6) /* src port in case of TCP/UDP/SCTP */
#define RXH_L4_B_2_3 (1 << 7) /* dst port in case of TCP/UDP/SCTP */
+#define RXH_GTP_TEID (1 << 8) /* teid in case of GTP */
#define RXH_DISCARD (1 << 31)
#define RX_CLS_FLOW_DISC 0xffffffffffffffffULL
diff --git a/include/standard-headers/linux/fuse.h b/include/standard-headers/linux/fuse.h
index fc0dcd1..bac9dbc 100644
--- a/include/standard-headers/linux/fuse.h
+++ b/include/standard-headers/linux/fuse.h
@@ -211,6 +211,12 @@
* 7.39
* - add FUSE_DIRECT_IO_ALLOW_MMAP
* - add FUSE_STATX and related structures
+ *
+ * 7.40
+ * - add max_stack_depth to fuse_init_out, add FUSE_PASSTHROUGH init flag
+ * - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag
+ * - add FUSE_NO_EXPORT_SUPPORT init flag
+ * - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag
*/
#ifndef _LINUX_FUSE_H
@@ -242,7 +248,7 @@
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 39
+#define FUSE_KERNEL_MINOR_VERSION 40
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -349,6 +355,7 @@
* FOPEN_STREAM: the file is stream-like (no file position at all)
* FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE)
* FOPEN_PARALLEL_DIRECT_WRITES: Allow concurrent direct writes on the same inode
+ * FOPEN_PASSTHROUGH: passthrough read/write io for this open file
*/
#define FOPEN_DIRECT_IO (1 << 0)
#define FOPEN_KEEP_CACHE (1 << 1)
@@ -357,6 +364,7 @@
#define FOPEN_STREAM (1 << 4)
#define FOPEN_NOFLUSH (1 << 5)
#define FOPEN_PARALLEL_DIRECT_WRITES (1 << 6)
+#define FOPEN_PASSTHROUGH (1 << 7)
/**
* INIT request/reply flags
@@ -406,6 +414,9 @@
* symlink and mknod (single group that matches parent)
* FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation
* FUSE_DIRECT_IO_ALLOW_MMAP: allow shared mmap in FOPEN_DIRECT_IO mode.
+ * FUSE_NO_EXPORT_SUPPORT: explicitly disable export support
+ * FUSE_HAS_RESEND: kernel supports resending pending requests, and the high bit
+ * of the request ID indicates resend requests
*/
#define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1)
@@ -445,6 +456,9 @@
#define FUSE_CREATE_SUPP_GROUP (1ULL << 34)
#define FUSE_HAS_EXPIRE_ONLY (1ULL << 35)
#define FUSE_DIRECT_IO_ALLOW_MMAP (1ULL << 36)
+#define FUSE_PASSTHROUGH (1ULL << 37)
+#define FUSE_NO_EXPORT_SUPPORT (1ULL << 38)
+#define FUSE_HAS_RESEND (1ULL << 39)
/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */
#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP
@@ -631,6 +645,7 @@
FUSE_NOTIFY_STORE = 4,
FUSE_NOTIFY_RETRIEVE = 5,
FUSE_NOTIFY_DELETE = 6,
+ FUSE_NOTIFY_RESEND = 7,
FUSE_NOTIFY_CODE_MAX,
};
@@ -757,7 +772,7 @@
struct fuse_open_out {
uint64_t fh;
uint32_t open_flags;
- uint32_t padding;
+ int32_t backing_id;
};
struct fuse_release_in {
@@ -873,7 +888,8 @@
uint16_t max_pages;
uint16_t map_alignment;
uint32_t flags2;
- uint32_t unused[7];
+ uint32_t max_stack_depth;
+ uint32_t unused[6];
};
#define CUSE_INIT_INFO_MAX 4096
@@ -956,6 +972,14 @@
uint32_t padding;
};
+/**
+ * FUSE request unique ID flag
+ *
+ * Indicates whether this is a resend request. The receiver should handle this
+ * request accordingly.
+ */
+#define FUSE_UNIQUE_RESEND (1ULL << 63)
+
struct fuse_in_header {
uint32_t len;
uint32_t opcode;
@@ -1045,9 +1069,18 @@
uint64_t dummy4;
};
+struct fuse_backing_map {
+ int32_t fd;
+ uint32_t flags;
+ uint64_t padding;
+};
+
/* Device ioctls: */
#define FUSE_DEV_IOC_MAGIC 229
#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t)
+#define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \
+ struct fuse_backing_map)
+#define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t)
struct fuse_lseek_in {
uint64_t fh;
diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h
index f6bab08..2221b0c 100644
--- a/include/standard-headers/linux/input-event-codes.h
+++ b/include/standard-headers/linux/input-event-codes.h
@@ -602,6 +602,7 @@
#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */
+#define KEY_REFRESH_RATE_TOGGLE 0x232 /* Display refresh rate toggle */
#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */
diff --git a/include/standard-headers/linux/virtio_gpu.h b/include/standard-headers/linux/virtio_gpu.h
index 2da48d3..2db643e 100644
--- a/include/standard-headers/linux/virtio_gpu.h
+++ b/include/standard-headers/linux/virtio_gpu.h
@@ -309,6 +309,8 @@
#define VIRTIO_GPU_CAPSET_VIRGL 1
#define VIRTIO_GPU_CAPSET_VIRGL2 2
+/* 3 is reserved for gfxstream */
+#define VIRTIO_GPU_CAPSET_VENUS 4
/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
struct virtio_gpu_get_capset_info {
diff --git a/include/standard-headers/linux/virtio_pci.h b/include/standard-headers/linux/virtio_pci.h
index 3e2bc2c..4010216 100644
--- a/include/standard-headers/linux/virtio_pci.h
+++ b/include/standard-headers/linux/virtio_pci.h
@@ -240,7 +240,7 @@
#define VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_READ 0x5
#define VIRTIO_ADMIN_CMD_LEGACY_NOTIFY_INFO 0x6
-struct QEMU_PACKED virtio_admin_cmd_hdr {
+struct virtio_admin_cmd_hdr {
uint16_t opcode;
/*
* 1 - SR-IOV
@@ -252,20 +252,20 @@
uint64_t group_member_id;
};
-struct QEMU_PACKED virtio_admin_cmd_status {
+struct virtio_admin_cmd_status {
uint16_t status;
uint16_t status_qualifier;
/* Unused, reserved for future extensions. */
uint8_t reserved2[4];
};
-struct QEMU_PACKED virtio_admin_cmd_legacy_wr_data {
+struct virtio_admin_cmd_legacy_wr_data {
uint8_t offset; /* Starting offset of the register(s) to write. */
uint8_t reserved[7];
uint8_t registers[];
};
-struct QEMU_PACKED virtio_admin_cmd_legacy_rd_data {
+struct virtio_admin_cmd_legacy_rd_data {
uint8_t offset; /* Starting offset of the register(s) to read. */
};
@@ -275,7 +275,7 @@
#define VIRTIO_ADMIN_CMD_MAX_NOTIFY_INFO 4
-struct QEMU_PACKED virtio_admin_cmd_notify_info_data {
+struct virtio_admin_cmd_notify_info_data {
uint8_t flags; /* 0 = end of list, 1 = owner device, 2 = member device */
uint8_t bar; /* BAR of the member or the owner device */
uint8_t padding[6];
diff --git a/include/standard-headers/linux/virtio_snd.h b/include/standard-headers/linux/virtio_snd.h
index 1af96b9..860f12e 100644
--- a/include/standard-headers/linux/virtio_snd.h
+++ b/include/standard-headers/linux/virtio_snd.h
@@ -8,6 +8,14 @@
#include "standard-headers/linux/virtio_types.h"
/*******************************************************************************
+ * FEATURE BITS
+ */
+enum {
+ /* device supports control elements */
+ VIRTIO_SND_F_CTLS = 0
+};
+
+/*******************************************************************************
* CONFIGURATION SPACE
*/
struct virtio_snd_config {
@@ -17,6 +25,8 @@
uint32_t streams;
/* # of available channel maps */
uint32_t chmaps;
+ /* # of available control elements */
+ uint32_t controls;
};
enum {
@@ -55,6 +65,15 @@
/* channel map control request types */
VIRTIO_SND_R_CHMAP_INFO = 0x0200,
+ /* control element request types */
+ VIRTIO_SND_R_CTL_INFO = 0x0300,
+ VIRTIO_SND_R_CTL_ENUM_ITEMS,
+ VIRTIO_SND_R_CTL_READ,
+ VIRTIO_SND_R_CTL_WRITE,
+ VIRTIO_SND_R_CTL_TLV_READ,
+ VIRTIO_SND_R_CTL_TLV_WRITE,
+ VIRTIO_SND_R_CTL_TLV_COMMAND,
+
/* jack event types */
VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000,
VIRTIO_SND_EVT_JACK_DISCONNECTED,
@@ -63,6 +82,9 @@
VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100,
VIRTIO_SND_EVT_PCM_XRUN,
+ /* control element event types */
+ VIRTIO_SND_EVT_CTL_NOTIFY = 0x1200,
+
/* common status codes */
VIRTIO_SND_S_OK = 0x8000,
VIRTIO_SND_S_BAD_MSG,
@@ -331,4 +353,136 @@
uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
};
+/*******************************************************************************
+ * CONTROL ELEMENTS MESSAGES
+ */
+struct virtio_snd_ctl_hdr {
+ /* VIRTIO_SND_R_CTL_XXX */
+ struct virtio_snd_hdr hdr;
+ /* 0 ... virtio_snd_config::controls - 1 */
+ uint32_t control_id;
+};
+
+/* supported roles for control elements */
+enum {
+ VIRTIO_SND_CTL_ROLE_UNDEFINED = 0,
+ VIRTIO_SND_CTL_ROLE_VOLUME,
+ VIRTIO_SND_CTL_ROLE_MUTE,
+ VIRTIO_SND_CTL_ROLE_GAIN
+};
+
+/* supported value types for control elements */
+enum {
+ VIRTIO_SND_CTL_TYPE_BOOLEAN = 0,
+ VIRTIO_SND_CTL_TYPE_INTEGER,
+ VIRTIO_SND_CTL_TYPE_INTEGER64,
+ VIRTIO_SND_CTL_TYPE_ENUMERATED,
+ VIRTIO_SND_CTL_TYPE_BYTES,
+ VIRTIO_SND_CTL_TYPE_IEC958
+};
+
+/* supported access rights for control elements */
+enum {
+ VIRTIO_SND_CTL_ACCESS_READ = 0,
+ VIRTIO_SND_CTL_ACCESS_WRITE,
+ VIRTIO_SND_CTL_ACCESS_VOLATILE,
+ VIRTIO_SND_CTL_ACCESS_INACTIVE,
+ VIRTIO_SND_CTL_ACCESS_TLV_READ,
+ VIRTIO_SND_CTL_ACCESS_TLV_WRITE,
+ VIRTIO_SND_CTL_ACCESS_TLV_COMMAND
+};
+
+struct virtio_snd_ctl_info {
+ /* common header */
+ struct virtio_snd_info hdr;
+ /* element role (VIRTIO_SND_CTL_ROLE_XXX) */
+ uint32_t role;
+ /* element value type (VIRTIO_SND_CTL_TYPE_XXX) */
+ uint32_t type;
+ /* element access right bit map (1 << VIRTIO_SND_CTL_ACCESS_XXX) */
+ uint32_t access;
+ /* # of members in the element value */
+ uint32_t count;
+ /* index for an element with a non-unique name */
+ uint32_t index;
+ /* name identifier string for the element */
+ uint8_t name[44];
+ /* additional information about the element's value */
+ union {
+ /* VIRTIO_SND_CTL_TYPE_INTEGER */
+ struct {
+ /* minimum supported value */
+ uint32_t min;
+ /* maximum supported value */
+ uint32_t max;
+ /* fixed step size for value (0 = variable size) */
+ uint32_t step;
+ } integer;
+ /* VIRTIO_SND_CTL_TYPE_INTEGER64 */
+ struct {
+ /* minimum supported value */
+ uint64_t min;
+ /* maximum supported value */
+ uint64_t max;
+ /* fixed step size for value (0 = variable size) */
+ uint64_t step;
+ } integer64;
+ /* VIRTIO_SND_CTL_TYPE_ENUMERATED */
+ struct {
+ /* # of options supported for value */
+ uint32_t items;
+ } enumerated;
+ } value;
+};
+
+struct virtio_snd_ctl_enum_item {
+ /* option name */
+ uint8_t item[64];
+};
+
+struct virtio_snd_ctl_iec958 {
+ /* AES/IEC958 channel status bits */
+ uint8_t status[24];
+ /* AES/IEC958 subcode bits */
+ uint8_t subcode[147];
+ /* nothing */
+ uint8_t pad;
+ /* AES/IEC958 subframe bits */
+ uint8_t dig_subframe[4];
+};
+
+struct virtio_snd_ctl_value {
+ union {
+ /* VIRTIO_SND_CTL_TYPE_BOOLEAN|INTEGER value */
+ uint32_t integer[128];
+ /* VIRTIO_SND_CTL_TYPE_INTEGER64 value */
+ uint64_t integer64[64];
+ /* VIRTIO_SND_CTL_TYPE_ENUMERATED value (option indexes) */
+ uint32_t enumerated[128];
+ /* VIRTIO_SND_CTL_TYPE_BYTES value */
+ uint8_t bytes[512];
+ /* VIRTIO_SND_CTL_TYPE_IEC958 value */
+ struct virtio_snd_ctl_iec958 iec958;
+ } value;
+};
+
+/* supported event reason types */
+enum {
+ /* element's value has changed */
+ VIRTIO_SND_CTL_EVT_MASK_VALUE = 0,
+ /* element's information has changed */
+ VIRTIO_SND_CTL_EVT_MASK_INFO,
+ /* element's metadata has changed */
+ VIRTIO_SND_CTL_EVT_MASK_TLV
+};
+
+struct virtio_snd_ctl_event {
+ /* VIRTIO_SND_EVT_CTL_NOTIFY */
+ struct virtio_snd_hdr hdr;
+ /* 0 ... virtio_snd_config::controls - 1 */
+ uint16_t control_id;
+ /* event reason bit map (1 << VIRTIO_SND_CTL_EVT_MASK_XXX) */
+ uint16_t mask;
+};
+
#endif /* VIRTIO_SND_IF_H */
diff --git a/include/sysemu/hostmem.h b/include/sysemu/hostmem.h
index 0e411aa..04b884b 100644
--- a/include/sysemu/hostmem.h
+++ b/include/sysemu/hostmem.h
@@ -74,6 +74,7 @@
uint64_t size;
bool merge, dump, use_canonical_path;
bool prealloc, is_mapped, share, reserve;
+ bool guest_memfd;
uint32_t prealloc_threads;
ThreadContext *prealloc_context;
DECLARE_BITMAP(host_nodes, MAX_NODES + 1);
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index fad9a7e..47f9e8b 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -224,7 +224,7 @@
* calling down to kvm_arch_update_guest_debug after the generic
* fields have been set.
*/
-#ifdef KVM_CAP_SET_GUEST_DEBUG
+#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap);
#else
static inline int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
@@ -525,23 +525,23 @@
/* Notify resamplefd for EOI of specific interrupts. */
void kvm_resample_fd_notify(int gsi);
-/**
- * kvm_cpu_check_are_resettable - return whether CPUs can be reset
- *
- * Returns: true: CPUs are resettable
- * false: CPUs are not resettable
- */
-bool kvm_cpu_check_are_resettable(void);
-
-bool kvm_arch_cpu_check_are_resettable(void);
-
bool kvm_dirty_ring_enabled(void);
uint32_t kvm_dirty_ring_size(void);
+void kvm_mark_guest_state_protected(void);
+
/**
* kvm_hwpoisoned_mem - indicate if there is any hwpoisoned page
* reported for the VM.
*/
bool kvm_hwpoisoned_mem(void);
+
+int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp);
+
+int kvm_set_memory_attributes_private(hwaddr start, uint64_t size);
+int kvm_set_memory_attributes_shared(hwaddr start, uint64_t size);
+
+int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private);
+
#endif
diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h
index 882e37e..3f3d13f 100644
--- a/include/sysemu/kvm_int.h
+++ b/include/sysemu/kvm_int.h
@@ -30,6 +30,8 @@
int as_id;
/* Cache of the offset in ram address space */
ram_addr_t ram_start_offset;
+ int guest_memfd;
+ hwaddr guest_memfd_offset;
} KVMSlot;
typedef struct KVMMemoryUpdate {
@@ -78,7 +80,7 @@
struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
bool coalesced_flush_in_progress;
int vcpu_events;
-#ifdef KVM_CAP_SET_GUEST_DEBUG
+#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints;
#endif
int max_nested_state_len;
@@ -87,6 +89,7 @@
bool kernel_irqchip_required;
OnOffAuto kernel_irqchip_split;
bool sync_mmu;
+ bool guest_state_protected;
uint64_t manual_dirty_log_protect;
/* The man page (and posix) say ioctl numbers are signed int, but
* they're not. Linux, glibc and *BSD all treat ioctl numbers as
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index eb1dc1e..5b4397e 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -71,8 +71,6 @@
extern Chardev *parallel_hds[MAX_PARALLEL_PORTS];
-void hmp_info_usb(Monitor *mon, const QDict *qdict);
-
void add_boot_device_path(int32_t bootindex, DeviceState *dev,
const char *suffix);
char *get_boot_devices_list(size_t *size);
diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index c59ea55..2af9931 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -37,9 +37,7 @@
#include <asm/ptrace.h>
#include <asm/sve_context.h>
-#define __KVM_HAVE_GUEST_DEBUG
#define __KVM_HAVE_IRQ_LINE
-#define __KVM_HAVE_READONLY_MEM
#define __KVM_HAVE_VCPU_EVENTS
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
@@ -76,11 +74,11 @@
/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
#define KVM_ARM_DEVICE_TYPE_SHIFT 0
-#define KVM_ARM_DEVICE_TYPE_MASK GENMASK(KVM_ARM_DEVICE_TYPE_SHIFT + 15, \
- KVM_ARM_DEVICE_TYPE_SHIFT)
+#define KVM_ARM_DEVICE_TYPE_MASK __GENMASK(KVM_ARM_DEVICE_TYPE_SHIFT + 15, \
+ KVM_ARM_DEVICE_TYPE_SHIFT)
#define KVM_ARM_DEVICE_ID_SHIFT 16
-#define KVM_ARM_DEVICE_ID_MASK GENMASK(KVM_ARM_DEVICE_ID_SHIFT + 15, \
- KVM_ARM_DEVICE_ID_SHIFT)
+#define KVM_ARM_DEVICE_ID_MASK __GENMASK(KVM_ARM_DEVICE_ID_SHIFT + 15, \
+ KVM_ARM_DEVICE_ID_SHIFT)
/* Supported device IDs */
#define KVM_ARM_DEVICE_VGIC_V2 0
@@ -162,6 +160,11 @@
__u64 device_irq_level;
};
+/* Bits for run->s.regs.device_irq_level */
+#define KVM_ARM_DEV_EL1_VTIMER (1 << 0)
+#define KVM_ARM_DEV_EL1_PTIMER (1 << 1)
+#define KVM_ARM_DEV_PMU (1 << 2)
+
/*
* PMU filter structure. Describe a range of events with a particular
* action. To be used with KVM_ARM_VCPU_PMU_V3_FILTER.
diff --git a/linux-headers/asm-arm64/sve_context.h b/linux-headers/asm-arm64/sve_context.h
index 1d0e3e1..d1b1ec8 100644
--- a/linux-headers/asm-arm64/sve_context.h
+++ b/linux-headers/asm-arm64/sve_context.h
@@ -13,6 +13,17 @@
#define __SVE_VQ_BYTES 16 /* number of bytes per quadword */
+/*
+ * Yes, __SVE_VQ_MAX is 512 QUADWORDS.
+ *
+ * To help ensure forward portability, this is much larger than the
+ * current maximum value defined by the SVE architecture. While arrays
+ * or static allocations can be sized based on this value, watch out!
+ * It will waste a surprisingly large amount of memory.
+ *
+ * Dynamic sizing based on the actual runtime vector length is likely to
+ * be preferable for most purposes.
+ */
#define __SVE_VQ_MIN 1
#define __SVE_VQ_MAX 512
diff --git a/linux-headers/asm-generic/bitsperlong.h b/linux-headers/asm-generic/bitsperlong.h
index 75f320f..1fb4f0c 100644
--- a/linux-headers/asm-generic/bitsperlong.h
+++ b/linux-headers/asm-generic/bitsperlong.h
@@ -24,4 +24,8 @@
#endif
#endif
+#ifndef __BITS_PER_LONG_LONG
+#define __BITS_PER_LONG_LONG 64
+#endif
+
#endif /* __ASM_GENERIC_BITS_PER_LONG */
diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h
index 923d0bd..1097859 100644
--- a/linux-headers/asm-loongarch/kvm.h
+++ b/linux-headers/asm-loongarch/kvm.h
@@ -14,8 +14,6 @@
* Some parts derived from the x86 version of this file.
*/
-#define __KVM_HAVE_READONLY_MEM
-
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
#define KVM_DIRTY_LOG_PAGE_OFFSET 64
diff --git a/linux-headers/asm-mips/kvm.h b/linux-headers/asm-mips/kvm.h
index edcf717..9673dc9 100644
--- a/linux-headers/asm-mips/kvm.h
+++ b/linux-headers/asm-mips/kvm.h
@@ -20,8 +20,6 @@
* Some parts derived from the x86 version of this file.
*/
-#define __KVM_HAVE_READONLY_MEM
-
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
/*
diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index 9f18fa0..1691297 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -28,7 +28,6 @@
#define __KVM_HAVE_PPC_SMT
#define __KVM_HAVE_IRQCHIP
#define __KVM_HAVE_IRQ_LINE
-#define __KVM_HAVE_GUEST_DEBUG
/* Not always available, but if it is, this is the correct offset. */
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
@@ -733,4 +732,48 @@
#define KVM_XIVE_TIMA_PAGE_OFFSET 0
#define KVM_XIVE_ESB_PAGE_OFFSET 4
+/* for KVM_PPC_GET_PVINFO */
+
+#define KVM_PPC_PVINFO_FLAGS_EV_IDLE (1<<0)
+
+struct kvm_ppc_pvinfo {
+ /* out */
+ __u32 flags;
+ __u32 hcall[4];
+ __u8 pad[108];
+};
+
+/* for KVM_PPC_GET_SMMU_INFO */
+#define KVM_PPC_PAGE_SIZES_MAX_SZ 8
+
+struct kvm_ppc_one_page_size {
+ __u32 page_shift; /* Page shift (or 0) */
+ __u32 pte_enc; /* Encoding in the HPTE (>>12) */
+};
+
+struct kvm_ppc_one_seg_page_size {
+ __u32 page_shift; /* Base page shift of segment (or 0) */
+ __u32 slb_enc; /* SLB encoding for BookS */
+ struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ];
+};
+
+#define KVM_PPC_PAGE_SIZES_REAL 0x00000001
+#define KVM_PPC_1T_SEGMENTS 0x00000002
+#define KVM_PPC_NO_HASH 0x00000004
+
+struct kvm_ppc_smmu_info {
+ __u64 flags;
+ __u32 slb_size;
+ __u16 data_keys; /* # storage keys supported for data */
+ __u16 instr_keys; /* # storage keys supported for instructions */
+ struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
+};
+
+/* for KVM_PPC_RESIZE_HPT_{PREPARE,COMMIT} */
+struct kvm_ppc_resize_hpt {
+ __u64 flags;
+ __u32 shift;
+ __u32 pad;
+};
+
#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/linux-headers/asm-riscv/kvm.h b/linux-headers/asm-riscv/kvm.h
index 7499e88..b1c503c 100644
--- a/linux-headers/asm-riscv/kvm.h
+++ b/linux-headers/asm-riscv/kvm.h
@@ -16,7 +16,6 @@
#include <asm/ptrace.h>
#define __KVM_HAVE_IRQ_LINE
-#define __KVM_HAVE_READONLY_MEM
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
@@ -166,6 +165,8 @@
KVM_RISCV_ISA_EXT_ZVFH,
KVM_RISCV_ISA_EXT_ZVFHMIN,
KVM_RISCV_ISA_EXT_ZFA,
+ KVM_RISCV_ISA_EXT_ZTSO,
+ KVM_RISCV_ISA_EXT_ZACAS,
KVM_RISCV_ISA_EXT_MAX,
};
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index 023a276..684c4e1 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -12,7 +12,320 @@
#include <linux/types.h>
#define __KVM_S390
-#define __KVM_HAVE_GUEST_DEBUG
+
+struct kvm_s390_skeys {
+ __u64 start_gfn;
+ __u64 count;
+ __u64 skeydata_addr;
+ __u32 flags;
+ __u32 reserved[9];
+};
+
+#define KVM_S390_CMMA_PEEK (1 << 0)
+
+/**
+ * kvm_s390_cmma_log - Used for CMMA migration.
+ *
+ * Used both for input and output.
+ *
+ * @start_gfn: Guest page number to start from.
+ * @count: Size of the result buffer.
+ * @flags: Control operation mode via KVM_S390_CMMA_* flags
+ * @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty
+ * pages are still remaining.
+ * @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set
+ * in the PGSTE.
+ * @values: Pointer to the values buffer.
+ *
+ * Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls.
+ */
+struct kvm_s390_cmma_log {
+ __u64 start_gfn;
+ __u32 count;
+ __u32 flags;
+ union {
+ __u64 remaining;
+ __u64 mask;
+ };
+ __u64 values;
+};
+
+#define KVM_S390_RESET_POR 1
+#define KVM_S390_RESET_CLEAR 2
+#define KVM_S390_RESET_SUBSYSTEM 4
+#define KVM_S390_RESET_CPU_INIT 8
+#define KVM_S390_RESET_IPL 16
+
+/* for KVM_S390_MEM_OP */
+struct kvm_s390_mem_op {
+ /* in */
+ __u64 gaddr; /* the guest address */
+ __u64 flags; /* flags */
+ __u32 size; /* amount of bytes */
+ __u32 op; /* type of operation */
+ __u64 buf; /* buffer in userspace */
+ union {
+ struct {
+ __u8 ar; /* the access register number */
+ __u8 key; /* access key, ignored if flag unset */
+ __u8 pad1[6]; /* ignored */
+ __u64 old_addr; /* ignored if cmpxchg flag unset */
+ };
+ __u32 sida_offset; /* offset into the sida */
+ __u8 reserved[32]; /* ignored */
+ };
+};
+/* types for kvm_s390_mem_op->op */
+#define KVM_S390_MEMOP_LOGICAL_READ 0
+#define KVM_S390_MEMOP_LOGICAL_WRITE 1
+#define KVM_S390_MEMOP_SIDA_READ 2
+#define KVM_S390_MEMOP_SIDA_WRITE 3
+#define KVM_S390_MEMOP_ABSOLUTE_READ 4
+#define KVM_S390_MEMOP_ABSOLUTE_WRITE 5
+#define KVM_S390_MEMOP_ABSOLUTE_CMPXCHG 6
+
+/* flags for kvm_s390_mem_op->flags */
+#define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0)
+#define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1)
+#define KVM_S390_MEMOP_F_SKEY_PROTECTION (1ULL << 2)
+
+/* flags specifying extension support via KVM_CAP_S390_MEM_OP_EXTENSION */
+#define KVM_S390_MEMOP_EXTENSION_CAP_BASE (1 << 0)
+#define KVM_S390_MEMOP_EXTENSION_CAP_CMPXCHG (1 << 1)
+
+struct kvm_s390_psw {
+ __u64 mask;
+ __u64 addr;
+};
+
+/* valid values for type in kvm_s390_interrupt */
+#define KVM_S390_SIGP_STOP 0xfffe0000u
+#define KVM_S390_PROGRAM_INT 0xfffe0001u
+#define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u
+#define KVM_S390_RESTART 0xfffe0003u
+#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u
+#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u
+#define KVM_S390_MCHK 0xfffe1000u
+#define KVM_S390_INT_CLOCK_COMP 0xffff1004u
+#define KVM_S390_INT_CPU_TIMER 0xffff1005u
+#define KVM_S390_INT_VIRTIO 0xffff2603u
+#define KVM_S390_INT_SERVICE 0xffff2401u
+#define KVM_S390_INT_EMERGENCY 0xffff1201u
+#define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u
+/* Anything below 0xfffe0000u is taken by INT_IO */
+#define KVM_S390_INT_IO(ai,cssid,ssid,schid) \
+ (((schid)) | \
+ ((ssid) << 16) | \
+ ((cssid) << 18) | \
+ ((ai) << 26))
+#define KVM_S390_INT_IO_MIN 0x00000000u
+#define KVM_S390_INT_IO_MAX 0xfffdffffu
+#define KVM_S390_INT_IO_AI_MASK 0x04000000u
+
+
+struct kvm_s390_interrupt {
+ __u32 type;
+ __u32 parm;
+ __u64 parm64;
+};
+
+struct kvm_s390_io_info {
+ __u16 subchannel_id;
+ __u16 subchannel_nr;
+ __u32 io_int_parm;
+ __u32 io_int_word;
+};
+
+struct kvm_s390_ext_info {
+ __u32 ext_params;
+ __u32 pad;
+ __u64 ext_params2;
+};
+
+struct kvm_s390_pgm_info {
+ __u64 trans_exc_code;
+ __u64 mon_code;
+ __u64 per_address;
+ __u32 data_exc_code;
+ __u16 code;
+ __u16 mon_class_nr;
+ __u8 per_code;
+ __u8 per_atmid;
+ __u8 exc_access_id;
+ __u8 per_access_id;
+ __u8 op_access_id;
+#define KVM_S390_PGM_FLAGS_ILC_VALID 0x01
+#define KVM_S390_PGM_FLAGS_ILC_0 0x02
+#define KVM_S390_PGM_FLAGS_ILC_1 0x04
+#define KVM_S390_PGM_FLAGS_ILC_MASK 0x06
+#define KVM_S390_PGM_FLAGS_NO_REWIND 0x08
+ __u8 flags;
+ __u8 pad[2];
+};
+
+struct kvm_s390_prefix_info {
+ __u32 address;
+};
+
+struct kvm_s390_extcall_info {
+ __u16 code;
+};
+
+struct kvm_s390_emerg_info {
+ __u16 code;
+};
+
+#define KVM_S390_STOP_FLAG_STORE_STATUS 0x01
+struct kvm_s390_stop_info {
+ __u32 flags;
+};
+
+struct kvm_s390_mchk_info {
+ __u64 cr14;
+ __u64 mcic;
+ __u64 failing_storage_address;
+ __u32 ext_damage_code;
+ __u32 pad;
+ __u8 fixed_logout[16];
+};
+
+struct kvm_s390_irq {
+ __u64 type;
+ union {
+ struct kvm_s390_io_info io;
+ struct kvm_s390_ext_info ext;
+ struct kvm_s390_pgm_info pgm;
+ struct kvm_s390_emerg_info emerg;
+ struct kvm_s390_extcall_info extcall;
+ struct kvm_s390_prefix_info prefix;
+ struct kvm_s390_stop_info stop;
+ struct kvm_s390_mchk_info mchk;
+ char reserved[64];
+ } u;
+};
+
+struct kvm_s390_irq_state {
+ __u64 buf;
+ __u32 flags; /* will stay unused for compatibility reasons */
+ __u32 len;
+ __u32 reserved[4]; /* will stay unused for compatibility reasons */
+};
+
+struct kvm_s390_ucas_mapping {
+ __u64 user_addr;
+ __u64 vcpu_addr;
+ __u64 length;
+};
+
+struct kvm_s390_pv_sec_parm {
+ __u64 origin;
+ __u64 length;
+};
+
+struct kvm_s390_pv_unp {
+ __u64 addr;
+ __u64 size;
+ __u64 tweak;
+};
+
+enum pv_cmd_dmp_id {
+ KVM_PV_DUMP_INIT,
+ KVM_PV_DUMP_CONFIG_STOR_STATE,
+ KVM_PV_DUMP_COMPLETE,
+ KVM_PV_DUMP_CPU,
+};
+
+struct kvm_s390_pv_dmp {
+ __u64 subcmd;
+ __u64 buff_addr;
+ __u64 buff_len;
+ __u64 gaddr; /* For dump storage state */
+ __u64 reserved[4];
+};
+
+enum pv_cmd_info_id {
+ KVM_PV_INFO_VM,
+ KVM_PV_INFO_DUMP,
+};
+
+struct kvm_s390_pv_info_dump {
+ __u64 dump_cpu_buffer_len;
+ __u64 dump_config_mem_buffer_per_1m;
+ __u64 dump_config_finalize_len;
+};
+
+struct kvm_s390_pv_info_vm {
+ __u64 inst_calls_list[4];
+ __u64 max_cpus;
+ __u64 max_guests;
+ __u64 max_guest_addr;
+ __u64 feature_indication;
+};
+
+struct kvm_s390_pv_info_header {
+ __u32 id;
+ __u32 len_max;
+ __u32 len_written;
+ __u32 reserved;
+};
+
+struct kvm_s390_pv_info {
+ struct kvm_s390_pv_info_header header;
+ union {
+ struct kvm_s390_pv_info_dump dump;
+ struct kvm_s390_pv_info_vm vm;
+ };
+};
+
+enum pv_cmd_id {
+ KVM_PV_ENABLE,
+ KVM_PV_DISABLE,
+ KVM_PV_SET_SEC_PARMS,
+ KVM_PV_UNPACK,
+ KVM_PV_VERIFY,
+ KVM_PV_PREP_RESET,
+ KVM_PV_UNSHARE_ALL,
+ KVM_PV_INFO,
+ KVM_PV_DUMP,
+ KVM_PV_ASYNC_CLEANUP_PREPARE,
+ KVM_PV_ASYNC_CLEANUP_PERFORM,
+};
+
+struct kvm_pv_cmd {
+ __u32 cmd; /* Command to be executed */
+ __u16 rc; /* Ultravisor return code */
+ __u16 rrc; /* Ultravisor return reason code */
+ __u64 data; /* Data or address */
+ __u32 flags; /* flags for future extensions. Must be 0 for now */
+ __u32 reserved[3];
+};
+
+struct kvm_s390_zpci_op {
+ /* in */
+ __u32 fh; /* target device */
+ __u8 op; /* operation to perform */
+ __u8 pad[3];
+ union {
+ /* for KVM_S390_ZPCIOP_REG_AEN */
+ struct {
+ __u64 ibv; /* Guest addr of interrupt bit vector */
+ __u64 sb; /* Guest addr of summary bit */
+ __u32 flags;
+ __u32 noi; /* Number of interrupts */
+ __u8 isc; /* Guest interrupt subclass */
+ __u8 sbo; /* Offset of guest summary bit vector */
+ __u16 pad;
+ } reg_aen;
+ __u64 reserved[8];
+ } u;
+};
+
+/* types for kvm_s390_zpci_op->op */
+#define KVM_S390_ZPCIOP_REG_AEN 0
+#define KVM_S390_ZPCIOP_DEREG_AEN 1
+
+/* flags for kvm_s390_zpci_op->u.reg_aen.flags */
+#define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0)
/* Device control API: s390-specific devices */
#define KVM_DEV_FLIC_GET_ALL_IRQS 1
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index 003fb74..31c95c2 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -7,6 +7,8 @@
*
*/
+#include <linux/const.h>
+#include <linux/bits.h>
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/stddef.h>
@@ -40,7 +42,6 @@
#define __KVM_HAVE_IRQ_LINE
#define __KVM_HAVE_MSI
#define __KVM_HAVE_USER_NMI
-#define __KVM_HAVE_GUEST_DEBUG
#define __KVM_HAVE_MSIX
#define __KVM_HAVE_MCE
#define __KVM_HAVE_PIT_STATE2
@@ -49,7 +50,6 @@
#define __KVM_HAVE_DEBUGREGS
#define __KVM_HAVE_XSAVE
#define __KVM_HAVE_XCRS
-#define __KVM_HAVE_READONLY_MEM
/* Architectural interrupt line count. */
#define KVM_NR_INTERRUPTS 256
@@ -455,8 +455,13 @@
#define KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE 0x00000001
-/* attributes for system fd (group 0) */
-#define KVM_X86_XCOMP_GUEST_SUPP 0
+/* vendor-independent attributes for system fd (group 0) */
+#define KVM_X86_GRP_SYSTEM 0
+# define KVM_X86_XCOMP_GUEST_SUPP 0
+
+/* vendor-specific groups and attributes for system fd */
+#define KVM_X86_GRP_SEV 1
+# define KVM_X86_SEV_VMSA_FEATURES 0
struct kvm_vmx_nested_state_data {
__u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
@@ -524,9 +529,310 @@
#define KVM_PMU_EVENT_ALLOW 0
#define KVM_PMU_EVENT_DENY 1
-#define KVM_PMU_EVENT_FLAG_MASKED_EVENTS BIT(0)
+#define KVM_PMU_EVENT_FLAG_MASKED_EVENTS _BITUL(0)
#define KVM_PMU_EVENT_FLAGS_VALID_MASK (KVM_PMU_EVENT_FLAG_MASKED_EVENTS)
+/* for KVM_CAP_MCE */
+struct kvm_x86_mce {
+ __u64 status;
+ __u64 addr;
+ __u64 misc;
+ __u64 mcg_status;
+ __u8 bank;
+ __u8 pad1[7];
+ __u64 pad2[3];
+};
+
+/* for KVM_CAP_XEN_HVM */
+#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR (1 << 0)
+#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL (1 << 1)
+#define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2)
+#define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3)
+#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4)
+#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5)
+#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6)
+#define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE (1 << 7)
+#define KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA (1 << 8)
+
+struct kvm_xen_hvm_config {
+ __u32 flags;
+ __u32 msr;
+ __u64 blob_addr_32;
+ __u64 blob_addr_64;
+ __u8 blob_size_32;
+ __u8 blob_size_64;
+ __u8 pad2[30];
+};
+
+struct kvm_xen_hvm_attr {
+ __u16 type;
+ __u16 pad[3];
+ union {
+ __u8 long_mode;
+ __u8 vector;
+ __u8 runstate_update_flag;
+ union {
+ __u64 gfn;
+#define KVM_XEN_INVALID_GFN ((__u64)-1)
+ __u64 hva;
+ } shared_info;
+ struct {
+ __u32 send_port;
+ __u32 type; /* EVTCHNSTAT_ipi / EVTCHNSTAT_interdomain */
+ __u32 flags;
+#define KVM_XEN_EVTCHN_DEASSIGN (1 << 0)
+#define KVM_XEN_EVTCHN_UPDATE (1 << 1)
+#define KVM_XEN_EVTCHN_RESET (1 << 2)
+ /*
+ * Events sent by the guest are either looped back to
+ * the guest itself (potentially on a different port#)
+ * or signalled via an eventfd.
+ */
+ union {
+ struct {
+ __u32 port;
+ __u32 vcpu;
+ __u32 priority;
+ } port;
+ struct {
+ __u32 port; /* Zero for eventfd */
+ __s32 fd;
+ } eventfd;
+ __u32 padding[4];
+ } deliver;
+ } evtchn;
+ __u32 xen_version;
+ __u64 pad[8];
+ } u;
+};
+
+
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
+#define KVM_XEN_ATTR_TYPE_LONG_MODE 0x0
+#define KVM_XEN_ATTR_TYPE_SHARED_INFO 0x1
+#define KVM_XEN_ATTR_TYPE_UPCALL_VECTOR 0x2
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
+#define KVM_XEN_ATTR_TYPE_EVTCHN 0x3
+#define KVM_XEN_ATTR_TYPE_XEN_VERSION 0x4
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG */
+#define KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG 0x5
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA */
+#define KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA 0x6
+
+struct kvm_xen_vcpu_attr {
+ __u16 type;
+ __u16 pad[3];
+ union {
+ __u64 gpa;
+#define KVM_XEN_INVALID_GPA ((__u64)-1)
+ __u64 hva;
+ __u64 pad[8];
+ struct {
+ __u64 state;
+ __u64 state_entry_time;
+ __u64 time_running;
+ __u64 time_runnable;
+ __u64 time_blocked;
+ __u64 time_offline;
+ } runstate;
+ __u32 vcpu_id;
+ struct {
+ __u32 port;
+ __u32 priority;
+ __u64 expires_ns;
+ } timer;
+ __u8 vector;
+ } u;
+};
+
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
+#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO 0x0
+#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO 0x1
+#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR 0x2
+#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT 0x3
+#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA 0x4
+#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST 0x5
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
+#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID 0x6
+#define KVM_XEN_VCPU_ATTR_TYPE_TIMER 0x7
+#define KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR 0x8
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA */
+#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO_HVA 0x9
+
+/* Secure Encrypted Virtualization command */
+enum sev_cmd_id {
+ /* Guest initialization commands */
+ KVM_SEV_INIT = 0,
+ KVM_SEV_ES_INIT,
+ /* Guest launch commands */
+ KVM_SEV_LAUNCH_START,
+ KVM_SEV_LAUNCH_UPDATE_DATA,
+ KVM_SEV_LAUNCH_UPDATE_VMSA,
+ KVM_SEV_LAUNCH_SECRET,
+ KVM_SEV_LAUNCH_MEASURE,
+ KVM_SEV_LAUNCH_FINISH,
+ /* Guest migration commands (outgoing) */
+ KVM_SEV_SEND_START,
+ KVM_SEV_SEND_UPDATE_DATA,
+ KVM_SEV_SEND_UPDATE_VMSA,
+ KVM_SEV_SEND_FINISH,
+ /* Guest migration commands (incoming) */
+ KVM_SEV_RECEIVE_START,
+ KVM_SEV_RECEIVE_UPDATE_DATA,
+ KVM_SEV_RECEIVE_UPDATE_VMSA,
+ KVM_SEV_RECEIVE_FINISH,
+ /* Guest status and debug commands */
+ KVM_SEV_GUEST_STATUS,
+ KVM_SEV_DBG_DECRYPT,
+ KVM_SEV_DBG_ENCRYPT,
+ /* Guest certificates commands */
+ KVM_SEV_CERT_EXPORT,
+ /* Attestation report */
+ KVM_SEV_GET_ATTESTATION_REPORT,
+ /* Guest Migration Extension */
+ KVM_SEV_SEND_CANCEL,
+
+ /* Second time is the charm; improved versions of the above ioctls. */
+ KVM_SEV_INIT2,
+
+ KVM_SEV_NR_MAX,
+};
+
+struct kvm_sev_cmd {
+ __u32 id;
+ __u32 pad0;
+ __u64 data;
+ __u32 error;
+ __u32 sev_fd;
+};
+
+struct kvm_sev_init {
+ __u64 vmsa_features;
+ __u32 flags;
+ __u32 pad[9];
+};
+
+struct kvm_sev_launch_start {
+ __u32 handle;
+ __u32 policy;
+ __u64 dh_uaddr;
+ __u32 dh_len;
+ __u32 pad0;
+ __u64 session_uaddr;
+ __u32 session_len;
+ __u32 pad1;
+};
+
+struct kvm_sev_launch_update_data {
+ __u64 uaddr;
+ __u32 len;
+ __u32 pad0;
+};
+
+
+struct kvm_sev_launch_secret {
+ __u64 hdr_uaddr;
+ __u32 hdr_len;
+ __u32 pad0;
+ __u64 guest_uaddr;
+ __u32 guest_len;
+ __u32 pad1;
+ __u64 trans_uaddr;
+ __u32 trans_len;
+ __u32 pad2;
+};
+
+struct kvm_sev_launch_measure {
+ __u64 uaddr;
+ __u32 len;
+ __u32 pad0;
+};
+
+struct kvm_sev_guest_status {
+ __u32 handle;
+ __u32 policy;
+ __u32 state;
+};
+
+struct kvm_sev_dbg {
+ __u64 src_uaddr;
+ __u64 dst_uaddr;
+ __u32 len;
+ __u32 pad0;
+};
+
+struct kvm_sev_attestation_report {
+ __u8 mnonce[16];
+ __u64 uaddr;
+ __u32 len;
+ __u32 pad0;
+};
+
+struct kvm_sev_send_start {
+ __u32 policy;
+ __u32 pad0;
+ __u64 pdh_cert_uaddr;
+ __u32 pdh_cert_len;
+ __u32 pad1;
+ __u64 plat_certs_uaddr;
+ __u32 plat_certs_len;
+ __u32 pad2;
+ __u64 amd_certs_uaddr;
+ __u32 amd_certs_len;
+ __u32 pad3;
+ __u64 session_uaddr;
+ __u32 session_len;
+ __u32 pad4;
+};
+
+struct kvm_sev_send_update_data {
+ __u64 hdr_uaddr;
+ __u32 hdr_len;
+ __u32 pad0;
+ __u64 guest_uaddr;
+ __u32 guest_len;
+ __u32 pad1;
+ __u64 trans_uaddr;
+ __u32 trans_len;
+ __u32 pad2;
+};
+
+struct kvm_sev_receive_start {
+ __u32 handle;
+ __u32 policy;
+ __u64 pdh_uaddr;
+ __u32 pdh_len;
+ __u32 pad0;
+ __u64 session_uaddr;
+ __u32 session_len;
+ __u32 pad1;
+};
+
+struct kvm_sev_receive_update_data {
+ __u64 hdr_uaddr;
+ __u32 hdr_len;
+ __u32 pad0;
+ __u64 guest_uaddr;
+ __u32 guest_len;
+ __u32 pad1;
+ __u64 trans_uaddr;
+ __u32 trans_len;
+ __u32 pad2;
+};
+
+#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0)
+#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1)
+
+struct kvm_hyperv_eventfd {
+ __u32 conn_id;
+ __s32 fd;
+ __u32 flags;
+ __u32 padding[3];
+};
+
+#define KVM_HYPERV_CONN_ID_MASK 0x00ffffff
+#define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0)
+
/*
* Masked event layout.
* Bits Description
@@ -547,10 +853,10 @@
((__u64)(!!(exclude)) << 55))
#define KVM_PMU_MASKED_ENTRY_EVENT_SELECT \
- (GENMASK_ULL(7, 0) | GENMASK_ULL(35, 32))
-#define KVM_PMU_MASKED_ENTRY_UMASK_MASK (GENMASK_ULL(63, 56))
-#define KVM_PMU_MASKED_ENTRY_UMASK_MATCH (GENMASK_ULL(15, 8))
-#define KVM_PMU_MASKED_ENTRY_EXCLUDE (BIT_ULL(55))
+ (__GENMASK_ULL(7, 0) | __GENMASK_ULL(35, 32))
+#define KVM_PMU_MASKED_ENTRY_UMASK_MASK (__GENMASK_ULL(63, 56))
+#define KVM_PMU_MASKED_ENTRY_UMASK_MATCH (__GENMASK_ULL(15, 8))
+#define KVM_PMU_MASKED_ENTRY_EXCLUDE (_BITULL(55))
#define KVM_PMU_MASKED_ENTRY_UMASK_MASK_SHIFT (56)
/* for KVM_{GET,SET,HAS}_DEVICE_ATTR */
@@ -558,9 +864,11 @@
#define KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */
/* x86-specific KVM_EXIT_HYPERCALL flags. */
-#define KVM_EXIT_HYPERCALL_LONG_MODE BIT(0)
+#define KVM_EXIT_HYPERCALL_LONG_MODE _BITULL(0)
#define KVM_X86_DEFAULT_VM 0
#define KVM_X86_SW_PROTECTED_VM 1
+#define KVM_X86_SEV_VM 2
+#define KVM_X86_SEV_ES_VM 3
#endif /* _ASM_X86_KVM_H */
diff --git a/linux-headers/linux/bits.h b/linux-headers/linux/bits.h
new file mode 100644
index 0000000..d989777
--- /dev/null
+++ b/linux-headers/linux/bits.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* bits.h: Macros for dealing with bitmasks. */
+
+#ifndef _LINUX_BITS_H
+#define _LINUX_BITS_H
+
+#define __GENMASK(h, l) \
+ (((~_UL(0)) - (_UL(1) << (l)) + 1) & \
+ (~_UL(0) >> (__BITS_PER_LONG - 1 - (h))))
+
+#define __GENMASK_ULL(h, l) \
+ (((~_ULL(0)) - (_ULL(1) << (l)) + 1) & \
+ (~_ULL(0) >> (__BITS_PER_LONG_LONG - 1 - (h))))
+
+#endif /* _LINUX_BITS_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 1783922..038731c 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -16,6 +16,11 @@
#define KVM_API_VERSION 12
+/*
+ * Backwards-compatible definitions.
+ */
+#define __KVM_HAVE_GUEST_DEBUG
+
/* for KVM_SET_USER_MEMORY_REGION */
struct kvm_userspace_memory_region {
__u32 slot;
@@ -85,43 +90,6 @@
#define KVM_PIT_SPEAKER_DUMMY 1
-struct kvm_s390_skeys {
- __u64 start_gfn;
- __u64 count;
- __u64 skeydata_addr;
- __u32 flags;
- __u32 reserved[9];
-};
-
-#define KVM_S390_CMMA_PEEK (1 << 0)
-
-/**
- * kvm_s390_cmma_log - Used for CMMA migration.
- *
- * Used both for input and output.
- *
- * @start_gfn: Guest page number to start from.
- * @count: Size of the result buffer.
- * @flags: Control operation mode via KVM_S390_CMMA_* flags
- * @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty
- * pages are still remaining.
- * @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set
- * in the PGSTE.
- * @values: Pointer to the values buffer.
- *
- * Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls.
- */
-struct kvm_s390_cmma_log {
- __u64 start_gfn;
- __u32 count;
- __u32 flags;
- union {
- __u64 remaining;
- __u64 mask;
- };
- __u64 values;
-};
-
struct kvm_hyperv_exit {
#define KVM_EXIT_HYPERV_SYNIC 1
#define KVM_EXIT_HYPERV_HCALL 2
@@ -313,11 +281,6 @@
__u32 ipb;
} s390_sieic;
/* KVM_EXIT_S390_RESET */
-#define KVM_S390_RESET_POR 1
-#define KVM_S390_RESET_CLEAR 2
-#define KVM_S390_RESET_SUBSYSTEM 4
-#define KVM_S390_RESET_CPU_INIT 8
-#define KVM_S390_RESET_IPL 16
__u64 s390_reset_flags;
/* KVM_EXIT_S390_UCONTROL */
struct {
@@ -532,43 +495,6 @@
__u8 pad[5];
};
-/* for KVM_S390_MEM_OP */
-struct kvm_s390_mem_op {
- /* in */
- __u64 gaddr; /* the guest address */
- __u64 flags; /* flags */
- __u32 size; /* amount of bytes */
- __u32 op; /* type of operation */
- __u64 buf; /* buffer in userspace */
- union {
- struct {
- __u8 ar; /* the access register number */
- __u8 key; /* access key, ignored if flag unset */
- __u8 pad1[6]; /* ignored */
- __u64 old_addr; /* ignored if cmpxchg flag unset */
- };
- __u32 sida_offset; /* offset into the sida */
- __u8 reserved[32]; /* ignored */
- };
-};
-/* types for kvm_s390_mem_op->op */
-#define KVM_S390_MEMOP_LOGICAL_READ 0
-#define KVM_S390_MEMOP_LOGICAL_WRITE 1
-#define KVM_S390_MEMOP_SIDA_READ 2
-#define KVM_S390_MEMOP_SIDA_WRITE 3
-#define KVM_S390_MEMOP_ABSOLUTE_READ 4
-#define KVM_S390_MEMOP_ABSOLUTE_WRITE 5
-#define KVM_S390_MEMOP_ABSOLUTE_CMPXCHG 6
-
-/* flags for kvm_s390_mem_op->flags */
-#define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0)
-#define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1)
-#define KVM_S390_MEMOP_F_SKEY_PROTECTION (1ULL << 2)
-
-/* flags specifying extension support via KVM_CAP_S390_MEM_OP_EXTENSION */
-#define KVM_S390_MEMOP_EXTENSION_CAP_BASE (1 << 0)
-#define KVM_S390_MEMOP_EXTENSION_CAP_CMPXCHG (1 << 1)
-
/* for KVM_INTERRUPT */
struct kvm_interrupt {
/* in */
@@ -633,124 +559,6 @@
__u32 mp_state;
};
-struct kvm_s390_psw {
- __u64 mask;
- __u64 addr;
-};
-
-/* valid values for type in kvm_s390_interrupt */
-#define KVM_S390_SIGP_STOP 0xfffe0000u
-#define KVM_S390_PROGRAM_INT 0xfffe0001u
-#define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u
-#define KVM_S390_RESTART 0xfffe0003u
-#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u
-#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u
-#define KVM_S390_MCHK 0xfffe1000u
-#define KVM_S390_INT_CLOCK_COMP 0xffff1004u
-#define KVM_S390_INT_CPU_TIMER 0xffff1005u
-#define KVM_S390_INT_VIRTIO 0xffff2603u
-#define KVM_S390_INT_SERVICE 0xffff2401u
-#define KVM_S390_INT_EMERGENCY 0xffff1201u
-#define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u
-/* Anything below 0xfffe0000u is taken by INT_IO */
-#define KVM_S390_INT_IO(ai,cssid,ssid,schid) \
- (((schid)) | \
- ((ssid) << 16) | \
- ((cssid) << 18) | \
- ((ai) << 26))
-#define KVM_S390_INT_IO_MIN 0x00000000u
-#define KVM_S390_INT_IO_MAX 0xfffdffffu
-#define KVM_S390_INT_IO_AI_MASK 0x04000000u
-
-
-struct kvm_s390_interrupt {
- __u32 type;
- __u32 parm;
- __u64 parm64;
-};
-
-struct kvm_s390_io_info {
- __u16 subchannel_id;
- __u16 subchannel_nr;
- __u32 io_int_parm;
- __u32 io_int_word;
-};
-
-struct kvm_s390_ext_info {
- __u32 ext_params;
- __u32 pad;
- __u64 ext_params2;
-};
-
-struct kvm_s390_pgm_info {
- __u64 trans_exc_code;
- __u64 mon_code;
- __u64 per_address;
- __u32 data_exc_code;
- __u16 code;
- __u16 mon_class_nr;
- __u8 per_code;
- __u8 per_atmid;
- __u8 exc_access_id;
- __u8 per_access_id;
- __u8 op_access_id;
-#define KVM_S390_PGM_FLAGS_ILC_VALID 0x01
-#define KVM_S390_PGM_FLAGS_ILC_0 0x02
-#define KVM_S390_PGM_FLAGS_ILC_1 0x04
-#define KVM_S390_PGM_FLAGS_ILC_MASK 0x06
-#define KVM_S390_PGM_FLAGS_NO_REWIND 0x08
- __u8 flags;
- __u8 pad[2];
-};
-
-struct kvm_s390_prefix_info {
- __u32 address;
-};
-
-struct kvm_s390_extcall_info {
- __u16 code;
-};
-
-struct kvm_s390_emerg_info {
- __u16 code;
-};
-
-#define KVM_S390_STOP_FLAG_STORE_STATUS 0x01
-struct kvm_s390_stop_info {
- __u32 flags;
-};
-
-struct kvm_s390_mchk_info {
- __u64 cr14;
- __u64 mcic;
- __u64 failing_storage_address;
- __u32 ext_damage_code;
- __u32 pad;
- __u8 fixed_logout[16];
-};
-
-struct kvm_s390_irq {
- __u64 type;
- union {
- struct kvm_s390_io_info io;
- struct kvm_s390_ext_info ext;
- struct kvm_s390_pgm_info pgm;
- struct kvm_s390_emerg_info emerg;
- struct kvm_s390_extcall_info extcall;
- struct kvm_s390_prefix_info prefix;
- struct kvm_s390_stop_info stop;
- struct kvm_s390_mchk_info mchk;
- char reserved[64];
- } u;
-};
-
-struct kvm_s390_irq_state {
- __u64 buf;
- __u32 flags; /* will stay unused for compatibility reasons */
- __u32 len;
- __u32 reserved[4]; /* will stay unused for compatibility reasons */
-};
-
/* for KVM_SET_GUEST_DEBUG */
#define KVM_GUESTDBG_ENABLE 0x00000001
@@ -806,50 +614,6 @@
__u8 pad[64];
};
-/* for KVM_PPC_GET_PVINFO */
-
-#define KVM_PPC_PVINFO_FLAGS_EV_IDLE (1<<0)
-
-struct kvm_ppc_pvinfo {
- /* out */
- __u32 flags;
- __u32 hcall[4];
- __u8 pad[108];
-};
-
-/* for KVM_PPC_GET_SMMU_INFO */
-#define KVM_PPC_PAGE_SIZES_MAX_SZ 8
-
-struct kvm_ppc_one_page_size {
- __u32 page_shift; /* Page shift (or 0) */
- __u32 pte_enc; /* Encoding in the HPTE (>>12) */
-};
-
-struct kvm_ppc_one_seg_page_size {
- __u32 page_shift; /* Base page shift of segment (or 0) */
- __u32 slb_enc; /* SLB encoding for BookS */
- struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ];
-};
-
-#define KVM_PPC_PAGE_SIZES_REAL 0x00000001
-#define KVM_PPC_1T_SEGMENTS 0x00000002
-#define KVM_PPC_NO_HASH 0x00000004
-
-struct kvm_ppc_smmu_info {
- __u64 flags;
- __u32 slb_size;
- __u16 data_keys; /* # storage keys supported for data */
- __u16 instr_keys; /* # storage keys supported for instructions */
- struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
-};
-
-/* for KVM_PPC_RESIZE_HPT_{PREPARE,COMMIT} */
-struct kvm_ppc_resize_hpt {
- __u64 flags;
- __u32 shift;
- __u32 pad;
-};
-
#define KVMIO 0xAE
/* machine type bits, to be used as argument to KVM_CREATE_VM */
@@ -919,9 +683,7 @@
/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
#define KVM_CAP_USER_NMI 22
-#ifdef __KVM_HAVE_GUEST_DEBUG
#define KVM_CAP_SET_GUEST_DEBUG 23
-#endif
#ifdef __KVM_HAVE_PIT
#define KVM_CAP_REINJECT_CONTROL 24
#endif
@@ -1152,8 +914,6 @@
#define KVM_CAP_GUEST_MEMFD 234
#define KVM_CAP_VM_TYPES 235
-#ifdef KVM_CAP_IRQ_ROUTING
-
struct kvm_irq_routing_irqchip {
__u32 irqchip;
__u32 pin;
@@ -1218,42 +978,6 @@
struct kvm_irq_routing_entry entries[];
};
-#endif
-
-#ifdef KVM_CAP_MCE
-/* x86 MCE */
-struct kvm_x86_mce {
- __u64 status;
- __u64 addr;
- __u64 misc;
- __u64 mcg_status;
- __u8 bank;
- __u8 pad1[7];
- __u64 pad2[3];
-};
-#endif
-
-#ifdef KVM_CAP_XEN_HVM
-#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR (1 << 0)
-#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL (1 << 1)
-#define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2)
-#define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3)
-#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4)
-#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5)
-#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6)
-#define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE (1 << 7)
-
-struct kvm_xen_hvm_config {
- __u32 flags;
- __u32 msr;
- __u64 blob_addr_32;
- __u64 blob_addr_64;
- __u8 blob_size_32;
- __u8 blob_size_64;
- __u8 pad2[30];
-};
-#endif
-
#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
/*
* Available with KVM_CAP_IRQFD_RESAMPLE
@@ -1438,11 +1162,6 @@
struct kvm_userspace_memory_region2)
/* enable ucontrol for s390 */
-struct kvm_s390_ucas_mapping {
- __u64 user_addr;
- __u64 vcpu_addr;
- __u64 length;
-};
#define KVM_S390_UCAS_MAP _IOW(KVMIO, 0x50, struct kvm_s390_ucas_mapping)
#define KVM_S390_UCAS_UNMAP _IOW(KVMIO, 0x51, struct kvm_s390_ucas_mapping)
#define KVM_S390_VCPU_FAULT _IOW(KVMIO, 0x52, unsigned long)
@@ -1637,89 +1356,6 @@
#define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3)
#define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4)
-struct kvm_s390_pv_sec_parm {
- __u64 origin;
- __u64 length;
-};
-
-struct kvm_s390_pv_unp {
- __u64 addr;
- __u64 size;
- __u64 tweak;
-};
-
-enum pv_cmd_dmp_id {
- KVM_PV_DUMP_INIT,
- KVM_PV_DUMP_CONFIG_STOR_STATE,
- KVM_PV_DUMP_COMPLETE,
- KVM_PV_DUMP_CPU,
-};
-
-struct kvm_s390_pv_dmp {
- __u64 subcmd;
- __u64 buff_addr;
- __u64 buff_len;
- __u64 gaddr; /* For dump storage state */
- __u64 reserved[4];
-};
-
-enum pv_cmd_info_id {
- KVM_PV_INFO_VM,
- KVM_PV_INFO_DUMP,
-};
-
-struct kvm_s390_pv_info_dump {
- __u64 dump_cpu_buffer_len;
- __u64 dump_config_mem_buffer_per_1m;
- __u64 dump_config_finalize_len;
-};
-
-struct kvm_s390_pv_info_vm {
- __u64 inst_calls_list[4];
- __u64 max_cpus;
- __u64 max_guests;
- __u64 max_guest_addr;
- __u64 feature_indication;
-};
-
-struct kvm_s390_pv_info_header {
- __u32 id;
- __u32 len_max;
- __u32 len_written;
- __u32 reserved;
-};
-
-struct kvm_s390_pv_info {
- struct kvm_s390_pv_info_header header;
- union {
- struct kvm_s390_pv_info_dump dump;
- struct kvm_s390_pv_info_vm vm;
- };
-};
-
-enum pv_cmd_id {
- KVM_PV_ENABLE,
- KVM_PV_DISABLE,
- KVM_PV_SET_SEC_PARMS,
- KVM_PV_UNPACK,
- KVM_PV_VERIFY,
- KVM_PV_PREP_RESET,
- KVM_PV_UNSHARE_ALL,
- KVM_PV_INFO,
- KVM_PV_DUMP,
- KVM_PV_ASYNC_CLEANUP_PREPARE,
- KVM_PV_ASYNC_CLEANUP_PERFORM,
-};
-
-struct kvm_pv_cmd {
- __u32 cmd; /* Command to be executed */
- __u16 rc; /* Ultravisor return code */
- __u16 rrc; /* Ultravisor return reason code */
- __u64 data; /* Data or address */
- __u32 flags; /* flags for future extensions. Must be 0 for now */
- __u32 reserved[3];
-};
-
/* Available with KVM_CAP_S390_PROTECTED */
#define KVM_S390_PV_COMMAND _IOWR(KVMIO, 0xc5, struct kvm_pv_cmd)
@@ -1733,58 +1369,6 @@
#define KVM_XEN_HVM_GET_ATTR _IOWR(KVMIO, 0xc8, struct kvm_xen_hvm_attr)
#define KVM_XEN_HVM_SET_ATTR _IOW(KVMIO, 0xc9, struct kvm_xen_hvm_attr)
-struct kvm_xen_hvm_attr {
- __u16 type;
- __u16 pad[3];
- union {
- __u8 long_mode;
- __u8 vector;
- __u8 runstate_update_flag;
- struct {
- __u64 gfn;
-#define KVM_XEN_INVALID_GFN ((__u64)-1)
- } shared_info;
- struct {
- __u32 send_port;
- __u32 type; /* EVTCHNSTAT_ipi / EVTCHNSTAT_interdomain */
- __u32 flags;
-#define KVM_XEN_EVTCHN_DEASSIGN (1 << 0)
-#define KVM_XEN_EVTCHN_UPDATE (1 << 1)
-#define KVM_XEN_EVTCHN_RESET (1 << 2)
- /*
- * Events sent by the guest are either looped back to
- * the guest itself (potentially on a different port#)
- * or signalled via an eventfd.
- */
- union {
- struct {
- __u32 port;
- __u32 vcpu;
- __u32 priority;
- } port;
- struct {
- __u32 port; /* Zero for eventfd */
- __s32 fd;
- } eventfd;
- __u32 padding[4];
- } deliver;
- } evtchn;
- __u32 xen_version;
- __u64 pad[8];
- } u;
-};
-
-
-/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
-#define KVM_XEN_ATTR_TYPE_LONG_MODE 0x0
-#define KVM_XEN_ATTR_TYPE_SHARED_INFO 0x1
-#define KVM_XEN_ATTR_TYPE_UPCALL_VECTOR 0x2
-/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
-#define KVM_XEN_ATTR_TYPE_EVTCHN 0x3
-#define KVM_XEN_ATTR_TYPE_XEN_VERSION 0x4
-/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG */
-#define KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG 0x5
-
/* Per-vCPU Xen attributes */
#define KVM_XEN_VCPU_GET_ATTR _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr)
#define KVM_XEN_VCPU_SET_ATTR _IOW(KVMIO, 0xcb, struct kvm_xen_vcpu_attr)
@@ -1795,242 +1379,6 @@
#define KVM_GET_SREGS2 _IOR(KVMIO, 0xcc, struct kvm_sregs2)
#define KVM_SET_SREGS2 _IOW(KVMIO, 0xcd, struct kvm_sregs2)
-struct kvm_xen_vcpu_attr {
- __u16 type;
- __u16 pad[3];
- union {
- __u64 gpa;
-#define KVM_XEN_INVALID_GPA ((__u64)-1)
- __u64 pad[8];
- struct {
- __u64 state;
- __u64 state_entry_time;
- __u64 time_running;
- __u64 time_runnable;
- __u64 time_blocked;
- __u64 time_offline;
- } runstate;
- __u32 vcpu_id;
- struct {
- __u32 port;
- __u32 priority;
- __u64 expires_ns;
- } timer;
- __u8 vector;
- } u;
-};
-
-/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
-#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO 0x0
-#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO 0x1
-#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR 0x2
-#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT 0x3
-#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA 0x4
-#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST 0x5
-/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
-#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID 0x6
-#define KVM_XEN_VCPU_ATTR_TYPE_TIMER 0x7
-#define KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR 0x8
-
-/* Secure Encrypted Virtualization command */
-enum sev_cmd_id {
- /* Guest initialization commands */
- KVM_SEV_INIT = 0,
- KVM_SEV_ES_INIT,
- /* Guest launch commands */
- KVM_SEV_LAUNCH_START,
- KVM_SEV_LAUNCH_UPDATE_DATA,
- KVM_SEV_LAUNCH_UPDATE_VMSA,
- KVM_SEV_LAUNCH_SECRET,
- KVM_SEV_LAUNCH_MEASURE,
- KVM_SEV_LAUNCH_FINISH,
- /* Guest migration commands (outgoing) */
- KVM_SEV_SEND_START,
- KVM_SEV_SEND_UPDATE_DATA,
- KVM_SEV_SEND_UPDATE_VMSA,
- KVM_SEV_SEND_FINISH,
- /* Guest migration commands (incoming) */
- KVM_SEV_RECEIVE_START,
- KVM_SEV_RECEIVE_UPDATE_DATA,
- KVM_SEV_RECEIVE_UPDATE_VMSA,
- KVM_SEV_RECEIVE_FINISH,
- /* Guest status and debug commands */
- KVM_SEV_GUEST_STATUS,
- KVM_SEV_DBG_DECRYPT,
- KVM_SEV_DBG_ENCRYPT,
- /* Guest certificates commands */
- KVM_SEV_CERT_EXPORT,
- /* Attestation report */
- KVM_SEV_GET_ATTESTATION_REPORT,
- /* Guest Migration Extension */
- KVM_SEV_SEND_CANCEL,
-
- KVM_SEV_NR_MAX,
-};
-
-struct kvm_sev_cmd {
- __u32 id;
- __u64 data;
- __u32 error;
- __u32 sev_fd;
-};
-
-struct kvm_sev_launch_start {
- __u32 handle;
- __u32 policy;
- __u64 dh_uaddr;
- __u32 dh_len;
- __u64 session_uaddr;
- __u32 session_len;
-};
-
-struct kvm_sev_launch_update_data {
- __u64 uaddr;
- __u32 len;
-};
-
-
-struct kvm_sev_launch_secret {
- __u64 hdr_uaddr;
- __u32 hdr_len;
- __u64 guest_uaddr;
- __u32 guest_len;
- __u64 trans_uaddr;
- __u32 trans_len;
-};
-
-struct kvm_sev_launch_measure {
- __u64 uaddr;
- __u32 len;
-};
-
-struct kvm_sev_guest_status {
- __u32 handle;
- __u32 policy;
- __u32 state;
-};
-
-struct kvm_sev_dbg {
- __u64 src_uaddr;
- __u64 dst_uaddr;
- __u32 len;
-};
-
-struct kvm_sev_attestation_report {
- __u8 mnonce[16];
- __u64 uaddr;
- __u32 len;
-};
-
-struct kvm_sev_send_start {
- __u32 policy;
- __u64 pdh_cert_uaddr;
- __u32 pdh_cert_len;
- __u64 plat_certs_uaddr;
- __u32 plat_certs_len;
- __u64 amd_certs_uaddr;
- __u32 amd_certs_len;
- __u64 session_uaddr;
- __u32 session_len;
-};
-
-struct kvm_sev_send_update_data {
- __u64 hdr_uaddr;
- __u32 hdr_len;
- __u64 guest_uaddr;
- __u32 guest_len;
- __u64 trans_uaddr;
- __u32 trans_len;
-};
-
-struct kvm_sev_receive_start {
- __u32 handle;
- __u32 policy;
- __u64 pdh_uaddr;
- __u32 pdh_len;
- __u64 session_uaddr;
- __u32 session_len;
-};
-
-struct kvm_sev_receive_update_data {
- __u64 hdr_uaddr;
- __u32 hdr_len;
- __u64 guest_uaddr;
- __u32 guest_len;
- __u64 trans_uaddr;
- __u32 trans_len;
-};
-
-#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
-#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
-#define KVM_DEV_ASSIGN_MASK_INTX (1 << 2)
-
-struct kvm_assigned_pci_dev {
- __u32 assigned_dev_id;
- __u32 busnr;
- __u32 devfn;
- __u32 flags;
- __u32 segnr;
- union {
- __u32 reserved[11];
- };
-};
-
-#define KVM_DEV_IRQ_HOST_INTX (1 << 0)
-#define KVM_DEV_IRQ_HOST_MSI (1 << 1)
-#define KVM_DEV_IRQ_HOST_MSIX (1 << 2)
-
-#define KVM_DEV_IRQ_GUEST_INTX (1 << 8)
-#define KVM_DEV_IRQ_GUEST_MSI (1 << 9)
-#define KVM_DEV_IRQ_GUEST_MSIX (1 << 10)
-
-#define KVM_DEV_IRQ_HOST_MASK 0x00ff
-#define KVM_DEV_IRQ_GUEST_MASK 0xff00
-
-struct kvm_assigned_irq {
- __u32 assigned_dev_id;
- __u32 host_irq; /* ignored (legacy field) */
- __u32 guest_irq;
- __u32 flags;
- union {
- __u32 reserved[12];
- };
-};
-
-struct kvm_assigned_msix_nr {
- __u32 assigned_dev_id;
- __u16 entry_nr;
- __u16 padding;
-};
-
-#define KVM_MAX_MSIX_PER_DEV 256
-struct kvm_assigned_msix_entry {
- __u32 assigned_dev_id;
- __u32 gsi;
- __u16 entry; /* The index of entry in the MSI-X table */
- __u16 padding[3];
-};
-
-#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0)
-#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1)
-
-/* Available with KVM_CAP_ARM_USER_IRQ */
-
-/* Bits for run->s.regs.device_irq_level */
-#define KVM_ARM_DEV_EL1_VTIMER (1 << 0)
-#define KVM_ARM_DEV_EL1_PTIMER (1 << 1)
-#define KVM_ARM_DEV_PMU (1 << 2)
-
-struct kvm_hyperv_eventfd {
- __u32 conn_id;
- __s32 fd;
- __u32 flags;
- __u32 padding[3];
-};
-
-#define KVM_HYPERV_CONN_ID_MASK 0x00ffffff
-#define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0)
-
#define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (1 << 0)
#define KVM_DIRTY_LOG_INITIALLY_SET (1 << 1)
@@ -2176,33 +1524,6 @@
/* Available with KVM_CAP_S390_ZPCI_OP */
#define KVM_S390_ZPCI_OP _IOW(KVMIO, 0xd1, struct kvm_s390_zpci_op)
-struct kvm_s390_zpci_op {
- /* in */
- __u32 fh; /* target device */
- __u8 op; /* operation to perform */
- __u8 pad[3];
- union {
- /* for KVM_S390_ZPCIOP_REG_AEN */
- struct {
- __u64 ibv; /* Guest addr of interrupt bit vector */
- __u64 sb; /* Guest addr of summary bit */
- __u32 flags;
- __u32 noi; /* Number of interrupts */
- __u8 isc; /* Guest interrupt subclass */
- __u8 sbo; /* Offset of guest summary bit vector */
- __u16 pad;
- } reg_aen;
- __u64 reserved[8];
- } u;
-};
-
-/* types for kvm_s390_zpci_op->op */
-#define KVM_S390_ZPCIOP_REG_AEN 0
-#define KVM_S390_ZPCIOP_DEREG_AEN 1
-
-/* flags for kvm_s390_zpci_op->u.reg_aen.flags */
-#define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0)
-
/* Available with KVM_CAP_MEMORY_ATTRIBUTES */
#define KVM_SET_MEMORY_ATTRIBUTES _IOW(KVMIO, 0xd2, struct kvm_memory_attributes)
diff --git a/linux-headers/linux/psp-sev.h b/linux-headers/linux/psp-sev.h
index bcb2133..c3046c6 100644
--- a/linux-headers/linux/psp-sev.h
+++ b/linux-headers/linux/psp-sev.h
@@ -28,6 +28,9 @@
SEV_PEK_CERT_IMPORT,
SEV_GET_ID, /* This command is deprecated, use SEV_GET_ID2 */
SEV_GET_ID2,
+ SNP_PLATFORM_STATUS,
+ SNP_COMMIT,
+ SNP_SET_CONFIG,
SEV_MAX,
};
@@ -69,6 +72,12 @@
SEV_RET_RESOURCE_LIMIT,
SEV_RET_SECURE_DATA_INVALID,
SEV_RET_INVALID_KEY = 0x27,
+ SEV_RET_INVALID_PAGE_SIZE,
+ SEV_RET_INVALID_PAGE_STATE,
+ SEV_RET_INVALID_MDATA_ENTRY,
+ SEV_RET_INVALID_PAGE_OWNER,
+ SEV_RET_INVALID_PAGE_AEAD_OFLOW,
+ SEV_RET_RMP_INIT_REQUIRED,
SEV_RET_MAX,
} sev_ret_code;
@@ -156,6 +165,56 @@
} __attribute__((packed));
/**
+ * struct sev_user_data_snp_status - SNP status
+ *
+ * @api_major: API major version
+ * @api_minor: API minor version
+ * @state: current platform state
+ * @is_rmp_initialized: whether RMP is initialized or not
+ * @rsvd: reserved
+ * @build_id: firmware build id for the API version
+ * @mask_chip_id: whether chip id is present in attestation reports or not
+ * @mask_chip_key: whether attestation reports are signed or not
+ * @vlek_en: VLEK (Version Loaded Endorsement Key) hashstick is loaded
+ * @rsvd1: reserved
+ * @guest_count: the number of guest currently managed by the firmware
+ * @current_tcb_version: current TCB version
+ * @reported_tcb_version: reported TCB version
+ */
+struct sev_user_data_snp_status {
+ __u8 api_major; /* Out */
+ __u8 api_minor; /* Out */
+ __u8 state; /* Out */
+ __u8 is_rmp_initialized:1; /* Out */
+ __u8 rsvd:7;
+ __u32 build_id; /* Out */
+ __u32 mask_chip_id:1; /* Out */
+ __u32 mask_chip_key:1; /* Out */
+ __u32 vlek_en:1; /* Out */
+ __u32 rsvd1:29;
+ __u32 guest_count; /* Out */
+ __u64 current_tcb_version; /* Out */
+ __u64 reported_tcb_version; /* Out */
+} __attribute__((packed));
+
+/**
+ * struct sev_user_data_snp_config - system wide configuration value for SNP.
+ *
+ * @reported_tcb: the TCB version to report in the guest attestation report.
+ * @mask_chip_id: whether chip id is present in attestation reports or not
+ * @mask_chip_key: whether attestation reports are signed or not
+ * @rsvd: reserved
+ * @rsvd1: reserved
+ */
+struct sev_user_data_snp_config {
+ __u64 reported_tcb ; /* In */
+ __u32 mask_chip_id:1; /* In */
+ __u32 mask_chip_key:1; /* In */
+ __u32 rsvd:30; /* In */
+ __u8 rsvd1[52];
+} __attribute__((packed));
+
+/**
* struct sev_issue_cmd - SEV ioctl parameters
*
* @cmd: SEV commands to execute
diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h
index 649560c..bea6973 100644
--- a/linux-headers/linux/vhost.h
+++ b/linux-headers/linux/vhost.h
@@ -227,4 +227,11 @@
*/
#define VHOST_VDPA_GET_VRING_DESC_GROUP _IOWR(VHOST_VIRTIO, 0x7F, \
struct vhost_vring_state)
+
+/* Get the queue size of a specific virtqueue.
+ * userspace set the vring index in vhost_vring_state.index
+ * kernel set the queue size in vhost_vring_state.num
+ */
+#define VHOST_VDPA_GET_VRING_SIZE _IOWR(VHOST_VIRTIO, 0x80, \
+ struct vhost_vring_state)
#endif
diff --git a/meson.build b/meson.build
index 34b0ab0..95cee70 100644
--- a/meson.build
+++ b/meson.build
@@ -3415,8 +3415,12 @@
subdir('authz')
subdir('crypto')
subdir('ui')
-subdir('hw')
subdir('gdbstub')
+if have_system
+ subdir('hw')
+else
+ subdir('hw/core')
+endif
if enable_modules
libmodulecommon = static_library('module-common', files('module-common.c') + genh, pic: true, c_args: '-DBUILD_DSO')
@@ -3445,7 +3449,7 @@
libqemuutil = static_library('qemuutil',
build_by_default: false,
sources: util_ss.sources() + stub_ss.sources() + genh,
- dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman])
+ dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc])
qemuutil = declare_dependency(link_with: libqemuutil,
sources: genh + version_res,
dependencies: [event_loop_base])
diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
index 2708abf..a7d5504 100644
--- a/migration/block-dirty-bitmap.c
+++ b/migration/block-dirty-bitmap.c
@@ -481,13 +481,13 @@
/* Called with the BQL taken. */
static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs,
- const char *bs_name, GHashTable *alias_map)
+ const char *bs_name, GHashTable *alias_map,
+ Error **errp)
{
BdrvDirtyBitmap *bitmap;
SaveBitmapState *dbms;
GHashTable *bitmap_aliases;
const char *node_alias, *bitmap_name, *bitmap_alias;
- Error *local_err = NULL;
/* When an alias map is given, @bs_name must be @bs's node name */
assert(!alias_map || !strcmp(bs_name, bdrv_get_node_name(bs)));
@@ -504,8 +504,8 @@
bitmap_name = bdrv_dirty_bitmap_name(bitmap);
if (!bs_name || strcmp(bs_name, "") == 0) {
- error_report("Bitmap '%s' in unnamed node can't be migrated",
- bitmap_name);
+ error_setg(errp, "Bitmap '%s' in unnamed node can't be migrated",
+ bitmap_name);
return -1;
}
@@ -525,9 +525,9 @@
}
if (node_alias[0] == '#') {
- error_report("Bitmap '%s' in a node with auto-generated "
- "name '%s' can't be migrated",
- bitmap_name, node_alias);
+ error_setg(errp, "Bitmap '%s' in a node with auto-generated "
+ "name '%s' can't be migrated",
+ bitmap_name, node_alias);
return -1;
}
@@ -538,8 +538,7 @@
continue;
}
- if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, &local_err)) {
- error_report_err(local_err);
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
return -1;
}
@@ -558,9 +557,9 @@
}
} else {
if (strlen(bitmap_name) > UINT8_MAX) {
- error_report("Cannot migrate bitmap '%s' on node '%s': "
- "Name is longer than %u bytes",
- bitmap_name, bs_name, UINT8_MAX);
+ error_setg(errp, "Cannot migrate bitmap '%s' on node '%s': "
+ "Name is longer than %u bytes",
+ bitmap_name, bs_name, UINT8_MAX);
return -1;
}
bitmap_alias = bitmap_name;
@@ -599,7 +598,7 @@
}
/* Called with the BQL taken. */
-static int init_dirty_bitmap_migration(DBMSaveState *s)
+static int init_dirty_bitmap_migration(DBMSaveState *s, Error **errp)
{
BlockDriverState *bs;
SaveBitmapState *dbms;
@@ -643,7 +642,7 @@
}
if (bs && bs->drv && !bs->drv->is_filter) {
- if (add_bitmaps_to_list(s, bs, name, NULL)) {
+ if (add_bitmaps_to_list(s, bs, name, NULL, errp)) {
goto fail;
}
g_hash_table_add(handled_by_blk, bs);
@@ -656,7 +655,8 @@
continue;
}
- if (add_bitmaps_to_list(s, bs, bdrv_get_node_name(bs), alias_map)) {
+ if (add_bitmaps_to_list(s, bs, bdrv_get_node_name(bs), alias_map,
+ errp)) {
goto fail;
}
}
@@ -1213,12 +1213,12 @@
return ret;
}
-static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque)
+static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque, Error **errp)
{
DBMSaveState *s = &((DBMState *)opaque)->save;
SaveBitmapState *dbms = NULL;
- if (init_dirty_bitmap_migration(s) < 0) {
+ if (init_dirty_bitmap_migration(s, errp) < 0) {
return -1;
}
diff --git a/migration/block.c b/migration/block.c
index 2b90548..bae6e94 100644
--- a/migration/block.c
+++ b/migration/block.c
@@ -367,7 +367,7 @@
}
}
-static int init_blk_migration(QEMUFile *f)
+static int init_blk_migration(QEMUFile *f, Error **errp)
{
BlockDriverState *bs;
BlkMigDevState *bmds;
@@ -378,7 +378,6 @@
BlkMigDevState *bmds;
BlockDriverState *bs;
} *bmds_bs;
- Error *local_err = NULL;
int ret;
GRAPH_RDLOCK_GUARD_MAINLOOP();
@@ -406,6 +405,8 @@
continue;
}
if (sectors < 0) {
+ error_setg(errp, "Error getting length of block device %s",
+ bdrv_get_device_name(bs));
ret = sectors;
bdrv_next_cleanup(&it);
goto out;
@@ -442,9 +443,8 @@
bs = bmds_bs[i].bs;
if (bmds) {
- ret = blk_insert_bs(bmds->blk, bs, &local_err);
+ ret = blk_insert_bs(bmds->blk, bs, errp);
if (ret < 0) {
- error_report_err(local_err);
goto out;
}
@@ -711,7 +711,7 @@
blk_mig_unlock();
}
-static int block_save_setup(QEMUFile *f, void *opaque)
+static int block_save_setup(QEMUFile *f, void *opaque, Error **errp)
{
int ret;
@@ -721,7 +721,7 @@
warn_report("block migration is deprecated;"
" use blockdev-mirror with NBD instead");
- ret = init_blk_migration(f);
+ ret = init_blk_migration(f, errp);
if (ret < 0) {
return ret;
}
@@ -729,10 +729,15 @@
/* start track dirty blocks */
ret = set_dirty_tracking();
if (ret) {
+ error_setg_errno(errp, -ret, "Failed to start block dirty tracking");
return ret;
}
ret = flush_blks(f);
+ if (ret) {
+ error_setg_errno(errp, -ret, "Flushing block failed");
+ return ret;
+ }
blk_mig_reset_dirty_cursor();
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
diff --git a/stubs/colo.c b/migration/colo-stubs.c
similarity index 100%
rename from stubs/colo.c
rename to migration/colo-stubs.c
diff --git a/migration/colo.c b/migration/colo.c
index 84632a6..5600a43 100644
--- a/migration/colo.c
+++ b/migration/colo.c
@@ -835,6 +835,16 @@
return NULL;
}
+ /* Make sure all file formats throw away their mutable metadata */
+ bql_lock();
+ bdrv_activate_all(&local_err);
+ if (local_err) {
+ bql_unlock();
+ error_report_err(local_err);
+ return NULL;
+ }
+ bql_unlock();
+
failover_init_state();
mis->to_src_file = qemu_file_get_return_path(mis->from_src_file);
@@ -922,7 +932,6 @@
int coroutine_fn colo_incoming_co(void)
{
MigrationIncomingState *mis = migration_incoming_get_current();
- Error *local_err = NULL;
QemuThread th;
assert(bql_locked());
@@ -931,13 +940,6 @@
return 0;
}
- /* Make sure all file formats throw away their mutable metadata */
- bdrv_activate_all(&local_err);
- if (local_err) {
- error_report_err(local_err);
- return -EINVAL;
- }
-
qemu_thread_create(&th, "COLO incoming", colo_process_incoming_thread,
mis, QEMU_THREAD_JOINABLE);
diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index 1d2e857..d02d70b 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -90,9 +90,15 @@
void global_dirty_log_change(unsigned int flag, bool start)
{
+ Error *local_err = NULL;
+ bool ret;
+
bql_lock();
if (start) {
- memory_global_dirty_log_start(flag);
+ ret = memory_global_dirty_log_start(flag, &local_err);
+ if (!ret) {
+ error_report_err(local_err);
+ }
} else {
memory_global_dirty_log_stop(flag);
}
@@ -608,9 +614,12 @@
{
int64_t start_time;
DirtyPageRecord dirty_pages;
+ Error *local_err = NULL;
bql_lock();
- memory_global_dirty_log_start(GLOBAL_DIRTY_DIRTY_RATE);
+ if (!memory_global_dirty_log_start(GLOBAL_DIRTY_DIRTY_RATE, &local_err)) {
+ error_report_err(local_err);
+ }
/*
* 1'round of log sync may return all 1 bits with
diff --git a/migration/meson.build b/migration/meson.build
index 1eeb915..f76b1ba 100644
--- a/migration/meson.build
+++ b/migration/meson.build
@@ -34,6 +34,8 @@
if get_option('replication').allowed()
system_ss.add(files('colo-failover.c', 'colo.c'))
+else
+ system_ss.add(files('colo-stubs.c'))
endif
system_ss.add(when: rdma, if_true: files('rdma.c'))
diff --git a/migration/migration.c b/migration/migration.c
index 86bf76e..b5af6b5 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1956,7 +1956,7 @@
}
if (migration_is_running()) {
- error_setg(errp, QERR_MIGRATION_ACTIVE);
+ error_setg(errp, "There's a migration process in progress");
return false;
}
@@ -3431,6 +3431,8 @@
int64_t setup_start = qemu_clock_get_ms(QEMU_CLOCK_HOST);
MigThrError thr_error;
bool urgent = false;
+ Error *local_err = NULL;
+ int ret;
thread = migration_threads_add("live_migration", qemu_get_thread_id());
@@ -3474,12 +3476,24 @@
}
bql_lock();
- qemu_savevm_state_setup(s->to_dst_file);
+ ret = qemu_savevm_state_setup(s->to_dst_file, &local_err);
bql_unlock();
qemu_savevm_wait_unplug(s, MIGRATION_STATUS_SETUP,
MIGRATION_STATUS_ACTIVE);
+ /*
+ * Handle SETUP failures after waiting for virtio-net-failover
+ * devices to unplug. This to preserve migration state transitions.
+ */
+ if (ret) {
+ migrate_set_error(s, local_err);
+ error_free(local_err);
+ migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE,
+ MIGRATION_STATUS_FAILED);
+ goto out;
+ }
+
s->setup_time = qemu_clock_get_ms(QEMU_CLOCK_HOST) - setup_start;
trace_migration_thread_setup_complete();
@@ -3553,6 +3567,8 @@
MigThrError thr_error;
QEMUFile *fb;
bool early_fail = true;
+ Error *local_err = NULL;
+ int ret;
rcu_register_thread();
object_ref(OBJECT(s));
@@ -3586,12 +3602,24 @@
bql_lock();
qemu_savevm_state_header(s->to_dst_file);
- qemu_savevm_state_setup(s->to_dst_file);
+ ret = qemu_savevm_state_setup(s->to_dst_file, &local_err);
bql_unlock();
qemu_savevm_wait_unplug(s, MIGRATION_STATUS_SETUP,
MIGRATION_STATUS_ACTIVE);
+ /*
+ * Handle SETUP failures after waiting for virtio-net-failover
+ * devices to unplug. This to preserve migration state transitions.
+ */
+ if (ret) {
+ migrate_set_error(s, local_err);
+ error_free(local_err);
+ migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE,
+ MIGRATION_STATUS_FAILED);
+ goto fail_setup;
+ }
+
s->setup_time = qemu_clock_get_ms(QEMU_CLOCK_HOST) - setup_start;
trace_migration_thread_setup_complete();
@@ -3660,6 +3688,7 @@
bql_unlock();
}
+fail_setup:
bg_migration_iteration_finish(s);
qemu_fclose(fb);
diff --git a/migration/multifd-zero-page.c b/migration/multifd-zero-page.c
index 1ba38be..e1b8370 100644
--- a/migration/multifd-zero-page.c
+++ b/migration/multifd-zero-page.c
@@ -80,8 +80,10 @@
{
for (int i = 0; i < p->zero_num; i++) {
void *page = p->host + p->zero[i];
- if (!buffer_is_zero(page, p->page_size)) {
+ if (ramblock_recv_bitmap_test_byte_offset(p->block, p->zero[i])) {
memset(page, 0, p->page_size);
+ } else {
+ ramblock_recv_bitmap_set_offset(p->block, p->zero[i]);
}
}
}
diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c
index 99821cd..737a964 100644
--- a/migration/multifd-zlib.c
+++ b/migration/multifd-zlib.c
@@ -284,6 +284,7 @@
int flush = Z_NO_FLUSH;
unsigned long start = zs->total_out;
+ ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
if (i == p->normal_num - 1) {
flush = Z_SYNC_FLUSH;
}
diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c
index 0211225..256858d 100644
--- a/migration/multifd-zstd.c
+++ b/migration/multifd-zstd.c
@@ -278,6 +278,7 @@
z->in.pos = 0;
for (i = 0; i < p->normal_num; i++) {
+ ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
z->out.dst = p->host + p->normal[i];
z->out.size = p->page_size;
z->out.pos = 0;
diff --git a/migration/multifd.c b/migration/multifd.c
index 2802afe..f317bff 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -277,6 +277,7 @@
for (int i = 0; i < p->normal_num; i++) {
p->iov[i].iov_base = p->host + p->normal[i];
p->iov[i].iov_len = p->page_size;
+ ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
}
return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp);
}
diff --git a/migration/options.c b/migration/options.c
index bfd7753..239f5ec 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -685,7 +685,7 @@
bool new_caps[MIGRATION_CAPABILITY__MAX];
if (migration_is_running()) {
- error_setg(errp, QERR_MIGRATION_ACTIVE);
+ error_setg(errp, "There's a migration process in progress");
return false;
}
@@ -729,7 +729,7 @@
bool new_caps[MIGRATION_CAPABILITY__MAX];
if (migration_is_running() || migration_in_colo_state()) {
- error_setg(errp, QERR_MIGRATION_ACTIVE);
+ error_setg(errp, "There's a migration process in progress");
return;
}
@@ -1286,9 +1286,8 @@
if (params->has_vcpu_dirty_limit &&
(params->vcpu_dirty_limit < 1)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "vcpu_dirty_limit",
- "is invalid, it must greater then 1 MB/s");
+ error_setg(errp,
+ "Parameter 'vcpu_dirty_limit' must be greater than 1 MB/s");
return false;
}
diff --git a/migration/ram.c b/migration/ram.c
index 8deb849..a975c5a 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -275,6 +275,10 @@
nr);
}
+void ramblock_recv_bitmap_set_offset(RAMBlock *rb, uint64_t byte_offset)
+{
+ set_bit_atomic(byte_offset >> TARGET_PAGE_BITS, rb->receivedmap);
+}
#define RAMBLOCK_RECV_BITMAP_ENDING (0x0123456789abcdefULL)
/*
@@ -2438,10 +2442,23 @@
XBZRLE_cache_unlock();
}
+static void ram_bitmaps_destroy(void)
+{
+ RAMBlock *block;
+
+ RAMBLOCK_FOREACH_NOT_IGNORED(block) {
+ g_free(block->clear_bmap);
+ block->clear_bmap = NULL;
+ g_free(block->bmap);
+ block->bmap = NULL;
+ g_free(block->file_bmap);
+ block->file_bmap = NULL;
+ }
+}
+
static void ram_save_cleanup(void *opaque)
{
RAMState **rsp = opaque;
- RAMBlock *block;
/* We don't use dirty log with background snapshots */
if (!migrate_background_snapshot()) {
@@ -2458,12 +2475,7 @@
}
}
- RAMBLOCK_FOREACH_NOT_IGNORED(block) {
- g_free(block->clear_bmap);
- block->clear_bmap = NULL;
- g_free(block->bmap);
- block->bmap = NULL;
- }
+ ram_bitmaps_destroy();
xbzrle_cleanup();
compress_threads_save_cleanup();
@@ -2719,44 +2731,41 @@
* For every allocation, we will try not to crash the VM if the
* allocation failed.
*/
-static int xbzrle_init(void)
+static bool xbzrle_init(Error **errp)
{
- Error *local_err = NULL;
-
if (!migrate_xbzrle()) {
- return 0;
+ return true;
}
XBZRLE_cache_lock();
XBZRLE.zero_target_page = g_try_malloc0(TARGET_PAGE_SIZE);
if (!XBZRLE.zero_target_page) {
- error_report("%s: Error allocating zero page", __func__);
+ error_setg(errp, "%s: Error allocating zero page", __func__);
goto err_out;
}
XBZRLE.cache = cache_init(migrate_xbzrle_cache_size(),
- TARGET_PAGE_SIZE, &local_err);
+ TARGET_PAGE_SIZE, errp);
if (!XBZRLE.cache) {
- error_report_err(local_err);
goto free_zero_page;
}
XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE);
if (!XBZRLE.encoded_buf) {
- error_report("%s: Error allocating encoded_buf", __func__);
+ error_setg(errp, "%s: Error allocating encoded_buf", __func__);
goto free_cache;
}
XBZRLE.current_buf = g_try_malloc(TARGET_PAGE_SIZE);
if (!XBZRLE.current_buf) {
- error_report("%s: Error allocating current_buf", __func__);
+ error_setg(errp, "%s: Error allocating current_buf", __func__);
goto free_encoded_buf;
}
/* We are all good */
XBZRLE_cache_unlock();
- return 0;
+ return true;
free_encoded_buf:
g_free(XBZRLE.encoded_buf);
@@ -2769,16 +2778,16 @@
XBZRLE.zero_target_page = NULL;
err_out:
XBZRLE_cache_unlock();
- return -ENOMEM;
+ return false;
}
-static int ram_state_init(RAMState **rsp)
+static bool ram_state_init(RAMState **rsp, Error **errp)
{
*rsp = g_try_new0(RAMState, 1);
if (!*rsp) {
- error_report("%s: Init ramstate fail", __func__);
- return -1;
+ error_setg(errp, "%s: Init ramstate fail", __func__);
+ return false;
}
qemu_mutex_init(&(*rsp)->bitmap_mutex);
@@ -2794,7 +2803,7 @@
(*rsp)->migration_dirty_pages = (*rsp)->ram_bytes_total >> TARGET_PAGE_BITS;
ram_state_reset(*rsp);
- return 0;
+ return true;
}
static void ram_list_init_bitmaps(void)
@@ -2852,39 +2861,53 @@
}
}
-static void ram_init_bitmaps(RAMState *rs)
+static bool ram_init_bitmaps(RAMState *rs, Error **errp)
{
+ bool ret = true;
+
qemu_mutex_lock_ramlist();
WITH_RCU_READ_LOCK_GUARD() {
ram_list_init_bitmaps();
/* We don't use dirty log with background snapshots */
if (!migrate_background_snapshot()) {
- memory_global_dirty_log_start(GLOBAL_DIRTY_MIGRATION);
+ ret = memory_global_dirty_log_start(GLOBAL_DIRTY_MIGRATION, errp);
+ if (!ret) {
+ goto out_unlock;
+ }
migration_bitmap_sync_precopy(rs, false);
}
}
+out_unlock:
qemu_mutex_unlock_ramlist();
+ if (!ret) {
+ ram_bitmaps_destroy();
+ return false;
+ }
+
/*
* After an eventual first bitmap sync, fixup the initial bitmap
* containing all 1s to exclude any discarded pages from migration.
*/
migration_bitmap_clear_discarded_pages(rs);
+ return true;
}
-static int ram_init_all(RAMState **rsp)
+static int ram_init_all(RAMState **rsp, Error **errp)
{
- if (ram_state_init(rsp)) {
+ if (!ram_state_init(rsp, errp)) {
return -1;
}
- if (xbzrle_init()) {
+ if (!xbzrle_init(errp)) {
ram_state_cleanup(rsp);
return -1;
}
- ram_init_bitmaps(*rsp);
+ if (!ram_init_bitmaps(*rsp, errp)) {
+ return -1;
+ }
return 0;
}
@@ -3066,20 +3089,22 @@
*
* @f: QEMUFile where to send the data
* @opaque: RAMState pointer
+ * @errp: pointer to Error*, to store an error if it happens.
*/
-static int ram_save_setup(QEMUFile *f, void *opaque)
+static int ram_save_setup(QEMUFile *f, void *opaque, Error **errp)
{
RAMState **rsp = opaque;
RAMBlock *block;
int ret, max_hg_page_size;
if (compress_threads_save_setup()) {
+ error_setg(errp, "%s: failed to start compress threads", __func__);
return -1;
}
/* migration has already setup the bitmap, reuse it. */
if (!migration_in_colo_state()) {
- if (ram_init_all(rsp) != 0) {
+ if (ram_init_all(rsp, errp) != 0) {
compress_threads_save_cleanup();
return -1;
}
@@ -3116,12 +3141,14 @@
ret = rdma_registration_start(f, RAM_CONTROL_SETUP);
if (ret < 0) {
+ error_setg(errp, "%s: failed to start RDMA registration", __func__);
qemu_file_set_error(f, ret);
return ret;
}
ret = rdma_registration_stop(f, RAM_CONTROL_SETUP);
if (ret < 0) {
+ error_setg(errp, "%s: failed to stop RDMA registration", __func__);
qemu_file_set_error(f, ret);
return ret;
}
@@ -3138,6 +3165,7 @@
ret = multifd_send_sync_main();
bql_lock();
if (ret < 0) {
+ error_setg(errp, "%s: multifd synchronization failed", __func__);
return ret;
}
@@ -3147,7 +3175,11 @@
}
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
- return qemu_fflush(f);
+ ret = qemu_fflush(f);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "%s failed", __func__);
+ }
+ return ret;
}
static void ram_save_file_bmap(QEMUFile *f)
@@ -3592,7 +3624,11 @@
static void colo_init_ram_state(void)
{
- ram_state_init(&ram_state);
+ Error *local_err = NULL;
+
+ if (!ram_state_init(&ram_state, &local_err)) {
+ error_report_err(local_err);
+ }
}
/*
@@ -3647,6 +3683,8 @@
void colo_incoming_start_dirty_log(void)
{
RAMBlock *block = NULL;
+ Error *local_err = NULL;
+
/* For memory_global_dirty_log_start below. */
bql_lock();
qemu_mutex_lock_ramlist();
@@ -3658,7 +3696,10 @@
/* Discard this dirty bitmap record */
bitmap_zero(block->bmap, block->max_length >> TARGET_PAGE_BITS);
}
- memory_global_dirty_log_start(GLOBAL_DIRTY_MIGRATION);
+ if (!memory_global_dirty_log_start(GLOBAL_DIRTY_MIGRATION,
+ &local_err)) {
+ error_report_err(local_err);
+ }
}
ram_state->migration_dirty_pages = 0;
qemu_mutex_unlock_ramlist();
@@ -3694,8 +3735,9 @@
*
* @f: QEMUFile where to receive the data
* @opaque: RAMState pointer
+ * @errp: pointer to Error*, to store an error if it happens.
*/
-static int ram_load_setup(QEMUFile *f, void *opaque)
+static int ram_load_setup(QEMUFile *f, void *opaque, Error **errp)
{
xbzrle_load_setup();
ramblock_recv_map_init();
diff --git a/migration/ram.h b/migration/ram.h
index 08feeca..bc0318b 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -69,6 +69,7 @@
bool ramblock_recv_bitmap_test_byte_offset(RAMBlock *rb, uint64_t byte_offset);
void ramblock_recv_bitmap_set(RAMBlock *rb, void *host_addr);
void ramblock_recv_bitmap_set_range(RAMBlock *rb, void *host_addr, size_t nr);
+void ramblock_recv_bitmap_set_offset(RAMBlock *rb, uint64_t byte_offset);
int64_t ramblock_recv_bitmap_send(QEMUFile *file,
const char *block_name);
bool ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *rb, Error **errp);
diff --git a/migration/savevm.c b/migration/savevm.c
index e7c1215..4509482 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1009,11 +1009,10 @@
}
}
-static int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc)
+static int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc,
+ Error **errp)
{
int ret;
- Error *local_err = NULL;
- MigrationState *s = migrate_get_current();
if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
return 0;
@@ -1035,10 +1034,9 @@
if (!se->vmsd) {
vmstate_save_old_style(f, se, vmdesc);
} else {
- ret = vmstate_save_state_with_err(f, se->vmsd, se->opaque, vmdesc, &local_err);
+ ret = vmstate_save_state_with_err(f, se->vmsd, se->opaque, vmdesc,
+ errp);
if (ret) {
- migrate_set_error(s, local_err);
- error_report_err(local_err);
return ret;
}
}
@@ -1312,11 +1310,11 @@
return 0;
}
-void qemu_savevm_state_setup(QEMUFile *f)
+int qemu_savevm_state_setup(QEMUFile *f, Error **errp)
{
+ ERRP_GUARD();
MigrationState *ms = migrate_get_current();
SaveStateEntry *se;
- Error *local_err = NULL;
int ret = 0;
json_writer_int64(ms->vmdesc, "page_size", qemu_target_page_size());
@@ -1325,8 +1323,9 @@
trace_savevm_state_setup();
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
if (se->vmsd && se->vmsd->early_setup) {
- ret = vmstate_save(f, se, ms->vmdesc);
+ ret = vmstate_save(f, se, ms->vmdesc, errp);
if (ret) {
+ migrate_set_error(ms, *errp);
qemu_file_set_error(f, ret);
break;
}
@@ -1343,7 +1342,7 @@
}
save_section_header(f, se, QEMU_VM_SECTION_START);
- ret = se->ops->save_setup(f, se->opaque);
+ ret = se->ops->save_setup(f, se->opaque, errp);
save_section_footer(f, se);
if (ret < 0) {
qemu_file_set_error(f, ret);
@@ -1352,12 +1351,11 @@
}
if (ret) {
- return;
+ return ret;
}
- if (precopy_notify(PRECOPY_NOTIFY_SETUP, &local_err)) {
- error_report_err(local_err);
- }
+ /* TODO: Should we check that errp is set in case of failure ? */
+ return precopy_notify(PRECOPY_NOTIFY_SETUP, errp);
}
int qemu_savevm_state_resume_prepare(MigrationState *s)
@@ -1542,6 +1540,7 @@
JSONWriter *vmdesc = ms->vmdesc;
int vmdesc_len;
SaveStateEntry *se;
+ Error *local_err = NULL;
int ret;
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
@@ -1552,8 +1551,10 @@
start_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
- ret = vmstate_save(f, se, vmdesc);
+ ret = vmstate_save(f, se, vmdesc, &local_err);
if (ret) {
+ migrate_set_error(ms, local_err);
+ error_report_err(local_err);
qemu_file_set_error(f, ret);
return ret;
}
@@ -1568,7 +1569,6 @@
* bdrv_activate_all() on the other end won't fail. */
ret = bdrv_inactivate_all();
if (ret) {
- Error *local_err = NULL;
error_setg(&local_err, "%s: bdrv_inactivate_all() failed (%d)",
__func__, ret);
migrate_set_error(ms, local_err);
@@ -1707,7 +1707,7 @@
MigrationStatus status;
if (migration_is_running()) {
- error_setg(errp, QERR_MIGRATION_ACTIVE);
+ error_setg(errp, "There's a migration process in progress");
return -EINVAL;
}
@@ -1723,7 +1723,10 @@
ms->to_dst_file = f;
qemu_savevm_state_header(f);
- qemu_savevm_state_setup(f);
+ ret = qemu_savevm_state_setup(f, errp);
+ if (ret) {
+ goto cleanup;
+ }
while (qemu_file_get_error(f) == 0) {
if (qemu_savevm_state_iterate(f, false) > 0) {
@@ -1736,10 +1739,11 @@
qemu_savevm_state_complete_precopy(f, false, false);
ret = qemu_file_get_error(f);
}
- qemu_savevm_state_cleanup();
if (ret != 0) {
error_setg_errno(errp, -ret, "Error while writing VM state");
}
+cleanup:
+ qemu_savevm_state_cleanup();
if (ret != 0) {
status = MIGRATION_STATUS_FAILED;
@@ -1764,6 +1768,8 @@
int qemu_save_device_state(QEMUFile *f)
{
+ MigrationState *ms = migrate_get_current();
+ Error *local_err = NULL;
SaveStateEntry *se;
if (!migration_in_colo_state()) {
@@ -1778,8 +1784,10 @@
if (se->is_ram) {
continue;
}
- ret = vmstate_save(f, se, NULL);
+ ret = vmstate_save(f, se, NULL, &local_err);
if (ret) {
+ migrate_set_error(ms, local_err);
+ error_report_err(local_err);
return ret;
}
}
@@ -2760,8 +2768,9 @@
trace_loadvm_state_switchover_ack_needed(mis->switchover_ack_pending_num);
}
-static int qemu_loadvm_state_setup(QEMUFile *f)
+static int qemu_loadvm_state_setup(QEMUFile *f, Error **errp)
{
+ ERRP_GUARD();
SaveStateEntry *se;
int ret;
@@ -2776,10 +2785,11 @@
}
}
- ret = se->ops->load_setup(f, se->opaque);
+ ret = se->ops->load_setup(f, se->opaque, errp);
if (ret < 0) {
+ error_prepend(errp, "Load state of device %s failed: ",
+ se->idstr);
qemu_file_set_error(f, ret);
- error_report("Load state of device %s failed", se->idstr);
return ret;
}
}
@@ -2960,7 +2970,8 @@
return ret;
}
- if (qemu_loadvm_state_setup(f) != 0) {
+ if (qemu_loadvm_state_setup(f, &local_err) != 0) {
+ error_report_err(local_err);
return -EINVAL;
}
diff --git a/migration/savevm.h b/migration/savevm.h
index 7466973..9ec96a9 100644
--- a/migration/savevm.h
+++ b/migration/savevm.h
@@ -32,7 +32,7 @@
bool qemu_savevm_state_blocked(Error **errp);
void qemu_savevm_non_migratable_list(strList **reasons);
int qemu_savevm_state_prepare(Error **errp);
-void qemu_savevm_state_setup(QEMUFile *f);
+int qemu_savevm_state_setup(QEMUFile *f, Error **errp);
bool qemu_savevm_state_guest_unplug_pending(void);
int qemu_savevm_state_resume_prepare(MigrationState *s);
void qemu_savevm_state_header(QEMUFile *f);
diff --git a/monitor/meson.build b/monitor/meson.build
index 5269492..a71523a 100644
--- a/monitor/meson.build
+++ b/monitor/meson.build
@@ -4,6 +4,7 @@
'fds.c',
'hmp-cmds.c',
'hmp.c',
+ 'qemu-config-qmp.c',
))
system_ss.add([spice_headers, files('qmp-cmds.c')])
diff --git a/monitor/qemu-config-qmp.c b/monitor/qemu-config-qmp.c
new file mode 100644
index 0000000..24477a0
--- /dev/null
+++ b/monitor/qemu-config-qmp.c
@@ -0,0 +1,206 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-misc.h"
+#include "qapi/qmp/qlist.h"
+#include "qemu/option.h"
+#include "qemu/config-file.h"
+#include "hw/boards.h"
+
+static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
+{
+ CommandLineParameterInfoList *param_list = NULL;
+ CommandLineParameterInfo *info;
+ int i;
+
+ for (i = 0; desc[i].name != NULL; i++) {
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(desc[i].name);
+
+ switch (desc[i].type) {
+ case QEMU_OPT_STRING:
+ info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
+ break;
+ case QEMU_OPT_BOOL:
+ info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
+ break;
+ case QEMU_OPT_NUMBER:
+ info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
+ break;
+ case QEMU_OPT_SIZE:
+ info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
+ break;
+ }
+
+ info->help = g_strdup(desc[i].help);
+ info->q_default = g_strdup(desc[i].def_value_str);
+
+ QAPI_LIST_PREPEND(param_list, info);
+ }
+
+ return param_list;
+}
+
+/* remove repeated entry from the info list */
+static void cleanup_infolist(CommandLineParameterInfoList *head)
+{
+ CommandLineParameterInfoList *pre_entry, *cur, *del_entry;
+
+ cur = head;
+ while (cur->next) {
+ pre_entry = head;
+ while (pre_entry != cur->next) {
+ if (!strcmp(pre_entry->value->name, cur->next->value->name)) {
+ del_entry = cur->next;
+ cur->next = cur->next->next;
+ del_entry->next = NULL;
+ qapi_free_CommandLineParameterInfoList(del_entry);
+ break;
+ }
+ pre_entry = pre_entry->next;
+ }
+ cur = cur->next;
+ }
+}
+
+/* merge the description items of two parameter infolists */
+static void connect_infolist(CommandLineParameterInfoList *head,
+ CommandLineParameterInfoList *new)
+{
+ CommandLineParameterInfoList *cur;
+
+ cur = head;
+ while (cur->next) {
+ cur = cur->next;
+ }
+ cur->next = new;
+}
+
+/* access all the local QemuOptsLists for drive option */
+static CommandLineParameterInfoList *get_drive_infolist(void)
+{
+ CommandLineParameterInfoList *head = NULL, *cur;
+ int i;
+
+ for (i = 0; drive_config_groups[i] != NULL; i++) {
+ if (!head) {
+ head = query_option_descs(drive_config_groups[i]->desc);
+ } else {
+ cur = query_option_descs(drive_config_groups[i]->desc);
+ connect_infolist(head, cur);
+ }
+ }
+ cleanup_infolist(head);
+
+ return head;
+}
+
+static CommandLineParameterInfo *objprop_to_cmdline_prop(ObjectProperty *prop)
+{
+ CommandLineParameterInfo *info;
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(prop->name);
+
+ if (g_str_equal(prop->type, "bool") || g_str_equal(prop->type, "OnOffAuto")) {
+ info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
+ } else if (g_str_equal(prop->type, "int")) {
+ info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
+ } else if (g_str_equal(prop->type, "size")) {
+ info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
+ } else {
+ info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
+ }
+
+ if (prop->description) {
+ info->help = g_strdup(prop->description);
+ }
+
+ return info;
+}
+
+static CommandLineParameterInfoList *query_all_machine_properties(void)
+{
+ CommandLineParameterInfoList *params = NULL, *clpiter;
+ CommandLineParameterInfo *info;
+ GSList *machines, *curr_mach;
+ ObjectPropertyIterator op_iter;
+ ObjectProperty *prop;
+ bool is_new;
+
+ machines = object_class_get_list(TYPE_MACHINE, false);
+ assert(machines);
+
+ /* Loop over all machine classes */
+ for (curr_mach = machines; curr_mach; curr_mach = curr_mach->next) {
+ object_class_property_iter_init(&op_iter, curr_mach->data);
+ /* ... and over the properties of each machine: */
+ while ((prop = object_property_iter_next(&op_iter))) {
+ if (!prop->set) {
+ continue;
+ }
+ /*
+ * Check whether the property has already been put into the list
+ * (via another machine class)
+ */
+ is_new = true;
+ for (clpiter = params; clpiter != NULL; clpiter = clpiter->next) {
+ if (g_str_equal(clpiter->value->name, prop->name)) {
+ is_new = false;
+ break;
+ }
+ }
+ /* If it hasn't been added before, add it now to the list */
+ if (is_new) {
+ info = objprop_to_cmdline_prop(prop);
+ QAPI_LIST_PREPEND(params, info);
+ }
+ }
+ }
+
+ g_slist_free(machines);
+
+ /* Add entry for the "type" parameter */
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup("type");
+ info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
+ info->help = g_strdup("machine type");
+ QAPI_LIST_PREPEND(params, info);
+
+ return params;
+}
+
+CommandLineOptionInfoList *qmp_query_command_line_options(const char *option,
+ Error **errp)
+{
+ CommandLineOptionInfoList *conf_list = NULL;
+ CommandLineOptionInfo *info;
+ int i;
+
+ for (i = 0; vm_config_groups[i] != NULL; i++) {
+ if (!option || !strcmp(option, vm_config_groups[i]->name)) {
+ info = g_malloc0(sizeof(*info));
+ info->option = g_strdup(vm_config_groups[i]->name);
+ if (!strcmp("drive", vm_config_groups[i]->name)) {
+ info->parameters = get_drive_infolist();
+ } else {
+ info->parameters =
+ query_option_descs(vm_config_groups[i]->desc);
+ }
+ QAPI_LIST_PREPEND(conf_list, info);
+ }
+ }
+
+ if (!option || !strcmp(option, "machine")) {
+ info = g_malloc0(sizeof(*info));
+ info->option = g_strdup("machine");
+ info->parameters = query_all_machine_properties();
+ QAPI_LIST_PREPEND(conf_list, info);
+ }
+
+ if (conf_list == NULL) {
+ error_setg(errp, "invalid option name: %s", option);
+ }
+
+ return conf_list;
+}
diff --git a/stubs/colo-compare.c b/net/colo-stubs.c
similarity index 100%
rename from stubs/colo-compare.c
rename to net/colo-stubs.c
diff --git a/net/meson.build b/net/meson.build
index 9432a58..e0cd714 100644
--- a/net/meson.build
+++ b/net/meson.build
@@ -20,6 +20,8 @@
get_option('colo_proxy').allowed()
system_ss.add(files('colo-compare.c'))
system_ss.add(files('colo.c'))
+else
+ system_ss.add(files('colo-stubs.c'))
endif
if get_option('colo_proxy').allowed()
diff --git a/pythondeps.toml b/pythondeps.toml
index 0e88415..9c16602 100644
--- a/pythondeps.toml
+++ b/pythondeps.toml
@@ -22,6 +22,7 @@
meson = { accepted = ">=0.63.0", installed = "1.2.3", canary = "meson" }
[docs]
+# Please keep the installed versions in sync with docs/requirements.txt
sphinx = { accepted = ">=1.6", installed = "5.3.0", canary = "sphinx-build" }
sphinx_rtd_theme = { accepted = ">=0.5", installed = "1.1.1" }
diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
index 8f1efab..3d1a28b 100644
--- a/qapi/opts-visitor.c
+++ b/qapi/opts-visitor.c
@@ -184,7 +184,7 @@
const QemuOpt *first;
first = g_queue_peek_head(any);
- error_setg(errp, QERR_INVALID_PARAMETER, first->name);
+ error_setg(errp, "Invalid parameter '%s'", first->name);
return false;
}
return true;
diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
index 3e8aca6..f110a80 100644
--- a/qapi/qobject-input-visitor.c
+++ b/qapi/qobject-input-visitor.c
@@ -288,8 +288,8 @@
return false;
}
if (qobject_type(qobj) != QTYPE_QDICT) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- full_name(qiv, name), "object");
+ error_setg(errp, "Invalid parameter type for '%s', expected: object",
+ full_name(qiv, name));
return false;
}
@@ -326,8 +326,8 @@
return false;
}
if (qobject_type(qobj) != QTYPE_QLIST) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- full_name(qiv, name), "array");
+ error_setg(errp, "Invalid parameter type for '%s', expected: array",
+ full_name(qiv, name));
return false;
}
@@ -405,8 +405,8 @@
}
qnum = qobject_to(QNum, qobj);
if (!qnum || !qnum_get_try_int(qnum, obj)) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- full_name(qiv, name), "integer");
+ error_setg(errp, "Invalid parameter type for '%s', expected: integer",
+ full_name(qiv, name));
return false;
}
return true;
@@ -494,8 +494,8 @@
}
qbool = qobject_to(QBool, qobj);
if (!qbool) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- full_name(qiv, name), "boolean");
+ error_setg(errp, "Invalid parameter type for '%s', expected: boolean",
+ full_name(qiv, name));
return false;
}
@@ -534,8 +534,8 @@
}
qstr = qobject_to(QString, qobj);
if (!qstr) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- full_name(qiv, name), "string");
+ error_setg(errp, "Invalid parameter type for '%s', expected: string",
+ full_name(qiv, name));
return false;
}
@@ -565,8 +565,8 @@
}
qnum = qobject_to(QNum, qobj);
if (!qnum) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- full_name(qiv, name), "number");
+ error_setg(errp, "Invalid parameter type for '%s', expected: number",
+ full_name(qiv, name));
return false;
}
@@ -587,8 +587,8 @@
if (qemu_strtod_finite(str, NULL, &val)) {
/* TODO report -ERANGE more nicely */
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- full_name(qiv, name), "number");
+ error_setg(errp, "Invalid parameter type for '%s', expected: number",
+ full_name(qiv, name));
return false;
}
@@ -623,8 +623,8 @@
}
if (qobject_type(qobj) != QTYPE_QNULL) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
- full_name(qiv, name), "null");
+ error_setg(errp, "Invalid parameter type for '%s', expected: null",
+ full_name(qiv, name));
return false;
}
*obj = qnull();
diff --git a/qapi/qom.json b/qapi/qom.json
index 85e6b4f..38dde6d 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -898,6 +898,14 @@
# designated guest firmware page for measured boot with -kernel
# (default: false) (since 6.2)
#
+# @legacy-vm-type: Use legacy KVM_SEV_INIT KVM interface for creating the VM.
+# The newer KVM_SEV_INIT2 interface syncs additional vCPU
+# state when initializing the VMSA structures, which will
+# result in a different guest measurement. Set this to
+# maintain compatibility with older QEMU or kernel versions
+# that rely on legacy KVM_SEV_INIT behavior.
+# (default: false) (since 9.1)
+#
# Since: 2.12
##
{ 'struct': 'SevGuestProperties',
@@ -908,7 +916,8 @@
'*handle': 'uint32',
'*cbitpos': 'uint32',
'reduced-phys-bits': 'uint32',
- '*kernel-hashes': 'bool' } }
+ '*kernel-hashes': 'bool',
+ '*legacy-vm-type': 'bool' } }
##
# @ThreadContextProperties:
diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c
index 197139c..3f1b9e9 100644
--- a/qapi/string-input-visitor.c
+++ b/qapi/string-input-visitor.c
@@ -353,8 +353,8 @@
assert(siv->lm == LM_NONE);
if (qemu_strtod_finite(siv->string, NULL, &val)) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
- "number");
+ error_setg(errp, "Invalid parameter type for '%s', expected: number",
+ name ? name : "null");
return false;
}
@@ -371,8 +371,8 @@
*obj = NULL;
if (siv->string[0]) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
- "null");
+ error_setg(errp, "Invalid parameter type for '%s', expected: null",
+ name ? name : "null");
return false;
}
diff --git a/qom/object.c b/qom/object.c
index d4a001c..44ec8f6 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -23,7 +23,6 @@
#include "qapi/qobject-input-visitor.h"
#include "qapi/forward-visitor.h"
#include "qapi/qapi-builtin-visit.h"
-#include "qapi/qmp/qerror.h"
#include "qapi/qmp/qjson.h"
#include "trace.h"
@@ -1495,7 +1494,8 @@
}
qstring = qobject_to(QString, ret);
if (!qstring) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
+ error_setg(errp, "Invalid parameter type for '%s', expected: string",
+ name);
retval = NULL;
} else {
retval = g_strdup(qstring_get_str(qstring));
@@ -1556,7 +1556,8 @@
}
qbool = qobject_to(QBool, ret);
if (!qbool) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
+ error_setg(errp, "Invalid parameter type for '%s', expected: boolean",
+ name);
retval = false;
} else {
retval = qbool_get_bool(qbool);
@@ -1589,7 +1590,8 @@
qnum = qobject_to(QNum, ret);
if (!qnum || !qnum_get_try_int(qnum, &retval)) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
+ error_setg(errp, "Invalid parameter type for '%s', expected: int",
+ name);
retval = -1;
}
@@ -1663,7 +1665,8 @@
}
qnum = qobject_to(QNum, ret);
if (!qnum || !qnum_get_try_uint(qnum, &retval)) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "uint");
+ error_setg(errp, "Invalid parameter type for '%s', expected: uint",
+ name);
retval = 0;
}
@@ -1908,7 +1911,8 @@
} else if (!target) {
target = object_resolve_path(path, &ambiguous);
if (target || ambiguous) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
+ error_setg(errp, "Invalid parameter type for '%s', expected: %s",
+ name, target_type);
} else {
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
"Device '%s' not found", path);
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index 67c7d89..4679b1b 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -227,10 +227,14 @@ def _use_type(self, typ: QAPISchemaType) -> str:
# Map the various integer types to plain int
if typ.json_type() == 'int':
- typ = self._schema.lookup_type('int')
+ type_int = self._schema.lookup_type('int')
+ assert type_int
+ typ = type_int
elif (isinstance(typ, QAPISchemaArrayType) and
typ.element_type.json_type() == 'int'):
- typ = self._schema.lookup_type('intList')
+ type_intList = self._schema.lookup_type('intList')
+ assert type_intList
+ typ = type_intList
# Add type to work queue if new
if typ not in self._used_types:
self._used_types.append(typ)
diff --git a/scripts/qapi/mypy.ini b/scripts/qapi/mypy.ini
index 56e0dfb..8109470 100644
--- a/scripts/qapi/mypy.ini
+++ b/scripts/qapi/mypy.ini
@@ -2,8 +2,3 @@
strict = True
disallow_untyped_calls = False
python_version = 3.8
-
-[mypy-qapi.schema]
-disallow_untyped_defs = False
-disallow_incomplete_defs = False
-check_untyped_defs = False
diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py
index d8f7606..7b13a58 100644
--- a/scripts/qapi/parser.py
+++ b/scripts/qapi/parser.py
@@ -19,6 +19,7 @@
import re
from typing import (
TYPE_CHECKING,
+ Any,
Dict,
List,
Mapping,
@@ -43,7 +44,7 @@
_ExprValue = Union[List[object], Dict[str, object], str, bool]
-class QAPIExpression(Dict[str, object]):
+class QAPIExpression(Dict[str, Any]):
# pylint: disable=too-few-public-methods
def __init__(self,
data: Mapping[str, object],
@@ -607,6 +608,7 @@ class QAPIDoc:
"""
class Section:
+ # pylint: disable=too-few-public-methods
def __init__(self, info: QAPISourceInfo,
tag: Optional[str] = None):
# section source info, i.e. where it begins
@@ -705,6 +707,7 @@ def append_line(self, line: str) -> None:
def connect_member(self, member: 'QAPISchemaMember') -> None:
if member.name not in self.args:
+ assert member.info
if self.symbol not in member.info.pragma.documentation_exceptions:
raise QAPISemError(member.info,
"%s '%s' lacks documentation"
@@ -733,7 +736,7 @@ def check_expr(self, expr: QAPIExpression) -> None:
"'Returns' section is only valid for commands")
if self.errors:
raise QAPISemError(
- self.returns.info,
+ self.errors.info,
"'Errors' section is only valid for commands")
def check(self) -> None:
diff --git a/scripts/qapi/pylintrc b/scripts/qapi/pylintrc
index 90546df..c028a1f 100644
--- a/scripts/qapi/pylintrc
+++ b/scripts/qapi/pylintrc
@@ -1,10 +1,5 @@
[MASTER]
-# Add files or directories matching the regex patterns to the ignore list.
-# The regex matches against base names, not paths.
-ignore-patterns=schema.py,
-
-
[MESSAGES CONTROL]
# Disable the message, report, category or checker with the given id(s). You
@@ -16,13 +11,13 @@
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
-disable=fixme,
+disable=consider-using-f-string,
+ fixme,
missing-docstring,
too-many-arguments,
too-many-branches,
- too-many-statements,
too-many-instance-attributes,
- consider-using-f-string,
+ too-many-statements,
useless-option-value,
[REPORTS]
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 8ba5665..5924947 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -12,12 +12,25 @@
# This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory.
+# pylint: disable=too-many-lines
+
# TODO catching name collisions in generated code would be nice
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
from collections import OrderedDict
import os
import re
-from typing import List, Optional
+from typing import (
+ Any,
+ Callable,
+ Dict,
+ List,
+ Optional,
+ Union,
+ cast,
+)
from .common import (
POINTER_SUFFIX,
@@ -29,140 +42,230 @@
)
from .error import QAPIError, QAPISemError, QAPISourceError
from .expr import check_exprs
-from .parser import QAPIExpression, QAPISchemaParser
+from .parser import QAPIDoc, QAPIExpression, QAPISchemaParser
+from .source import QAPISourceInfo
class QAPISchemaIfCond:
- def __init__(self, ifcond=None):
+ def __init__(
+ self,
+ ifcond: Optional[Union[str, Dict[str, object]]] = None,
+ ) -> None:
self.ifcond = ifcond
- def _cgen(self):
+ def _cgen(self) -> str:
return cgen_ifcond(self.ifcond)
- def gen_if(self):
+ def gen_if(self) -> str:
return gen_if(self._cgen())
- def gen_endif(self):
+ def gen_endif(self) -> str:
return gen_endif(self._cgen())
- def docgen(self):
+ def docgen(self) -> str:
return docgen_ifcond(self.ifcond)
- def is_present(self):
+ def is_present(self) -> bool:
return bool(self.ifcond)
class QAPISchemaEntity:
- meta: Optional[str] = None
+ """
+ A schema entity.
- def __init__(self, name: str, info, doc, ifcond=None, features=None):
- assert name is None or isinstance(name, str)
- for f in features or []:
- assert isinstance(f, QAPISchemaFeature)
- f.set_defined_in(name)
- self.name = name
- self._module = None
+ This is either a directive, such as include, or a definition.
+ The latter uses sub-class `QAPISchemaDefinition`.
+ """
+ def __init__(self, info: Optional[QAPISourceInfo]):
+ self._module: Optional[QAPISchemaModule] = None
# For explicitly defined entities, info points to the (explicit)
# definition. For builtins (and their arrays), info is None.
# For implicitly defined entities, info points to a place that
# triggered the implicit definition (there may be more than one
# such place).
self.info = info
- self.doc = doc
- self._ifcond = ifcond or QAPISchemaIfCond()
- self.features = features or []
self._checked = False
- def __repr__(self):
- if self.name is None:
- return "<%s at 0x%x>" % (type(self).__name__, id(self))
- return "<%s:%s at 0x%x>" % (type(self).__name__, self.name,
- id(self))
+ def __repr__(self) -> str:
+ return "<%s at 0x%x>" % (type(self).__name__, id(self))
- def c_name(self):
- return c_name(self.name)
-
- def check(self, schema):
- assert not self._checked
- seen = {}
- for f in self.features:
- f.check_clash(self.info, seen)
+ def check(self, schema: QAPISchema) -> None:
+ # pylint: disable=unused-argument
self._checked = True
- def connect_doc(self, doc=None):
- doc = doc or self.doc
- if doc:
- for f in self.features:
- doc.connect_feature(f)
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
+ pass
- def _set_module(self, schema, info):
+ def _set_module(
+ self, schema: QAPISchema, info: Optional[QAPISourceInfo]
+ ) -> None:
assert self._checked
fname = info.fname if info else QAPISchemaModule.BUILTIN_MODULE_NAME
self._module = schema.module_by_fname(fname)
self._module.add_entity(self)
- def set_module(self, schema):
+ def set_module(self, schema: QAPISchema) -> None:
self._set_module(schema, self.info)
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
+ # pylint: disable=unused-argument
+ assert self._checked
+
+
+class QAPISchemaDefinition(QAPISchemaEntity):
+ meta: str
+
+ def __init__(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ doc: Optional[QAPIDoc],
+ ifcond: Optional[QAPISchemaIfCond] = None,
+ features: Optional[List[QAPISchemaFeature]] = None,
+ ):
+ super().__init__(info)
+ for f in features or []:
+ f.set_defined_in(name)
+ self.name = name
+ self.doc = doc
+ self._ifcond = ifcond or QAPISchemaIfCond()
+ self.features = features or []
+
+ def __repr__(self) -> str:
+ return "<%s:%s at 0x%x>" % (type(self).__name__, self.name,
+ id(self))
+
+ def c_name(self) -> str:
+ return c_name(self.name)
+
+ def check(self, schema: QAPISchema) -> None:
+ assert not self._checked
+ super().check(schema)
+ seen: Dict[str, QAPISchemaMember] = {}
+ for f in self.features:
+ f.check_clash(self.info, seen)
+
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
+ super().connect_doc(doc)
+ doc = doc or self.doc
+ if doc:
+ for f in self.features:
+ doc.connect_feature(f)
+
@property
- def ifcond(self):
+ def ifcond(self) -> QAPISchemaIfCond:
assert self._checked
return self._ifcond
- def is_implicit(self):
+ def is_implicit(self) -> bool:
return not self.info
- def visit(self, visitor):
- assert self._checked
-
- def describe(self):
- assert self.meta
+ def describe(self) -> str:
return "%s '%s'" % (self.meta, self.name)
class QAPISchemaVisitor:
- def visit_begin(self, schema):
+ def visit_begin(self, schema: QAPISchema) -> None:
pass
- def visit_end(self):
+ def visit_end(self) -> None:
pass
- def visit_module(self, name):
+ def visit_module(self, name: str) -> None:
pass
- def visit_needed(self, entity):
+ def visit_needed(self, entity: QAPISchemaEntity) -> bool:
+ # pylint: disable=unused-argument
# Default to visiting everything
return True
- def visit_include(self, name, info):
+ def visit_include(self, name: str, info: Optional[QAPISourceInfo]) -> None:
pass
- def visit_builtin_type(self, name, info, json_type):
+ def visit_builtin_type(
+ self, name: str, info: Optional[QAPISourceInfo], json_type: str
+ ) -> None:
pass
- def visit_enum_type(self, name, info, ifcond, features, members, prefix):
+ def visit_enum_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ members: List[QAPISchemaEnumMember],
+ prefix: Optional[str],
+ ) -> None:
pass
- def visit_array_type(self, name, info, ifcond, element_type):
+ def visit_array_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ element_type: QAPISchemaType,
+ ) -> None:
pass
- def visit_object_type(self, name, info, ifcond, features,
- base, members, variants):
+ def visit_object_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ base: Optional[QAPISchemaObjectType],
+ members: List[QAPISchemaObjectTypeMember],
+ variants: Optional[QAPISchemaVariants],
+ ) -> None:
pass
- def visit_object_type_flat(self, name, info, ifcond, features,
- members, variants):
+ def visit_object_type_flat(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ members: List[QAPISchemaObjectTypeMember],
+ variants: Optional[QAPISchemaVariants],
+ ) -> None:
pass
- def visit_alternate_type(self, name, info, ifcond, features, variants):
+ def visit_alternate_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ variants: QAPISchemaVariants,
+ ) -> None:
pass
- def visit_command(self, name, info, ifcond, features,
- arg_type, ret_type, gen, success_response, boxed,
- allow_oob, allow_preconfig, coroutine):
+ def visit_command(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ arg_type: Optional[QAPISchemaObjectType],
+ ret_type: Optional[QAPISchemaType],
+ gen: bool,
+ success_response: bool,
+ boxed: bool,
+ allow_oob: bool,
+ allow_preconfig: bool,
+ coroutine: bool,
+ ) -> None:
pass
- def visit_event(self, name, info, ifcond, features, arg_type, boxed):
+ def visit_event(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ arg_type: Optional[QAPISchemaObjectType],
+ boxed: bool,
+ ) -> None:
pass
@@ -170,9 +273,9 @@ class QAPISchemaModule:
BUILTIN_MODULE_NAME = './builtin'
- def __init__(self, name):
+ def __init__(self, name: str):
self.name = name
- self._entity_list = []
+ self._entity_list: List[QAPISchemaEntity] = []
@staticmethod
def is_system_module(name: str) -> bool:
@@ -201,10 +304,10 @@ def is_builtin_module(cls, name: str) -> bool:
"""
return name == cls.BUILTIN_MODULE_NAME
- def add_entity(self, ent):
+ def add_entity(self, ent: QAPISchemaEntity) -> None:
self._entity_list.append(ent)
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
visitor.visit_module(self.name)
for entity in self._entity_list:
if visitor.visit_needed(entity):
@@ -212,33 +315,35 @@ def visit(self, visitor):
class QAPISchemaInclude(QAPISchemaEntity):
- def __init__(self, sub_module, info):
- super().__init__(None, info, None)
+ def __init__(self, sub_module: QAPISchemaModule, info: QAPISourceInfo):
+ super().__init__(info)
self._sub_module = sub_module
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_include(self._sub_module.name, self.info)
-class QAPISchemaType(QAPISchemaEntity):
+class QAPISchemaType(QAPISchemaDefinition, ABC):
# Return the C type for common use.
# For the types we commonly box, this is a pointer type.
- def c_type(self):
+ @abstractmethod
+ def c_type(self) -> str:
pass
# Return the C type to be used in a parameter list.
- def c_param_type(self):
+ def c_param_type(self) -> str:
return self.c_type()
# Return the C type to be used where we suppress boxing.
- def c_unboxed_type(self):
+ def c_unboxed_type(self) -> str:
return self.c_type()
- def json_type(self):
+ @abstractmethod
+ def json_type(self) -> str:
pass
- def alternate_qtype(self):
+ def alternate_qtype(self) -> Optional[str]:
json2qtype = {
'null': 'QTYPE_QNULL',
'string': 'QTYPE_QSTRING',
@@ -250,17 +355,17 @@ def alternate_qtype(self):
}
return json2qtype.get(self.json_type())
- def doc_type(self):
+ def doc_type(self) -> Optional[str]:
if self.is_implicit():
return None
return self.name
- def need_has_if_optional(self):
+ def need_has_if_optional(self) -> bool:
# When FOO is a pointer, has_FOO == !!FOO, i.e. has_FOO is redundant.
# Except for arrays; see QAPISchemaArrayType.need_has_if_optional().
return not self.c_type().endswith(POINTER_SUFFIX)
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
super().check(schema)
for feat in self.features:
if feat.is_special():
@@ -268,40 +373,38 @@ def check(self, schema):
self.info,
f"feature '{feat.name}' is not supported for types")
- def describe(self):
- assert self.meta
+ def describe(self) -> str:
return "%s type '%s'" % (self.meta, self.name)
class QAPISchemaBuiltinType(QAPISchemaType):
meta = 'built-in'
- def __init__(self, name, json_type, c_type):
+ def __init__(self, name: str, json_type: str, c_type: str):
super().__init__(name, None, None)
- assert not c_type or isinstance(c_type, str)
assert json_type in ('string', 'number', 'int', 'boolean', 'null',
'value')
self._json_type_name = json_type
self._c_type_name = c_type
- def c_name(self):
+ def c_name(self) -> str:
return self.name
- def c_type(self):
+ def c_type(self) -> str:
return self._c_type_name
- def c_param_type(self):
+ def c_param_type(self) -> str:
if self.name == 'str':
return 'const ' + self._c_type_name
return self._c_type_name
- def json_type(self):
+ def json_type(self) -> str:
return self._json_type_name
- def doc_type(self):
+ def doc_type(self) -> str:
return self.json_type()
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_builtin_type(self.name, self.info, self.json_type())
@@ -309,41 +412,48 @@ def visit(self, visitor):
class QAPISchemaEnumType(QAPISchemaType):
meta = 'enum'
- def __init__(self, name, info, doc, ifcond, features, members, prefix):
+ def __init__(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ doc: Optional[QAPIDoc],
+ ifcond: Optional[QAPISchemaIfCond],
+ features: Optional[List[QAPISchemaFeature]],
+ members: List[QAPISchemaEnumMember],
+ prefix: Optional[str],
+ ):
super().__init__(name, info, doc, ifcond, features)
for m in members:
- assert isinstance(m, QAPISchemaEnumMember)
m.set_defined_in(name)
- assert prefix is None or isinstance(prefix, str)
self.members = members
self.prefix = prefix
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
super().check(schema)
- seen = {}
+ seen: Dict[str, QAPISchemaMember] = {}
for m in self.members:
m.check_clash(self.info, seen)
- def connect_doc(self, doc=None):
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
super().connect_doc(doc)
doc = doc or self.doc
for m in self.members:
m.connect_doc(doc)
- def is_implicit(self):
+ def is_implicit(self) -> bool:
# See QAPISchema._def_predefineds()
return self.name == 'QType'
- def c_type(self):
+ def c_type(self) -> str:
return c_name(self.name)
- def member_names(self):
+ def member_names(self) -> List[str]:
return [m.name for m in self.members]
- def json_type(self):
+ def json_type(self) -> str:
return 'string'
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_enum_type(
self.name, self.info, self.ifcond, self.features,
@@ -353,82 +463,89 @@ def visit(self, visitor):
class QAPISchemaArrayType(QAPISchemaType):
meta = 'array'
- def __init__(self, name, info, element_type):
+ def __init__(
+ self, name: str, info: Optional[QAPISourceInfo], element_type: str
+ ):
super().__init__(name, info, None)
- assert isinstance(element_type, str)
self._element_type_name = element_type
- self.element_type = None
+ self.element_type: QAPISchemaType
- def need_has_if_optional(self):
+ def need_has_if_optional(self) -> bool:
# When FOO is an array, we still need has_FOO to distinguish
# absent (!has_FOO) from present and empty (has_FOO && !FOO).
return True
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
super().check(schema)
self.element_type = schema.resolve_type(
self._element_type_name, self.info,
- self.info and self.info.defn_meta)
+ self.info.defn_meta if self.info else None)
assert not isinstance(self.element_type, QAPISchemaArrayType)
- def set_module(self, schema):
+ def set_module(self, schema: QAPISchema) -> None:
self._set_module(schema, self.element_type.info)
@property
- def ifcond(self):
+ def ifcond(self) -> QAPISchemaIfCond:
assert self._checked
return self.element_type.ifcond
- def is_implicit(self):
+ def is_implicit(self) -> bool:
return True
- def c_type(self):
+ def c_type(self) -> str:
return c_name(self.name) + POINTER_SUFFIX
- def json_type(self):
+ def json_type(self) -> str:
return 'array'
- def doc_type(self):
+ def doc_type(self) -> Optional[str]:
elt_doc_type = self.element_type.doc_type()
if not elt_doc_type:
return None
return 'array of ' + elt_doc_type
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_array_type(self.name, self.info, self.ifcond,
self.element_type)
- def describe(self):
- assert self.meta
+ def describe(self) -> str:
return "%s type ['%s']" % (self.meta, self._element_type_name)
class QAPISchemaObjectType(QAPISchemaType):
- def __init__(self, name, info, doc, ifcond, features,
- base, local_members, variants):
+ def __init__(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ doc: Optional[QAPIDoc],
+ ifcond: Optional[QAPISchemaIfCond],
+ features: Optional[List[QAPISchemaFeature]],
+ base: Optional[str],
+ local_members: List[QAPISchemaObjectTypeMember],
+ variants: Optional[QAPISchemaVariants],
+ ):
# struct has local_members, optional base, and no variants
# union has base, variants, and no local_members
super().__init__(name, info, doc, ifcond, features)
self.meta = 'union' if variants else 'struct'
- assert base is None or isinstance(base, str)
for m in local_members:
- assert isinstance(m, QAPISchemaObjectTypeMember)
m.set_defined_in(name)
if variants is not None:
- assert isinstance(variants, QAPISchemaVariants)
variants.set_defined_in(name)
self._base_name = base
self.base = None
self.local_members = local_members
self.variants = variants
- self.members = None
+ self.members: List[QAPISchemaObjectTypeMember]
+ self._check_complete = False
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
# This calls another type T's .check() exactly when the C
# struct emitted by gen_object() contains that T's C struct
# (pointers don't count).
- if self.members is not None:
+ if self._check_complete:
# A previous .check() completed: nothing to do
return
if self._checked:
@@ -437,7 +554,7 @@ def check(self, schema):
"object %s contains itself" % self.name)
super().check(schema)
- assert self._checked and self.members is None
+ assert self._checked and not self._check_complete
seen = OrderedDict()
if self._base_name:
@@ -454,25 +571,34 @@ def check(self, schema):
for m in self.local_members:
m.check(schema)
m.check_clash(self.info, seen)
- members = seen.values()
+
+ # self.check_clash() works in terms of the supertype, but
+ # self.members is declared List[QAPISchemaObjectTypeMember].
+ # Cast down to the subtype.
+ members = cast(List[QAPISchemaObjectTypeMember], list(seen.values()))
if self.variants:
self.variants.check(schema, seen)
self.variants.check_clash(self.info, seen)
- self.members = members # mark completed
+ self.members = members
+ self._check_complete = True # mark completed
# Check that the members of this type do not cause duplicate JSON members,
# and update seen to track the members seen so far. Report any errors
# on behalf of info, which is not necessarily self.info
- def check_clash(self, info, seen):
+ def check_clash(
+ self,
+ info: Optional[QAPISourceInfo],
+ seen: Dict[str, QAPISchemaMember],
+ ) -> None:
assert self._checked
for m in self.members:
m.check_clash(info, seen)
if self.variants:
self.variants.check_clash(info, seen)
- def connect_doc(self, doc=None):
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
super().connect_doc(doc)
doc = doc or self.doc
if self.base and self.base.is_implicit():
@@ -480,34 +606,32 @@ def connect_doc(self, doc=None):
for m in self.local_members:
m.connect_doc(doc)
- def is_implicit(self):
+ def is_implicit(self) -> bool:
# See QAPISchema._make_implicit_object_type(), as well as
# _def_predefineds()
return self.name.startswith('q_')
- def is_empty(self):
- assert self.members is not None
+ def is_empty(self) -> bool:
return not self.members and not self.variants
- def has_conditional_members(self):
- assert self.members is not None
+ def has_conditional_members(self) -> bool:
return any(m.ifcond.is_present() for m in self.members)
- def c_name(self):
+ def c_name(self) -> str:
assert self.name != 'q_empty'
return super().c_name()
- def c_type(self):
+ def c_type(self) -> str:
assert not self.is_implicit()
return c_name(self.name) + POINTER_SUFFIX
- def c_unboxed_type(self):
+ def c_unboxed_type(self) -> str:
return c_name(self.name)
- def json_type(self):
+ def json_type(self) -> str:
return 'object'
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_object_type(
self.name, self.info, self.ifcond, self.features,
@@ -520,15 +644,22 @@ def visit(self, visitor):
class QAPISchemaAlternateType(QAPISchemaType):
meta = 'alternate'
- def __init__(self, name, info, doc, ifcond, features, variants):
+ def __init__(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ doc: Optional[QAPIDoc],
+ ifcond: Optional[QAPISchemaIfCond],
+ features: List[QAPISchemaFeature],
+ variants: QAPISchemaVariants,
+ ):
super().__init__(name, info, doc, ifcond, features)
- assert isinstance(variants, QAPISchemaVariants)
assert variants.tag_member
variants.set_defined_in(name)
variants.tag_member.set_defined_in(self.name)
self.variants = variants
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
super().check(schema)
self.variants.tag_member.check(schema)
# Not calling self.variants.check_clash(), because there's nothing
@@ -536,8 +667,8 @@ def check(self, schema):
self.variants.check(schema, {})
# Alternate branch names have no relation to the tag enum values;
# so we have to check for potential name collisions ourselves.
- seen = {}
- types_seen = {}
+ seen: Dict[str, QAPISchemaMember] = {}
+ types_seen: Dict[str, str] = {}
for v in self.variants.variants:
v.check_clash(self.info, seen)
qtype = v.type.alternate_qtype()
@@ -566,55 +697,75 @@ def check(self, schema):
% (v.describe(self.info), types_seen[qt]))
types_seen[qt] = v.name
- def connect_doc(self, doc=None):
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
super().connect_doc(doc)
doc = doc or self.doc
for v in self.variants.variants:
v.connect_doc(doc)
- def c_type(self):
+ def c_type(self) -> str:
return c_name(self.name) + POINTER_SUFFIX
- def json_type(self):
+ def json_type(self) -> str:
return 'value'
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_alternate_type(
self.name, self.info, self.ifcond, self.features, self.variants)
class QAPISchemaVariants:
- def __init__(self, tag_name, info, tag_member, variants):
+ def __init__(
+ self,
+ tag_name: Optional[str],
+ info: QAPISourceInfo,
+ tag_member: Optional[QAPISchemaObjectTypeMember],
+ variants: List[QAPISchemaVariant],
+ ):
# Unions pass tag_name but not tag_member.
# Alternates pass tag_member but not tag_name.
# After check(), tag_member is always set.
assert bool(tag_member) != bool(tag_name)
assert (isinstance(tag_name, str) or
isinstance(tag_member, QAPISchemaObjectTypeMember))
- for v in variants:
- assert isinstance(v, QAPISchemaVariant)
self._tag_name = tag_name
self.info = info
- self.tag_member = tag_member
+ self._tag_member = tag_member
self.variants = variants
- def set_defined_in(self, name):
+ @property
+ def tag_member(self) -> QAPISchemaObjectTypeMember:
+ if self._tag_member is None:
+ raise RuntimeError(
+ "QAPISchemaVariants has no tag_member property until "
+ "after check() has been run."
+ )
+ return self._tag_member
+
+ def set_defined_in(self, name: str) -> None:
for v in self.variants:
v.set_defined_in(name)
- def check(self, schema, seen):
+ def check(
+ self, schema: QAPISchema, seen: Dict[str, QAPISchemaMember]
+ ) -> None:
if self._tag_name: # union
- self.tag_member = seen.get(c_name(self._tag_name))
+ # We need to narrow the member type:
+ tmp = seen.get(c_name(self._tag_name))
+ assert tmp is None or isinstance(tmp, QAPISchemaObjectTypeMember)
+ self._tag_member = tmp
+
base = "'base'"
# Pointing to the base type when not implicit would be
# nice, but we don't know it here
- if not self.tag_member or self._tag_name != self.tag_member.name:
+ if not self._tag_member or self._tag_name != self._tag_member.name:
raise QAPISemError(
self.info,
"discriminator '%s' is not a member of %s"
% (self._tag_name, base))
# Here we do:
+ assert self.tag_member.defined_in
base_type = schema.lookup_type(self.tag_member.defined_in)
assert base_type
if not base_type.is_implicit():
@@ -635,11 +786,13 @@ def check(self, schema, seen):
"discriminator member '%s' of %s must not be conditional"
% (self._tag_name, base))
else: # alternate
+ assert self._tag_member
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
assert not self.tag_member.optional
assert not self.tag_member.ifcond.is_present()
if self._tag_name: # union
# branches that are not explicitly covered get an empty type
+ assert self.tag_member.defined_in
cases = {v.name for v in self.variants}
for m in self.tag_member.type.members:
if m.name not in cases:
@@ -666,10 +819,17 @@ def check(self, schema, seen):
% (v.describe(self.info), v.type.describe()))
v.type.check(schema)
- def check_clash(self, info, seen):
+ def check_clash(
+ self,
+ info: Optional[QAPISourceInfo],
+ seen: Dict[str, QAPISchemaMember],
+ ) -> None:
for v in self.variants:
# Reset seen map for each variant, since qapi names from one
- # branch do not affect another branch
+ # branch do not affect another branch.
+ #
+ # v.type's typing is enforced in check() above.
+ assert isinstance(v.type, QAPISchemaObjectType)
v.type.check_clash(info, dict(seen))
@@ -677,18 +837,26 @@ class QAPISchemaMember:
""" Represents object members, enum members and features """
role = 'member'
- def __init__(self, name, info, ifcond=None):
- assert isinstance(name, str)
+ def __init__(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: Optional[QAPISchemaIfCond] = None,
+ ):
self.name = name
self.info = info
self.ifcond = ifcond or QAPISchemaIfCond()
- self.defined_in = None
+ self.defined_in: Optional[str] = None
- def set_defined_in(self, name):
+ def set_defined_in(self, name: str) -> None:
assert not self.defined_in
self.defined_in = name
- def check_clash(self, info, seen):
+ def check_clash(
+ self,
+ info: Optional[QAPISourceInfo],
+ seen: Dict[str, QAPISchemaMember],
+ ) -> None:
cname = c_name(self.name)
if cname in seen:
raise QAPISemError(
@@ -697,11 +865,11 @@ def check_clash(self, info, seen):
% (self.describe(info), seen[cname].describe(info)))
seen[cname] = self
- def connect_doc(self, doc):
+ def connect_doc(self, doc: Optional[QAPIDoc]) -> None:
if doc:
doc.connect_member(self)
- def describe(self, info):
+ def describe(self, info: Optional[QAPISourceInfo]) -> str:
role = self.role
meta = 'type'
defined_in = self.defined_in
@@ -724,6 +892,7 @@ def describe(self, info):
else:
assert False
+ assert info is not None
if defined_in != info.defn_name:
return "%s '%s' of %s '%s'" % (role, self.name, meta, defined_in)
return "%s '%s'" % (role, self.name)
@@ -732,14 +901,19 @@ def describe(self, info):
class QAPISchemaEnumMember(QAPISchemaMember):
role = 'value'
- def __init__(self, name, info, ifcond=None, features=None):
+ def __init__(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: Optional[QAPISchemaIfCond] = None,
+ features: Optional[List[QAPISchemaFeature]] = None,
+ ):
super().__init__(name, info, ifcond)
for f in features or []:
- assert isinstance(f, QAPISchemaFeature)
f.set_defined_in(name)
self.features = features or []
- def connect_doc(self, doc):
+ def connect_doc(self, doc: Optional[QAPIDoc]) -> None:
super().connect_doc(doc)
if doc:
for f in self.features:
@@ -749,36 +923,40 @@ def connect_doc(self, doc):
class QAPISchemaFeature(QAPISchemaMember):
role = 'feature'
- def is_special(self):
+ def is_special(self) -> bool:
return self.name in ('deprecated', 'unstable')
class QAPISchemaObjectTypeMember(QAPISchemaMember):
- def __init__(self, name, info, typ, optional, ifcond=None, features=None):
+ def __init__(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ typ: str,
+ optional: bool,
+ ifcond: Optional[QAPISchemaIfCond] = None,
+ features: Optional[List[QAPISchemaFeature]] = None,
+ ):
super().__init__(name, info, ifcond)
- assert isinstance(typ, str)
- assert isinstance(optional, bool)
for f in features or []:
- assert isinstance(f, QAPISchemaFeature)
f.set_defined_in(name)
self._type_name = typ
- self.type = None
+ self.type: QAPISchemaType # set during check()
self.optional = optional
self.features = features or []
- def need_has(self):
- assert self.type
+ def need_has(self) -> bool:
return self.optional and self.type.need_has_if_optional()
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
assert self.defined_in
self.type = schema.resolve_type(self._type_name, self.info,
self.describe)
- seen = {}
+ seen: Dict[str, QAPISchemaMember] = {}
for f in self.features:
f.check_clash(self.info, seen)
- def connect_doc(self, doc):
+ def connect_doc(self, doc: Optional[QAPIDoc]) -> None:
super().connect_doc(doc)
if doc:
for f in self.features:
@@ -788,24 +966,40 @@ def connect_doc(self, doc):
class QAPISchemaVariant(QAPISchemaObjectTypeMember):
role = 'branch'
- def __init__(self, name, info, typ, ifcond=None):
+ def __init__(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ typ: str,
+ ifcond: QAPISchemaIfCond,
+ ):
super().__init__(name, info, typ, False, ifcond)
-class QAPISchemaCommand(QAPISchemaEntity):
+class QAPISchemaCommand(QAPISchemaDefinition):
meta = 'command'
- def __init__(self, name, info, doc, ifcond, features,
- arg_type, ret_type,
- gen, success_response, boxed, allow_oob, allow_preconfig,
- coroutine):
+ def __init__(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ doc: Optional[QAPIDoc],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ arg_type: Optional[str],
+ ret_type: Optional[str],
+ gen: bool,
+ success_response: bool,
+ boxed: bool,
+ allow_oob: bool,
+ allow_preconfig: bool,
+ coroutine: bool,
+ ):
super().__init__(name, info, doc, ifcond, features)
- assert not arg_type or isinstance(arg_type, str)
- assert not ret_type or isinstance(ret_type, str)
self._arg_type_name = arg_type
- self.arg_type = None
+ self.arg_type: Optional[QAPISchemaObjectType] = None
self._ret_type_name = ret_type
- self.ret_type = None
+ self.ret_type: Optional[QAPISchemaType] = None
self.gen = gen
self.success_response = success_response
self.boxed = boxed
@@ -813,16 +1007,18 @@ def __init__(self, name, info, doc, ifcond, features,
self.allow_preconfig = allow_preconfig
self.coroutine = coroutine
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
+ assert self.info is not None
super().check(schema)
if self._arg_type_name:
- self.arg_type = schema.resolve_type(
+ arg_type = schema.resolve_type(
self._arg_type_name, self.info, "command's 'data'")
- if not isinstance(self.arg_type, QAPISchemaObjectType):
+ if not isinstance(arg_type, QAPISchemaObjectType):
raise QAPISemError(
self.info,
"command's 'data' cannot take %s"
- % self.arg_type.describe())
+ % arg_type.describe())
+ self.arg_type = arg_type
if self.arg_type.variants and not self.boxed:
raise QAPISemError(
self.info,
@@ -839,22 +1035,21 @@ def check(self, schema):
if self.name not in self.info.pragma.command_returns_exceptions:
typ = self.ret_type
if isinstance(typ, QAPISchemaArrayType):
- typ = self.ret_type.element_type
- assert typ
+ typ = typ.element_type
if not isinstance(typ, QAPISchemaObjectType):
raise QAPISemError(
self.info,
"command's 'returns' cannot take %s"
% self.ret_type.describe())
- def connect_doc(self, doc=None):
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
super().connect_doc(doc)
doc = doc or self.doc
if doc:
if self.arg_type and self.arg_type.is_implicit():
self.arg_type.connect_doc(doc)
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_command(
self.name, self.info, self.ifcond, self.features,
@@ -863,26 +1058,35 @@ def visit(self, visitor):
self.coroutine)
-class QAPISchemaEvent(QAPISchemaEntity):
+class QAPISchemaEvent(QAPISchemaDefinition):
meta = 'event'
- def __init__(self, name, info, doc, ifcond, features, arg_type, boxed):
+ def __init__(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ doc: Optional[QAPIDoc],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ arg_type: Optional[str],
+ boxed: bool,
+ ):
super().__init__(name, info, doc, ifcond, features)
- assert not arg_type or isinstance(arg_type, str)
self._arg_type_name = arg_type
- self.arg_type = None
+ self.arg_type: Optional[QAPISchemaObjectType] = None
self.boxed = boxed
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
super().check(schema)
if self._arg_type_name:
- self.arg_type = schema.resolve_type(
+ typ = schema.resolve_type(
self._arg_type_name, self.info, "event's 'data'")
- if not isinstance(self.arg_type, QAPISchemaObjectType):
+ if not isinstance(typ, QAPISchemaObjectType):
raise QAPISemError(
self.info,
"event's 'data' cannot take %s"
- % self.arg_type.describe())
+ % typ.describe())
+ self.arg_type = typ
if self.arg_type.variants and not self.boxed:
raise QAPISemError(
self.info,
@@ -894,14 +1098,14 @@ def check(self, schema):
self.info,
"conditional event arguments require 'boxed': true")
- def connect_doc(self, doc=None):
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
super().connect_doc(doc)
doc = doc or self.doc
if doc:
if self.arg_type and self.arg_type.is_implicit():
self.arg_type.connect_doc(doc)
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_event(
self.name, self.info, self.ifcond, self.features,
@@ -909,7 +1113,7 @@ def visit(self, visitor):
class QAPISchema:
- def __init__(self, fname):
+ def __init__(self, fname: str):
self.fname = fname
try:
@@ -921,9 +1125,9 @@ def __init__(self, fname):
exprs = check_exprs(parser.exprs)
self.docs = parser.docs
- self._entity_list = []
- self._entity_dict = {}
- self._module_dict = OrderedDict()
+ self._entity_list: List[QAPISchemaEntity] = []
+ self._entity_dict: Dict[str, QAPISchemaDefinition] = {}
+ self._module_dict: Dict[str, QAPISchemaModule] = OrderedDict()
self._schema_dir = os.path.dirname(fname)
self._make_module(QAPISchemaModule.BUILTIN_MODULE_NAME)
self._make_module(fname)
@@ -933,37 +1137,44 @@ def __init__(self, fname):
self._def_exprs(exprs)
self.check()
- def _def_entity(self, ent):
- # Only the predefined types are allowed to not have info
- assert ent.info or self._predefining
+ def _def_entity(self, ent: QAPISchemaEntity) -> None:
self._entity_list.append(ent)
- if ent.name is None:
- return
+
+ def _def_definition(self, defn: QAPISchemaDefinition) -> None:
+ # Only the predefined types are allowed to not have info
+ assert defn.info or self._predefining
+ self._def_entity(defn)
# TODO reject names that differ only in '_' vs. '.' vs. '-',
# because they're liable to clash in generated C.
- other_ent = self._entity_dict.get(ent.name)
- if other_ent:
- if other_ent.info:
- where = QAPISourceError(other_ent.info, "previous definition")
+ other_defn = self._entity_dict.get(defn.name)
+ if other_defn:
+ if other_defn.info:
+ where = QAPISourceError(other_defn.info, "previous definition")
raise QAPISemError(
- ent.info,
- "'%s' is already defined\n%s" % (ent.name, where))
+ defn.info,
+ "'%s' is already defined\n%s" % (defn.name, where))
raise QAPISemError(
- ent.info, "%s is already defined" % other_ent.describe())
- self._entity_dict[ent.name] = ent
+ defn.info, "%s is already defined" % other_defn.describe())
+ self._entity_dict[defn.name] = defn
- def lookup_entity(self, name, typ=None):
- ent = self._entity_dict.get(name)
- if typ and not isinstance(ent, typ):
- return None
- return ent
+ def lookup_entity(self,name: str) -> Optional[QAPISchemaEntity]:
+ return self._entity_dict.get(name)
- def lookup_type(self, name):
- return self.lookup_entity(name, QAPISchemaType)
+ def lookup_type(self, name: str) -> Optional[QAPISchemaType]:
+ typ = self.lookup_entity(name)
+ if isinstance(typ, QAPISchemaType):
+ return typ
+ return None
- def resolve_type(self, name, info, what):
+ def resolve_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ what: Union[None, str, Callable[[QAPISourceInfo], str]],
+ ) -> QAPISchemaType:
typ = self.lookup_type(name)
if not typ:
+ assert info and what # built-in types must not fail lookup
if callable(what):
what = what(info)
raise QAPISemError(
@@ -975,31 +1186,33 @@ def _module_name(self, fname: str) -> str:
return fname
return os.path.relpath(fname, self._schema_dir)
- def _make_module(self, fname):
+ def _make_module(self, fname: str) -> QAPISchemaModule:
name = self._module_name(fname)
if name not in self._module_dict:
self._module_dict[name] = QAPISchemaModule(name)
return self._module_dict[name]
- def module_by_fname(self, fname):
+ def module_by_fname(self, fname: str) -> QAPISchemaModule:
name = self._module_name(fname)
return self._module_dict[name]
- def _def_include(self, expr: QAPIExpression):
+ def _def_include(self, expr: QAPIExpression) -> None:
include = expr['include']
assert expr.doc is None
self._def_entity(
QAPISchemaInclude(self._make_module(include), expr.info))
- def _def_builtin_type(self, name, json_type, c_type):
- self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
+ def _def_builtin_type(
+ self, name: str, json_type: str, c_type: str
+ ) -> None:
+ self._def_definition(QAPISchemaBuiltinType(name, json_type, c_type))
# Instantiating only the arrays that are actually used would
# be nice, but we can't as long as their generated code
# (qapi-builtin-types.[ch]) may be shared by some other
# schema.
self._make_array_type(name, None)
- def _def_predefineds(self):
+ def _def_predefineds(self) -> None:
for t in [('str', 'string', 'char' + POINTER_SUFFIX),
('number', 'number', 'double'),
('int', 'int', 'int64_t'),
@@ -1018,67 +1231,97 @@ def _def_predefineds(self):
self._def_builtin_type(*t)
self.the_empty_object_type = QAPISchemaObjectType(
'q_empty', None, None, None, None, None, [], None)
- self._def_entity(self.the_empty_object_type)
+ self._def_definition(self.the_empty_object_type)
qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist',
'qbool']
qtype_values = self._make_enum_members(
[{'name': n} for n in qtypes], None)
- self._def_entity(QAPISchemaEnumType('QType', None, None, None, None,
- qtype_values, 'QTYPE'))
+ self._def_definition(QAPISchemaEnumType(
+ 'QType', None, None, None, None, qtype_values, 'QTYPE'))
- def _make_features(self, features, info):
+ def _make_features(
+ self,
+ features: Optional[List[Dict[str, Any]]],
+ info: Optional[QAPISourceInfo],
+ ) -> List[QAPISchemaFeature]:
if features is None:
return []
return [QAPISchemaFeature(f['name'], info,
QAPISchemaIfCond(f.get('if')))
for f in features]
- def _make_enum_member(self, name, ifcond, features, info):
+ def _make_enum_member(
+ self,
+ name: str,
+ ifcond: Optional[Union[str, Dict[str, Any]]],
+ features: Optional[List[Dict[str, Any]]],
+ info: Optional[QAPISourceInfo],
+ ) -> QAPISchemaEnumMember:
return QAPISchemaEnumMember(name, info,
QAPISchemaIfCond(ifcond),
self._make_features(features, info))
- def _make_enum_members(self, values, info):
+ def _make_enum_members(
+ self, values: List[Dict[str, Any]], info: Optional[QAPISourceInfo]
+ ) -> List[QAPISchemaEnumMember]:
return [self._make_enum_member(v['name'], v.get('if'),
v.get('features'), info)
for v in values]
- def _make_array_type(self, element_type, info):
+ def _make_array_type(
+ self, element_type: str, info: Optional[QAPISourceInfo]
+ ) -> str:
name = element_type + 'List' # reserved by check_defn_name_str()
if not self.lookup_type(name):
- self._def_entity(QAPISchemaArrayType(name, info, element_type))
+ self._def_definition(QAPISchemaArrayType(
+ name, info, element_type))
return name
- def _make_implicit_object_type(self, name, info, ifcond, role, members):
+ def _make_implicit_object_type(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ ifcond: QAPISchemaIfCond,
+ role: str,
+ members: List[QAPISchemaObjectTypeMember],
+ ) -> Optional[str]:
if not members:
return None
# See also QAPISchemaObjectTypeMember.describe()
name = 'q_obj_%s-%s' % (name, role)
- typ = self.lookup_entity(name, QAPISchemaObjectType)
+ typ = self.lookup_entity(name)
if typ:
+ assert(isinstance(typ, QAPISchemaObjectType))
# The implicit object type has multiple users. This can
# only be a duplicate definition, which will be flagged
# later.
pass
else:
- self._def_entity(QAPISchemaObjectType(
+ self._def_definition(QAPISchemaObjectType(
name, info, None, ifcond, None, None, members, None))
return name
- def _def_enum_type(self, expr: QAPIExpression):
+ def _def_enum_type(self, expr: QAPIExpression) -> None:
name = expr['enum']
data = expr['data']
prefix = expr.get('prefix')
ifcond = QAPISchemaIfCond(expr.get('if'))
info = expr.info
features = self._make_features(expr.get('features'), info)
- self._def_entity(QAPISchemaEnumType(
+ self._def_definition(QAPISchemaEnumType(
name, info, expr.doc, ifcond, features,
self._make_enum_members(data, info), prefix))
- def _make_member(self, name, typ, ifcond, features, info):
+ def _make_member(
+ self,
+ name: str,
+ typ: Union[List[str], str],
+ ifcond: QAPISchemaIfCond,
+ features: Optional[List[Dict[str, Any]]],
+ info: QAPISourceInfo,
+ ) -> QAPISchemaObjectTypeMember:
optional = False
if name.startswith('*'):
name = name[1:]
@@ -1089,31 +1332,41 @@ def _make_member(self, name, typ, ifcond, features, info):
return QAPISchemaObjectTypeMember(name, info, typ, optional, ifcond,
self._make_features(features, info))
- def _make_members(self, data, info):
+ def _make_members(
+ self,
+ data: Dict[str, Any],
+ info: QAPISourceInfo,
+ ) -> List[QAPISchemaObjectTypeMember]:
return [self._make_member(key, value['type'],
QAPISchemaIfCond(value.get('if')),
value.get('features'), info)
for (key, value) in data.items()]
- def _def_struct_type(self, expr: QAPIExpression):
+ def _def_struct_type(self, expr: QAPIExpression) -> None:
name = expr['struct']
base = expr.get('base')
data = expr['data']
info = expr.info
ifcond = QAPISchemaIfCond(expr.get('if'))
features = self._make_features(expr.get('features'), info)
- self._def_entity(QAPISchemaObjectType(
+ self._def_definition(QAPISchemaObjectType(
name, info, expr.doc, ifcond, features, base,
self._make_members(data, info),
None))
- def _make_variant(self, case, typ, ifcond, info):
+ def _make_variant(
+ self,
+ case: str,
+ typ: str,
+ ifcond: QAPISchemaIfCond,
+ info: QAPISourceInfo,
+ ) -> QAPISchemaVariant:
if isinstance(typ, list):
assert len(typ) == 1
typ = self._make_array_type(typ[0], info)
return QAPISchemaVariant(case, info, typ, ifcond)
- def _def_union_type(self, expr: QAPIExpression):
+ def _def_union_type(self, expr: QAPIExpression) -> None:
name = expr['union']
base = expr['base']
tag_name = expr['discriminator']
@@ -1132,13 +1385,13 @@ def _def_union_type(self, expr: QAPIExpression):
info)
for (key, value) in data.items()]
members: List[QAPISchemaObjectTypeMember] = []
- self._def_entity(
+ self._def_definition(
QAPISchemaObjectType(name, info, expr.doc, ifcond, features,
base, members,
QAPISchemaVariants(
tag_name, info, None, variants)))
- def _def_alternate_type(self, expr: QAPIExpression):
+ def _def_alternate_type(self, expr: QAPIExpression) -> None:
name = expr['alternate']
data = expr['data']
assert isinstance(data, dict)
@@ -1151,12 +1404,12 @@ def _def_alternate_type(self, expr: QAPIExpression):
info)
for (key, value) in data.items()]
tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False)
- self._def_entity(
+ self._def_definition(
QAPISchemaAlternateType(
name, info, expr.doc, ifcond, features,
QAPISchemaVariants(None, info, tag_member, variants)))
- def _def_command(self, expr: QAPIExpression):
+ def _def_command(self, expr: QAPIExpression) -> None:
name = expr['command']
data = expr.get('data')
rets = expr.get('returns')
@@ -1176,13 +1429,12 @@ def _def_command(self, expr: QAPIExpression):
if isinstance(rets, list):
assert len(rets) == 1
rets = self._make_array_type(rets[0], info)
- self._def_entity(QAPISchemaCommand(name, info, expr.doc, ifcond,
- features, data, rets,
- gen, success_response,
- boxed, allow_oob, allow_preconfig,
- coroutine))
+ self._def_definition(
+ QAPISchemaCommand(name, info, expr.doc, ifcond, features, data,
+ rets, gen, success_response, boxed, allow_oob,
+ allow_preconfig, coroutine))
- def _def_event(self, expr: QAPIExpression):
+ def _def_event(self, expr: QAPIExpression) -> None:
name = expr['event']
data = expr.get('data')
boxed = expr.get('boxed', False)
@@ -1193,10 +1445,10 @@ def _def_event(self, expr: QAPIExpression):
data = self._make_implicit_object_type(
name, info, ifcond,
'arg', self._make_members(data, info))
- self._def_entity(QAPISchemaEvent(name, info, expr.doc, ifcond,
- features, data, boxed))
+ self._def_definition(QAPISchemaEvent(name, info, expr.doc, ifcond,
+ features, data, boxed))
- def _def_exprs(self, exprs):
+ def _def_exprs(self, exprs: List[QAPIExpression]) -> None:
for expr in exprs:
if 'enum' in expr:
self._def_enum_type(expr)
@@ -1215,7 +1467,7 @@ def _def_exprs(self, exprs):
else:
assert False
- def check(self):
+ def check(self) -> None:
for ent in self._entity_list:
ent.check(self)
ent.connect_doc()
@@ -1224,7 +1476,7 @@ def check(self):
for doc in self.docs:
doc.check()
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
visitor.visit_begin(self)
for mod in self._module_dict.values():
mod.visit(visitor)
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index c56ea4d..a21b7b1 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -278,8 +278,8 @@ def gen_visit_alternate(name: str, variants: QAPISchemaVariants) -> str:
abort();
default:
assert(visit_is_input(v));
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
- "%(name)s");
+ error_setg(errp, "Invalid parameter type for '%%s', expected: %(name)s",
+ name ? name : "null");
/* Avoid passing invalid *obj to qapi_free_%(c_name)s() */
g_free(*obj);
*obj = NULL;
@@ -356,7 +356,6 @@ def _begin_user_module(self, name: str) -> None:
self._genc.preamble_add(mcgen('''
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qapi/qmp/qerror.h"
#include "%(visit)s.h"
''',
visit=visit))
diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index 73c292b..36f3e91 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -60,7 +60,7 @@
-e 'linux/const' \
-e 'linux/kernel' \
-e 'linux/sysinfo' \
- -e 'asm-generic/kvm_para' \
+ -e 'asm/setup_data.h' \
> /dev/null
then
echo "Unexpected #include in input file $f".
@@ -76,6 +76,7 @@
-e 's/__be\([0-9][0-9]*\)/uint\1_t/g' \
-e 's/"\(input-event-codes\.h\)"/"standard-headers\/linux\/\1"/' \
-e 's/<linux\/\([^>]*\)>/"standard-headers\/linux\/\1"/' \
+ -e 's/<asm\/\([^>]*\)>/"standard-headers\/asm-'$arch'\/\1"/' \
-e 's/__bitwise//' \
-e 's/__attribute__((packed))/QEMU_PACKED/' \
-e 's/__inline__/inline/' \
@@ -154,17 +155,20 @@
"$tmpdir/include/asm/bootparam.h" > "$tmpdir/bootparam.h"
cp_portable "$tmpdir/bootparam.h" \
"$output/include/standard-headers/asm-$arch"
+ cp_portable "$tmpdir/include/asm/setup_data.h" \
+ "$output/standard-headers/asm-x86"
fi
if [ $arch = riscv ]; then
cp "$tmpdir/include/asm/ptrace.h" "$output/linux-headers/asm-riscv/"
fi
done
+arch=
rm -rf "$output/linux-headers/linux"
mkdir -p "$output/linux-headers/linux"
for header in const.h stddef.h kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h \
psci.h psp-sev.h userfaultfd.h memfd.h mman.h nvme_ioctl.h \
- vduse.h iommufd.h; do
+ vduse.h iommufd.h bits.h; do
cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux"
done
diff --git a/semihosting/meson.build b/semihosting/meson.build
index b07cbd9..34933e5 100644
--- a/semihosting/meson.build
+++ b/semihosting/meson.build
@@ -9,5 +9,8 @@
'uaccess.c',
))
+common_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_SYSTEM_ONLY'], if_false: files('stubs-all.c'))
+system_ss.add(when: ['CONFIG_SEMIHOSTING'], if_false: files('stubs-system.c'))
+
specific_ss.add(when: ['CONFIG_ARM_COMPATIBLE_SEMIHOSTING'],
if_true: files('arm-compat-semi.c'))
diff --git a/stubs/semihost-all.c b/semihosting/stubs-all.c
similarity index 100%
rename from stubs/semihost-all.c
rename to semihosting/stubs-all.c
diff --git a/stubs/semihost.c b/semihosting/stubs-system.c
similarity index 100%
rename from stubs/semihost.c
rename to semihosting/stubs-system.c
diff --git a/stubs/fdset.c b/stubs/fdset.c
index 56b3663..d7c39a2 100644
--- a/stubs/fdset.c
+++ b/stubs/fdset.c
@@ -1,5 +1,7 @@
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "monitor/monitor.h"
+#include "../monitor/monitor-internal.h"
int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags)
{
@@ -15,3 +17,7 @@
void monitor_fdset_dup_fd_remove(int dupfd)
{
}
+
+void monitor_fdsets_cleanup(void)
+{
+}
diff --git a/hw/core/hotplug-stubs.c b/stubs/hotplug-stubs.c
similarity index 100%
rename from hw/core/hotplug-stubs.c
rename to stubs/hotplug-stubs.c
diff --git a/stubs/isa-bus.c b/stubs/isa-bus.c
deleted file mode 100644
index 522f448..0000000
--- a/stubs/isa-bus.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/isa/isa.h"
-
-ISADevice *isa_create_simple(ISABus *bus, const char *name)
-{
- g_assert_not_reached();
-}
diff --git a/stubs/meson.build b/stubs/meson.build
index 0bf25e6..8ee1fd5 100644
--- a/stubs/meson.build
+++ b/stubs/meson.build
@@ -1,67 +1,86 @@
-stub_ss.add(files('bdrv-next-monitor-owned.c'))
-stub_ss.add(files('blk-commit-all.c'))
-stub_ss.add(files('blk-exp-close-all.c'))
-stub_ss.add(files('blockdev-close-all-bdrv-states.c'))
-stub_ss.add(files('change-state-handler.c'))
-stub_ss.add(files('cmos.c'))
+# If possible, add new files to other directories, by using "if_false".
+# If you need them here, try to add them under one of the if statements
+# below, so that it is clear who needs the stubbed functionality.
+
stub_ss.add(files('cpu-get-clock.c'))
-stub_ss.add(files('cpus-get-virtual-clock.c'))
-stub_ss.add(files('qemu-timer-notify-cb.c'))
-stub_ss.add(files('icount.c'))
-stub_ss.add(files('dump.c'))
-stub_ss.add(files('error-printf.c'))
stub_ss.add(files('fdset.c'))
-stub_ss.add(files('gdbstub.c'))
-stub_ss.add(files('get-vm-name.c'))
-stub_ss.add(files('graph-lock.c'))
-if linux_io_uring.found()
- stub_ss.add(files('io_uring.c'))
-endif
stub_ss.add(files('iothread-lock.c'))
-if have_block
- stub_ss.add(files('iothread-lock-block.c'))
-endif
-stub_ss.add(files('isa-bus.c'))
stub_ss.add(files('is-daemonized.c'))
-if libaio.found()
- stub_ss.add(files('linux-aio.c'))
-endif
-stub_ss.add(files('migr-blocker.c'))
-stub_ss.add(files('module-opts.c'))
-stub_ss.add(files('monitor.c'))
stub_ss.add(files('monitor-core.c'))
-stub_ss.add(files('physmem.c'))
-stub_ss.add(files('qemu-timer-notify-cb.c'))
-stub_ss.add(files('memory_device.c'))
-stub_ss.add(files('qmp-command-available.c'))
-stub_ss.add(files('qmp-quit.c'))
-stub_ss.add(files('qtest.c'))
-stub_ss.add(files('ram-block.c'))
-stub_ss.add(files('ramfb.c'))
-stub_ss.add(files('replay.c'))
-stub_ss.add(files('runstate-check.c'))
-stub_ss.add(files('sysbus.c'))
-stub_ss.add(files('target-get-monitor-def.c'))
-stub_ss.add(files('target-monitor-defs.c'))
+stub_ss.add(files('replay-mode.c'))
stub_ss.add(files('trace-control.c'))
-stub_ss.add(files('uuid.c'))
-stub_ss.add(files('colo.c'))
-stub_ss.add(files('colo-compare.c'))
-stub_ss.add(files('vmstate.c'))
-stub_ss.add(files('vm-stop.c'))
-stub_ss.add(files('win32-kbd-hook.c'))
-stub_ss.add(files('cpu-synchronize-state.c'))
-if have_block or have_ga
+
+if have_block
+ stub_ss.add(files('bdrv-next-monitor-owned.c'))
+ stub_ss.add(files('blk-commit-all.c'))
+ stub_ss.add(files('blk-exp-close-all.c'))
+ stub_ss.add(files('blockdev-close-all-bdrv-states.c'))
+ stub_ss.add(files('change-state-handler.c'))
+ stub_ss.add(files('get-vm-name.c'))
+ stub_ss.add(files('iothread-lock-block.c'))
+ stub_ss.add(files('migr-blocker.c'))
+ stub_ss.add(files('physmem.c'))
+ stub_ss.add(files('ram-block.c'))
stub_ss.add(files('replay-tools.c'))
+ stub_ss.add(files('runstate-check.c'))
+ stub_ss.add(files('uuid.c'))
endif
-if have_system
- stub_ss.add(files('fw_cfg.c'))
- stub_ss.add(files('pci-bus.c'))
- stub_ss.add(files('semihost.c'))
- stub_ss.add(files('usb-dev-stub.c'))
- stub_ss.add(files('xen-hw-stub.c'))
- stub_ss.add(files('virtio-md-pci.c'))
-else
+
+if have_block or have_ga
+ # stubs for hooks in util/main-loop.c, util/async.c etc.
+ stub_ss.add(files('cpus-get-virtual-clock.c'))
+ stub_ss.add(files('icount.c'))
+ stub_ss.add(files('graph-lock.c'))
+ if linux_io_uring.found()
+ stub_ss.add(files('io_uring.c'))
+ endif
+ if libaio.found()
+ stub_ss.add(files('linux-aio.c'))
+ endif
+ stub_ss.add(files('qemu-timer-notify-cb.c'))
+
+ # stubs for monitor
+ stub_ss.add(files('monitor-internal.c'))
+ stub_ss.add(files('qmp-command-available.c'))
+ stub_ss.add(files('qmp-quit.c'))
+endif
+
+if have_block or have_user
+ stub_ss.add(files('qtest.c'))
+ stub_ss.add(files('vm-stop.c'))
+ stub_ss.add(files('vmstate.c'))
+
+ # more symbols provided by the monitor
+ stub_ss.add(files('error-printf.c'))
+endif
+
+if have_user
+ # Symbols that are used by hw/core.
+ stub_ss.add(files('cpu-synchronize-state.c'))
stub_ss.add(files('qdev.c'))
endif
-stub_ss.add(files('semihost-all.c'))
+
+if have_system
+ # Symbols that are only needed in some configurations. Try not
+ # adding more of these. If the symbol is used in specific_ss,
+ # in particular, consider defining a preprocessor macro via
+ # Kconfig or configs/targets/.
+ stub_ss.add(files('dump.c'))
+ stub_ss.add(files('cmos.c'))
+ stub_ss.add(files('fw_cfg.c'))
+ stub_ss.add(files('target-get-monitor-def.c'))
+ stub_ss.add(files('target-monitor-defs.c'))
+ stub_ss.add(files('win32-kbd-hook.c'))
+ stub_ss.add(files('xen-hw-stub.c'))
+endif
+
+if have_system or have_user
+ stub_ss.add(files('gdbstub.c'))
+
+ # Also included in have_system for --disable-tcg builds
+ stub_ss.add(files('replay.c'))
+
+ # Also included in have_system for tests/unit/test-qdev-global-props
+ stub_ss.add(files('hotplug-stubs.c'))
+ stub_ss.add(files('sysbus.c'))
+endif
diff --git a/stubs/module-opts.c b/stubs/module-opts.c
deleted file mode 100644
index 5412429..0000000
--- a/stubs/module-opts.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu/config-file.h"
diff --git a/stubs/monitor-core.c b/stubs/monitor-core.c
index afa477a..1894cdf 100644
--- a/stubs/monitor-core.c
+++ b/stubs/monitor-core.c
@@ -12,10 +12,6 @@
return NULL;
}
-void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp)
-{
-}
-
void qapi_event_emit(QAPIEvent event, QDict *qdict)
{
}
@@ -24,5 +20,3 @@
{
abort();
}
-
-
diff --git a/stubs/monitor.c b/stubs/monitor-internal.c
similarity index 78%
rename from stubs/monitor.c
rename to stubs/monitor-internal.c
index 20786ac..4fece49 100644
--- a/stubs/monitor.c
+++ b/stubs/monitor-internal.c
@@ -1,7 +1,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "monitor/monitor.h"
-#include "../monitor/monitor-internal.h"
int monitor_get_fd(Monitor *mon, const char *name, Error **errp)
{
@@ -12,7 +11,3 @@
void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp)
{
}
-
-void monitor_fdsets_cleanup(void)
-{
-}
diff --git a/stubs/pci-bus.c b/stubs/pci-bus.c
deleted file mode 100644
index a8932fa..0000000
--- a/stubs/pci-bus.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/pci/pci.h"
-
-PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
-{
- g_assert_not_reached();
-}
diff --git a/stubs/qdev.c b/stubs/qdev.c
index 6869f6f..7e957b3 100644
--- a/stubs/qdev.c
+++ b/stubs/qdev.c
@@ -20,9 +20,3 @@
{
/* Nothing to do. */
}
-
-void qapi_event_send_device_unplug_guest_error(const char *device,
- const char *path)
-{
- /* Nothing to do. */
-}
diff --git a/stubs/qtest.c b/stubs/qtest.c
index 4666a49..39e376e 100644
--- a/stubs/qtest.c
+++ b/stubs/qtest.c
@@ -13,13 +13,3 @@
/* Needed for qtest_allowed() */
bool qtest_allowed;
-
-bool qtest_driver(void)
-{
- return false;
-}
-
-int64_t qtest_get_virtual_clock(void)
-{
- return 0;
-}
diff --git a/stubs/replay-mode.c b/stubs/replay-mode.c
new file mode 100644
index 0000000..264be9d
--- /dev/null
+++ b/stubs/replay-mode.c
@@ -0,0 +1,4 @@
+#include "qemu/osdep.h"
+#include "sysemu/replay.h"
+
+ReplayMode replay_mode;
diff --git a/stubs/replay.c b/stubs/replay.c
index 42c92e4..b4dd6a5 100644
--- a/stubs/replay.c
+++ b/stubs/replay.c
@@ -1,8 +1,6 @@
#include "qemu/osdep.h"
#include "exec/replay-core.h"
-ReplayMode replay_mode;
-
void replay_finish(void)
{
}
diff --git a/system/memory.c b/system/memory.c
index a229a79..49f1cb2 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -1850,6 +1850,11 @@
return mr->ram && (mr->ram_block->flags & RAM_PROTECTED);
}
+bool memory_region_has_guest_memfd(MemoryRegion *mr)
+{
+ return mr->ram_block && mr->ram_block->guest_memfd >= 0;
+}
+
uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr)
{
uint8_t mask = mr->dirty_log_mask;
@@ -2914,7 +2919,30 @@
static VMChangeStateEntry *vmstate_change;
static void memory_global_dirty_log_stop_postponed_run(void);
-void memory_global_dirty_log_start(unsigned int flags)
+static bool memory_global_dirty_log_do_start(Error **errp)
+{
+ MemoryListener *listener;
+
+ QTAILQ_FOREACH(listener, &memory_listeners, link) {
+ if (listener->log_global_start) {
+ if (!listener->log_global_start(listener, errp)) {
+ goto err;
+ }
+ }
+ }
+ return true;
+
+err:
+ while ((listener = QTAILQ_PREV(listener, link)) != NULL) {
+ if (listener->log_global_stop) {
+ listener->log_global_stop(listener);
+ }
+ }
+
+ return false;
+}
+
+bool memory_global_dirty_log_start(unsigned int flags, Error **errp)
{
unsigned int old_flags;
@@ -2928,7 +2956,7 @@
flags &= ~global_dirty_tracking;
if (!flags) {
- return;
+ return true;
}
old_flags = global_dirty_tracking;
@@ -2936,11 +2964,17 @@
trace_global_dirty_changed(global_dirty_tracking);
if (!old_flags) {
- MEMORY_LISTENER_CALL_GLOBAL(log_global_start, Forward);
+ if (!memory_global_dirty_log_do_start(errp)) {
+ global_dirty_tracking &= ~flags;
+ trace_global_dirty_changed(global_dirty_tracking);
+ return false;
+ }
+
memory_region_transaction_begin();
memory_region_update_pending = true;
memory_region_transaction_commit();
}
+ return true;
}
static void memory_global_dirty_log_do_stop(unsigned int flags)
@@ -3014,8 +3048,15 @@
listener->begin(listener);
}
if (global_dirty_tracking) {
+ /*
+ * Currently only VFIO can fail log_global_start(), and it's not
+ * yet allowed to hotplug any PCI device during migration. So this
+ * should never fail when invoked, guard it with error_abort. If
+ * it can start to fail in the future, we need to be able to fail
+ * the whole listener_add_address_space() and its callers.
+ */
if (listener->log_global_start) {
- listener->log_global_start(listener);
+ listener->log_global_start(listener, &error_abort);
}
}
diff --git a/system/physmem.c b/system/physmem.c
index a4fe3d2..c3d04ca 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -1808,6 +1808,7 @@
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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(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 @@
} 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 @@
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;
diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c
index 840177d..6af6ef7 100644
--- a/system/qdev-monitor.c
+++ b/system/qdev-monitor.c
@@ -660,7 +660,8 @@
if (qdev_should_hide_device(opts, from_json, errp)) {
if (bus && !qbus_is_hotpluggable(bus)) {
- error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
+ error_setg(errp, "Bus '%s' does not support hotplugging",
+ bus->name);
}
return NULL;
} else if (*errp) {
@@ -668,7 +669,7 @@
}
if (phase_check(PHASE_MACHINE_READY) && bus && !qbus_is_hotpluggable(bus)) {
- error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
+ error_setg(errp, "Bus '%s' does not support hotplugging", bus->name);
return NULL;
}
@@ -910,12 +911,13 @@
}
if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) {
- error_setg(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
+ error_setg(errp, "Bus '%s' does not support hotplugging",
+ dev->parent_bus->name);
return;
}
if (!dc->hotpluggable) {
- error_setg(errp, QERR_DEVICE_NO_HOTPLUG,
+ error_setg(errp, "Device '%s' does not support hotplugging",
object_get_typename(OBJECT(dev)));
return;
}
diff --git a/system/rtc.c b/system/rtc.c
index 4904581..dc44576 100644
--- a/system/rtc.c
+++ b/system/rtc.c
@@ -25,7 +25,6 @@
#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
-#include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
#include "qemu/timer.h"
diff --git a/system/runstate.c b/system/runstate.c
index d6ab860..cb4905a 100644
--- a/system/runstate.c
+++ b/system/runstate.c
@@ -501,7 +501,20 @@
default:
qapi_event_send_reset(shutdown_caused_by_guest(reason), reason);
}
- cpu_synchronize_all_post_reset();
+
+ /*
+ * Some boards use the machine reset callback to point CPUs to the firmware
+ * entry point. Assume that this is not the case for boards that support
+ * non-resettable CPUs (currently used only for confidential guests), in
+ * which case cpu_synchronize_all_post_init() is enough because
+ * it does _more_ than cpu_synchronize_all_post_reset().
+ */
+ if (cpus_are_resettable()) {
+ cpu_synchronize_all_post_reset();
+ } else {
+ assert(runstate_check(RUN_STATE_PRELAUNCH));
+ }
+
vm_set_suspended(false);
}
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index ab85d62..21ebbf3 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1598,11 +1598,6 @@
return (data - 32) & 0xffff;
}
-bool kvm_arch_cpu_check_are_resettable(void)
-{
- return true;
-}
-
static void kvm_arch_get_eager_split_size(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
diff --git a/target/i386/confidential-guest.c b/target/i386/confidential-guest.c
new file mode 100644
index 0000000..b372784
--- /dev/null
+++ b/target/i386/confidential-guest.c
@@ -0,0 +1,33 @@
+/*
+ * QEMU Confidential Guest support
+ *
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * Authors:
+ * Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "confidential-guest.h"
+
+OBJECT_DEFINE_ABSTRACT_TYPE(X86ConfidentialGuest,
+ x86_confidential_guest,
+ X86_CONFIDENTIAL_GUEST,
+ CONFIDENTIAL_GUEST_SUPPORT)
+
+static void x86_confidential_guest_class_init(ObjectClass *oc, void *data)
+{
+}
+
+static void x86_confidential_guest_init(Object *obj)
+{
+}
+
+static void x86_confidential_guest_finalize(Object *obj)
+{
+}
diff --git a/target/i386/confidential-guest.h b/target/i386/confidential-guest.h
new file mode 100644
index 0000000..532e172
--- /dev/null
+++ b/target/i386/confidential-guest.h
@@ -0,0 +1,59 @@
+/*
+ * x86-specific confidential guest methods.
+ *
+ * Copyright (c) 2024 Red Hat Inc.
+ *
+ * Authors:
+ * Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef TARGET_I386_CG_H
+#define TARGET_I386_CG_H
+
+#include "qom/object.h"
+
+#include "exec/confidential-guest-support.h"
+
+#define TYPE_X86_CONFIDENTIAL_GUEST "x86-confidential-guest"
+
+OBJECT_DECLARE_TYPE(X86ConfidentialGuest,
+ X86ConfidentialGuestClass,
+ X86_CONFIDENTIAL_GUEST)
+
+struct X86ConfidentialGuest {
+ /* <private> */
+ ConfidentialGuestSupport parent_obj;
+};
+
+/**
+ * X86ConfidentialGuestClass:
+ *
+ * Class to be implemented by confidential-guest-support concrete objects
+ * for the x86 target.
+ */
+struct X86ConfidentialGuestClass {
+ /* <private> */
+ ConfidentialGuestSupportClass parent;
+
+ /* <public> */
+ int (*kvm_type)(X86ConfidentialGuest *cg);
+};
+
+/**
+ * x86_confidential_guest_kvm_type:
+ *
+ * Calls #X86ConfidentialGuestClass.unplug callback of @plug_handler.
+ */
+static inline int x86_confidential_guest_kvm_type(X86ConfidentialGuest *cg)
+{
+ X86ConfidentialGuestClass *klass = X86_CONFIDENTIAL_GUEST_GET_CLASS(cg);
+
+ if (klass->kvm_type) {
+ return klass->kvm_type(cg);
+ } else {
+ return 0;
+ }
+}
+#endif
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 33760a2..fd6af0d 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1158,8 +1158,8 @@
NULL, "sbdr-ssdp-no", "fbsdp-no", "psdp-no",
NULL, "fb-clear", NULL, NULL,
NULL, NULL, NULL, NULL,
- "pbrsb-no", NULL, "gds-no", NULL,
- NULL, NULL, NULL, NULL,
+ "pbrsb-no", NULL, "gds-no", "rfds-no",
+ "rfds-clear", NULL, NULL, NULL,
},
.msr = {
.index = MSR_IA32_ARCH_CAPABILITIES,
@@ -3822,6 +3822,16 @@
{ /* end of list */ }
},
},
+ {
+ .version = 7,
+ .note = "TSX, taa-no",
+ .props = (PropValue[]) {
+ /* Restore TSX features removed by -v2 above */
+ { "hle", "on" },
+ { "rtm", "on" },
+ { /* end of list */ }
+ },
+ },
{ /* end of list */ }
}
},
@@ -4100,6 +4110,132 @@
},
},
{
+ .name = "SierraForest",
+ .level = 0x23,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 175,
+ .stepping = 0,
+ /*
+ * please keep the ascending order so that we can have a clear view of
+ * bit position of each feature.
+ */
+ .features[FEAT_1_EDX] =
+ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
+ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
+ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
+ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR |
+ CPUID_SSE | CPUID_SSE2,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 |
+ CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 |
+ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE |
+ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_AES |
+ CPUID_EXT_XSAVE | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB |
+ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH,
+ .features[FEAT_8000_0008_EBX] =
+ CPUID_8000_0008_EBX_WBNOINVD,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 |
+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS |
+ CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB |
+ CPUID_7_0_EBX_SHA_NI,
+ .features[FEAT_7_0_ECX] =
+ CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_GFNI |
+ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ |
+ CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_BUS_LOCK_DETECT,
+ .features[FEAT_7_0_EDX] =
+ CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_SERIALIZE |
+ CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_ARCH_CAPABILITIES |
+ CPUID_7_0_EDX_SPEC_CTRL_SSBD,
+ .features[FEAT_ARCH_CAPABILITIES] =
+ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL |
+ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO |
+ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_SBDR_SSDP_NO |
+ MSR_ARCH_CAP_FBSDP_NO | MSR_ARCH_CAP_PSDP_NO |
+ MSR_ARCH_CAP_PBRSB_NO,
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
+ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .features[FEAT_7_1_EAX] =
+ CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_CMPCCXADD |
+ CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_AVX_IFMA,
+ .features[FEAT_7_1_EDX] =
+ CPUID_7_1_EDX_AVX_VNNI_INT8 | CPUID_7_1_EDX_AVX_NE_CONVERT,
+ .features[FEAT_7_2_EDX] =
+ CPUID_7_2_EDX_MCDT_NO,
+ .features[FEAT_VMX_BASIC] =
+ MSR_VMX_BASIC_INS_OUTS | MSR_VMX_BASIC_TRUE_CTLS,
+ .features[FEAT_VMX_ENTRY_CTLS] =
+ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_IA32E_MODE |
+ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL |
+ VMX_VM_ENTRY_LOAD_IA32_PAT | VMX_VM_ENTRY_LOAD_IA32_EFER,
+ .features[FEAT_VMX_EPT_VPID_CAPS] =
+ MSR_VMX_EPT_EXECONLY | MSR_VMX_EPT_PAGE_WALK_LENGTH_4 |
+ MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB |
+ MSR_VMX_EPT_INVEPT | MSR_VMX_EPT_AD_BITS |
+ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT |
+ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR |
+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT |
+ MSR_VMX_EPT_INVVPID_ALL_CONTEXT |
+ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS,
+ .features[FEAT_VMX_EXIT_CTLS] =
+ VMX_VM_EXIT_SAVE_DEBUG_CONTROLS |
+ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |
+ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_IA32_PAT |
+ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER |
+ VMX_VM_EXIT_LOAD_IA32_EFER | VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER,
+ .features[FEAT_VMX_MISC] =
+ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_ACTIVITY_HLT |
+ MSR_VMX_MISC_VMWRITE_VMEXIT,
+ .features[FEAT_VMX_PINBASED_CTLS] =
+ VMX_PIN_BASED_EXT_INTR_MASK | VMX_PIN_BASED_NMI_EXITING |
+ VMX_PIN_BASED_VIRTUAL_NMIS | VMX_PIN_BASED_VMX_PREEMPTION_TIMER |
+ VMX_PIN_BASED_POSTED_INTR,
+ .features[FEAT_VMX_PROCBASED_CTLS] =
+ VMX_CPU_BASED_VIRTUAL_INTR_PENDING |
+ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING |
+ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING |
+ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING |
+ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING |
+ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING |
+ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_VIRTUAL_NMI_PENDING |
+ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING |
+ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_TRAP_FLAG |
+ VMX_CPU_BASED_USE_MSR_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING |
+ VMX_CPU_BASED_PAUSE_EXITING |
+ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS,
+ .features[FEAT_VMX_SECONDARY_CTLS] =
+ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
+ VMX_SECONDARY_EXEC_ENABLE_EPT | VMX_SECONDARY_EXEC_DESC |
+ VMX_SECONDARY_EXEC_RDTSCP |
+ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE |
+ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_WBINVD_EXITING |
+ VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST |
+ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT |
+ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
+ VMX_SECONDARY_EXEC_RDRAND_EXITING |
+ VMX_SECONDARY_EXEC_ENABLE_INVPCID |
+ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS |
+ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML |
+ VMX_SECONDARY_EXEC_XSAVES,
+ .features[FEAT_VMX_VMFUNC] =
+ MSR_VMX_VMFUNC_EPT_SWITCHING,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Xeon Processor (SierraForest)",
+ .versions = (X86CPUVersionDefinition[]) {
+ { .version = 1 },
+ { /* end of list */ },
+ },
+ },
+ {
.name = "Denverton",
.level = 21,
.vendor = CPUID_VENDOR_INTEL,
@@ -6570,6 +6706,7 @@
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
/* 64 bit processor */
*eax |= (cpu_x86_virtual_addr_width(env) << 8);
+ *eax |= (cpu->guest_phys_bits << 16);
}
*ebx = env->features[FEAT_8000_0008_EBX];
if (cs->nr_cores * cs->nr_threads > 1) {
@@ -7230,7 +7367,6 @@
X86CPUClass *xcc = X86_CPU_GET_CLASS(dev);
CPUX86State *env = &cpu->env;
Error *local_err = NULL;
- static bool ht_warned;
unsigned requested_lbr_fmt;
#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
@@ -7329,6 +7465,14 @@
goto out;
}
+ if (cpu->guest_phys_bits == -1) {
+ /*
+ * If it was not set by the user, or by the accelerator via
+ * cpu_exec_realizefn, clear.
+ */
+ cpu->guest_phys_bits = 0;
+ }
+
if (cpu->ucode_rev == 0) {
/*
* The default is the same as KVM's. Note that this check
@@ -7379,6 +7523,14 @@
if (cpu->phys_bits == 0) {
cpu->phys_bits = TCG_PHYS_ADDR_BITS;
}
+ if (cpu->guest_phys_bits &&
+ (cpu->guest_phys_bits > cpu->phys_bits ||
+ cpu->guest_phys_bits < 32)) {
+ error_setg(errp, "guest-phys-bits should be between 32 and %u "
+ " (but is %u)",
+ cpu->phys_bits, cpu->guest_phys_bits);
+ return;
+ }
} else {
/* For 32 bit systems don't use the user set value, but keep
* phys_bits consistent with what we tell the guest.
@@ -7387,6 +7539,10 @@
error_setg(errp, "phys-bits is not user-configurable in 32 bit");
return;
}
+ if (cpu->guest_phys_bits != 0) {
+ error_setg(errp, "guest-phys-bits is not user-configurable in 32 bit");
+ return;
+ }
if (env->features[FEAT_1_EDX] & (CPUID_PSE36 | CPUID_PAE)) {
cpu->phys_bits = 36;
@@ -7453,13 +7609,11 @@
*/
if (IS_AMD_CPU(env) &&
!(env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_TOPOEXT) &&
- cs->nr_threads > 1 && !ht_warned) {
- warn_report("This family of AMD CPU doesn't support "
- "hyperthreading(%d)",
- cs->nr_threads);
- error_printf("Please configure -smp options properly"
- " or try enabling topoext feature.\n");
- ht_warned = true;
+ cs->nr_threads > 1) {
+ warn_report_once("This family of AMD CPU doesn't support "
+ "hyperthreading(%d). Please configure -smp "
+ "options properly or try enabling topoext "
+ "feature.", cs->nr_threads);
}
#ifndef CONFIG_USER_ONLY
@@ -7887,6 +8041,7 @@
DEFINE_PROP_BOOL("x-force-features", X86CPU, force_features, false),
DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true),
DEFINE_PROP_UINT32("phys-bits", X86CPU, phys_bits, 0),
+ DEFINE_PROP_UINT32("guest-phys-bits", X86CPU, guest_phys_bits, -1),
DEFINE_PROP_BOOL("host-phys-bits", X86CPU, host_phys_bits, false),
DEFINE_PROP_UINT8("host-phys-bits-limit", X86CPU, host_phys_bits_limit, 0),
DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true),
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 6b05738..6112e27 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2027,6 +2027,14 @@
/* Number of physical address bits supported */
uint32_t phys_bits;
+ /*
+ * Number of guest physical address bits available. Usually this is
+ * identical to host physical address bits. With NPT or EPT 4-level
+ * paging, guest physical address space might be restricted to 48 bits
+ * even if the host cpu supports more physical address bits.
+ */
+ uint32_t guest_phys_bits;
+
/* in order to simplify APIC support, we leave this pointer to the
user */
struct DeviceState *apic_state;
diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c
index 92ecb72..280e427 100644
--- a/target/i386/host-cpu.c
+++ b/target/i386/host-cpu.c
@@ -55,18 +55,15 @@
{
uint32_t host_phys_bits = host_cpu_phys_bits();
uint32_t phys_bits = cpu->phys_bits;
- static bool warned;
/*
* Print a warning if the user set it to a value that's not the
* host value.
*/
- if (phys_bits != host_phys_bits && phys_bits != 0 &&
- !warned) {
- warn_report("Host physical bits (%u)"
- " does not match phys-bits property (%u)",
- host_phys_bits, phys_bits);
- warned = true;
+ if (phys_bits != host_phys_bits && phys_bits != 0) {
+ warn_report_once("Host physical bits (%u)"
+ " does not match phys-bits property (%u)",
+ host_phys_bits, phys_bits);
}
if (cpu->host_phys_bits) {
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 9c791b7..f76972e 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -18,10 +18,32 @@
#include "kvm_i386.h"
#include "hw/core/accel-cpu.h"
+static void kvm_set_guest_phys_bits(CPUState *cs)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ uint32_t eax, guest_phys_bits;
+
+ eax = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x80000008, 0, R_EAX);
+ guest_phys_bits = (eax >> 16) & 0xff;
+ if (!guest_phys_bits) {
+ return;
+ }
+ cpu->guest_phys_bits = guest_phys_bits;
+ if (cpu->guest_phys_bits > cpu->phys_bits) {
+ cpu->guest_phys_bits = cpu->phys_bits;
+ }
+
+ if (cpu->host_phys_bits && cpu->host_phys_bits_limit &&
+ cpu->guest_phys_bits > cpu->host_phys_bits_limit) {
+ cpu->guest_phys_bits = cpu->host_phys_bits_limit;
+ }
+}
+
static bool kvm_cpu_realizefn(CPUState *cs, Error **errp)
{
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
+ bool ret;
/*
* The realize order is important, since x86_cpu_realize() checks if
@@ -32,13 +54,15 @@
*
* realize order:
*
- * x86_cpu_realize():
- * -> x86_cpu_expand_features()
- * -> cpu_exec_realizefn():
- * -> accel_cpu_common_realize()
- * kvm_cpu_realizefn() -> host_cpu_realizefn()
- * -> cpu_common_realizefn()
- * -> check/update ucode_rev, phys_bits, mwait
+ * x86_cpu_realizefn():
+ * x86_cpu_expand_features()
+ * cpu_exec_realizefn():
+ * accel_cpu_common_realize()
+ * kvm_cpu_realizefn()
+ * host_cpu_realizefn()
+ * kvm_set_guest_phys_bits()
+ * check/update ucode_rev, phys_bits, guest_phys_bits, mwait
+ * cpu_common_realizefn() (via xcc->parent_realize)
*/
if (cpu->max_features) {
if (enable_cpu_pm && kvm_has_waitpkg()) {
@@ -50,7 +74,17 @@
MSR_IA32_UCODE_REV);
}
}
- return host_cpu_realizefn(cs, errp);
+ ret = host_cpu_realizefn(cs, errp);
+ if (!ret) {
+ return ret;
+ }
+
+ if ((env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) &&
+ cpu->guest_phys_bits == -1) {
+ kvm_set_guest_phys_bits(cs);
+ }
+
+ return true;
}
static bool lmce_supported(void)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index e68cbe9..c594360 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -31,6 +31,7 @@
#include "sysemu/kvm_int.h"
#include "sysemu/runstate.h"
#include "kvm_i386.h"
+#include "../confidential-guest.h"
#include "sev.h"
#include "xen-emu.h"
#include "hyperv.h"
@@ -161,6 +162,51 @@
static RateLimit bus_lock_ratelimit_ctrl;
static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value);
+static const char *vm_type_name[] = {
+ [KVM_X86_DEFAULT_VM] = "default",
+ [KVM_X86_SEV_VM] = "SEV",
+ [KVM_X86_SEV_ES_VM] = "SEV-ES",
+};
+
+bool kvm_is_vm_type_supported(int type)
+{
+ uint32_t machine_types;
+
+ /*
+ * old KVM doesn't support KVM_CAP_VM_TYPES but KVM_X86_DEFAULT_VM
+ * is always supported
+ */
+ if (type == KVM_X86_DEFAULT_VM) {
+ return true;
+ }
+
+ machine_types = kvm_check_extension(KVM_STATE(current_machine->accelerator),
+ KVM_CAP_VM_TYPES);
+ return !!(machine_types & BIT(type));
+}
+
+int kvm_get_vm_type(MachineState *ms)
+{
+ int kvm_type = KVM_X86_DEFAULT_VM;
+
+ if (ms->cgs) {
+ if (!object_dynamic_cast(OBJECT(ms->cgs), TYPE_X86_CONFIDENTIAL_GUEST)) {
+ error_report("configuration type %s not supported for x86 guests",
+ object_get_typename(OBJECT(ms->cgs)));
+ exit(1);
+ }
+ kvm_type = x86_confidential_guest_kvm_type(
+ X86_CONFIDENTIAL_GUEST(ms->cgs));
+ }
+
+ if (!kvm_is_vm_type_supported(kvm_type)) {
+ error_report("vm-type %s not supported by KVM", vm_type_name[kvm_type]);
+ exit(1);
+ }
+
+ return kvm_type;
+}
+
bool kvm_has_smm(void)
{
return kvm_vm_check_extension(kvm_state, KVM_CAP_X86_SMM);
@@ -1706,6 +1752,231 @@
}
}
+static uint32_t kvm_x86_build_cpuid(CPUX86State *env,
+ struct kvm_cpuid_entry2 *entries,
+ uint32_t cpuid_i)
+{
+ uint32_t limit, i, j;
+ uint32_t unused;
+ struct kvm_cpuid_entry2 *c;
+
+ cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
+
+ for (i = 0; i <= limit; i++) {
+ j = 0;
+ if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
+ goto full;
+ }
+ c = &entries[cpuid_i++];
+ switch (i) {
+ case 2: {
+ /* Keep reading function 2 till all the input is received */
+ int times;
+
+ c->function = i;
+ c->flags = KVM_CPUID_FLAG_STATEFUL_FUNC |
+ KVM_CPUID_FLAG_STATE_READ_NEXT;
+ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ times = c->eax & 0xff;
+
+ for (j = 1; j < times; ++j) {
+ if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
+ goto full;
+ }
+ c = &entries[cpuid_i++];
+ c->function = i;
+ c->flags = KVM_CPUID_FLAG_STATEFUL_FUNC;
+ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ }
+ break;
+ }
+ case 0x1f:
+ if (env->nr_dies < 2) {
+ cpuid_i--;
+ break;
+ }
+ /* fallthrough */
+ case 4:
+ case 0xb:
+ case 0xd:
+ for (j = 0; ; j++) {
+ if (i == 0xd && j == 64) {
+ break;
+ }
+
+ c->function = i;
+ c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+ c->index = j;
+ cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
+
+ if (i == 4 && c->eax == 0) {
+ break;
+ }
+ if (i == 0xb && !(c->ecx & 0xff00)) {
+ break;
+ }
+ if (i == 0x1f && !(c->ecx & 0xff00)) {
+ break;
+ }
+ if (i == 0xd && c->eax == 0) {
+ continue;
+ }
+ if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
+ goto full;
+ }
+ c = &entries[cpuid_i++];
+ }
+ break;
+ case 0x12:
+ for (j = 0; ; j++) {
+ c->function = i;
+ c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+ c->index = j;
+ cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
+
+ if (j > 1 && (c->eax & 0xf) != 1) {
+ break;
+ }
+
+ if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
+ goto full;
+ }
+ c = &entries[cpuid_i++];
+ }
+ break;
+ case 0x7:
+ case 0x14:
+ case 0x1d:
+ case 0x1e: {
+ uint32_t times;
+
+ c->function = i;
+ c->index = 0;
+ c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ times = c->eax;
+
+ for (j = 1; j <= times; ++j) {
+ if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
+ goto full;
+ }
+ c = &entries[cpuid_i++];
+ c->function = i;
+ c->index = j;
+ c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+ cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ }
+ break;
+ }
+ default:
+ c->function = i;
+ c->flags = 0;
+ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ if (!c->eax && !c->ebx && !c->ecx && !c->edx) {
+ /*
+ * KVM already returns all zeroes if a CPUID entry is missing,
+ * so we can omit it and avoid hitting KVM's 80-entry limit.
+ */
+ cpuid_i--;
+ }
+ break;
+ }
+ }
+
+ if (limit >= 0x0a) {
+ uint32_t eax, edx;
+
+ cpu_x86_cpuid(env, 0x0a, 0, &eax, &unused, &unused, &edx);
+
+ has_architectural_pmu_version = eax & 0xff;
+ if (has_architectural_pmu_version > 0) {
+ num_architectural_pmu_gp_counters = (eax & 0xff00) >> 8;
+
+ /* Shouldn't be more than 32, since that's the number of bits
+ * available in EBX to tell us _which_ counters are available.
+ * Play it safe.
+ */
+ if (num_architectural_pmu_gp_counters > MAX_GP_COUNTERS) {
+ num_architectural_pmu_gp_counters = MAX_GP_COUNTERS;
+ }
+
+ if (has_architectural_pmu_version > 1) {
+ num_architectural_pmu_fixed_counters = edx & 0x1f;
+
+ if (num_architectural_pmu_fixed_counters > MAX_FIXED_COUNTERS) {
+ num_architectural_pmu_fixed_counters = MAX_FIXED_COUNTERS;
+ }
+ }
+ }
+ }
+
+ cpu_x86_cpuid(env, 0x80000000, 0, &limit, &unused, &unused, &unused);
+
+ for (i = 0x80000000; i <= limit; i++) {
+ j = 0;
+ if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
+ goto full;
+ }
+ c = &entries[cpuid_i++];
+
+ switch (i) {
+ case 0x8000001d:
+ /* Query for all AMD cache information leaves */
+ for (j = 0; ; j++) {
+ c->function = i;
+ c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+ c->index = j;
+ cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
+
+ if (c->eax == 0) {
+ break;
+ }
+ if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
+ goto full;
+ }
+ c = &entries[cpuid_i++];
+ }
+ break;
+ default:
+ c->function = i;
+ c->flags = 0;
+ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ if (!c->eax && !c->ebx && !c->ecx && !c->edx) {
+ /*
+ * KVM already returns all zeroes if a CPUID entry is missing,
+ * so we can omit it and avoid hitting KVM's 80-entry limit.
+ */
+ cpuid_i--;
+ }
+ break;
+ }
+ }
+
+ /* Call Centaur's CPUID instructions they are supported. */
+ if (env->cpuid_xlevel2 > 0) {
+ cpu_x86_cpuid(env, 0xC0000000, 0, &limit, &unused, &unused, &unused);
+
+ for (i = 0xC0000000; i <= limit; i++) {
+ j = 0;
+ if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
+ goto full;
+ }
+ c = &entries[cpuid_i++];
+
+ c->function = i;
+ c->flags = 0;
+ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ }
+ }
+
+ return cpuid_i;
+
+full:
+ fprintf(stderr, "cpuid_data is full, no space for "
+ "cpuid(eax:0x%x,ecx:0x%x)\n", i, j);
+ abort();
+}
+
int kvm_arch_init_vcpu(CPUState *cs)
{
struct {
@@ -1722,8 +1993,7 @@
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
- uint32_t limit, i, j, cpuid_i;
- uint32_t unused;
+ uint32_t cpuid_i;
struct kvm_cpuid_entry2 *c;
uint32_t signature[3];
int kvm_base = KVM_CPUID_SIGNATURE;
@@ -1876,8 +2146,6 @@
c->edx = env->features[FEAT_KVM_HINTS];
}
- cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
-
if (cpu->kvm_pv_enforce_cpuid) {
r = kvm_vcpu_enable_cap(cs, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 0, 1);
if (r < 0) {
@@ -1888,224 +2156,7 @@
}
}
- for (i = 0; i <= limit; i++) {
- if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
- fprintf(stderr, "unsupported level value: 0x%x\n", limit);
- abort();
- }
- c = &cpuid_data.entries[cpuid_i++];
-
- switch (i) {
- case 2: {
- /* Keep reading function 2 till all the input is received */
- int times;
-
- c->function = i;
- c->flags = KVM_CPUID_FLAG_STATEFUL_FUNC |
- KVM_CPUID_FLAG_STATE_READ_NEXT;
- cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
- times = c->eax & 0xff;
-
- for (j = 1; j < times; ++j) {
- if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
- fprintf(stderr, "cpuid_data is full, no space for "
- "cpuid(eax:2):eax & 0xf = 0x%x\n", times);
- abort();
- }
- c = &cpuid_data.entries[cpuid_i++];
- c->function = i;
- c->flags = KVM_CPUID_FLAG_STATEFUL_FUNC;
- cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
- }
- break;
- }
- case 0x1f:
- if (env->nr_dies < 2) {
- cpuid_i--;
- break;
- }
- /* fallthrough */
- case 4:
- case 0xb:
- case 0xd:
- for (j = 0; ; j++) {
- if (i == 0xd && j == 64) {
- break;
- }
-
- c->function = i;
- c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
- c->index = j;
- cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
-
- if (i == 4 && c->eax == 0) {
- break;
- }
- if (i == 0xb && !(c->ecx & 0xff00)) {
- break;
- }
- if (i == 0x1f && !(c->ecx & 0xff00)) {
- break;
- }
- if (i == 0xd && c->eax == 0) {
- continue;
- }
- if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
- fprintf(stderr, "cpuid_data is full, no space for "
- "cpuid(eax:0x%x,ecx:0x%x)\n", i, j);
- abort();
- }
- c = &cpuid_data.entries[cpuid_i++];
- }
- break;
- case 0x12:
- for (j = 0; ; j++) {
- c->function = i;
- c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
- c->index = j;
- cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
-
- if (j > 1 && (c->eax & 0xf) != 1) {
- break;
- }
-
- if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
- fprintf(stderr, "cpuid_data is full, no space for "
- "cpuid(eax:0x12,ecx:0x%x)\n", j);
- abort();
- }
- c = &cpuid_data.entries[cpuid_i++];
- }
- break;
- case 0x7:
- case 0x14:
- case 0x1d:
- case 0x1e: {
- uint32_t times;
-
- c->function = i;
- c->index = 0;
- c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
- cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
- times = c->eax;
-
- for (j = 1; j <= times; ++j) {
- if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
- fprintf(stderr, "cpuid_data is full, no space for "
- "cpuid(eax:0x%x,ecx:0x%x)\n", i, j);
- abort();
- }
- c = &cpuid_data.entries[cpuid_i++];
- c->function = i;
- c->index = j;
- c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
- cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
- }
- break;
- }
- default:
- c->function = i;
- c->flags = 0;
- cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
- if (!c->eax && !c->ebx && !c->ecx && !c->edx) {
- /*
- * KVM already returns all zeroes if a CPUID entry is missing,
- * so we can omit it and avoid hitting KVM's 80-entry limit.
- */
- cpuid_i--;
- }
- break;
- }
- }
-
- if (limit >= 0x0a) {
- uint32_t eax, edx;
-
- cpu_x86_cpuid(env, 0x0a, 0, &eax, &unused, &unused, &edx);
-
- has_architectural_pmu_version = eax & 0xff;
- if (has_architectural_pmu_version > 0) {
- num_architectural_pmu_gp_counters = (eax & 0xff00) >> 8;
-
- /* Shouldn't be more than 32, since that's the number of bits
- * available in EBX to tell us _which_ counters are available.
- * Play it safe.
- */
- if (num_architectural_pmu_gp_counters > MAX_GP_COUNTERS) {
- num_architectural_pmu_gp_counters = MAX_GP_COUNTERS;
- }
-
- if (has_architectural_pmu_version > 1) {
- num_architectural_pmu_fixed_counters = edx & 0x1f;
-
- if (num_architectural_pmu_fixed_counters > MAX_FIXED_COUNTERS) {
- num_architectural_pmu_fixed_counters = MAX_FIXED_COUNTERS;
- }
- }
- }
- }
-
- cpu_x86_cpuid(env, 0x80000000, 0, &limit, &unused, &unused, &unused);
-
- for (i = 0x80000000; i <= limit; i++) {
- if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
- fprintf(stderr, "unsupported xlevel value: 0x%x\n", limit);
- abort();
- }
- c = &cpuid_data.entries[cpuid_i++];
-
- switch (i) {
- case 0x8000001d:
- /* Query for all AMD cache information leaves */
- for (j = 0; ; j++) {
- c->function = i;
- c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
- c->index = j;
- cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
-
- if (c->eax == 0) {
- break;
- }
- if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
- fprintf(stderr, "cpuid_data is full, no space for "
- "cpuid(eax:0x%x,ecx:0x%x)\n", i, j);
- abort();
- }
- c = &cpuid_data.entries[cpuid_i++];
- }
- break;
- default:
- c->function = i;
- c->flags = 0;
- cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
- if (!c->eax && !c->ebx && !c->ecx && !c->edx) {
- /*
- * KVM already returns all zeroes if a CPUID entry is missing,
- * so we can omit it and avoid hitting KVM's 80-entry limit.
- */
- cpuid_i--;
- }
- break;
- }
- }
-
- /* Call Centaur's CPUID instructions they are supported. */
- if (env->cpuid_xlevel2 > 0) {
- cpu_x86_cpuid(env, 0xC0000000, 0, &limit, &unused, &unused, &unused);
-
- for (i = 0xC0000000; i <= limit; i++) {
- if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
- fprintf(stderr, "unsupported xlevel2 value: 0x%x\n", limit);
- abort();
- }
- c = &cpuid_data.entries[cpuid_i++];
-
- c->function = i;
- c->flags = 0;
- cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
- }
- }
-
+ cpuid_i = kvm_x86_build_cpuid(env, cpuid_data.entries, cpuid_i);
cpuid_data.cpuid.nent = cpuid_i;
if (((env->cpuid_version >> 8)&0xF) >= 6
@@ -2538,10 +2589,12 @@
* mechanisms are supported in future (e.g. TDX), they'll need
* their own initialization either here or elsewhere.
*/
- ret = sev_kvm_init(ms->cgs, &local_err);
- if (ret < 0) {
- error_report_err(local_err);
- return ret;
+ if (ms->cgs) {
+ ret = confidential_guest_kvm_init(ms->cgs, &local_err);
+ if (ret < 0) {
+ error_report_err(local_err);
+ return ret;
+ }
}
has_xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
@@ -5612,11 +5665,6 @@
return has_msr_umwait;
}
-bool kvm_arch_cpu_check_are_resettable(void)
-{
- return !sev_es_enabled();
-}
-
#define ARCH_REQ_XCOMP_GUEST_PERM 0x1025
void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask)
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 30fedcf..6b44844 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -37,6 +37,7 @@
bool kvm_enable_sgx_provisioning(KVMState *s);
bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp);
+int kvm_get_vm_type(MachineState *ms);
void kvm_arch_reset_vcpu(X86CPU *cs);
void kvm_arch_after_reset_vcpu(X86CPU *cpu);
void kvm_arch_do_init_vcpu(X86CPU *cs);
@@ -49,6 +50,7 @@
#ifdef CONFIG_KVM
+bool kvm_is_vm_type_supported(int type);
bool kvm_has_adjust_clock_stable(void);
bool kvm_has_exception_payload(void);
void kvm_synchronize_all_tsc(void);
diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build
index 84d9143..e785098 100644
--- a/target/i386/kvm/meson.build
+++ b/target/i386/kvm/meson.build
@@ -7,8 +7,6 @@
i386_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files('xen-emu.c'))
-i386_kvm_ss.add(when: 'CONFIG_SEV', if_false: files('sev-stub.c'))
-
i386_system_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c'))
i386_system_ss.add_all(when: 'CONFIG_KVM', if_true: i386_kvm_ss)
diff --git a/target/i386/kvm/sev-stub.c b/target/i386/kvm/sev-stub.c
deleted file mode 100644
index 1be5341..0000000
--- a/target/i386/kvm/sev-stub.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * QEMU SEV stub
- *
- * Copyright Advanced Micro Devices 2018
- *
- * Authors:
- * Brijesh Singh <brijesh.singh@amd.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "sev.h"
-
-int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
-{
- /* If we get here, cgs must be some non-SEV thing */
- return 0;
-}
diff --git a/target/i386/meson.build b/target/i386/meson.build
index 7c74bfa..8abce72 100644
--- a/target/i386/meson.build
+++ b/target/i386/meson.build
@@ -6,7 +6,7 @@
'xsave_helper.c',
'cpu-dump.c',
))
-i386_ss.add(when: 'CONFIG_SEV', if_true: files('host-cpu.c'))
+i386_ss.add(when: 'CONFIG_SEV', if_true: files('host-cpu.c', 'confidential-guest.c'))
# x86 cpu type
i386_ss.add(when: 'CONFIG_KVM', if_true: files('host-cpu.c'))
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 72930ff..d30b68c 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -26,6 +26,7 @@
#include "qemu/error-report.h"
#include "crypto/hash.h"
#include "sysemu/kvm.h"
+#include "kvm/kvm_i386.h"
#include "sev.h"
#include "sysemu/sysemu.h"
#include "sysemu/runstate.h"
@@ -35,7 +36,7 @@
#include "monitor/monitor.h"
#include "monitor/hmp-target.h"
#include "qapi/qapi-commands-misc-target.h"
-#include "exec/confidential-guest-support.h"
+#include "confidential-guest.h"
#include "hw/i386/pc.h"
#include "exec/address-spaces.h"
@@ -54,7 +55,9 @@
* -machine ...,memory-encryption=sev0
*/
struct SevGuestState {
- ConfidentialGuestSupport parent_obj;
+ X86ConfidentialGuest parent_obj;
+
+ int kvm_type;
/* configuration parameters */
char *sev_device;
@@ -64,6 +67,7 @@
uint32_t cbitpos;
uint32_t reduced_phys_bits;
bool kernel_hashes;
+ bool legacy_vm_type;
/* runtime state */
uint32_t handle;
@@ -353,63 +357,16 @@
sev->kernel_hashes = value;
}
-static void
-sev_guest_class_init(ObjectClass *oc, void *data)
+static bool sev_guest_get_legacy_vm_type(Object *obj, Error **errp)
{
- object_class_property_add_str(oc, "sev-device",
- sev_guest_get_sev_device,
- sev_guest_set_sev_device);
- object_class_property_set_description(oc, "sev-device",
- "SEV device to use");
- object_class_property_add_str(oc, "dh-cert-file",
- sev_guest_get_dh_cert_file,
- sev_guest_set_dh_cert_file);
- object_class_property_set_description(oc, "dh-cert-file",
- "guest owners DH certificate (encoded with base64)");
- object_class_property_add_str(oc, "session-file",
- sev_guest_get_session_file,
- sev_guest_set_session_file);
- object_class_property_set_description(oc, "session-file",
- "guest owners session parameters (encoded with base64)");
- object_class_property_add_bool(oc, "kernel-hashes",
- sev_guest_get_kernel_hashes,
- sev_guest_set_kernel_hashes);
- object_class_property_set_description(oc, "kernel-hashes",
- "add kernel hashes to guest firmware for measured Linux boot");
+ return SEV_GUEST(obj)->legacy_vm_type;
}
-static void
-sev_guest_instance_init(Object *obj)
+static void sev_guest_set_legacy_vm_type(Object *obj, bool value, Error **errp)
{
- SevGuestState *sev = SEV_GUEST(obj);
-
- sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
- sev->policy = DEFAULT_GUEST_POLICY;
- object_property_add_uint32_ptr(obj, "policy", &sev->policy,
- OBJ_PROP_FLAG_READWRITE);
- object_property_add_uint32_ptr(obj, "handle", &sev->handle,
- OBJ_PROP_FLAG_READWRITE);
- object_property_add_uint32_ptr(obj, "cbitpos", &sev->cbitpos,
- OBJ_PROP_FLAG_READWRITE);
- object_property_add_uint32_ptr(obj, "reduced-phys-bits",
- &sev->reduced_phys_bits,
- OBJ_PROP_FLAG_READWRITE);
+ SEV_GUEST(obj)->legacy_vm_type = value;
}
-/* sev guest info */
-static const TypeInfo sev_guest_info = {
- .parent = TYPE_CONFIDENTIAL_GUEST_SUPPORT,
- .name = TYPE_SEV_GUEST,
- .instance_size = sizeof(SevGuestState),
- .instance_finalize = sev_guest_finalize,
- .class_init = sev_guest_class_init,
- .instance_init = sev_guest_instance_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_USER_CREATABLE },
- { }
- }
-};
-
bool
sev_enabled(void)
{
@@ -812,6 +769,7 @@
if (ret) {
exit(1);
}
+ kvm_mark_guest_state_protected();
}
/* query the measurement blob length */
@@ -906,20 +864,35 @@
}
}
-int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
+static int sev_kvm_type(X86ConfidentialGuest *cg)
{
- SevGuestState *sev
- = (SevGuestState *)object_dynamic_cast(OBJECT(cgs), TYPE_SEV_GUEST);
+ SevGuestState *sev = SEV_GUEST(cg);
+ int kvm_type;
+
+ if (sev->kvm_type != -1) {
+ goto out;
+ }
+
+ kvm_type = (sev->policy & SEV_POLICY_ES) ? KVM_X86_SEV_ES_VM : KVM_X86_SEV_VM;
+ if (kvm_is_vm_type_supported(kvm_type) && !sev->legacy_vm_type) {
+ sev->kvm_type = kvm_type;
+ } else {
+ sev->kvm_type = KVM_X86_DEFAULT_VM;
+ }
+
+out:
+ return sev->kvm_type;
+}
+
+static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
+{
+ SevGuestState *sev = SEV_GUEST(cgs);
char *devname;
int ret, fw_error, cmd;
uint32_t ebx;
uint32_t host_cbitpos;
struct sev_user_data_status status = {};
- if (!sev) {
- return 0;
- }
-
ret = ram_block_discard_disable(true);
if (ret) {
error_report("%s: cannot disable RAM discard", __func__);
@@ -990,13 +963,19 @@
__func__);
goto err;
}
- cmd = KVM_SEV_ES_INIT;
- } else {
- cmd = KVM_SEV_INIT;
}
trace_kvm_sev_init();
- ret = sev_ioctl(sev->sev_fd, cmd, NULL, &fw_error);
+ if (sev_kvm_type(X86_CONFIDENTIAL_GUEST(sev)) == KVM_X86_DEFAULT_VM) {
+ cmd = sev_es_enabled() ? KVM_SEV_ES_INIT : KVM_SEV_INIT;
+
+ ret = sev_ioctl(sev->sev_fd, cmd, NULL, &fw_error);
+ } else {
+ struct kvm_sev_init args = { 0 };
+
+ ret = sev_ioctl(sev->sev_fd, KVM_SEV_INIT2, &args, &fw_error);
+ }
+
if (ret) {
error_setg(errp, "%s: failed to initialize ret=%d fw_error=%d '%s'",
__func__, ret, fw_error, fw_error_to_str(fw_error));
@@ -1385,6 +1364,77 @@
}
static void
+sev_guest_class_init(ObjectClass *oc, void *data)
+{
+ ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
+ X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc);
+
+ klass->kvm_init = sev_kvm_init;
+ x86_klass->kvm_type = sev_kvm_type;
+
+ object_class_property_add_str(oc, "sev-device",
+ sev_guest_get_sev_device,
+ sev_guest_set_sev_device);
+ object_class_property_set_description(oc, "sev-device",
+ "SEV device to use");
+ object_class_property_add_str(oc, "dh-cert-file",
+ sev_guest_get_dh_cert_file,
+ sev_guest_set_dh_cert_file);
+ object_class_property_set_description(oc, "dh-cert-file",
+ "guest owners DH certificate (encoded with base64)");
+ object_class_property_add_str(oc, "session-file",
+ sev_guest_get_session_file,
+ sev_guest_set_session_file);
+ object_class_property_set_description(oc, "session-file",
+ "guest owners session parameters (encoded with base64)");
+ object_class_property_add_bool(oc, "kernel-hashes",
+ sev_guest_get_kernel_hashes,
+ sev_guest_set_kernel_hashes);
+ object_class_property_set_description(oc, "kernel-hashes",
+ "add kernel hashes to guest firmware for measured Linux boot");
+ object_class_property_add_bool(oc, "legacy-vm-type",
+ sev_guest_get_legacy_vm_type,
+ sev_guest_set_legacy_vm_type);
+ object_class_property_set_description(oc, "legacy-vm-type",
+ "use legacy VM type to maintain measurement compatibility with older QEMU or kernel versions.");
+}
+
+static void
+sev_guest_instance_init(Object *obj)
+{
+ SevGuestState *sev = SEV_GUEST(obj);
+
+ sev->kvm_type = -1;
+
+ sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
+ sev->policy = DEFAULT_GUEST_POLICY;
+ object_property_add_uint32_ptr(obj, "policy", &sev->policy,
+ OBJ_PROP_FLAG_READWRITE);
+ object_property_add_uint32_ptr(obj, "handle", &sev->handle,
+ OBJ_PROP_FLAG_READWRITE);
+ object_property_add_uint32_ptr(obj, "cbitpos", &sev->cbitpos,
+ OBJ_PROP_FLAG_READWRITE);
+ object_property_add_uint32_ptr(obj, "reduced-phys-bits",
+ &sev->reduced_phys_bits,
+ OBJ_PROP_FLAG_READWRITE);
+ object_apply_compat_props(obj);
+}
+
+/* sev guest info */
+static const TypeInfo sev_guest_info = {
+ .parent = TYPE_X86_CONFIDENTIAL_GUEST,
+ .name = TYPE_SEV_GUEST,
+ .instance_size = sizeof(SevGuestState),
+ .instance_finalize = sev_guest_finalize,
+ .class_init = sev_guest_class_init,
+ .instance_init = sev_guest_instance_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_USER_CREATABLE },
+ { }
+ }
+};
+
+static void
sev_register_types(void)
{
type_register_static(&sev_guest_info);
diff --git a/target/i386/sev.h b/target/i386/sev.h
index e7499c9..9e10d09 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -57,6 +57,4 @@
int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size);
void sev_es_set_reset_vector(CPUState *cpu);
-int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp);
-
#endif
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 76a42c6..c05d9e5 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -5846,9 +5846,10 @@
gen_op_st_v(s, MO_16, s->T0, s->A0);
gen_add_A0_im(s, 2);
tcg_gen_ld_tl(s->T0, tcg_env, offsetof(CPUX86State, gdt.base));
- if (dflag == MO_16) {
- tcg_gen_andi_tl(s->T0, s->T0, 0xffffff);
- }
+ /*
+ * NB: Despite a confusing description in Intel CPU documentation,
+ * all 32-bits are written regardless of operand size.
+ */
gen_op_st_v(s, CODE64(s) + MO_32, s->T0, s->A0);
break;
@@ -5901,9 +5902,10 @@
gen_op_st_v(s, MO_16, s->T0, s->A0);
gen_add_A0_im(s, 2);
tcg_gen_ld_tl(s->T0, tcg_env, offsetof(CPUX86State, idt.base));
- if (dflag == MO_16) {
- tcg_gen_andi_tl(s->T0, s->T0, 0xffffff);
- }
+ /*
+ * NB: Despite a confusing description in Intel CPU documentation,
+ * all 32-bits are written regardless of operand size.
+ */
gen_op_st_v(s, CODE64(s) + MO_32, s->T0, s->A0);
break;
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index d630cc3..8224d94 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -733,11 +733,6 @@
return true;
}
-bool kvm_arch_cpu_check_are_resettable(void)
-{
- return true;
-}
-
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
{
int ret = 0;
diff --git a/target/mips/kvm.c b/target/mips/kvm.c
index 6c52e59..a631ab5 100644
--- a/target/mips/kvm.c
+++ b/target/mips/kvm.c
@@ -1273,11 +1273,6 @@
return -1;
}
-bool kvm_arch_cpu_check_are_resettable(void)
-{
- return true;
-}
-
void kvm_arch_accel_class_init(ObjectClass *oc)
{
}
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 8231feb..63930d4 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2956,11 +2956,6 @@
}
}
-bool kvm_arch_cpu_check_are_resettable(void)
-{
- return true;
-}
-
void kvm_arch_accel_class_init(ObjectClass *oc)
{
}
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 6a6c6ca..49d2f3a 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1475,11 +1475,6 @@
}
}
-bool kvm_arch_cpu_check_are_resettable(void)
-{
- return true;
-}
-
static int aia_mode;
static const char *kvm_aia_mode_str(uint64_t mode)
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 4ce809c..4dcd757 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -2622,11 +2622,6 @@
kvm_s390_vcpu_interrupt(cpu, &irq);
}
-bool kvm_arch_cpu_check_are_resettable(void)
-{
- return true;
-}
-
int kvm_s390_get_zpci_op(void)
{
return cap_zpci_op;
diff --git a/target/s390x/kvm/pv.c b/target/s390x/kvm/pv.c
index 7ca7fae..dde836d 100644
--- a/target/s390x/kvm/pv.c
+++ b/target/s390x/kvm/pv.c
@@ -334,12 +334,17 @@
return s390_pv_check_cpus(errp);
}
-int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
+static int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
{
if (!object_dynamic_cast(OBJECT(cgs), TYPE_S390_PV_GUEST)) {
return 0;
}
+ if (!kvm_enabled()) {
+ error_setg(errp, "Protected Virtualization requires KVM");
+ return -1;
+ }
+
if (!s390_has_feat(S390_FEAT_UNPACK)) {
error_setg(errp,
"CPU model does not support Protected Virtualization");
@@ -364,6 +369,9 @@
static void s390_pv_guest_class_init(ObjectClass *oc, void *data)
{
+ ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
+
+ klass->kvm_init = s390_pv_kvm_init;
}
static void s390_pv_guest_init(Object *obj)
diff --git a/target/s390x/kvm/pv.h b/target/s390x/kvm/pv.h
index 5877d28..4b40817 100644
--- a/target/s390x/kvm/pv.h
+++ b/target/s390x/kvm/pv.h
@@ -80,18 +80,4 @@
static inline int kvm_s390_dump_completion_data(void *buff) { return 0; }
#endif /* CONFIG_KVM */
-int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp);
-static inline int s390_pv_init(ConfidentialGuestSupport *cgs, Error **errp)
-{
- if (!cgs) {
- return 0;
- }
- if (kvm_enabled()) {
- return s390_pv_kvm_init(cgs, errp);
- }
-
- error_setg(errp, "Protected Virtualization requires KVM");
- return -1;
-}
-
#endif /* HW_S390_PV_H */
diff --git a/tests/meson.build b/tests/meson.build
index 0a6f96f..acb6807 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -78,9 +78,9 @@
if 'CONFIG_TCG' in config_all_accel
subdir('fp')
+ subdir('plugin')
endif
-subdir('plugin')
subdir('unit')
subdir('qapi-schema')
subdir('qtest')
diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c
index e451dbd..ce6d661 100644
--- a/tests/qtest/migration-helpers.c
+++ b/tests/qtest/migration-helpers.c
@@ -13,6 +13,11 @@
#include "qemu/osdep.h"
#include "qemu/ctype.h"
#include "qapi/qmp/qjson.h"
+#include "qapi/qapi-visit-sockets.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qlist.h"
+#include "qemu/cutils.h"
#include "migration-helpers.h"
@@ -24,6 +29,127 @@
*/
#define MIGRATION_STATUS_WAIT_TIMEOUT 120
+static char *SocketAddress_to_str(SocketAddress *addr)
+{
+ switch (addr->type) {
+ case SOCKET_ADDRESS_TYPE_INET:
+ return g_strdup_printf("tcp:%s:%s",
+ addr->u.inet.host,
+ addr->u.inet.port);
+ case SOCKET_ADDRESS_TYPE_UNIX:
+ return g_strdup_printf("unix:%s",
+ addr->u.q_unix.path);
+ case SOCKET_ADDRESS_TYPE_FD:
+ return g_strdup_printf("fd:%s", addr->u.fd.str);
+ case SOCKET_ADDRESS_TYPE_VSOCK:
+ return g_strdup_printf("vsock:%s:%s",
+ addr->u.vsock.cid,
+ addr->u.vsock.port);
+ default:
+ return g_strdup("unknown address type");
+ }
+}
+
+static QDict *SocketAddress_to_qdict(SocketAddress *addr)
+{
+ QDict *dict = qdict_new();
+
+ switch (addr->type) {
+ case SOCKET_ADDRESS_TYPE_INET:
+ qdict_put_str(dict, "type", "inet");
+ qdict_put_str(dict, "host", addr->u.inet.host);
+ qdict_put_str(dict, "port", addr->u.inet.port);
+ break;
+ case SOCKET_ADDRESS_TYPE_UNIX:
+ qdict_put_str(dict, "type", "unix");
+ qdict_put_str(dict, "path", addr->u.q_unix.path);
+ break;
+ case SOCKET_ADDRESS_TYPE_FD:
+ qdict_put_str(dict, "type", "fd");
+ qdict_put_str(dict, "str", addr->u.fd.str);
+ break;
+ case SOCKET_ADDRESS_TYPE_VSOCK:
+ qdict_put_str(dict, "type", "vsock");
+ qdict_put_str(dict, "cid", addr->u.vsock.cid);
+ qdict_put_str(dict, "port", addr->u.vsock.port);
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ return dict;
+}
+
+static SocketAddress *migrate_get_socket_address(QTestState *who)
+{
+ QDict *rsp;
+ SocketAddressList *addrs;
+ SocketAddress *addr;
+ Visitor *iv = NULL;
+ QObject *object;
+
+ rsp = migrate_query(who);
+ object = qdict_get(rsp, "socket-address");
+
+ iv = qobject_input_visitor_new(object);
+ visit_type_SocketAddressList(iv, NULL, &addrs, &error_abort);
+ addr = addrs->value;
+ visit_free(iv);
+
+ qobject_unref(rsp);
+ return addr;
+}
+
+static char *
+migrate_get_connect_uri(QTestState *who)
+{
+ SocketAddress *addrs;
+ char *connect_uri;
+
+ addrs = migrate_get_socket_address(who);
+ connect_uri = SocketAddress_to_str(addrs);
+
+ qapi_free_SocketAddress(addrs);
+ return connect_uri;
+}
+
+static QDict *
+migrate_get_connect_qdict(QTestState *who)
+{
+ SocketAddress *addrs;
+ QDict *connect_qdict;
+
+ addrs = migrate_get_socket_address(who);
+ connect_qdict = SocketAddress_to_qdict(addrs);
+
+ qapi_free_SocketAddress(addrs);
+ return connect_qdict;
+}
+
+static void migrate_set_ports(QTestState *to, QList *channel_list)
+{
+ QDict *addr;
+ QListEntry *entry;
+ const char *addr_port = NULL;
+
+ addr = migrate_get_connect_qdict(to);
+
+ QLIST_FOREACH_ENTRY(channel_list, entry) {
+ QDict *channel = qobject_to(QDict, qlist_entry_obj(entry));
+ QDict *addrdict = qdict_get_qdict(channel, "addr");
+
+ if (qdict_haskey(addrdict, "port") &&
+ qdict_haskey(addr, "port") &&
+ (strcmp(qdict_get_str(addrdict, "port"), "0") == 0)) {
+ addr_port = qdict_get_str(addr, "port");
+ qdict_put_str(addrdict, "port", g_strdup(addr_port));
+ }
+ }
+
+ qobject_unref(addr);
+}
+
bool migrate_watch_for_events(QTestState *who, const char *name,
QDict *event, void *opaque)
{
@@ -43,7 +169,8 @@
return false;
}
-void migrate_qmp_fail(QTestState *who, const char *uri, const char *fmt, ...)
+void migrate_qmp_fail(QTestState *who, const char *uri,
+ const char *channels, const char *fmt, ...)
{
va_list ap;
QDict *args, *err;
@@ -53,7 +180,15 @@
va_end(ap);
g_assert(!qdict_haskey(args, "uri"));
- qdict_put_str(args, "uri", uri);
+ if (uri) {
+ qdict_put_str(args, "uri", uri);
+ }
+
+ g_assert(!qdict_haskey(args, "channels"));
+ if (channels) {
+ QObject *channels_obj = qobject_from_json(channels, &error_abort);
+ qdict_put_obj(args, "channels", channels_obj);
+ }
err = qtest_qmp_assert_failure_ref(
who, "{ 'execute': 'migrate', 'arguments': %p}", args);
@@ -68,17 +203,32 @@
* Arguments are built from @fmt... (formatted like
* qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
*/
-void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...)
+void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
+ const char *channels, const char *fmt, ...)
{
va_list ap;
QDict *args;
+ g_autofree char *connect_uri = NULL;
va_start(ap, fmt);
args = qdict_from_vjsonf_nofail(fmt, ap);
va_end(ap);
g_assert(!qdict_haskey(args, "uri"));
- qdict_put_str(args, "uri", uri);
+ if (uri) {
+ qdict_put_str(args, "uri", uri);
+ } else if (!channels) {
+ connect_uri = migrate_get_connect_uri(to);
+ qdict_put_str(args, "uri", connect_uri);
+ }
+
+ g_assert(!qdict_haskey(args, "channels"));
+ if (channels) {
+ QObject *channels_obj = qobject_from_json(channels, &error_abort);
+ QList *channel_list = qobject_to(QList, channels_obj);
+ migrate_set_ports(to, channel_list);
+ qdict_put_obj(args, "channels", channels_obj);
+ }
qtest_qmp_assert_success(who,
"{ 'execute': 'migrate', 'arguments': %p}", args);
diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h
index 3bf7ded..1339835 100644
--- a/tests/qtest/migration-helpers.h
+++ b/tests/qtest/migration-helpers.h
@@ -25,15 +25,17 @@
bool migrate_watch_for_events(QTestState *who, const char *name,
QDict *event, void *opaque);
-G_GNUC_PRINTF(3, 4)
-void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...);
+G_GNUC_PRINTF(5, 6)
+void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
+ const char *channels, const char *fmt, ...);
G_GNUC_PRINTF(3, 4)
void migrate_incoming_qmp(QTestState *who, const char *uri,
const char *fmt, ...);
-G_GNUC_PRINTF(3, 4)
-void migrate_qmp_fail(QTestState *who, const char *uri, const char *fmt, ...);
+G_GNUC_PRINTF(4, 5)
+void migrate_qmp_fail(QTestState *who, const char *uri,
+ const char *channels, const char *fmt, ...);
void migrate_set_capability(QTestState *who, const char *capability,
bool value);
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 1d2cee8..5d6d8cd 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -13,16 +13,12 @@
#include "qemu/osdep.h"
#include "libqtest.h"
-#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/range.h"
#include "qemu/sockets.h"
#include "chardev/char.h"
-#include "qapi/qapi-visit-sockets.h"
-#include "qapi/qobject-input-visitor.h"
-#include "qapi/qobject-output-visitor.h"
#include "crypto/tlscredspsk.h"
#include "qapi/qmp/qlist.h"
@@ -369,50 +365,6 @@
unlink(path);
}
-static char *SocketAddress_to_str(SocketAddress *addr)
-{
- switch (addr->type) {
- case SOCKET_ADDRESS_TYPE_INET:
- return g_strdup_printf("tcp:%s:%s",
- addr->u.inet.host,
- addr->u.inet.port);
- case SOCKET_ADDRESS_TYPE_UNIX:
- return g_strdup_printf("unix:%s",
- addr->u.q_unix.path);
- case SOCKET_ADDRESS_TYPE_FD:
- return g_strdup_printf("fd:%s", addr->u.fd.str);
- case SOCKET_ADDRESS_TYPE_VSOCK:
- return g_strdup_printf("tcp:%s:%s",
- addr->u.vsock.cid,
- addr->u.vsock.port);
- default:
- return g_strdup("unknown address type");
- }
-}
-
-static char *migrate_get_socket_address(QTestState *who, const char *parameter)
-{
- QDict *rsp;
- char *result;
- SocketAddressList *addrs;
- Visitor *iv = NULL;
- QObject *object;
-
- rsp = migrate_query(who);
- object = qdict_get(rsp, parameter);
-
- iv = qobject_input_visitor_new(object);
- visit_type_SocketAddressList(iv, NULL, &addrs, &error_abort);
- visit_free(iv);
-
- /* we are only using a single address */
- result = SocketAddress_to_str(addrs->value);
-
- qapi_free_SocketAddressList(addrs);
- qobject_unref(rsp);
- return result;
-}
-
static long long migrate_get_parameter_int(QTestState *who,
const char *parameter)
{
@@ -703,6 +655,13 @@
*/
const char *connect_uri;
+ /*
+ * Optional: JSON-formatted list of src QEMU URIs. If a port is
+ * defined as '0' in any QDict key a value of '0' will be
+ * automatically converted to the correct destination port.
+ */
+ const char *connect_channels;
+
/* Optional: callback to run at start to set migration parameters */
TestMigrateStartHook start_hook;
/* Optional: callback to run at finish to cleanup */
@@ -1349,8 +1308,7 @@
wait_for_serial("src_serial");
wait_for_suspend(from, &src_state);
- g_autofree char *uri = migrate_get_socket_address(to, "socket-address");
- migrate_qmp(from, uri, "{}");
+ migrate_qmp(from, to, NULL, NULL, "{}");
migrate_wait_for_dirty_mem(from, to);
@@ -1500,7 +1458,7 @@
g_assert_cmpint(ret, ==, 1);
migrate_recover(to, "fd:fd-mig");
- migrate_qmp(from, "fd:fd-mig", "{'resume': true}");
+ migrate_qmp(from, to, "fd:fd-mig", NULL, "{'resume': true}");
/*
* Make sure both QEMU instances will go into RECOVER stage, then test
@@ -1588,7 +1546,7 @@
* Try to rebuild the migration channel using the resume flag and
* the newly created channel
*/
- migrate_qmp(from, uri, "{'resume': true}");
+ migrate_qmp(from, to, uri, NULL, "{'resume': true}");
/* Restore the postcopy bandwidth to unlimited */
migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0);
@@ -1669,7 +1627,7 @@
if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
return;
}
- migrate_qmp(from, "tcp:127.0.0.1:0", "{}");
+ migrate_qmp(from, to, "tcp:127.0.0.1:0", NULL, "{}");
wait_for_migration_fail(from, false);
test_migrate_end(from, to, false);
}
@@ -1708,7 +1666,7 @@
uri = g_strdup_printf("exec:cat > %s", file);
migrate_ensure_converge(from);
- migrate_qmp(from, uri, "{}");
+ migrate_qmp(from, to, uri, NULL, "{}");
wait_for_migration_complete(from);
pid = fork();
@@ -1733,7 +1691,6 @@
{
QTestState *from, *to;
void *data_hook = NULL;
- g_autofree char *connect_uri = NULL;
if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) {
return;
@@ -1766,18 +1723,12 @@
}
}
- if (!args->connect_uri) {
- connect_uri = migrate_get_socket_address(to, "socket-address");
- } else {
- connect_uri = g_strdup(args->connect_uri);
- }
-
if (args->result == MIG_TEST_QMP_ERROR) {
- migrate_qmp_fail(from, connect_uri, "{}");
+ migrate_qmp_fail(from, args->connect_uri, args->connect_channels, "{}");
goto finish;
}
- migrate_qmp(from, connect_uri, "{}");
+ migrate_qmp(from, to, args->connect_uri, args->connect_channels, "{}");
if (args->result != MIG_TEST_SUCCEED) {
bool allow_active = args->result == MIG_TEST_FAIL;
@@ -1843,7 +1794,6 @@
{
QTestState *from, *to;
void *data_hook = NULL;
- g_autofree char *connect_uri = g_strdup(args->connect_uri);
if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) {
return;
@@ -1869,18 +1819,18 @@
}
if (args->result == MIG_TEST_QMP_ERROR) {
- migrate_qmp_fail(from, connect_uri, "{}");
+ migrate_qmp_fail(from, args->connect_uri, NULL, "{}");
goto finish;
}
- migrate_qmp(from, connect_uri, "{}");
+ migrate_qmp(from, to, args->connect_uri, NULL, "{}");
wait_for_migration_complete(from);
/*
* We need to wait for the source to finish before starting the
* destination.
*/
- migrate_incoming_qmp(to, connect_uri, "{}");
+ migrate_incoming_qmp(to, args->connect_uri, "{}");
wait_for_migration_complete(to);
if (stop_src) {
@@ -2029,7 +1979,7 @@
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
- migrate_qmp(from, uri, "{}");
+ migrate_qmp(from, to, uri, NULL, "{}");
migrate_wait_for_dirty_mem(from, to);
@@ -2568,7 +2518,7 @@
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
- migrate_qmp(from, uri, "{}");
+ migrate_qmp(from, to, uri, NULL, "{}");
if (should_fail) {
qtest_set_expected_status(to, EXIT_FAILURE);
@@ -2621,6 +2571,55 @@
do_test_validate_uuid(&args, false);
}
+static void do_test_validate_uri_channel(MigrateCommon *args)
+{
+ QTestState *from, *to;
+
+ if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) {
+ return;
+ }
+
+ /* Wait for the first serial output from the source */
+ wait_for_serial("src_serial");
+
+ /*
+ * 'uri' and 'channels' validation is checked even before the migration
+ * starts.
+ */
+ migrate_qmp_fail(from, args->connect_uri, args->connect_channels, "{}");
+ test_migrate_end(from, to, false);
+}
+
+static void test_validate_uri_channels_both_set(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .listen_uri = "defer",
+ .connect_uri = "tcp:127.0.0.1:0",
+ .connect_channels = "[ { 'channel-type': 'main',"
+ " 'addr': { 'transport': 'socket',"
+ " 'type': 'inet',"
+ " 'host': '127.0.0.1',"
+ " 'port': '0' } } ]",
+ };
+
+ do_test_validate_uri_channel(&args);
+}
+
+static void test_validate_uri_channels_none_set(void)
+{
+ MigrateCommon args = {
+ .start = {
+ .hide_stderr = true,
+ },
+ .listen_uri = "defer",
+ };
+
+ do_test_validate_uri_channel(&args);
+}
+
/*
* The way auto_converge works, we need to do too many passes to
* run this test. Auto_converge logic is only run once every
@@ -2671,7 +2670,7 @@
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
- migrate_qmp(from, uri, "{}");
+ migrate_qmp(from, to, uri, NULL, "{}");
/* Wait for throttling begins */
percentage = 0;
@@ -2778,7 +2777,7 @@
}
#endif /* CONFIG_ZSTD */
-static void test_multifd_tcp_none(void)
+static void test_multifd_tcp_uri_none(void)
{
MigrateCommon args = {
.listen_uri = "defer",
@@ -2823,6 +2822,21 @@
test_precopy_common(&args);
}
+static void test_multifd_tcp_channels_none(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start_hook = test_migrate_precopy_tcp_multifd_start,
+ .live = true,
+ .connect_channels = "[ { 'channel-type': 'main',"
+ " 'addr': { 'transport': 'socket',"
+ " 'type': 'inet',"
+ " 'host': '127.0.0.1',"
+ " 'port': '0' } } ]",
+ };
+ test_precopy_common(&args);
+}
+
static void test_multifd_tcp_zlib(void)
{
MigrateCommon args = {
@@ -3017,7 +3031,6 @@
.hide_stderr = true,
};
QTestState *from, *to, *to2;
- g_autofree char *uri = NULL;
if (test_migrate_start(&from, &to, "defer", &args)) {
return;
@@ -3038,9 +3051,7 @@
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
- uri = migrate_get_socket_address(to, "socket-address");
-
- migrate_qmp(from, uri, "{}");
+ migrate_qmp(from, to, NULL, NULL, "{}");
migrate_wait_for_dirty_mem(from, to);
@@ -3065,14 +3076,11 @@
/* Start incoming migration from the 1st socket */
migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", "{}");
- g_free(uri);
- uri = migrate_get_socket_address(to2, "socket-address");
-
wait_for_migration_status(from, "cancelled", NULL);
migrate_ensure_non_converge(from);
- migrate_qmp(from, uri, "{}");
+ migrate_qmp(from, to2, NULL, NULL, "{}");
migrate_wait_for_dirty_mem(from, to2);
@@ -3405,7 +3413,7 @@
migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
/* Start migrate */
- migrate_qmp(from, uri, "{}");
+ migrate_qmp(from, to, args.connect_uri, NULL, "{}");
/* Wait for dirty limit throttle begin */
throttle_us_per_full = 0;
@@ -3446,7 +3454,7 @@
}
/* Start migrate */
- migrate_qmp(from, uri, "{}");
+ migrate_qmp(from, to, args.connect_uri, NULL, "{}");
/* Wait for dirty limit throttle begin */
throttle_us_per_full = 0;
@@ -3720,6 +3728,10 @@
test_validate_uuid_src_not_set);
migration_test_add("/migration/validate_uuid_dst_not_set",
test_validate_uuid_dst_not_set);
+ migration_test_add("/migration/validate_uri/channels/both_set",
+ test_validate_uri_channels_both_set);
+ migration_test_add("/migration/validate_uri/channels/none_set",
+ test_validate_uri_channels_none_set);
/*
* See explanation why this test is slow on function definition
*/
@@ -3732,8 +3744,10 @@
test_migrate_dirty_limit);
}
}
- migration_test_add("/migration/multifd/tcp/plain/none",
- test_multifd_tcp_none);
+ migration_test_add("/migration/multifd/tcp/uri/plain/none",
+ test_multifd_tcp_uri_none);
+ migration_test_add("/migration/multifd/tcp/channels/plain/none",
+ test_multifd_tcp_channels_none);
migration_test_add("/migration/multifd/tcp/plain/zero-page/legacy",
test_multifd_tcp_zero_page_legacy);
migration_test_add("/migration/multifd/tcp/plain/zero-page/none",
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index 228a21d..26c109c 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -18,7 +18,6 @@
'test-forward-visitor': [testqapi],
'test-string-input-visitor': [testqapi],
'test-string-output-visitor': [testqapi],
- 'test-opts-visitor': [testqapi],
'test-visitor-serialization': [testqapi],
'test-bitmap': [],
'test-resv-mem': [],
@@ -46,12 +45,8 @@
'test-qemu-opts': [],
'test-keyval': [testqapi],
'test-logging': [],
- 'test-uuid': [],
- 'ptimer-test': ['ptimer-test-stubs.c', meson.project_source_root() / 'hw/core/ptimer.c'],
'test-qapi-util': [],
'test-interval-tree': [],
- 'test-xs-node': [qom],
- 'test-virtio-dmabuf': [meson.project_source_root() / 'hw/display/virtio-dmabuf.c'],
}
if have_system or have_tools
@@ -97,6 +92,8 @@
'test-crypto-ivgen': [io],
'test-crypto-afsplit': [io],
'test-crypto-block': [io],
+ 'test-timed-average': [],
+ 'test-uuid': [],
}
if gnutls.found() and \
tasn1.found() and \
@@ -131,10 +128,13 @@
if have_system
tests += {
+ 'ptimer-test': ['ptimer-test-stubs.c', meson.project_source_root() / 'hw/core/ptimer.c'],
'test-iov': [],
+ 'test-opts-visitor': [testqapi],
+ 'test-xs-node': [qom],
+ 'test-virtio-dmabuf': [meson.project_source_root() / 'hw/display/virtio-dmabuf.c'],
'test-qmp-cmds': [testqapi],
'test-xbzrle': [migration],
- 'test-timed-average': [],
'test-util-sockets': ['socket-helpers.c'],
'test-base64': [],
'test-bufferiszero': [],
diff --git a/util/meson.build b/util/meson.build
index 0ef9886..2ad57b1 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -60,7 +60,6 @@
util_ss.add(files('systemd.c'))
util_ss.add(files('transactions.c'))
util_ss.add(files('guest-random.c'))
-util_ss.add(files('yank.c'))
util_ss.add(files('int128.c'))
util_ss.add(files('memalign.c'))
util_ss.add(files('interval-tree.c'))
@@ -117,6 +116,7 @@
util_ss.add(files('vfio-helpers.c'))
util_ss.add(files('chardev_open.c'))
endif
+ util_ss.add(files('yank.c'))
endif
if cpu == 'aarch64'
diff --git a/util/qemu-config.c b/util/qemu-config.c
index 42076ef..a90c18d 100644
--- a/util/qemu-config.c
+++ b/util/qemu-config.c
@@ -1,16 +1,14 @@
#include "qemu/osdep.h"
#include "block/qdict.h" /* for qdict_extract_subqdict() */
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qlist.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
-#include "hw/boards.h"
-static QemuOptsList *vm_config_groups[48];
-static QemuOptsList *drive_config_groups[5];
+QemuOptsList *vm_config_groups[48];
+QemuOptsList *drive_config_groups[5];
static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
Error **errp)
@@ -55,204 +53,6 @@
return opts;
}
-static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
-{
- CommandLineParameterInfoList *param_list = NULL;
- CommandLineParameterInfo *info;
- int i;
-
- for (i = 0; desc[i].name != NULL; i++) {
- info = g_malloc0(sizeof(*info));
- info->name = g_strdup(desc[i].name);
-
- switch (desc[i].type) {
- case QEMU_OPT_STRING:
- info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
- break;
- case QEMU_OPT_BOOL:
- info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
- break;
- case QEMU_OPT_NUMBER:
- info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
- break;
- case QEMU_OPT_SIZE:
- info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
- break;
- }
-
- info->help = g_strdup(desc[i].help);
- info->q_default = g_strdup(desc[i].def_value_str);
-
- QAPI_LIST_PREPEND(param_list, info);
- }
-
- return param_list;
-}
-
-/* remove repeated entry from the info list */
-static void cleanup_infolist(CommandLineParameterInfoList *head)
-{
- CommandLineParameterInfoList *pre_entry, *cur, *del_entry;
-
- cur = head;
- while (cur->next) {
- pre_entry = head;
- while (pre_entry != cur->next) {
- if (!strcmp(pre_entry->value->name, cur->next->value->name)) {
- del_entry = cur->next;
- cur->next = cur->next->next;
- del_entry->next = NULL;
- qapi_free_CommandLineParameterInfoList(del_entry);
- break;
- }
- pre_entry = pre_entry->next;
- }
- cur = cur->next;
- }
-}
-
-/* merge the description items of two parameter infolists */
-static void connect_infolist(CommandLineParameterInfoList *head,
- CommandLineParameterInfoList *new)
-{
- CommandLineParameterInfoList *cur;
-
- cur = head;
- while (cur->next) {
- cur = cur->next;
- }
- cur->next = new;
-}
-
-/* access all the local QemuOptsLists for drive option */
-static CommandLineParameterInfoList *get_drive_infolist(void)
-{
- CommandLineParameterInfoList *head = NULL, *cur;
- int i;
-
- for (i = 0; drive_config_groups[i] != NULL; i++) {
- if (!head) {
- head = query_option_descs(drive_config_groups[i]->desc);
- } else {
- cur = query_option_descs(drive_config_groups[i]->desc);
- connect_infolist(head, cur);
- }
- }
- cleanup_infolist(head);
-
- return head;
-}
-
-static CommandLineParameterInfo *objprop_to_cmdline_prop(ObjectProperty *prop)
-{
- CommandLineParameterInfo *info;
-
- info = g_malloc0(sizeof(*info));
- info->name = g_strdup(prop->name);
-
- if (g_str_equal(prop->type, "bool") || g_str_equal(prop->type, "OnOffAuto")) {
- info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
- } else if (g_str_equal(prop->type, "int")) {
- info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
- } else if (g_str_equal(prop->type, "size")) {
- info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
- } else {
- info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
- }
-
- if (prop->description) {
- info->help = g_strdup(prop->description);
- }
-
- return info;
-}
-
-static CommandLineParameterInfoList *query_all_machine_properties(void)
-{
- CommandLineParameterInfoList *params = NULL, *clpiter;
- CommandLineParameterInfo *info;
- GSList *machines, *curr_mach;
- ObjectPropertyIterator op_iter;
- ObjectProperty *prop;
- bool is_new;
-
- machines = object_class_get_list(TYPE_MACHINE, false);
- assert(machines);
-
- /* Loop over all machine classes */
- for (curr_mach = machines; curr_mach; curr_mach = curr_mach->next) {
- object_class_property_iter_init(&op_iter, curr_mach->data);
- /* ... and over the properties of each machine: */
- while ((prop = object_property_iter_next(&op_iter))) {
- if (!prop->set) {
- continue;
- }
- /*
- * Check whether the property has already been put into the list
- * (via another machine class)
- */
- is_new = true;
- for (clpiter = params; clpiter != NULL; clpiter = clpiter->next) {
- if (g_str_equal(clpiter->value->name, prop->name)) {
- is_new = false;
- break;
- }
- }
- /* If it hasn't been added before, add it now to the list */
- if (is_new) {
- info = objprop_to_cmdline_prop(prop);
- QAPI_LIST_PREPEND(params, info);
- }
- }
- }
-
- g_slist_free(machines);
-
- /* Add entry for the "type" parameter */
- info = g_malloc0(sizeof(*info));
- info->name = g_strdup("type");
- info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
- info->help = g_strdup("machine type");
- QAPI_LIST_PREPEND(params, info);
-
- return params;
-}
-
-CommandLineOptionInfoList *qmp_query_command_line_options(const char *option,
- Error **errp)
-{
- CommandLineOptionInfoList *conf_list = NULL;
- CommandLineOptionInfo *info;
- int i;
-
- for (i = 0; vm_config_groups[i] != NULL; i++) {
- if (!option || !strcmp(option, vm_config_groups[i]->name)) {
- info = g_malloc0(sizeof(*info));
- info->option = g_strdup(vm_config_groups[i]->name);
- if (!strcmp("drive", vm_config_groups[i]->name)) {
- info->parameters = get_drive_infolist();
- } else {
- info->parameters =
- query_option_descs(vm_config_groups[i]->desc);
- }
- QAPI_LIST_PREPEND(conf_list, info);
- }
- }
-
- if (!option || !strcmp(option, "machine")) {
- info = g_malloc0(sizeof(*info));
- info->option = g_strdup("machine");
- info->parameters = query_all_machine_properties();
- QAPI_LIST_PREPEND(conf_list, info);
- }
-
- if (conf_list == NULL) {
- error_setg(errp, "invalid option name: %s", option);
- }
-
- return conf_list;
-}
-
QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
{
return find_list(vm_config_groups, group, errp);
diff --git a/util/qemu-option.c b/util/qemu-option.c
index eedd089..201f7a8 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -498,7 +498,7 @@
desc = find_desc_by_name(list->desc, opt->name);
if (!desc && !opts_accepts_any(list)) {
- error_setg(errp, QERR_INVALID_PARAMETER, opt->name);
+ error_setg(errp, "Invalid parameter '%s'", opt->name);
return false;
}
@@ -531,7 +531,7 @@
desc = find_desc_by_name(list->desc, name);
if (!desc && !opts_accepts_any(list)) {
- error_setg(errp, QERR_INVALID_PARAMETER, name);
+ error_setg(errp, "Invalid parameter '%s'", name);
return false;
}
@@ -554,7 +554,7 @@
desc = find_desc_by_name(list->desc, name);
if (!desc && !opts_accepts_any(list)) {
- error_setg(errp, QERR_INVALID_PARAMETER, name);
+ error_setg(errp, "Invalid parameter '%s'", name);
return false;
}
@@ -612,7 +612,7 @@
if (list->merge_lists) {
if (id) {
- error_setg(errp, QERR_INVALID_PARAMETER, "id");
+ error_setg(errp, "Invalid parameter 'id'");
return NULL;
}
opts = qemu_opts_find(list, NULL);
@@ -1103,7 +1103,7 @@
QTAILQ_FOREACH(opt, &opts->head, next) {
opt->desc = find_desc_by_name(desc, opt->name);
if (!opt->desc) {
- error_setg(errp, QERR_INVALID_PARAMETER, opt->name);
+ error_setg(errp, "Invalid parameter '%s'", opt->name);
return false;
}