diff options
113 files changed, 2077 insertions, 1112 deletions
@@ -100,7 +100,19 @@ pointer, you're guaranteed that it is used to modify the storage it points to, or it is aliased to another pointer that is. 2.3. Typedefs -Typedefs are used to eliminate the redundant 'struct' keyword. + +Typedefs are used to eliminate the redundant 'struct' keyword, since type +names have a different style than other identifiers ("CamelCase" versus +"snake_case"). Each named struct type should have a CamelCase name and a +corresponding typedef. + +Since certain C compilers choke on duplicated typedefs, you should avoid +them and declare a typedef only in one header file. For common types, +you can use "include/qemu/typedefs.h" for example. However, as a matter +of convenience it is also perfectly fine to use forward struct +definitions instead of typedefs in headers and function prototypes; this +avoids problems with duplicated typedefs and reduces the need to include +headers from other headers. 2.4. Reserved namespaces in C and POSIX Underscore capital, double underscore, and underscore 't' suffixes should be diff --git a/Kconfig.host b/Kconfig.host index aec95365ff..bb6e116e2a 100644 --- a/Kconfig.host +++ b/Kconfig.host @@ -28,6 +28,7 @@ config VHOST_USER config XEN bool + select FSDEV_9P if VIRTFS config VIRTFS bool diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 6c85c3ee1e..48272c781b 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -169,7 +169,6 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb) } #endif /* DEBUG_DISAS */ - cpu->can_do_io = !use_icount; ret = tcg_qemu_tb_exec(env, tb_ptr); cpu->can_do_io = 1; last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK); diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 9226a348a3..70c66c538c 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -90,7 +90,6 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, /* Accept I/O on the last instruction. */ gen_io_start(); ops->translate_insn(db, cpu); - gen_io_end(); } else { ops->translate_insn(db, cpu); } @@ -7431,11 +7431,16 @@ for target in $target_list; do target_dir="$target" config_target_mak=$target_dir/config-target.mak target_name=$(echo $target | cut -d '-' -f 1) +target_aligned_only="no" +case "$target_name" in + alpha|hppa|mips64el|mips64|mipsel|mips|mipsn32|mipsn32el|sh4|sh4eb|sparc|sparc64|sparc32plus|xtensa|xtensaeb) + target_aligned_only="yes" + ;; +esac target_bigendian="no" - case "$target_name" in armeb|aarch64_be|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) - target_bigendian=yes + target_bigendian="yes" ;; esac target_softmmu="no" @@ -7717,6 +7722,9 @@ fi if supported_whpx_target $target; then echo "CONFIG_WHPX=y" >> $config_target_mak fi +if test "$target_aligned_only" = "yes" ; then + echo "TARGET_ALIGNED_ONLY=y" >> $config_target_mak +fi if test "$target_bigendian" = "yes" ; then echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak fi diff --git a/cpus-common.c b/cpus-common.c index 3ca58c64e8..023cfebfa3 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -69,12 +69,6 @@ static int cpu_get_free_index(void) return cpu_index; } -static void finish_safe_work(CPUState *cpu) -{ - cpu_exec_start(cpu); - cpu_exec_end(cpu); -} - void cpu_list_add(CPUState *cpu) { qemu_mutex_lock(&qemu_cpu_list_lock); @@ -86,8 +80,6 @@ void cpu_list_add(CPUState *cpu) } QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node); qemu_mutex_unlock(&qemu_cpu_list_lock); - - finish_safe_work(cpu); } void cpu_list_remove(CPUState *cpu) @@ -556,7 +556,8 @@ void qtest_clock_warp(int64_t dest) assert(qtest_enabled()); aio_context = qemu_get_aio_context(); while (clock < dest) { - int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, + QEMU_TIMER_ATTR_ALL); int64_t warp = qemu_soonest_timeout(dest - clock, deadline); seqlock_write_lock(&timers_state.vm_clock_seqlock, @@ -616,7 +617,8 @@ void qemu_start_warp_timer(void) /* We want to use the earliest deadline from ALL vm_clocks */ clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT); - deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, + ~QEMU_TIMER_ATTR_EXTERNAL); if (deadline < 0) { static bool notified; if (!icount_sleep && !notified) { @@ -1352,7 +1354,12 @@ static int64_t tcg_get_icount_limit(void) int64_t deadline; if (replay_mode != REPLAY_MODE_PLAY) { - deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + /* + * Include all the timers, because they may need an attention. + * Too long CPU execution may create unnecessary delay in UI. + */ + deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, + QEMU_TIMER_ATTR_ALL); /* Maintain prior (possibly buggy) behaviour where if no deadline * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than @@ -1373,8 +1380,8 @@ static void handle_icount_deadline(void) { assert(qemu_in_vcpu_thread()); if (use_icount) { - int64_t deadline = - qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, + QEMU_TIMER_ATTR_ALL); if (deadline == 0) { /* Wake up other AioContexts. */ diff --git a/disas/ppc.c b/disas/ppc.c index a545437de9..63e97cfe1d 100644 --- a/disas/ppc.c +++ b/disas/ppc.c @@ -1765,6 +1765,9 @@ extract_tbr (unsigned long insn, /* An X_MASK with the RA and RB fields fixed. */ #define XRARB_MASK (X_MASK | RA_MASK | RB_MASK) +/* An X form instruction with the RA field fixed. */ +#define XRA(op, xop, ra) (X((op), (xop)) | (((ra) << 16) & XRA_MASK)) + /* An XRARB_MASK, but with the L bit clear. */ #define XRLARB_MASK (XRARB_MASK & ~((unsigned long) 1 << 16)) @@ -4998,6 +5001,8 @@ const struct powerpc_opcode powerpc_opcodes[] = { { "ddivq", XRC(63,546,0), X_MASK, POWER6, { FRT, FRA, FRB } }, { "ddivq.", XRC(63,546,1), X_MASK, POWER6, { FRT, FRA, FRB } }, +{ "mffsl", XRA(63,583,12), XRARB_MASK, POWER9, { FRT } }, + { "mffs", XRC(63,583,0), XRARB_MASK, COM, { FRT } }, { "mffs.", XRC(63,583,1), XRARB_MASK, COM, { FRT } }, diff --git a/docs/devel/replay.txt b/docs/devel/replay.txt new file mode 100644 index 0000000000..e641c35add --- /dev/null +++ b/docs/devel/replay.txt @@ -0,0 +1,46 @@ +Record/replay mechanism, that could be enabled through icount mode, expects +the virtual devices to satisfy the following requirements. + +The main idea behind this document is that everything that affects +the guest state during execution in icount mode should be deterministic. + +Timers +====== + +All virtual devices should use virtual clock for timers that change the guest +state. Virtual clock is deterministic, therefore such timers are deterministic +too. + +Virtual devices can also use realtime clock for the events that do not change +the guest state directly. When the clock ticking should depend on VM execution +speed, use virtual clock with EXTERNAL attribute. It is not deterministic, +but its speed depends on the guest execution. This clock is used by +the virtual devices (e.g., slirp routing device) that lie outside the +replayed guest. + +Bottom halves +============= + +Bottom half callbacks, that affect the guest state, should be invoked through +replay_bh_schedule_event or replay_bh_schedule_oneshot_event functions. +Their invocations are saved in record mode and synchronized with the existing +log in replay mode. + +Saving/restoring the VM state +============================= + +All fields in the device state structure (including virtual timers) +should be restored by loadvm to the same values they had before savevm. + +Avoid accessing other devices' state, because the order of saving/restoring +is not defined. It means that you should not call functions like +'update_irq' in post_load callback. Save everything explicitly to avoid +the dependencies that may make restoring the VM state non-deterministic. + +Stopping the VM +=============== + +Stopping the guest should not interfere with its state (with the exception +of the network connections, that could be broken by the remote timeouts). +VM can be stopped at any moment of replay by the user. Restarting the VM +after that stop should not break the replay by the unneeded guest state change. diff --git a/docs/specs/ppc-spapr-uv-hcalls.txt b/docs/specs/ppc-spapr-uv-hcalls.txt new file mode 100644 index 0000000000..389c2740d7 --- /dev/null +++ b/docs/specs/ppc-spapr-uv-hcalls.txt @@ -0,0 +1,76 @@ +On PPC64 systems supporting Protected Execution Facility (PEF), system +memory can be placed in a secured region where only an "ultravisor" +running in firmware can provide to access it. pseries guests on such +systems can communicate with the ultravisor (via ultracalls) to switch to a +secure VM mode (SVM) where the guest's memory is relocated to this secured +region, making its memory inaccessible to normal processes/guests running on +the host. + +The various ultracalls/hypercalls relating to SVM mode are currently +only documented internally, but are planned for direct inclusion into the +public OpenPOWER version of the PAPR specification (LoPAPR/LoPAR). An internal +ACR has been filed to reserve a hypercall number range specific to this +use-case to avoid any future conflicts with the internally-maintained PAPR +specification. This document summarizes some of these details as they relate +to QEMU. + +== hypercalls needed by the ultravisor == + +Switching to SVM mode involves a number of hcalls issued by the ultravisor +to the hypervisor to orchestrate the movement of guest memory to secure +memory and various other aspects SVM mode. Numbers are assigned for these +hcalls within the reserved range 0xEF00-0xEF80. The below documents the +hcalls relevant to QEMU. + +- H_TPM_COMM (0xef10) + + For TPM_COMM_OP_EXECUTE operation: + Send a request to a TPM and receive a response, opening a new TPM session + if one has not already been opened. + + For TPM_COMM_OP_CLOSE_SESSION operation: + Close the existing TPM session, if any. + + Arguments: + + r3 : H_TPM_COMM (0xef10) + r4 : TPM operation, one of: + TPM_COMM_OP_EXECUTE (0x1) + TPM_COMM_OP_CLOSE_SESSION (0x2) + r5 : in_buffer, guest physical address of buffer containing the request + - Caller may use the same address for both request and response + r6 : in_size, size of the in buffer + - Must be less than or equal to 4KB + r7 : out_buffer, guest physical address of buffer to store the response + - Caller may use the same address for both request and response + r8 : out_size, size of the out buffer + - Must be at least 4KB, as this is the maximum request/response size + supported by most TPM implementations, including the TPM Resource + Manager in the linux kernel. + + Return values: + + r3 : H_Success request processed successfully + H_PARAMETER invalid TPM operation + H_P2 in_buffer is invalid + H_P3 in_size is invalid + H_P4 out_buffer is invalid + H_P5 out_size is invalid + H_RESOURCE problem communicating with TPM + H_FUNCTION TPM access is not currently allowed/configured + r4 : For TPM_COMM_OP_EXECUTE, the size of the response will be stored here + upon success. + + Use-case/notes: + + SVM filesystems are encrypted using a symmetric key. This key is then + wrapped/encrypted using the public key of a trusted system which has the + private key stored in the system's TPM. An Ultravisor will use this + hcall to unwrap/unseal the symmetric key using the system's TPM device + or a TPM Resource Manager associated with the device. + + The Ultravisor sets up a separate session key with the TPM in advance + during host system boot. All sensitive in and out values will be + encrypted using the session key. Though the hypervisor will see the 'in' + and 'out' buffers in raw form, any sensitive contents will generally be + encrypted using this session key. @@ -197,6 +197,7 @@ typedef struct subpage_t { static void io_mem_init(void); static void memory_map_init(void); +static void tcg_log_global_after_sync(MemoryListener *listener); static void tcg_commit(MemoryListener *listener); static MemoryRegion io_mem_watch; @@ -905,6 +906,7 @@ void cpu_address_space_init(CPUState *cpu, int asidx, newas->cpu = cpu; newas->as = as; if (tcg_enabled()) { + newas->tcg_as_listener.log_global_after_sync = tcg_log_global_after_sync; newas->tcg_as_listener.commit = tcg_commit; memory_listener_register(&newas->tcg_as_listener, as); } @@ -3142,6 +3144,35 @@ void address_space_dispatch_free(AddressSpaceDispatch *d) g_free(d); } +static void do_nothing(CPUState *cpu, run_on_cpu_data d) +{ +} + +static void tcg_log_global_after_sync(MemoryListener *listener) +{ + CPUAddressSpace *cpuas; + + /* Wait for the CPU to end the current TB. This avoids the following + * incorrect race: + * + * vCPU migration + * ---------------------- ------------------------- + * TLB check -> slow path + * notdirty_mem_write + * write to RAM + * mark dirty + * clear dirty flag + * TLB check -> fast path + * read memory + * write to RAM + * + * by pushing the migration thread's memory read after the vCPU thread has + * written the memory. + */ + cpuas = container_of(listener, CPUAddressSpace, tcg_as_listener); + run_on_cpu(cpuas->cpu, do_nothing, RUN_ON_CPU_NULL); +} + static void tcg_commit(MemoryListener *listener) { CPUAddressSpace *cpuas; diff --git a/fsdev/Makefile.objs b/fsdev/Makefile.objs index 24bbb3e75c..42cd70c367 100644 --- a/fsdev/Makefile.objs +++ b/fsdev/Makefile.objs @@ -1,6 +1,6 @@ # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add. # only pull in the actual 9p backend if we also enabled virtio or xen. -ifeq ($(call land,$(CONFIG_VIRTFS),$(call lor,$(CONFIG_VIRTIO_9P),$(CONFIG_XEN))),y) +ifeq ($(CONFIG_FSDEV_9P),y) common-obj-y = qemu-fsdev.o 9p-marshal.o 9p-iov-marshal.o else common-obj-y = qemu-fsdev-dummy.o diff --git a/hw/9pfs/Kconfig b/hw/9pfs/Kconfig index 8c5032c575..3ae5749661 100644 --- a/hw/9pfs/Kconfig +++ b/hw/9pfs/Kconfig @@ -1,4 +1,9 @@ +config FSDEV_9P + bool + depends on VIRTFS + config VIRTIO_9P bool default y depends on VIRTFS && VIRTIO + select FSDEV_9P diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 02510acb81..0d1629ccb3 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2050,10 +2050,17 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); +static void virt_machine_4_2_options(MachineClass *mc) +{ +} +DEFINE_VIRT_MACHINE_AS_LATEST(4, 2) + static void virt_machine_4_1_options(MachineClass *mc) { + virt_machine_4_2_options(mc); + compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len); } -DEFINE_VIRT_MACHINE_AS_LATEST(4, 1) +DEFINE_VIRT_MACHINE(4, 1) static void virt_machine_4_0_options(MachineClass *mc) { diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c index 7f860fcce7..087c93e4fa 100644 --- a/hw/char/spapr_vty.c +++ b/hw/char/spapr_vty.c @@ -59,25 +59,19 @@ static int vty_getchars(SpaprVioDevice *sdev, uint8_t *buf, int max) int n = 0; while ((n < max) && (dev->out != dev->in)) { - buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE]; - - /* PowerVM's vty implementation has a bug where it inserts a - * \0 after every \r going to the guest. Existing guests have - * a workaround for this which removes every \0 immediately - * following a \r, so here we make ourselves bug-for-bug - * compatible, so that the guest won't drop a real \0-after-\r - * that happens to occur in a binary stream. */ - if (buf[n - 1] == '\r') { - if (n < max) { - buf[n++] = '\0'; - } else { - /* No room for the extra \0, roll back and try again - * next time */ - dev->out--; - n--; - break; - } + /* + * Long ago, PowerVM's vty implementation had a bug where it + * inserted a \0 after every \r going to the guest. Existing + * guests have a workaround for this which removes every \0 + * immediately following a \r. To avoid triggering this + * workaround, we stop before inserting a \0 if the preceding + * character in the output buffer is a \r. + */ + if (n > 0 && (buf[n - 1] == '\r') && + (dev->buf[dev->out % VTERM_BUFSIZE] == '\0')) { + break; } + buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE]; } qemu_chr_fe_accept_input(&dev->chardev); diff --git a/hw/core/loader.c b/hw/core/loader.c index 84e4f3efac..32f7cc7c33 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -58,6 +58,7 @@ #include "exec/address-spaces.h" #include "hw/boards.h" #include "qemu/cutils.h" +#include "sysemu/runstate.h" #include <zlib.h> @@ -838,6 +839,7 @@ struct Rom { int isrom; char *fw_dir; char *fw_file; + GMappedFile *mapped_file; bool committed; @@ -848,10 +850,25 @@ struct Rom { static FWCfgState *fw_cfg; static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms); -/* rom->data must be heap-allocated (do not use with rom_add_elf_program()) */ +/* + * rom->data can be heap-allocated or memory-mapped (e.g. when added with + * rom_add_elf_program()) + */ +static void rom_free_data(Rom *rom) +{ + if (rom->mapped_file) { + g_mapped_file_unref(rom->mapped_file); + rom->mapped_file = NULL; + } else { + g_free(rom->data); + } + + rom->data = NULL; +} + static void rom_free(Rom *rom) { - g_free(rom->data); + rom_free_data(rom); g_free(rom->path); g_free(rom->name); g_free(rom->fw_dir); @@ -1058,11 +1075,12 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, /* This function is specific for elf program because we don't need to allocate * all the rom. We just allocate the first part and the rest is just zeros. This - * is why romsize and datasize are different. Also, this function seize the - * memory ownership of "data", so we don't have to allocate and copy the buffer. + * is why romsize and datasize are different. Also, this function takes its own + * reference to "mapped_file", so we don't have to allocate and copy the buffer. */ -int rom_add_elf_program(const char *name, void *data, size_t datasize, - size_t romsize, hwaddr addr, AddressSpace *as) +int rom_add_elf_program(const char *name, GMappedFile *mapped_file, void *data, + size_t datasize, size_t romsize, hwaddr addr, + AddressSpace *as) { Rom *rom; @@ -1073,6 +1091,12 @@ int rom_add_elf_program(const char *name, void *data, size_t datasize, rom->romsize = romsize; rom->data = data; rom->as = as; + + if (mapped_file && data) { + g_mapped_file_ref(mapped_file); + rom->mapped_file = mapped_file; + } + rom_insert(rom); return 0; } @@ -1091,6 +1115,15 @@ static void rom_reset(void *unused) { Rom *rom; + /* + * We don't need to fill in the RAM with ROM data because we'll fill + * the data in during the next incoming migration in all cases. Note + * that some of those RAMs can actually be modified by the guest on ARM + * so this is probably the only right thing to do here. + */ + if (runstate_check(RUN_STATE_INMIGRATE)) + return; + QTAILQ_FOREACH(rom, &roms, next) { if (rom->fw_file) { continue; @@ -1107,8 +1140,7 @@ static void rom_reset(void *unused) } if (rom->isrom) { /* rom needs to be written only once */ - g_free(rom->data); - rom->data = NULL; + rom_free_data(rom); } /* * The rom loader is really on the same level as firmware in the guest diff --git a/hw/core/machine.c b/hw/core/machine.c index 32d1ca9abc..83cd1bfeec 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -27,6 +27,9 @@ #include "hw/pci/pci.h" #include "hw/mem/nvdimm.h" +GlobalProperty hw_compat_4_1[] = {}; +const size_t hw_compat_4_1_len = G_N_ELEMENTS(hw_compat_4_1); + GlobalProperty hw_compat_4_0[] = { { "VGA", "edid", "false" }, { "secondary-vga", "edid", "false" }, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 3ab4bcb3ca..697c33606a 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -119,6 +119,9 @@ struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX}; /* Physical Address of PVH entry point read from kernel ELF NOTE */ static size_t pvh_start_addr; +GlobalProperty pc_compat_4_1[] = {}; +const size_t pc_compat_4_1_len = G_N_ELEMENTS(pc_compat_4_1); + GlobalProperty pc_compat_4_0[] = {}; const size_t pc_compat_4_0_len = G_N_ELEMENTS(pc_compat_4_0); @@ -1244,17 +1247,21 @@ static void load_linux(PCMachineState *pcms, /* load initrd */ if (initrd_filename) { + GMappedFile *mapped_file; gsize initrd_size; gchar *initrd_data; GError *gerr = NULL; - if (!g_file_get_contents(initrd_filename, &initrd_data, - &initrd_size, &gerr)) { + mapped_file = g_mapped_file_new(initrd_filename, false, &gerr); + if (!mapped_file) { fprintf(stderr, "qemu: error reading initrd %s: %s\n", initrd_filename, gerr->message); exit(1); } + pcms->initrd_mapped_file = mapped_file; + initrd_data = g_mapped_file_get_contents(mapped_file); + initrd_size = g_mapped_file_get_length(mapped_file); initrd_max = pcms->below_4g_mem_size - pcmc->acpi_data_size - 1; if (initrd_size >= initrd_max) { fprintf(stderr, "qemu: initrd is too large, cannot support." @@ -1381,6 +1388,7 @@ static void load_linux(PCMachineState *pcms, /* load initrd */ if (initrd_filename) { + GMappedFile *mapped_file; gsize initrd_size; gchar *initrd_data; GError *gerr = NULL; @@ -1390,12 +1398,16 @@ static void load_linux(PCMachineState *pcms, exit(1); } - if (!g_file_get_contents(initrd_filename, &initrd_data, - &initrd_size, &gerr)) { + mapped_file = g_mapped_file_new(initrd_filename, false, &gerr); + if (!mapped_file) { fprintf(stderr, "qemu: error reading initrd %s: %s\n", initrd_filename, gerr->message); exit(1); } + pcms->initrd_mapped_file = mapped_file; + + initrd_data = g_mapped_file_get_contents(mapped_file); + initrd_size = g_mapped_file_get_length(mapped_file); if (initrd_size >= initrd_max) { fprintf(stderr, "qemu: initrd is too large, cannot support." "(max: %"PRIu32", need %"PRId64")\n", @@ -2831,6 +2843,13 @@ static void pc_machine_reset(MachineState *machine) } } +static void pc_machine_wakeup(MachineState *machine) +{ + cpu_synchronize_all_states(); + pc_machine_reset(machine); + cpu_synchronize_all_post_reset(); +} + static CpuInstanceProperties pc_cpu_index_to_props(MachineState *ms, unsigned cpu_index) { @@ -2943,6 +2962,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) mc->block_default_type = IF_IDE; mc->max_cpus = 255; mc->reset = pc_machine_reset; + mc->wakeup = pc_machine_wakeup; hc->pre_plug = pc_machine_device_pre_plug_cb; hc->plug = pc_machine_device_plug_cb; hc->unplug_request = pc_machine_device_unplug_request_cb; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 9e187f856a..a70cf0aafc 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -432,7 +432,7 @@ static void pc_i440fx_machine_options(MachineClass *m) machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE); } -static void pc_i440fx_4_1_machine_options(MachineClass *m) +static void pc_i440fx_4_2_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_machine_options(m); @@ -441,6 +441,18 @@ static void pc_i440fx_4_1_machine_options(MachineClass *m) pcmc->default_cpu_version = 1; } +DEFINE_I440FX_MACHINE(v4_2, "pc-i440fx-4.2", NULL, + pc_i440fx_4_2_machine_options); + +static void pc_i440fx_4_1_machine_options(MachineClass *m) +{ + pc_i440fx_4_2_machine_options(m); + m->alias = NULL; + m->is_default = 0; + compat_props_add(m->compat_props, hw_compat_4_1, hw_compat_4_1_len); + compat_props_add(m->compat_props, pc_compat_4_1, pc_compat_4_1_len); +} + DEFINE_I440FX_MACHINE(v4_1, "pc-i440fx-4.1", NULL, pc_i440fx_4_1_machine_options); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index be3464f485..d4e8a1cb9f 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -364,7 +364,7 @@ static void pc_q35_machine_options(MachineClass *m) m->max_cpus = 288; } -static void pc_q35_4_1_machine_options(MachineClass *m) +static void pc_q35_4_2_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_machine_options(m); @@ -372,6 +372,17 @@ static void pc_q35_4_1_machine_options(MachineClass *m) pcmc->default_cpu_version = 1; } +DEFINE_Q35_MACHINE(v4_2, "pc-q35-4.2", NULL, + pc_q35_4_2_machine_options); + +static void pc_q35_4_1_machine_options(MachineClass *m) +{ + pc_q35_4_2_machine_options(m); + m->alias = NULL; + compat_props_add(m->compat_props, hw_compat_4_1, hw_compat_4_1_len); + compat_props_add(m->compat_props, pc_compat_4_1, pc_compat_4_1_len); +} + DEFINE_Q35_MACHINE(v4_1, "pc-q35-4.1", NULL, pc_q35_4_1_machine_options); diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index a8caf258fd..ed6e9d71bb 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -1595,6 +1595,15 @@ void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon) } xive_end_pic_print_info(&end, i, mon); } + + monitor_printf(mon, "XIVE[%x] END Escalation %08x .. %08x\n", blk, 0, + nr_ends - 1); + for (i = 0; i < nr_ends; i++) { + if (xive_router_get_end(xrtr, blk, i, &end)) { + break; + } + xive_end_eas_pic_print_info(&end, i, mon); + } } static void pnv_xive_reset(void *dev) diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index aad981cb78..c1c97192a7 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -146,7 +146,6 @@ static void spapr_xive_end_pic_print_info(SpaprXive *xive, XiveEND *end, priority, qindex, qentries, qaddr_base, qgen); xive_end_queue_pic_print_info(end, 6, mon); - monitor_printf(mon, "]"); } void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon) @@ -537,7 +536,10 @@ bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi) return false; } - xive->eat[lisn].w |= cpu_to_be64(EAS_VALID); + /* + * Set default values when allocating an IRQ number + */ + xive->eat[lisn].w |= cpu_to_be64(EAS_VALID | EAS_MASKED); if (lsi) { xive_source_irq_set_lsi(xsrc, lisn); } diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 7a6e4b763a..b7417210d8 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -337,6 +337,17 @@ static void xive_tm_set_os_pending(XiveTCTX *tctx, hwaddr offset, xive_tctx_notify(tctx, TM_QW1_OS); } +static uint64_t xive_tm_pull_os_ctx(XiveTCTX *tctx, hwaddr offset, + unsigned size) +{ + uint32_t qw1w2_prev = xive_tctx_word2(&tctx->regs[TM_QW1_OS]); + uint32_t qw1w2; + + qw1w2 = xive_set_field32(TM_QW1W2_VO, qw1w2_prev, 0); + memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2, 4); + return qw1w2; +} + /* * Define a mapping of "special" operations depending on the TIMA page * offset and the size of the operation. @@ -363,6 +374,8 @@ static const XiveTmOp xive_tm_operations[] = { /* MMIOs above 2K : special operations with side effects */ { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg }, { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL }, + { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL, xive_tm_pull_os_ctx }, + { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL, xive_tm_pull_os_ctx }, { XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL, xive_tm_ack_hv_reg }, { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL, xive_tm_pull_pool_ctx }, { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL, xive_tm_pull_pool_ctx }, @@ -406,7 +419,7 @@ void xive_tctx_tm_write(XiveTCTX *tctx, hwaddr offset, uint64_t value, if (offset & 0x800) { xto = xive_tm_find_op(offset, size, true); if (!xto) { - qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA" + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA " "@%"HWADDR_PRIx"\n", offset); } else { xto->write_handler(tctx, offset, value, size); @@ -1145,6 +1158,7 @@ void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon) be32_to_cpu(qdata)); qindex = (qindex + 1) & (qentries - 1); } + monitor_printf(mon, "]"); } void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon) @@ -1155,24 +1169,36 @@ void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon) uint32_t qsize = xive_get_field32(END_W0_QSIZE, end->w0); uint32_t qentries = 1 << (qsize + 10); - uint32_t nvt = xive_get_field32(END_W6_NVT_INDEX, end->w6); + uint32_t nvt_blk = xive_get_field32(END_W6_NVT_BLOCK, end->w6); + uint32_t nvt_idx = xive_get_field32(END_W6_NVT_INDEX, end->w6); uint8_t priority = xive_get_field32(END_W7_F0_PRIORITY, end->w7); + uint8_t pq; if (!xive_end_is_valid(end)) { return; } - monitor_printf(mon, " %08x %c%c%c%c%c prio:%d nvt:%04x eq:@%08"PRIx64 - "% 6d/%5d ^%d", end_idx, + pq = xive_get_field32(END_W1_ESn, end->w1); + + monitor_printf(mon, " %08x %c%c %c%c%c%c%c%c%c prio:%d nvt:%02x/%04x", + end_idx, + pq & XIVE_ESB_VAL_P ? 'P' : '-', + pq & XIVE_ESB_VAL_Q ? 'Q' : '-', xive_end_is_valid(end) ? 'v' : '-', xive_end_is_enqueue(end) ? 'q' : '-', xive_end_is_notify(end) ? 'n' : '-', xive_end_is_backlog(end) ? 'b' : '-', xive_end_is_escalate(end) ? 'e' : '-', - priority, nvt, qaddr_base, qindex, qentries, qgen); + xive_end_is_uncond_escalation(end) ? 'u' : '-', + xive_end_is_silent_escalation(end) ? 's' : '-', + priority, nvt_blk, nvt_idx); - xive_end_queue_pic_print_info(end, 6, mon); - monitor_printf(mon, "]\n"); + if (qaddr_base) { + monitor_printf(mon, " eq:@%08"PRIx64"% 6d/%5d ^%d", + qaddr_base, qindex, qentries, qgen); + xive_end_queue_pic_print_info(end, 6, mon); + } + monitor_printf(mon, "\n"); } static void xive_end_enqueue(XiveEND *end, uint32_t data) @@ -1200,6 +1226,29 @@ static void xive_end_enqueue(XiveEND *end, uint32_t data) end->w1 = xive_set_field32(END_W1_PAGE_OFF, end->w1, qindex); } +void xive_end_eas_pic_print_info(XiveEND *end, uint32_t end_idx, + Monitor *mon) +{ + XiveEAS *eas = (XiveEAS *) &end->w4; + uint8_t pq; + + if (!xive_end_is_escalate(end)) { + return; + } + + pq = xive_get_field32(END_W1_ESe, end->w1); + + monitor_printf(mon, " %08x %c%c %c%c end:%02x/%04x data:%08x\n", + end_idx, + pq & XIVE_ESB_VAL_P ? 'P' : '-', + pq & XIVE_ESB_VAL_Q ? 'Q' : '-', + xive_eas_is_valid(eas) ? 'V' : ' ', + xive_eas_is_masked(eas) ? 'M' : ' ', + (uint8_t) xive_get_field64(EAS_END_BLOCK, eas->w), + (uint32_t) xive_get_field64(EAS_END_INDEX, eas->w), + (uint32_t) xive_get_field64(EAS_END_DATA, eas->w)); +} + /* * XIVE Router (aka. Virtualization Controller or IVRE) */ @@ -1398,46 +1447,43 @@ static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format, * * The parameters represent what is sent on the PowerBus */ -static void xive_presenter_notify(XiveRouter *xrtr, uint8_t format, +static bool xive_presenter_notify(XiveRouter *xrtr, uint8_t format, uint8_t nvt_blk, uint32_t nvt_idx, bool cam_ignore, uint8_t priority, uint32_t logic_serv) { - XiveNVT nvt; XiveTCTXMatch match = { .tctx = NULL, .ring = 0 }; bool found; - /* NVT cache lookup */ - if (xive_router_get_nvt(xrtr, nvt_blk, nvt_idx, &nvt)) { - qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVT %x/%x\n", - nvt_blk, nvt_idx); - return; - } - - if (!xive_nvt_is_valid(&nvt)) { - qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is invalid\n", - nvt_blk, nvt_idx); - return; - } - found = xive_presenter_match(xrtr, format, nvt_blk, nvt_idx, cam_ignore, priority, logic_serv, &match); if (found) { ipb_update(&match.tctx->regs[match.ring], priority); xive_tctx_notify(match.tctx, match.ring); - return; } - /* Record the IPB in the associated NVT structure */ - ipb_update((uint8_t *) &nvt.w4, priority); - xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4); + return found; +} - /* - * If no matching NVT is dispatched on a HW thread : - * - update the NVT structure if backlog is activated - * - escalate (ESe PQ bits and EAS in w4-5) if escalation is - * activated - */ +/* + * Notification using the END ESe/ESn bit (Event State Buffer for + * escalation and notification). Profide futher coalescing in the + * Router. + */ +static bool xive_router_end_es_notify(XiveRouter *xrtr, uint8_t end_blk, + uint32_t end_idx, XiveEND *end, + uint32_t end_esmask) +{ + uint8_t pq = xive_get_field32(end_esmask, end->w1); + bool notify = xive_esb_trigger(&pq); + + if (pq != xive_get_field32(end_esmask, end->w1)) { + end->w1 = xive_set_field32(end_esmask, end->w1, pq); + xive_router_write_end(xrtr, end_blk, end_idx, end, 1); + } + + /* ESe/n[Q]=1 : end of notification */ + return notify; } /* @@ -1451,6 +1497,10 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk, XiveEND end; uint8_t priority; uint8_t format; + uint8_t nvt_blk; + uint32_t nvt_idx; + XiveNVT nvt; + bool found; /* END cache lookup */ if (xive_router_get_end(xrtr, end_blk, end_idx, &end)) { @@ -1472,6 +1522,13 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk, } /* + * When the END is silent, we skip the notification part. + */ + if (xive_end_is_silent_escalation(&end)) { + goto do_escalation; + } + + /* * The W7 format depends on the F bit in W6. It defines the type * of the notification : * @@ -1492,16 +1549,9 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk, * even futher coalescing in the Router */ if (!xive_end_is_notify(&end)) { - uint8_t pq = xive_get_field32(END_W1_ESn, end.w1); - bool notify = xive_esb_trigger(&pq); - - if (pq != xive_get_field32(END_W1_ESn, end.w1)) { - end.w1 = xive_set_field32(END_W1_ESn, end.w1, pq); - xive_router_write_end(xrtr, end_blk, end_idx, &end, 1); - } - /* ESn[Q]=1 : end of notification */ - if (!notify) { + if (!xive_router_end_es_notify(xrtr, end_blk, end_idx, + &end, END_W1_ESn)) { return; } } @@ -1509,14 +1559,82 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk, /* * Follows IVPE notification */ - xive_presenter_notify(xrtr, format, - xive_get_field32(END_W6_NVT_BLOCK, end.w6), - xive_get_field32(END_W6_NVT_INDEX, end.w6), + nvt_blk = xive_get_field32(END_W6_NVT_BLOCK, end.w6); + nvt_idx = xive_get_field32(END_W6_NVT_INDEX, end.w6); + + /* NVT cache lookup */ + if (xive_router_get_nvt(xrtr, nvt_blk, nvt_idx, &nvt)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVT %x/%x\n", + nvt_blk, nvt_idx); + return; + } + + if (!xive_nvt_is_valid(&nvt)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is invalid\n", + nvt_blk, nvt_idx); + return; + } + + found = xive_presenter_notify(xrtr, format, nvt_blk, nvt_idx, xive_get_field32(END_W7_F0_IGNORE, end.w7), priority, xive_get_field32(END_W7_F1_LOG_SERVER_ID, end.w7)); /* TODO: Auto EOI. */ + + if (found) { + return; + } + + /* + * If no matching NVT is dispatched on a HW thread : + * - specific VP: update the NVT structure if backlog is activated + * - logical server : forward request to IVPE (not supported) + */ + if (xive_end_is_backlog(&end)) { + if (format == 1) { + qemu_log_mask(LOG_GUEST_ERROR, + "XIVE: END %x/%x invalid config: F1 & backlog\n", + end_blk, end_idx); + return; + } + /* Record the IPB in the associated NVT structure */ + ipb_update((uint8_t *) &nvt.w4, priority); + xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4); + + /* + * On HW, follows a "Broadcast Backlog" to IVPEs + */ + } + +do_escalation: + /* + * If activated, escalate notification using the ESe PQ bits and + * the EAS in w4-5 + */ + if (!xive_end_is_escalate(&end)) { + return; + } + + /* + * Check the END ESe (Event State Buffer for escalation) for even + * futher coalescing in the Router + */ + if (!xive_end_is_uncond_escalation(&end)) { + /* ESe[Q]=1 : end of notification */ + if (!xive_router_end_es_notify(xrtr, end_blk, end_idx, + &end, END_W1_ESe)) { + return; + } + } + + /* + * The END trigger becomes an Escalation trigger + */ + xive_router_end_notify(xrtr, + xive_get_field32(END_W4_ESC_END_BLOCK, end.w4), + xive_get_field32(END_W4_ESC_END_INDEX, end.w4), + xive_get_field32(END_W5_ESC_END_DATA, end.w5)); } void xive_router_notify(XiveNotifier *xn, uint32_t lisn) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 9da93af905..2c4e1c8de0 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -5,6 +5,7 @@ obj-$(CONFIG_PSERIES) += spapr.o spapr_caps.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o spapr_irq.o +obj-$(CONFIG_PSERIES) += spapr_tpm_proxy.o obj-$(CONFIG_SPAPR_RNG) += spapr_rng.o # IBM PowerNV obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o pnv_occ.o pnv_bmc.o diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index 7963feeab4..52a18eb7d7 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -1011,6 +1011,8 @@ static void timebase_save(PPCTimebase *tb) * there is no need to update it from KVM here */ tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; + + tb->runstate_paused = runstate_check(RUN_STATE_PAUSED); } static void timebase_load(PPCTimebase *tb) @@ -1054,9 +1056,9 @@ void cpu_ppc_clock_vm_state_change(void *opaque, int running, } /* - * When migrating, read the clock just before migration, - * so that the guest clock counts during the events - * between: + * When migrating a running guest, read the clock just + * before migration, so that the guest clock counts + * during the events between: * * * vm_stop() * * @@ -1071,7 +1073,10 @@ static int timebase_pre_save(void *opaque) { PPCTimebase *tb = opaque; - timebase_save(tb); + /* guest_timebase won't be overridden in case of paused guest */ + if (!tb->runstate_paused) { + timebase_save(tb); + } return 0; } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index e09c67eb75..64fc2255cc 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -79,6 +79,7 @@ #include "qemu/cutils.h" #include "hw/ppc/spapr_cpu_core.h" #include "hw/mem/memory-device.h" +#include "hw/ppc/spapr_tpm_proxy.h" #include <libfdt.h> @@ -1070,6 +1071,7 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt) add_str(hypertas, "hcall-tce"); add_str(hypertas, "hcall-vio"); add_str(hypertas, "hcall-splpar"); + add_str(hypertas, "hcall-join"); add_str(hypertas, "hcall-bulk"); add_str(hypertas, "hcall-set-mode"); add_str(hypertas, "hcall-sprg0"); @@ -1753,10 +1755,6 @@ static void spapr_machine_reset(MachineState *machine) ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal); } - if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { - spapr_irq_msi_reset(spapr); - } - /* * This is fixing some of the default configuration of the XIVE * devices. To be called after the reset of the machine devices. @@ -3081,6 +3079,13 @@ static void spapr_machine_init(MachineState *machine) qemu_register_boot_set(spapr_boot_set, spapr); + /* + * Nothing needs to be done to resume a suspended guest because + * suspending does not change the machine state, so no need for + * a ->wakeup method. + */ + qemu_register_wakeup_support(); + if (kvm_enabled()) { /* to stop and start vmclock */ qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change, @@ -4035,6 +4040,29 @@ static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev, } } +static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); + SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev); + + if (spapr->tpm_proxy != NULL) { + error_setg(errp, "Only one TPM proxy can be specified for this machine"); + return; + } + + spapr->tpm_proxy = tpm_proxy; +} + +static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) +{ + SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); + + object_property_set_bool(OBJECT(dev), false, "realized", NULL); + object_unparent(OBJECT(dev)); + spapr->tpm_proxy = NULL; +} + static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -4044,6 +4072,8 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, spapr_core_plug(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) { spapr_phb_plug(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) { + spapr_tpm_proxy_plug(hotplug_dev, dev, errp); } } @@ -4056,6 +4086,8 @@ static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev, spapr_core_unplug(hotplug_dev, dev); } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) { spapr_phb_unplug(hotplug_dev, dev); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) { + spapr_tpm_proxy_unplug(hotplug_dev, dev); } } @@ -4090,6 +4122,8 @@ static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev, return; } spapr_phb_unplug_request(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) { + spapr_tpm_proxy_unplug(hotplug_dev, dev); } } @@ -4110,7 +4144,8 @@ static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine, { if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) || - object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) { + object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE) || + object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) { return HOTPLUG_HANDLER(machine); } if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { @@ -4306,6 +4341,53 @@ PowerPCCPU *spapr_find_cpu(int vcpu_id) return NULL; } +static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) +{ + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); + + /* These are only called by TCG, KVM maintains dispatch state */ + + spapr_cpu->prod = false; + if (spapr_cpu->vpa_addr) { + CPUState *cs = CPU(cpu); + uint32_t dispatch; + + dispatch = ldl_be_phys(cs->as, + spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER); + dispatch++; + if ((dispatch & 1) != 0) { + qemu_log_mask(LOG_GUEST_ERROR, + "VPA: incorrect dispatch counter value for " + "dispatched partition %u, correcting.\n", dispatch); + dispatch++; + } + stl_be_phys(cs->as, + spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch); + } +} + +static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) +{ + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); + + if (spapr_cpu->vpa_addr) { + CPUState *cs = CPU(cpu); + uint32_t dispatch; + + dispatch = ldl_be_phys(cs->as, + spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER); + dispatch++; + if ((dispatch & 1) != 1) { + qemu_log_mask(LOG_GUEST_ERROR, + "VPA: incorrect dispatch counter value for " + "preempted partition %u, correcting.\n", dispatch); + dispatch++; + } + stl_be_phys(cs->as, + spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch); + } +} + static void spapr_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -4362,6 +4444,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) vhc->hpte_set_r = spapr_hpte_set_r; vhc->get_pate = spapr_get_pate; vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr; + vhc->cpu_exec_enter = spapr_cpu_exec_enter; + vhc->cpu_exec_exit = spapr_cpu_exec_exit; xic->ics_get = spapr_ics_get; xic->ics_resend = spapr_ics_resend; xic->icp_get = spapr_icp_get; @@ -4431,14 +4515,31 @@ static const TypeInfo spapr_machine_info = { type_init(spapr_machine_register_##suffix) /* + * pseries-4.2 + */ +static void spapr_machine_4_2_class_options(MachineClass *mc) +{ + /* Defaults for the latest behaviour inherited from the base class */ +} + +DEFINE_SPAPR_MACHINE(4_2, "4.2", true); + +/* * pseries-4.1 */ static void spapr_machine_4_1_class_options(MachineClass *mc) { - /* Defaults for the latest behaviour inherited from the base class */ + static GlobalProperty compat[] = { + /* Only allow 4kiB and 64kiB IOMMU pagesizes */ + { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" }, + }; + + spapr_machine_4_2_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); } -DEFINE_SPAPR_MACHINE(4_1, "4.1", true); +DEFINE_SPAPR_MACHINE(4_1, "4.1", false); /* * pseries-4.0 diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 7830d66d77..481dfd2a27 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -195,10 +195,12 @@ static void cap_htm_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) } if (tcg_enabled()) { error_setg(errp, - "No Transactional Memory support in TCG, try cap-htm=off"); + "No Transactional Memory support in TCG," + " try appending -machine cap-htm=off"); } else if (kvm_enabled() && !kvmppc_has_cap_htm()) { error_setg(errp, -"KVM implementation does not support Transactional Memory, try cap-htm=off" +"KVM implementation does not support Transactional Memory," + " try appending -machine cap-htm=off" ); } } @@ -216,7 +218,8 @@ static void cap_vsx_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) * rid of anything that doesn't do VMX */ g_assert(env->insns_flags & PPC_ALTIVEC); if (!(env->insns_flags2 & PPC2_VSX)) { - error_setg(errp, "VSX support not available, try cap-vsx=off"); + error_setg(errp, "VSX support not available," + " try appending -machine cap-vsx=off"); } } @@ -230,7 +233,8 @@ static void cap_dfp_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) return; } if (!(env->insns_flags2 & PPC2_DFP)) { - error_setg(errp, "DFP support not available, try cap-dfp=off"); + error_setg(errp, "DFP support not available," + " try appending -machine cap-dfp=off"); } } @@ -254,7 +258,8 @@ static void cap_safe_cache_apply(SpaprMachineState *spapr, uint8_t val, cap_cfpc_possible.vals[val]); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, -"Requested safe cache capability level not supported by kvm, try cap-cfpc=%s", + "Requested safe cache capability level not supported by kvm," + " try appending -machine cap-cfpc=%s", cap_cfpc_possible.vals[kvm_val]); } @@ -282,7 +287,8 @@ static void cap_safe_bounds_check_apply(SpaprMachineState *spapr, uint8_t val, cap_sbbc_possible.vals[val]); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, -"Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s", +"Requested safe bounds check capability level not supported by kvm," + " try appending -machine cap-sbbc=%s", cap_sbbc_possible.vals[kvm_val]); } @@ -313,7 +319,8 @@ static void cap_safe_indirect_branch_apply(SpaprMachineState *spapr, cap_ibs_possible.vals[val]); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, -"Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s", +"Requested safe indirect branch capability level not supported by kvm," + " try appending -machine cap-ibs=%s", cap_ibs_possible.vals[kvm_val]); } @@ -402,11 +409,13 @@ static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr, if (tcg_enabled()) { error_setg(errp, - "No Nested KVM-HV support in tcg, try cap-nested-hv=off"); + "No Nested KVM-HV support in tcg," + " try appending -machine cap-nested-hv=off"); } else if (kvm_enabled()) { if (!kvmppc_has_cap_nested_kvm_hv()) { error_setg(errp, -"KVM implementation does not support Nested KVM-HV, try cap-nested-hv=off"); +"KVM implementation does not support Nested KVM-HV," + " try appending -machine cap-nested-hv=off"); } else if (kvmppc_set_cap_nested_kvm_hv(val) < 0) { error_setg(errp, "Error enabling cap-nested-hv with KVM, try cap-nested-hv=off"); @@ -436,10 +445,12 @@ static void cap_large_decr_apply(SpaprMachineState *spapr, if (!kvm_nr_bits) { error_setg(errp, - "No large decrementer support, try cap-large-decr=off"); + "No large decrementer support," + " try appending -machine cap-large-decr=off"); } else if (pcc->lrg_decr_bits != kvm_nr_bits) { error_setg(errp, -"KVM large decrementer size (%d) differs to model (%d), try -cap-large-decr=off", +"KVM large decrementer size (%d) differs to model (%d)," + " try appending -machine cap-large-decr=off", kvm_nr_bits, pcc->lrg_decr_bits); } } @@ -455,7 +466,8 @@ static void cap_large_decr_cpu_apply(SpaprMachineState *spapr, if (kvm_enabled()) { if (kvmppc_enable_cap_large_decr(cpu, val)) { error_setg(errp, - "No large decrementer support, try cap-large-decr=off"); + "No large decrementer support," + " try appending -machine cap-large-decr=off"); } } @@ -475,10 +487,12 @@ static void cap_ccf_assist_apply(SpaprMachineState *spapr, uint8_t val, if (tcg_enabled() && val) { /* TODO - for now only allow broken for TCG */ error_setg(errp, -"Requested count cache flush assist capability level not supported by tcg, try cap-ccf-assist=off"); +"Requested count cache flush assist capability level not supported by tcg," + " try appending -machine cap-ccf-assist=off"); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, -"Requested count cache flush assist capability level not supported by kvm, try cap-ccf-assist=off"); +"Requested count cache flush assist capability level not supported by kvm," + " try appending -machine cap-ccf-assist=off"); } } @@ -779,7 +793,7 @@ void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp) for (i = 0; i < ARRAY_SIZE(capability_table); i++) { SpaprCapabilityInfo *cap = &capability_table[i]; - const char *name = g_strdup_printf("cap-%s", cap->name); + char *name = g_strdup_printf("cap-%s", cap->name); char *desc; object_class_property_add(klass, name, cap->type, @@ -787,11 +801,13 @@ void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp) NULL, cap, &local_err); if (local_err) { error_propagate(errp, local_err); + g_free(name); return; } desc = g_strdup_printf("%s", cap->description); object_class_property_set_description(klass, name, desc, &local_err); + g_free(name); g_free(desc); if (local_err) { error_propagate(errp, local_err); diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 09255f4951..62f1a42592 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -227,7 +227,7 @@ static uint32_t drc_set_unusable(SpaprDrc *drc) return RTAS_OUT_SUCCESS; } -static const char *spapr_drc_name(SpaprDrc *drc) +static char *spapr_drc_name(SpaprDrc *drc) { SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); @@ -828,6 +828,7 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask) Object *obj; SpaprDrc *drc; SpaprDrcClass *drck; + char *drc_name = NULL; uint32_t drc_index, drc_power_domain; if (!strstart(prop->type, "link<", NULL)) { @@ -857,8 +858,10 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask) g_array_append_val(drc_power_domains, drc_power_domain); /* ibm,drc-names */ - drc_names = g_string_append(drc_names, spapr_drc_name(drc)); + drc_name = spapr_drc_name(drc); + drc_names = g_string_append(drc_names, drc_name); drc_names = g_string_insert_len(drc_names, -1, "\0", 1); + g_free(drc_name); /* ibm,drc-types */ drc_types = g_string_append(drc_types, drck->typename); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 225c60a9fc..e20a946b99 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -875,11 +875,6 @@ unmap_out: #define FLAGS_DEREGISTER_DTL 0x0000c00000000000ULL #define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL -#define VPA_MIN_SIZE 640 -#define VPA_SIZE_OFFSET 0x4 -#define VPA_SHARED_PROC_OFFSET 0x9 -#define VPA_SHARED_PROC_VAL 0x2 - static target_ulong register_vpa(PowerPCCPU *cpu, target_ulong vpa) { CPUState *cs = CPU(cpu); @@ -1056,14 +1051,155 @@ static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr, { CPUPPCState *env = &cpu->env; CPUState *cs = CPU(cpu); + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); env->msr |= (1ULL << MSR_EE); hreg_compute_hflags(env); + + if (spapr_cpu->prod) { + spapr_cpu->prod = false; + return H_SUCCESS; + } + if (!cpu_has_work(cs)) { cs->halted = 1; cs->exception_index = EXCP_HLT; cs->exit_request = 1; } + + return H_SUCCESS; +} + +/* + * Confer to self, aka join. Cede could use the same pattern as well, if + * EXCP_HLT can be changed to ECXP_HALTED. + */ +static target_ulong h_confer_self(PowerPCCPU *cpu) +{ + CPUState *cs = CPU(cpu); + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); + + if (spapr_cpu->prod) { + spapr_cpu->prod = false; + return H_SUCCESS; + } + cs->halted = 1; + cs->exception_index = EXCP_HALTED; + cs->exit_request = 1; + + return H_SUCCESS; +} + +static target_ulong h_join(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + CPUState *cs; + bool last_unjoined = true; + + if (env->msr & (1ULL << MSR_EE)) { + return H_BAD_MODE; + } + + /* + * Must not join the last CPU running. Interestingly, no such restriction + * for H_CONFER-to-self, but that is probably not intended to be used + * when H_JOIN is available. + */ + CPU_FOREACH(cs) { + PowerPCCPU *c = POWERPC_CPU(cs); + CPUPPCState *e = &c->env; + if (c == cpu) { + continue; + } + + /* Don't have a way to indicate joined, so use halted && MSR[EE]=0 */ + if (!cs->halted || (e->msr & (1ULL << MSR_EE))) { + last_unjoined = false; + break; + } + } + if (last_unjoined) { + return H_CONTINUE; + } + + return h_confer_self(cpu); +} + +static target_ulong h_confer(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_long target = args[0]; + uint32_t dispatch = args[1]; + CPUState *cs = CPU(cpu); + SpaprCpuState *spapr_cpu; + + /* + * -1 means confer to all other CPUs without dispatch counter check, + * otherwise it's a targeted confer. + */ + if (target != -1) { + PowerPCCPU *target_cpu = spapr_find_cpu(target); + uint32_t target_dispatch; + + if (!target_cpu) { + return H_PARAMETER; + } + + /* + * target == self is a special case, we wait until prodded, without + * dispatch counter check. + */ + if (cpu == target_cpu) { + return h_confer_self(cpu); + } + + spapr_cpu = spapr_cpu_state(target_cpu); + if (!spapr_cpu->vpa_addr || ((dispatch & 1) == 0)) { + return H_SUCCESS; + } + + target_dispatch = ldl_be_phys(cs->as, + spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER); + if (target_dispatch != dispatch) { + return H_SUCCESS; + } + + /* + * The targeted confer does not do anything special beyond yielding + * the current vCPU, but even this should be better than nothing. + * At least for single-threaded tcg, it gives the target a chance to + * run before we run again. Multi-threaded tcg does not really do + * anything with EXCP_YIELD yet. + */ + } + + cs->exception_index = EXCP_YIELD; + cs->exit_request = 1; + cpu_loop_exit(cs); + + return H_SUCCESS; +} + +static target_ulong h_prod(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_long target = args[0]; + PowerPCCPU *tcpu; + CPUState *cs; + SpaprCpuState *spapr_cpu; + + tcpu = spapr_find_cpu(target); + cs = CPU(tcpu); + if (!cs) { + return H_PARAMETER; + } + + spapr_cpu = spapr_cpu_state(tcpu); + spapr_cpu->prod = true; + cs->halted = 0; + qemu_cpu_kick(cs); + return H_SUCCESS; } @@ -1613,6 +1749,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, ov5_updates = spapr_ovec_new(); spapr->cas_reboot = spapr_ovec_diff(ov5_updates, ov5_cas_old, spapr->ov5_cas); + spapr_ovec_cleanup(ov5_cas_old); /* Now that processing is finished, set the radix/hash bit for the * guest if it requested a valid mode; otherwise terminate the boot. */ if (guest_radix) { @@ -1630,6 +1767,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, } spapr->cas_legacy_guest_workaround = !spapr_ovec_test(ov1_guest, OV1_PPC_3_00); + spapr_ovec_cleanup(ov1_guest); if (!spapr->cas_reboot) { /* If spapr_machine_reset() did not set up a HPT but one is necessary * (because the guest isn't going to use radix) then set it up here. */ @@ -1825,6 +1963,7 @@ static target_ulong h_update_dt(PowerPCCPU *cpu, SpaprMachineState *spapr, static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1]; +static spapr_hcall_fn svm_hypercall_table[(SVM_HCALL_MAX - SVM_HCALL_BASE) / 4 + 1]; void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) { @@ -1834,6 +1973,11 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) assert((opcode & 0x3) == 0); slot = &papr_hypercall_table[opcode / 4]; + } else if (opcode >= SVM_HCALL_BASE && opcode <= SVM_HCALL_MAX) { + /* we only have SVM-related hcall numbers assigned in multiples of 4 */ + assert((opcode & 0x3) == 0); + + slot = &svm_hypercall_table[(opcode - SVM_HCALL_BASE) / 4]; } else { assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX)); @@ -1856,6 +2000,13 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, if (fn) { return fn(cpu, spapr, opcode, args); } + } else if ((opcode >= SVM_HCALL_BASE) && + (opcode <= SVM_HCALL_MAX)) { + spapr_hcall_fn fn = svm_hypercall_table[(opcode - SVM_HCALL_BASE) / 4]; + + if (fn) { + return fn(cpu, spapr, opcode, args); + } } else if ((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX)) { spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE]; @@ -1888,6 +2039,12 @@ static void hypercall_register_types(void) /* hcall-splpar */ spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa); spapr_register_hypercall(H_CEDE, h_cede); + spapr_register_hypercall(H_CONFER, h_confer); + spapr_register_hypercall(H_PROD, h_prod); + + /* hcall-join */ + spapr_register_hypercall(H_JOIN, h_join); + spapr_register_hypercall(H_SIGNAL_SYS_RESET, h_signal_sys_reset); /* processor register resource access h-calls */ diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index ce85f8ac63..e87b3d50f7 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -136,7 +136,7 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu, ret.addr_mask = ~page_mask; ret.perm = spapr_tce_iommu_access_flags(tce); } - trace_spapr_iommu_xlate(tcet->liobn, addr, ret.iova, ret.perm, + trace_spapr_iommu_xlate(tcet->liobn, addr, ret.translated_addr, ret.perm, ret.addr_mask); return ret; diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 2f87fe08f3..06fe2432ba 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -59,11 +59,6 @@ void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num) bitmap_clear(spapr->irq_map, irq - SPAPR_IRQ_MSI, num); } -void spapr_irq_msi_reset(SpaprMachineState *spapr) -{ - bitmap_clear(spapr->irq_map, 0, spapr->irq_map_nr); -} - static void spapr_irq_init_kvm(SpaprMachineState *spapr, SpaprIrq *irq, Error **errp) { @@ -731,6 +726,8 @@ int spapr_irq_post_load(SpaprMachineState *spapr, int version_id) void spapr_irq_reset(SpaprMachineState *spapr, Error **errp) { + assert(!spapr->irq_map || bitmap_empty(spapr->irq_map, spapr->irq_map_nr)); + if (spapr->irq->reset) { spapr->irq->reset(spapr, errp); } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index bf31fd854c..deb0b0c80c 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -338,10 +338,6 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr, return; } - if (!smc->legacy_irq_allocation) { - spapr_irq_msi_free(spapr, msi->first_irq, msi->num); - } - spapr_irq_free(spapr, msi->first_irq, msi->num); if (msi_present(pdev)) { spapr_msi_setmsg(pdev, 0, false, 0, 0); } @@ -411,10 +407,6 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr, /* Release previous MSIs */ if (msi) { - if (!smc->legacy_irq_allocation) { - spapr_irq_msi_free(spapr, msi->first_irq, msi->num); - } - spapr_irq_free(spapr, msi->first_irq, msi->num); g_hash_table_remove(phb->msi, &config_addr); } @@ -1808,6 +1800,19 @@ static void spapr_phb_unrealize(DeviceState *dev, Error **errp) memory_region_del_subregion(get_system_memory(), &sphb->mem32window); } +static void spapr_phb_destroy_msi(gpointer opaque) +{ + SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + spapr_pci_msi *msi = opaque; + + if (!smc->legacy_irq_allocation) { + spapr_irq_msi_free(spapr, msi->first_irq, msi->num); + } + spapr_irq_free(spapr, msi->first_irq, msi->num); + g_free(msi); +} + static void spapr_phb_realize(DeviceState *dev, Error **errp) { /* We don't use SPAPR_MACHINE() in order to exit gracefully if the user @@ -2019,7 +2024,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) spapr_tce_get_iommu(tcet)); } - sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); + sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, + spapr_phb_destroy_msi); return; unrealize: @@ -2074,6 +2080,8 @@ static void spapr_phb_reset(DeviceState *qdev) if (spapr_phb_eeh_available(SPAPR_PCI_HOST_BRIDGE(qdev))) { spapr_phb_vfio_reset(qdev); } + + g_hash_table_remove_all(sphb->msi); } static Property spapr_phb_properties[] = { @@ -2093,7 +2101,8 @@ static Property spapr_phb_properties[] = { 0x800000000000000ULL), DEFINE_PROP_BOOL("ddw", SpaprPhbState, ddw_enabled, true), DEFINE_PROP_UINT64("pgsz", SpaprPhbState, page_size_mask, - (1ULL << 12) | (1ULL << 16)), + (1ULL << 12) | (1ULL << 16) + | (1ULL << 21) | (1ULL << 24)), DEFINE_PROP_UINT32("numa_node", SpaprPhbState, numa_node, -1), DEFINE_PROP_BOOL("pre-2.8-migration", SpaprPhbState, pre_2_8_migration, false), diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index d3f9a69a51..526b489297 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -217,6 +217,36 @@ static void rtas_stop_self(PowerPCCPU *cpu, SpaprMachineState *spapr, qemu_cpu_kick(cs); } +static void rtas_ibm_suspend_me(PowerPCCPU *cpu, SpaprMachineState *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + CPUState *cs; + + if (nargs != 0 || nret != 1) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + CPU_FOREACH(cs) { + PowerPCCPU *c = POWERPC_CPU(cs); + CPUPPCState *e = &c->env; + if (c == cpu) { + continue; + } + + /* See h_join */ + if (!cs->halted || (e->msr & (1ULL << MSR_EE))) { + rtas_st(rets, 0, H_MULTI_THREADS_ACTIVE); + return; + } + } + + qemu_system_suspend_request(); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); +} + static inline int sysparm_st(target_ulong addr, target_ulong len, const void *val, uint16_t vallen) { @@ -484,6 +514,8 @@ static void core_rtas_register_types(void) rtas_query_cpu_stopped_state); spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu); spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self); + spapr_rtas_register(RTAS_IBM_SUSPEND_ME, "ibm,suspend-me", + rtas_ibm_suspend_me); spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER, "ibm,get-system-parameter", rtas_ibm_get_system_parameter); diff --git a/hw/ppc/spapr_tpm_proxy.c b/hw/ppc/spapr_tpm_proxy.c new file mode 100644 index 0000000000..b835d25be6 --- /dev/null +++ b/hw/ppc/spapr_tpm_proxy.c @@ -0,0 +1,178 @@ +/* + * SPAPR TPM Proxy/Hypercall + * + * Copyright IBM Corp. 2019 + * + * Authors: + * Michael Roth <mdroth@linux.vnet.ibm.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 "qemu-common.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "sysemu/reset.h" +#include "cpu.h" +#include "hw/ppc/spapr.h" +#include "hw/qdev-properties.h" +#include "trace.h" + +#define TPM_SPAPR_BUFSIZE 4096 + +enum { + TPM_COMM_OP_EXECUTE = 1, + TPM_COMM_OP_CLOSE_SESSION = 2, +}; + +static void spapr_tpm_proxy_reset(void *opaque) +{ + SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(opaque); + + if (tpm_proxy->host_fd != -1) { + close(tpm_proxy->host_fd); + tpm_proxy->host_fd = -1; + } +} + +static ssize_t tpm_execute(SpaprTpmProxy *tpm_proxy, target_ulong *args) +{ + uint64_t data_in = ppc64_phys_to_real(args[1]); + target_ulong data_in_size = args[2]; + uint64_t data_out = ppc64_phys_to_real(args[3]); + target_ulong data_out_size = args[4]; + uint8_t buf_in[TPM_SPAPR_BUFSIZE]; + uint8_t buf_out[TPM_SPAPR_BUFSIZE]; + ssize_t ret; + + trace_spapr_tpm_execute(data_in, data_in_size, data_out, data_out_size); + + if (data_in_size > TPM_SPAPR_BUFSIZE) { + error_report("invalid TPM input buffer size: " TARGET_FMT_lu, + data_in_size); + return H_P3; + } + + if (data_out_size < TPM_SPAPR_BUFSIZE) { + error_report("invalid TPM output buffer size: " TARGET_FMT_lu, + data_out_size); + return H_P5; + } + + if (tpm_proxy->host_fd == -1) { + tpm_proxy->host_fd = open(tpm_proxy->host_path, O_RDWR); + if (tpm_proxy->host_fd == -1) { + error_report("failed to open TPM device %s: %d", + tpm_proxy->host_path, errno); + return H_RESOURCE; + } + } + + cpu_physical_memory_read(data_in, buf_in, data_in_size); + + do { + ret = write(tpm_proxy->host_fd, buf_in, data_in_size); + if (ret > 0) { + data_in_size -= ret; + } + } while ((ret >= 0 && data_in_size > 0) || (ret == -1 && errno == EINTR)); + + if (ret == -1) { + error_report("failed to write to TPM device %s: %d", + tpm_proxy->host_path, errno); + return H_RESOURCE; + } + + do { + ret = read(tpm_proxy->host_fd, buf_out, data_out_size); + } while (ret == 0 || (ret == -1 && errno == EINTR)); + + if (ret == -1) { + error_report("failed to read from TPM device %s: %d", + tpm_proxy->host_path, errno); + return H_RESOURCE; + } + + cpu_physical_memory_write(data_out, buf_out, ret); + args[0] = ret; + + return H_SUCCESS; +} + +static target_ulong h_tpm_comm(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong op = args[0]; + SpaprTpmProxy *tpm_proxy = spapr->tpm_proxy; + + if (!tpm_proxy) { + error_report("TPM proxy not available"); + return H_FUNCTION; + } + + trace_spapr_h_tpm_comm(tpm_proxy->host_path ?: "null", op); + + switch (op) { + case TPM_COMM_OP_EXECUTE: + return tpm_execute(tpm_proxy, args); + case TPM_COMM_OP_CLOSE_SESSION: + spapr_tpm_proxy_reset(tpm_proxy); + return H_SUCCESS; + default: + return H_PARAMETER; + } +} + +static void spapr_tpm_proxy_realize(DeviceState *d, Error **errp) +{ + SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(d); + + if (tpm_proxy->host_path == NULL) { + error_setg(errp, "must specify 'host-path' option for device"); + return; + } + + tpm_proxy->host_fd = -1; + qemu_register_reset(spapr_tpm_proxy_reset, tpm_proxy); +} + +static void spapr_tpm_proxy_unrealize(DeviceState *d, Error **errp) +{ + SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(d); + + qemu_unregister_reset(spapr_tpm_proxy_reset, tpm_proxy); +} + +static Property spapr_tpm_proxy_properties[] = { + DEFINE_PROP_STRING("host-path", SpaprTpmProxy, host_path), + DEFINE_PROP_END_OF_LIST(), +}; + +static void spapr_tpm_proxy_class_init(ObjectClass *k, void *data) +{ + DeviceClass *dk = DEVICE_CLASS(k); + + dk->realize = spapr_tpm_proxy_realize; + dk->unrealize = spapr_tpm_proxy_unrealize; + dk->user_creatable = true; + dk->props = spapr_tpm_proxy_properties; +} + +static const TypeInfo spapr_tpm_proxy_info = { + .name = TYPE_SPAPR_TPM_PROXY, + .parent = TYPE_DEVICE, + .instance_size = sizeof(SpaprTpmProxy), + .class_init = spapr_tpm_proxy_class_init, +}; + +static void spapr_tpm_proxy_register_types(void) +{ + type_register_static(&spapr_tpm_proxy_info); + spapr_register_hypercall(SVM_H_TPM_COMM, h_tpm_comm); +} + +type_init(spapr_tpm_proxy_register_types) diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index f76448f532..96dad767a1 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -25,6 +25,10 @@ spapr_update_dt(unsigned cb) "New blob %u bytes" spapr_update_dt_failed_size(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x" spapr_update_dt_failed_check(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x" +# spapr_hcall_tpm.c +spapr_h_tpm_comm(const char *device_path, uint64_t operation) "tpm_device_path=%s operation=0x%"PRIu64 +spapr_tpm_execute(uint64_t data_in, uint64_t data_in_sz, uint64_t data_out, uint64_t data_out_sz) "data_in=0x%"PRIx64", data_in_sz=%"PRIu64", data_out=0x%"PRIx64", data_out_sz=%"PRIu64 + # spapr_iommu.c spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=0x%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64 spapr_iommu_get(uint64_t liobn, uint64_t ioba, uint64_t ret, uint64_t tce) "liobn=0x%"PRIx64" ioba=0x%"PRIx64" ret=%"PRId64" tce=0x%"PRIx64 diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 434d933ec9..8bfb6684cb 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -663,14 +663,26 @@ bool css_migration_enabled(void) } \ type_init(ccw_machine_register_##suffix) +static void ccw_machine_4_2_instance_options(MachineState *machine) +{ +} + +static void ccw_machine_4_2_class_options(MachineClass *mc) +{ +} +DEFINE_CCW_MACHINE(4_2, "4.2", true); + static void ccw_machine_4_1_instance_options(MachineState *machine) { + ccw_machine_4_2_instance_options(machine); } static void ccw_machine_4_1_class_options(MachineClass *mc) { + ccw_machine_4_2_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len); } -DEFINE_CCW_MACHINE(4_1, "4.1", true); +DEFINE_CCW_MACHINE(4_1, "4.1", false); static void ccw_machine_4_0_instance_options(MachineState *machine) { diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 222a286d44..ec53b14f7f 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -186,6 +186,9 @@ static const char *names[] = { /* Flag set if this is a tagged command. */ #define LSI_TAG_VALID (1 << 16) +/* Maximum instructions to process. */ +#define LSI_MAX_INSN 10000 + typedef struct lsi_request { SCSIRequest *req; uint32_t tag; @@ -1133,7 +1136,21 @@ static void lsi_execute_script(LSIState *s) s->istat1 |= LSI_ISTAT1_SRUN; again: - insn_processed++; + if (++insn_processed > LSI_MAX_INSN) { + /* Some windows drivers make the device spin waiting for a memory + location to change. If we have been executed a lot of code then + assume this is the case and force an unexpected device disconnect. + This is apparently sufficient to beat the drivers into submission. + */ + if (!(s->sien0 & LSI_SIST0_UDC)) { + qemu_log_mask(LOG_GUEST_ERROR, + "lsi_scsi: inf. loop with UDC masked"); + } + lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0); + lsi_disconnect(s); + trace_lsi_execute_script_stop(); + return; + } insn = read_dword(s, s->dsp); if (!insn) { /* If we receive an empty opcode increment the DSP by 4 bytes @@ -1570,19 +1587,7 @@ again: } } } - if (insn_processed > 10000 && s->waiting == LSI_NOWAIT) { - /* Some windows drivers make the device spin waiting for a memory - location to change. If we have been executed a lot of code then - assume this is the case and force an unexpected device disconnect. - This is apparently sufficient to beat the drivers into submission. - */ - if (!(s->sien0 & LSI_SIST0_UDC)) { - qemu_log_mask(LOG_GUEST_ERROR, - "lsi_scsi: inf. loop with UDC masked"); - } - lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0); - lsi_disconnect(s); - } else if (s->istat1 & LSI_ISTAT1_SRUN && s->waiting == LSI_NOWAIT) { + if (s->istat1 & LSI_ISTAT1_SRUN && s->waiting == LSI_NOWAIT) { if (s->dcntl & LSI_DCNTL_SSM) { lsi_script_dma_interrupt(s, LSI_DSTAT_SSI); } else { @@ -1970,6 +1975,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) case 0x2f: /* DSP[24:31] */ s->dsp &= 0x00ffffff; s->dsp |= val << 24; + /* + * FIXME: if s->waiting != LSI_NOWAIT, this will only execute one + * instruction. Is this correct? + */ if ((s->dmode & LSI_DMODE_MAN) == 0 && (s->istat1 & LSI_ISTAT1_SRUN) == 0) lsi_execute_script(s); @@ -1988,6 +1997,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) break; case 0x3b: /* DCNTL */ s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD); + /* + * FIXME: if s->waiting != LSI_NOWAIT, this will only execute one + * instruction. Is this correct? + */ if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0) lsi_execute_script(s); break; diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 26618842c9..6cb378751b 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -96,7 +96,6 @@ typedef struct RTCState { uint32_t irq_coalesced; uint32_t period; QEMUTimer *coalesced_timer; - Notifier clock_reset_notifier; LostTickPolicy lost_tick_policy; Notifier suspend_notifier; QLIST_ENTRY(RTCState) link; @@ -889,20 +888,6 @@ static const VMStateDescription vmstate_rtc = { } }; -static void rtc_notify_clock_reset(Notifier *notifier, void *data) -{ - RTCState *s = container_of(notifier, RTCState, clock_reset_notifier); - int64_t now = *(int64_t *)data; - - rtc_set_date_from_host(ISA_DEVICE(s)); - periodic_timer_update(s, now, 0); - check_update_timer(s); - - if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { - rtc_coalesced_timer_update(s); - } -} - /* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE) BIOS will read it and start S3 resume at POST Entry */ static void rtc_notify_suspend(Notifier *notifier, void *data) @@ -988,10 +973,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) s->update_timer = timer_new_ns(rtc_clock, rtc_update_timer, s); check_update_timer(s); - s->clock_reset_notifier.notify = rtc_notify_clock_reset; - qemu_clock_register_reset_notifier(rtc_clock, - &s->clock_reset_notifier); - s->suspend_notifier.notify = rtc_notify_suspend; qemu_register_suspend_notifier(&s->suspend_notifier); diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index f7669b6841..822c43cfd3 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -7,6 +7,31 @@ static TCGOp *icount_start_insn; +static inline void gen_io_start(void) +{ + TCGv_i32 tmp = tcg_const_i32(1); + tcg_gen_st_i32(tmp, cpu_env, + offsetof(ArchCPU, parent_obj.can_do_io) - + offsetof(ArchCPU, env)); + tcg_temp_free_i32(tmp); +} + +/* + * cpu->can_do_io is cleared automatically at the beginning of + * each translation block. The cost is minimal and only paid + * for -icount, plus it would be very easy to forget doing it + * in the translator. Therefore, backends only need to call + * gen_io_start. + */ +static inline void gen_io_end(void) +{ + TCGv_i32 tmp = tcg_const_i32(0); + tcg_gen_st_i32(tmp, cpu_env, + offsetof(ArchCPU, parent_obj.can_do_io) - + offsetof(ArchCPU, env)); + tcg_temp_free_i32(tmp); +} + static inline void gen_tb_start(TranslationBlock *tb) { TCGv_i32 count, imm; @@ -40,6 +65,7 @@ static inline void gen_tb_start(TranslationBlock *tb) tcg_gen_st16_i32(count, cpu_env, offsetof(ArchCPU, neg.icount_decr.u16.low) - offsetof(ArchCPU, env)); + gen_io_end(); } tcg_temp_free_i32(count); @@ -57,22 +83,4 @@ static inline void gen_tb_end(TranslationBlock *tb, int num_insns) tcg_gen_exit_tb(tb, TB_EXIT_REQUESTED); } -static inline void gen_io_start(void) -{ - TCGv_i32 tmp = tcg_const_i32(1); - tcg_gen_st_i32(tmp, cpu_env, - offsetof(ArchCPU, parent_obj.can_do_io) - - offsetof(ArchCPU, env)); - tcg_temp_free_i32(tmp); -} - -static inline void gen_io_end(void) -{ - TCGv_i32 tmp = tcg_const_i32(0); - tcg_gen_st_i32(tmp, cpu_env, - offsetof(ArchCPU, parent_obj.can_do_io) - - offsetof(ArchCPU, env)); - tcg_temp_free_i32(tmp); -} - #endif diff --git a/include/exec/memory.h b/include/exec/memory.h index d99eb25d2e..fddc2ff48a 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -425,6 +425,7 @@ struct MemoryListener { void (*log_clear)(MemoryListener *listener, MemoryRegionSection *section); void (*log_global_start)(MemoryListener *listener); void (*log_global_stop)(MemoryListener *listener); + void (*log_global_after_sync)(MemoryListener *listener); void (*eventfd_add)(MemoryListener *listener, MemoryRegionSection *section, bool match_data, uint64_t data, EventNotifier *e); void (*eventfd_del)(MemoryListener *listener, MemoryRegionSection *section, @@ -1688,6 +1689,17 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr, void memory_global_dirty_log_sync(void); /** + * memory_global_dirty_log_sync: synchronize the dirty log for all memory + * + * Synchronizes the vCPUs with a thread that is reading the dirty bitmap. + * This function must be called after the dirty log bitmap is cleared, and + * before dirty guest memory pages are read. If you are using + * #DirtyBitmapSnapshot, memory_region_snapshot_and_clear_dirty() takes + * care of doing this. + */ +void memory_global_after_dirty_log_sync(void); + +/** * memory_region_transaction_begin: Start a transaction. * * During a transaction, changes will be accumulated and made visible diff --git a/include/exec/poison.h b/include/exec/poison.h index b862320fa6..955eb863ab 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -35,6 +35,7 @@ #pragma GCC poison TARGET_UNICORE32 #pragma GCC poison TARGET_XTENSA +#pragma GCC poison TARGET_ALIGNED_ONLY #pragma GCC poison TARGET_HAS_BFLT #pragma GCC poison TARGET_NAME #pragma GCC poison TARGET_SUPPORTS_MTTCG diff --git a/include/hw/boards.h b/include/hw/boards.h index 739d109fe1..60d69217b4 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -180,6 +180,7 @@ struct MachineClass { void (*init)(MachineState *state); void (*reset)(MachineState *state); + void (*wakeup)(MachineState *state); void (*hot_add_cpu)(MachineState *state, const int64_t id, Error **errp); int (*kvm_type)(MachineState *machine, const char *arg); void (*smp_parse)(MachineState *ms, QemuOpts *opts); @@ -317,6 +318,9 @@ struct MachineState { } \ type_init(machine_initfn##_register_types) +extern GlobalProperty hw_compat_4_1[]; +extern const size_t hw_compat_4_1_len; + extern GlobalProperty hw_compat_4_0[]; extern const size_t hw_compat_4_0_len; diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index 690f9238c8..1496d7e753 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -323,8 +323,9 @@ static int glue(load_elf, SZ)(const char *name, int fd, struct elfhdr ehdr; struct elf_phdr *phdr = NULL, *ph; int size, i, total_size; - elf_word mem_size, file_size; + elf_word mem_size, file_size, data_offset; uint64_t addr, low = (uint64_t)-1, high = 0; + GMappedFile *mapped_file = NULL; uint8_t *data = NULL; char label[128]; int ret = ELF_LOAD_FAILED; @@ -409,20 +410,32 @@ static int glue(load_elf, SZ)(const char *name, int fd, } } + /* + * Since we want to be able to modify the mapped buffer, we set the + * 'writeble' parameter to 'true'. Modifications to the buffer are not + * written back to the file. + */ + mapped_file = g_mapped_file_new_from_fd(fd, true, NULL); + if (!mapped_file) { + goto fail; + } + total_size = 0; for(i = 0; i < ehdr.e_phnum; i++) { ph = &phdr[i]; if (ph->p_type == PT_LOAD) { mem_size = ph->p_memsz; /* Size of the ROM */ file_size = ph->p_filesz; /* Size of the allocated data */ - data = g_malloc0(file_size); - if (ph->p_filesz > 0) { - if (lseek(fd, ph->p_offset, SEEK_SET) < 0) { - goto fail; - } - if (read(fd, data, file_size) != file_size) { + data_offset = ph->p_offset; /* Offset where the data is located */ + + if (file_size > 0) { + if (g_mapped_file_get_length(mapped_file) < + file_size + data_offset) { goto fail; } + + data = (uint8_t *)g_mapped_file_get_contents(mapped_file); + data += data_offset; } /* The ELF spec is somewhat vague about the purpose of the @@ -513,25 +526,25 @@ static int glue(load_elf, SZ)(const char *name, int fd, *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr; } - if (mem_size == 0) { - /* Some ELF files really do have segments of zero size; - * just ignore them rather than trying to create empty - * ROM blobs, because the zero-length blob can falsely - * trigger the overlapping-ROM-blobs check. - */ - g_free(data); - } else { + /* Some ELF files really do have segments of zero size; + * just ignore them rather than trying to create empty + * ROM blobs, because the zero-length blob can falsely + * trigger the overlapping-ROM-blobs check. + */ + if (mem_size != 0) { if (load_rom) { snprintf(label, sizeof(label), "phdr #%d: %s", i, name); - /* rom_add_elf_program() seize the ownership of 'data' */ - rom_add_elf_program(label, data, file_size, mem_size, - addr, as); + /* + * rom_add_elf_program() takes its own reference to + * 'mapped_file'. + */ + rom_add_elf_program(label, mapped_file, data, file_size, + mem_size, addr, as); } else { address_space_write(as ? as : &address_space_memory, addr, MEMTXATTRS_UNSPECIFIED, data, file_size); - g_free(data); } } @@ -547,14 +560,16 @@ static int glue(load_elf, SZ)(const char *name, int fd, struct elf_note *nhdr = NULL; file_size = ph->p_filesz; /* Size of the range of ELF notes */ - data = g_malloc0(file_size); - if (ph->p_filesz > 0) { - if (lseek(fd, ph->p_offset, SEEK_SET) < 0) { - goto fail; - } - if (read(fd, data, file_size) != file_size) { + data_offset = ph->p_offset; /* Offset where the notes are located */ + + if (file_size > 0) { + if (g_mapped_file_get_length(mapped_file) < + file_size + data_offset) { goto fail; } + + data = (uint8_t *)g_mapped_file_get_contents(mapped_file); + data += data_offset; } /* @@ -570,19 +585,17 @@ static int glue(load_elf, SZ)(const char *name, int fd, sizeof(struct elf_note) == sizeof(struct elf64_note); elf_note_fn((void *)nhdr, (void *)&ph->p_align, is64); } - g_free(data); data = NULL; } } - g_free(phdr); if (lowaddr) *lowaddr = (uint64_t)(elf_sword)low; if (highaddr) *highaddr = (uint64_t)(elf_sword)high; - return total_size; + ret = total_size; fail: - g_free(data); + g_mapped_file_unref(mapped_file); g_free(phdr); return ret; } diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 4bb9e29114..19a837889d 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -41,6 +41,7 @@ struct PCMachineState { FWCfgState *fw_cfg; qemu_irq *gsi; PFlashCFI01 *flash[2]; + GMappedFile *initrd_mapped_file; /* Configuration options: */ uint64_t max_ram_below_4g; @@ -301,6 +302,9 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t); int e820_get_num_entries(void); bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); +extern GlobalProperty pc_compat_4_1[]; +extern const size_t pc_compat_4_1_len; + extern GlobalProperty pc_compat_4_0[]; extern const size_t pc_compat_4_0_len; diff --git a/include/hw/loader.h b/include/hw/loader.h index 3e1b3a4566..07fd9286e7 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -258,8 +258,9 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, FWCfgCallback fw_callback, void *callback_opaque, AddressSpace *as, bool read_only); -int rom_add_elf_program(const char *name, void *data, size_t datasize, - size_t romsize, hwaddr addr, AddressSpace *as); +int rom_add_elf_program(const char *name, GMappedFile *mapped_file, void *data, + size_t datasize, size_t romsize, hwaddr addr, + AddressSpace *as); int rom_check_and_register_reset(void); void rom_set_fw(FWCfgState *f); void rom_set_order_override(int order); diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 60553d32c4..fa7c380edb 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -10,6 +10,7 @@ #include "hw/ppc/spapr_irq.h" #include "hw/ppc/spapr_xive.h" /* For SpaprXive */ #include "hw/ppc/xics.h" /* For ICSState */ +#include "hw/ppc/spapr_tpm_proxy.h" struct SpaprVioBus; struct SpaprPhbState; @@ -203,6 +204,7 @@ struct SpaprMachineState { SpaprCapabilities def, eff, mig; unsigned gpu_numa_id; + SpaprTpmProxy *tpm_proxy; }; #define H_SUCCESS 0 @@ -508,6 +510,15 @@ struct SpaprMachineState { #define KVMPPC_H_UPDATE_DT (KVMPPC_HCALL_BASE + 0x3) #define KVMPPC_HCALL_MAX KVMPPC_H_UPDATE_DT +/* + * The hcall range 0xEF00 to 0xEF80 is reserved for use in facilitating + * Secure VM mode via an Ultravisor / Protected Execution Facility + */ +#define SVM_HCALL_BASE 0xEF00 +#define SVM_H_TPM_COMM 0xEF10 +#define SVM_HCALL_MAX SVM_H_TPM_COMM + + typedef struct SpaprDeviceTreeUpdateHeader { uint32_t version_id; } SpaprDeviceTreeUpdateHeader; @@ -525,6 +536,13 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, target_ulong *args); +/* Virtual Processor Area structure constants */ +#define VPA_MIN_SIZE 640 +#define VPA_SIZE_OFFSET 0x4 +#define VPA_SHARED_PROC_OFFSET 0x9 +#define VPA_SHARED_PROC_VAL 0x2 +#define VPA_DISPATCH_COUNTER 0x100 + /* ibm,set-eeh-option */ #define RTAS_EEH_DISABLE 0 #define RTAS_EEH_ENABLE 1 @@ -624,8 +642,9 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, #define RTAS_IBM_CREATE_PE_DMA_WINDOW (RTAS_TOKEN_BASE + 0x27) #define RTAS_IBM_REMOVE_PE_DMA_WINDOW (RTAS_TOKEN_BASE + 0x28) #define RTAS_IBM_RESET_PE_DMA_WINDOW (RTAS_TOKEN_BASE + 0x29) +#define RTAS_IBM_SUSPEND_ME (RTAS_TOKEN_BASE + 0x2A) -#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x2A) +#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x2B) /* RTAS ibm,get-system-parameter token values */ #define RTAS_SYSPARM_SPLPAR_CHARACTERISTICS 20 diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h index 35e0a7eead..1c4cc6559c 100644 --- a/include/hw/ppc/spapr_cpu_core.h +++ b/include/hw/ppc/spapr_cpu_core.h @@ -46,6 +46,7 @@ typedef struct SpaprCpuState { uint64_t vpa_addr; uint64_t slb_shadow_addr, slb_shadow_size; uint64_t dtl_addr, dtl_size; + bool prod; /* not migrated, only used to improve dispatch latencies */ struct ICPState *icp; struct XiveTCTX *tctx; } SpaprCpuState; diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index 8132e00366..5db305165c 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -30,7 +30,6 @@ void spapr_irq_msi_init(SpaprMachineState *spapr, uint32_t nr_msis); int spapr_irq_msi_alloc(SpaprMachineState *spapr, uint32_t num, bool align, Error **errp); void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num); -void spapr_irq_msi_reset(SpaprMachineState *spapr); typedef struct SpaprIrq { uint32_t nr_irqs; diff --git a/include/hw/ppc/spapr_tpm_proxy.h b/include/hw/ppc/spapr_tpm_proxy.h new file mode 100644 index 0000000000..c574e22ba4 --- /dev/null +++ b/include/hw/ppc/spapr_tpm_proxy.h @@ -0,0 +1,31 @@ +/* + * SPAPR TPM Proxy/Hypercall + * + * Copyright IBM Corp. 2019 + * + * Authors: + * Michael Roth <mdroth@linux.vnet.ibm.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 HW_SPAPR_TPM_PROXY_H +#define HW_SPAPR_TPM_PROXY_H + +#include "qom/object.h" +#include "hw/qdev-core.h" + +#define TYPE_SPAPR_TPM_PROXY "spapr-tpm-proxy" +#define SPAPR_TPM_PROXY(obj) OBJECT_CHECK(SpaprTpmProxy, (obj), \ + TYPE_SPAPR_TPM_PROXY) + +typedef struct SpaprTpmProxy { + /*< private >*/ + DeviceState parent; + + char *host_path; + int host_fd; +} SpaprTpmProxy; + +#endif /* HW_SPAPR_TPM_PROXY_H */ diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 9399c77d2d..6d38755f84 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -148,13 +148,11 @@ * XIVE Notifier (Interface between Source and Router) */ -typedef struct XiveNotifier { - Object parent; -} XiveNotifier; +typedef struct XiveNotifier XiveNotifier; #define TYPE_XIVE_NOTIFIER "xive-notifier" #define XIVE_NOTIFIER(obj) \ - OBJECT_CHECK(XiveNotifier, (obj), TYPE_XIVE_NOTIFIER) + INTERFACE_CHECK(XiveNotifier, (obj), TYPE_XIVE_NOTIFIER) #define XIVE_NOTIFIER_CLASS(klass) \ OBJECT_CLASS_CHECK(XiveNotifierClass, (klass), TYPE_XIVE_NOTIFIER) #define XIVE_NOTIFIER_GET_CLASS(obj) \ @@ -356,8 +354,6 @@ typedef struct XiveRouterClass { XiveTCTX *(*get_tctx)(XiveRouter *xrtr, CPUState *cs); } XiveRouterClass; -void xive_eas_pic_print_info(XiveEAS *eas, uint32_t lisn, Monitor *mon); - int xive_router_get_eas(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx, XiveEAS *eas); int xive_router_get_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx, @@ -399,9 +395,6 @@ typedef struct XiveENDSource { */ #define XIVE_PRIORITY_MAX 7 -void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon); -void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon); - /* * XIVE Thread Interrupt Management Aera (TIMA) * diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h index b0c68ab5f7..08c8bf7172 100644 --- a/include/hw/ppc/xive_regs.h +++ b/include/hw/ppc/xive_regs.h @@ -131,6 +131,8 @@ typedef struct XiveEAS { #define xive_eas_is_valid(eas) (be64_to_cpu((eas)->w) & EAS_VALID) #define xive_eas_is_masked(eas) (be64_to_cpu((eas)->w) & EAS_MASKED) +void xive_eas_pic_print_info(XiveEAS *eas, uint32_t lisn, Monitor *mon); + static inline uint64_t xive_get_field64(uint64_t mask, uint64_t word) { return (be64_to_cpu(word) & mask) >> ctz64(mask); @@ -210,6 +212,10 @@ typedef struct XiveEND { #define xive_end_is_notify(end) (be32_to_cpu((end)->w0) & END_W0_UCOND_NOTIFY) #define xive_end_is_backlog(end) (be32_to_cpu((end)->w0) & END_W0_BACKLOG) #define xive_end_is_escalate(end) (be32_to_cpu((end)->w0) & END_W0_ESCALATE_CTL) +#define xive_end_is_uncond_escalation(end) \ + (be32_to_cpu((end)->w0) & END_W0_UNCOND_ESCALATE) +#define xive_end_is_silent_escalation(end) \ + (be32_to_cpu((end)->w0) & END_W0_SILENT_ESCALATE) static inline uint64_t xive_end_qaddr(XiveEND *end) { @@ -217,6 +223,10 @@ static inline uint64_t xive_end_qaddr(XiveEND *end) be32_to_cpu(end->w3); } +void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon); +void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon); +void xive_end_eas_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon); + /* Notification Virtual Target (NVT) */ typedef struct XiveNVT { uint32_t w0; diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 5d978e1634..85bc6eb00b 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -62,13 +62,15 @@ typedef enum { * The following attributes are available: * * QEMU_TIMER_ATTR_EXTERNAL: drives external subsystem + * QEMU_TIMER_ATTR_ALL: mask for all existing attributes * * Timers with this attribute do not recorded in rr mode, therefore it could be * used for the subsystems that operate outside the guest core. Applicable only * with virtual clock type. */ -#define QEMU_TIMER_ATTR_EXTERNAL BIT(0) +#define QEMU_TIMER_ATTR_EXTERNAL ((int)BIT(0)) +#define QEMU_TIMER_ATTR_ALL 0xffffffff typedef struct QEMUTimerList QEMUTimerList; @@ -177,6 +179,8 @@ bool qemu_clock_use_for_deadline(QEMUClockType type); /** * qemu_clock_deadline_ns_all: * @type: the clock type + * @attr_mask: mask for the timer attributes that are included + * in deadline calculation * * Calculate the deadline across all timer lists associated * with a clock (as opposed to just the default one) @@ -184,7 +188,7 @@ bool qemu_clock_use_for_deadline(QEMUClockType type); * * Returns: time until expiry in nanoseconds or -1 */ -int64_t qemu_clock_deadline_ns_all(QEMUClockType type); +int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask); /** * qemu_clock_get_main_loop_timerlist: @@ -228,28 +232,6 @@ void qemu_clock_enable(QEMUClockType type, bool enabled); void qemu_start_warp_timer(void); /** - * qemu_clock_register_reset_notifier: - * @type: the clock type - * @notifier: the notifier function - * - * Register a notifier function to call when the clock - * concerned is reset. - */ -void qemu_clock_register_reset_notifier(QEMUClockType type, - Notifier *notifier); - -/** - * qemu_clock_unregister_reset_notifier: - * @type: the clock type - * @notifier: the notifier function - * - * Unregister a notifier function to call when the clock - * concerned is reset. - */ -void qemu_clock_unregister_reset_notifier(QEMUClockType type, - Notifier *notifier); - -/** * qemu_clock_run_timers: * @type: clock on which to operate * @@ -270,19 +252,6 @@ bool qemu_clock_run_timers(QEMUClockType type); */ bool qemu_clock_run_all_timers(void); -/** - * qemu_clock_get_last: - * - * Returns last clock query time. - */ -uint64_t qemu_clock_get_last(QEMUClockType type); -/** - * qemu_clock_set_last: - * - * Sets last clock query time. - */ -void qemu_clock_set_last(QEMUClockType type, uint64_t last); - /* * QEMUTimerList diff --git a/include/qom/cpu.h b/include/qom/cpu.h index ddb91bbaff..77fca95a40 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -89,7 +89,7 @@ struct TranslationBlock; * @do_unassigned_access: Callback for unassigned access handling. * (this is deprecated: new targets should use do_transaction_failed instead) * @do_unaligned_access: Callback for unaligned access handling, if - * the target defines #ALIGNED_ONLY. + * the target defines #TARGET_ALIGNED_ONLY. * @do_transaction_failed: Callback for handling failed memory transactions * (ie bus faults or external aborts; not MMU faults) * @virtio_is_big_endian: Callback to return %true if a CPU which supports diff --git a/include/standard-headers/asm-x86/kvm_para.h b/include/standard-headers/asm-x86/kvm_para.h index 35cd8d651f..e1715143fd 100644 --- a/include/standard-headers/asm-x86/kvm_para.h +++ b/include/standard-headers/asm-x86/kvm_para.h @@ -29,6 +29,7 @@ #define KVM_FEATURE_PV_TLB_FLUSH 9 #define KVM_FEATURE_ASYNC_PF_VMEXIT 10 #define KVM_FEATURE_PV_SEND_IPI 11 +#define KVM_FEATURE_POLL_CONTROL 12 #define KVM_HINTS_REALTIME 0 @@ -47,6 +48,7 @@ #define MSR_KVM_ASYNC_PF_EN 0x4b564d02 #define MSR_KVM_STEAL_TIME 0x4b564d03 #define MSR_KVM_PV_EOI_EN 0x4b564d04 +#define MSR_KVM_POLL_CONTROL 0x4b564d05 struct kvm_steal_time { uint64_t steal; diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index df248af581..dfc7a31c66 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -75,7 +75,7 @@ void replay_add_blocker(Error *reason); /* Processing the instructions */ /*! Returns number of executed instructions. */ -uint64_t replay_get_current_step(void); +uint64_t replay_get_current_icount(void); /*! Returns number of instructions to execute in replay mode. */ int replay_get_instructions(void); /*! Updates instructions counter in replay mode. */ @@ -1942,16 +1942,18 @@ void memory_region_notify_one(IOMMUNotifier *notifier, IOMMUTLBEntry *entry) { IOMMUNotifierFlag request_flags; + hwaddr entry_end = entry->iova + entry->addr_mask; /* * Skip the notification if the notification does not overlap * with registered range. */ - if (notifier->start > entry->iova + entry->addr_mask || - notifier->end < entry->iova) { + if (notifier->start > entry_end || notifier->end < entry->iova) { return; } + assert(entry->iova >= notifier->start && entry_end <= notifier->end); + if (entry->perm & IOMMU_RW) { request_flags = IOMMU_NOTIFIER_MAP; } else { @@ -2125,9 +2127,12 @@ DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr, hwaddr size, unsigned client) { + DirtyBitmapSnapshot *snapshot; assert(mr->ram_block); memory_region_sync_dirty_bitmap(mr); - return cpu_physical_memory_snapshot_and_clear_dirty(mr, addr, size, client); + snapshot = cpu_physical_memory_snapshot_and_clear_dirty(mr, addr, size, client); + memory_global_after_dirty_log_sync(); + return snapshot; } bool memory_region_snapshot_get_dirty(MemoryRegion *mr, DirtyBitmapSnapshot *snap, @@ -2618,6 +2623,11 @@ void memory_global_dirty_log_sync(void) memory_region_sync_dirty_bitmap(NULL); } +void memory_global_after_dirty_log_sync(void) +{ + MEMORY_LISTENER_CALL_GLOBAL(log_global_after_sync, Forward); +} + static VMChangeStateEntry *vmstate_change; void memory_global_dirty_log_start(void) diff --git a/migration/ram.c b/migration/ram.c index 35552c090b..b01a37e7ca 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1857,6 +1857,7 @@ static void migration_bitmap_sync(RAMState *rs) rcu_read_unlock(); qemu_mutex_unlock(&rs->bitmap_mutex); + memory_global_after_dirty_log_sync(); trace_migration_bitmap_sync_end(rs->num_dirty_pages_period); end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); diff --git a/pc-bios/README b/pc-bios/README index 68b4a81103..d59cd25461 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20190703. + built from git tag qemu-slof-20190719. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin Binary files differindex 2def514717..fb0837508b 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin @@ -654,7 +654,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words) int ret = qemu_strtoi64(words[1], NULL, 0, &ns); g_assert(ret == 0); } else { - ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, + QEMU_TIMER_ATTR_ALL); } qtest_clock_warp(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns); qtest_send_prefix(chr); diff --git a/replay/replay-events.c b/replay/replay-events.c index 60d17f6edb..008e80f636 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -124,7 +124,7 @@ void replay_add_event(ReplayAsyncEventKind event_kind, void replay_bh_schedule_event(QEMUBH *bh) { if (events_enabled) { - uint64_t id = replay_get_current_step(); + uint64_t id = replay_get_current_icount(); replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); } else { qemu_bh_schedule(bh); diff --git a/replay/replay-internal.c b/replay/replay-internal.c index c013b23820..eba8246aae 100644 --- a/replay/replay-internal.c +++ b/replay/replay-internal.c @@ -173,7 +173,7 @@ void replay_fetch_data_kind(void) if (!replay_state.has_unread_data) { replay_state.data_kind = replay_get_byte(); if (replay_state.data_kind == EVENT_INSTRUCTION) { - replay_state.instructions_count = replay_get_dword(); + replay_state.instruction_count = replay_get_dword(); } replay_check_error(); replay_state.has_unread_data = 1; @@ -227,9 +227,9 @@ void replay_mutex_unlock(void) } } -void replay_advance_current_step(uint64_t current_step) +void replay_advance_current_icount(uint64_t current_icount) { - int diff = (int)(replay_get_current_step() - replay_state.current_step); + int diff = (int)(current_icount - replay_state.current_icount); /* Time can only go forward */ assert(diff >= 0); @@ -237,7 +237,7 @@ void replay_advance_current_step(uint64_t current_step) if (diff > 0) { replay_put_event(EVENT_INSTRUCTION); replay_put_dword(diff); - replay_state.current_step += diff; + replay_state.current_icount += diff; } } @@ -246,6 +246,6 @@ void replay_save_instructions(void) { if (replay_file && replay_mode == REPLAY_MODE_RECORD) { g_assert(replay_mutex_locked()); - replay_advance_current_step(replay_get_current_step()); + replay_advance_current_icount(replay_get_current_icount()); } } diff --git a/replay/replay-internal.h b/replay/replay-internal.h index af6f4d55d4..afba9a3e0c 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -64,10 +64,10 @@ typedef enum ReplayAsyncEventKind ReplayAsyncEventKind; typedef struct ReplayState { /*! Cached clock values. */ int64_t cached_clock[REPLAY_CLOCK_COUNT]; - /*! Current step - number of processed instructions and timer events. */ - uint64_t current_step; + /*! Current icount - number of processed instructions. */ + uint64_t current_icount; /*! Number of instructions to be executed before other events happen. */ - int instructions_count; + int instruction_count; /*! Type of the currently executed event. */ unsigned int data_kind; /*! Flag which indicates that event is not processed yet. */ @@ -122,8 +122,8 @@ void replay_finish_event(void); data_kind variable. */ void replay_fetch_data_kind(void); -/*! Advance replay_state.current_step to the specified value. */ -void replay_advance_current_step(uint64_t current_step); +/*! Advance replay_state.current_icount to the specified value. */ +void replay_advance_current_icount(uint64_t current_icount); /*! Saves queued events (like instructions and sound). */ void replay_save_instructions(void); diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c index 5dd8680480..e26fa4c892 100644 --- a/replay/replay-snapshot.c +++ b/replay/replay-snapshot.c @@ -23,7 +23,6 @@ static int replay_pre_save(void *opaque) { ReplayState *state = opaque; state->file_offset = ftell(replay_file); - state->host_clock_last = qemu_clock_get_last(QEMU_CLOCK_HOST); return 0; } @@ -33,14 +32,13 @@ static int replay_post_load(void *opaque, int version_id) ReplayState *state = opaque; if (replay_mode == REPLAY_MODE_PLAY) { fseek(replay_file, state->file_offset, SEEK_SET); - qemu_clock_set_last(QEMU_CLOCK_HOST, state->host_clock_last); /* If this was a vmstate, saved in recording mode, we need to initialize replay data fields. */ replay_fetch_data_kind(); } else if (replay_mode == REPLAY_MODE_RECORD) { /* This is only useful for loading the initial state. Therefore reset all the counters. */ - state->instructions_count = 0; + state->instruction_count = 0; state->block_request_id = 0; } @@ -49,19 +47,18 @@ static int replay_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_replay = { .name = "replay", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .pre_save = replay_pre_save, .post_load = replay_post_load, .fields = (VMStateField[]) { VMSTATE_INT64_ARRAY(cached_clock, ReplayState, REPLAY_CLOCK_COUNT), - VMSTATE_UINT64(current_step, ReplayState), - VMSTATE_INT32(instructions_count, ReplayState), + VMSTATE_UINT64(current_icount, ReplayState), + VMSTATE_INT32(instruction_count, ReplayState), VMSTATE_UINT32(data_kind, ReplayState), VMSTATE_UINT32(has_unread_data, ReplayState), VMSTATE_UINT64(file_offset, ReplayState), VMSTATE_UINT64(block_request_id, ReplayState), - VMSTATE_UINT64(host_clock_last, ReplayState), VMSTATE_INT32(read_event_kind, ReplayState), VMSTATE_UINT64(read_event_id, ReplayState), VMSTATE_INT32(read_event_checkpoint, ReplayState), diff --git a/replay/replay-time.c b/replay/replay-time.c index 5154cb0ce9..43357c9f24 100644 --- a/replay/replay-time.c +++ b/replay/replay-time.c @@ -14,18 +14,19 @@ #include "replay-internal.h" #include "qemu/error-report.h" -int64_t replay_save_clock(ReplayClockKind kind, int64_t clock, int64_t raw_icount) +int64_t replay_save_clock(ReplayClockKind kind, int64_t clock, + int64_t raw_icount) { - if (replay_file) { - g_assert(replay_mutex_locked()); + g_assert(replay_file); + g_assert(replay_mutex_locked()); - /* Due to the caller's locking requirements we get the icount from it - * instead of using replay_save_instructions(). - */ - replay_advance_current_step(raw_icount); - replay_put_event(EVENT_CLOCK + kind); - replay_put_qword(clock); - } + /* + * Due to the caller's locking requirements we get the icount from it + * instead of using replay_save_instructions(). + */ + replay_advance_current_icount(raw_icount); + replay_put_event(EVENT_CLOCK + kind); + replay_put_qword(clock); return clock; } @@ -47,20 +48,15 @@ void replay_read_next_clock(ReplayClockKind kind) /*! Reads next clock event from the input. */ int64_t replay_read_clock(ReplayClockKind kind) { + int64_t ret; g_assert(replay_file && replay_mutex_locked()); replay_account_executed_instructions(); - if (replay_file) { - int64_t ret; - if (replay_next_event_is(EVENT_CLOCK + kind)) { - replay_read_next_clock(kind); - } - ret = replay_state.cached_clock[kind]; - - return ret; + if (replay_next_event_is(EVENT_CLOCK + kind)) { + replay_read_next_clock(kind); } + ret = replay_state.cached_clock[kind]; - error_report("REPLAY INTERNAL ERROR %d", __LINE__); - exit(1); + return ret; } diff --git a/replay/replay.c b/replay/replay.c index 7fc9891d2e..713395b33d 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -39,20 +39,20 @@ bool replay_next_event_is(int event) bool res = false; /* nothing to skip - not all instructions used */ - if (replay_state.instructions_count != 0) { + if (replay_state.instruction_count != 0) { assert(replay_state.data_kind == EVENT_INSTRUCTION); return event == EVENT_INSTRUCTION; } while (true) { - if (event == replay_state.data_kind) { + unsigned int data_kind = replay_state.data_kind; + if (event == data_kind) { res = true; } - switch (replay_state.data_kind) { + switch (data_kind) { case EVENT_SHUTDOWN ... EVENT_SHUTDOWN_LAST: replay_finish_event(); - qemu_system_shutdown_request(replay_state.data_kind - - EVENT_SHUTDOWN); + qemu_system_shutdown_request(data_kind - EVENT_SHUTDOWN); break; default: /* clock, time_t, checkpoint and other events */ @@ -62,7 +62,7 @@ bool replay_next_event_is(int event) return res; } -uint64_t replay_get_current_step(void) +uint64_t replay_get_current_icount(void) { return cpu_get_icount_raw(); } @@ -72,7 +72,7 @@ int replay_get_instructions(void) int res = 0; replay_mutex_lock(); if (replay_next_event_is(EVENT_INSTRUCTION)) { - res = replay_state.instructions_count; + res = replay_state.instruction_count; } replay_mutex_unlock(); return res; @@ -82,16 +82,16 @@ void replay_account_executed_instructions(void) { if (replay_mode == REPLAY_MODE_PLAY) { g_assert(replay_mutex_locked()); - if (replay_state.instructions_count > 0) { - int count = (int)(replay_get_current_step() - - replay_state.current_step); + if (replay_state.instruction_count > 0) { + int count = (int)(replay_get_current_icount() + - replay_state.current_icount); /* Time can only go forward */ assert(count >= 0); - replay_state.instructions_count -= count; - replay_state.current_step += count; - if (replay_state.instructions_count == 0) { + replay_state.instruction_count -= count; + replay_state.current_icount += count; + if (replay_state.instruction_count == 0) { assert(replay_state.data_kind == EVENT_INSTRUCTION); replay_finish_event(); /* Wake up iothread. This is required because @@ -273,8 +273,8 @@ static void replay_enable(const char *fname, int mode) replay_mutex_init(); replay_state.data_kind = -1; - replay_state.instructions_count = 0; - replay_state.current_step = 0; + replay_state.instruction_count = 0; + replay_state.current_icount = 0; replay_state.has_unread_data = 0; /* skip file header for RECORD and check it for PLAY */ diff --git a/roms/SLOF b/roms/SLOF -Subproject ba1ab360eebe6338bb8d7d83a9220ccf7e213af +Subproject 7bfe584e321946771692711ff83ad2b5850daca diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap index 99a8146aaa..d8c7d6dfb8 100755 --- a/scripts/kvm/vmxcap +++ b/scripts/kvm/vmxcap @@ -178,7 +178,11 @@ controls = [ 19: 'Conceal non-root operation from PT', 20: 'Enable XSAVES/XRSTORS', 22: 'Mode-based execute control (XS/XU)', + 23: 'Sub-page write permissions', + 24: 'GPA translation for PT', 25: 'TSC scaling', + 26: 'User wait and pause', + 28: 'ENCLV exiting', }, cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2, ), @@ -197,6 +201,7 @@ controls = [ 22: 'Save VMX-preemption timer value', 23: 'Clear IA32_BNDCFGS', 24: 'Conceal VM exits from PT', + 25: 'Clear IA32_RTIT_CTL', }, cap_msr = MSR_IA32_VMX_EXIT_CTLS, true_cap_msr = MSR_IA32_VMX_TRUE_EXIT_CTLS, @@ -214,6 +219,7 @@ controls = [ 15: 'Load IA32_EFER', 16: 'Load IA32_BNDCFGS', 17: 'Conceal VM entries from PT', + 18: 'Load IA32_RTIT_CTL', }, cap_msr = MSR_IA32_VMX_ENTRY_CTLS, true_cap_msr = MSR_IA32_VMX_TRUE_ENTRY_CTLS, @@ -227,6 +233,7 @@ controls = [ 6: 'HLT activity state', 7: 'Shutdown activity state', 8: 'Wait-for-SIPI activity state', + 14: 'PT in VMX operation', 15: 'IA32_SMBASE support', (16,24): 'Number of CR3-target values', (25,27): 'MSR-load/store count recommendation', @@ -249,6 +256,7 @@ controls = [ 17: '1GB EPT pages', 20: 'INVEPT supported', 21: 'EPT accessed and dirty flags', + 22: 'Advanced VM-exit information for EPT violations', 25: 'Single-context INVEPT', 26: 'All-context INVEPT', 32: 'INVVPID supported', diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h index 4619530660..a530249a5b 100644 --- a/target/alpha/cpu.h +++ b/target/alpha/cpu.h @@ -23,8 +23,6 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" -#define ALIGNED_ONLY - /* Alpha processors have a weak memory model */ #define TCG_GUEST_DEFAULT_MO (0) diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 2c9cccf6c1..1e29653aac 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -1332,7 +1332,6 @@ static DisasJumpType gen_mfpr(DisasContext *ctx, TCGv va, int regno) if (use_icount) { gen_io_start(); helper(va); - gen_io_end(); return DISAS_PC_STALE; } else { helper(va); @@ -2398,7 +2397,6 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); gen_helper_load_pcc(va, cpu_env); - gen_io_end(); ret = DISAS_PC_STALE; } else { gen_helper_load_pcc(va, cpu_env); diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index fc3e5f5c38..6fd0b779d3 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1775,7 +1775,6 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { /* I/O operations must end the TB here (whether read or write) */ - gen_io_end(); s->base.is_jmp = DISAS_UPDATE; } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) { /* We default to ending the TB on a coprocessor register write, @@ -2084,9 +2083,6 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn) gen_helper_exception_return(cpu_env, dst); tcg_temp_free_i64(dst); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } /* Must exit loop to check un-masked IRQs */ s->base.is_jmp = DISAS_EXIT; return; diff --git a/target/arm/translate.c b/target/arm/translate.c index d948757131..cbe19b7a62 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3213,9 +3213,6 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr) gen_io_start(); } gen_helper_cpsr_write_eret(cpu_env, cpsr); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } tcg_temp_free_i32(cpsr); /* Must exit loop to check un-masked IRQs */ s->base.is_jmp = DISAS_EXIT; @@ -7303,7 +7300,6 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn) if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { /* I/O operations must end the TB here (whether read or write) */ - gen_io_end(); gen_lookup_tb(s); } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) { /* We default to ending the TB on a coprocessor register write, @@ -9163,9 +9159,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) gen_io_start(); } gen_helper_cpsr_write_eret(cpu_env, tmp); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } tcg_temp_free_i32(tmp); /* Must exit loop to check un-masked IRQs */ s->base.is_jmp = DISAS_EXIT; diff --git a/target/cris/translate.c b/target/cris/translate.c index 3429a3b768..e752bd0609 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -3225,8 +3225,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) npc = dc->pc; - if (tb_cflags(tb) & CF_LAST_IO) - gen_io_end(); /* Force an update if the per-tb cpu state has changed. */ if (dc->is_jmp == DISAS_NEXT && (dc->cpustate_changed || !dc->flagx_known diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 4b816cc13a..6713d04f11 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -30,7 +30,6 @@ basis. It's probably easier to fall back to a strong memory model. */ #define TCG_GUEST_DEFAULT_MO TCG_MO_ALL -#define ALIGNED_ONLY #define MMU_KERNEL_IDX 0 #define MMU_USER_IDX 3 #define MMU_PHYS_IDX 4 diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 188fe688cb..8c6189512c 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -2161,7 +2161,6 @@ static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); gen_helper_read_interval_timer(tmp); - gen_io_end(); ctx->base.is_jmp = DISAS_IAQ_N_STALE; } else { gen_helper_read_interval_timer(tmp); diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ff65e11008..9e0bac31e8 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -770,6 +770,7 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, /* CPUID_7_0_ECX_OSPKE is dynamic */ \ CPUID_7_0_ECX_LA57) #define TCG_7_0_EDX_FEATURES 0 +#define TCG_7_1_EAX_FEATURES 0 #define TCG_APM_FEATURES 0 #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT #define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1) @@ -906,7 +907,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "kvmclock", "kvm-nopiodelay", "kvm-mmu", "kvmclock", "kvm-asyncpf", "kvm-steal-time", "kvm-pv-eoi", "kvm-pv-unhalt", NULL, "kvm-pv-tlb-flush", NULL, "kvm-pv-ipi", - NULL, NULL, NULL, NULL, + "kvm-poll-control", "kvm-pv-sched-yield", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "kvmclock-stable-bit", NULL, NULL, NULL, @@ -1095,6 +1096,25 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, .tcg_features = TCG_7_0_EDX_FEATURES, }, + [FEAT_7_1_EAX] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { + NULL, NULL, NULL, NULL, + NULL, "avx512-bf16", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .cpuid = { + .eax = 7, + .needs_ecx = true, .ecx = 1, + .reg = R_EAX, + }, + .tcg_features = TCG_7_1_EAX_FEATURES, + }, [FEAT_8000_0007_EDX] = { .type = CPUID_FEATURE_WORD, .feat_names = { @@ -4292,13 +4312,19 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 7: /* Structured Extended Feature Flags Enumeration Leaf */ if (count == 0) { - *eax = 0; /* Maximum ECX value for sub-leaves */ + /* Maximum ECX value for sub-leaves */ + *eax = env->cpuid_level_func7; *ebx = env->features[FEAT_7_0_EBX]; /* Feature flags */ *ecx = env->features[FEAT_7_0_ECX]; /* Feature flags */ if ((*ecx & CPUID_7_0_ECX_PKU) && env->cr[4] & CR4_PKE_MASK) { *ecx |= CPUID_7_0_ECX_OSPKE; } *edx = env->features[FEAT_7_0_EDX]; /* Feature flags */ + } else if (count == 1) { + *eax = env->features[FEAT_7_1_EAX]; + *ebx = 0; + *ecx = 0; + *edx = 0; } else { *eax = 0; *ebx = 0; @@ -4948,6 +4974,11 @@ static void x86_cpu_adjust_feat_level(X86CPU *cpu, FeatureWord w) x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel2, eax); break; } + + if (eax == 7) { + x86_cpu_adjust_level(cpu, &env->cpuid_min_level_func7, + fi->cpuid.ecx); + } } /* Calculate XSAVE components based on the configured CPU feature flags */ @@ -5066,6 +5097,7 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) x86_cpu_adjust_feat_level(cpu, FEAT_1_ECX); x86_cpu_adjust_feat_level(cpu, FEAT_6_EAX); x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX); + x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EAX); x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX); x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX); x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX); @@ -5097,6 +5129,9 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) } /* Set cpuid_*level* based on cpuid_min_*level, if not explicitly set */ + if (env->cpuid_level_func7 == UINT32_MAX) { + env->cpuid_level_func7 = env->cpuid_min_level_func7; + } if (env->cpuid_level == UINT32_MAX) { env->cpuid_level = env->cpuid_min_level; } @@ -5660,6 +5695,8 @@ static void x86_cpu_initfn(Object *obj) object_property_add_alias(obj, "kvm_steal_time", obj, "kvm-steal-time", &error_abort); object_property_add_alias(obj, "kvm_pv_eoi", obj, "kvm-pv-eoi", &error_abort); object_property_add_alias(obj, "kvm_pv_unhalt", obj, "kvm-pv-unhalt", &error_abort); + object_property_add_alias(obj, "kvm_poll_control", obj, "kvm-poll-control", + &error_abort); object_property_add_alias(obj, "svm_lock", obj, "svm-lock", &error_abort); object_property_add_alias(obj, "nrip_save", obj, "nrip-save", &error_abort); object_property_add_alias(obj, "tsc_scale", obj, "tsc-scale", &error_abort); @@ -5868,6 +5905,8 @@ static Property x86_cpu_properties[] = { 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), + DEFINE_PROP_UINT32("level-func7", X86CPU, env.cpuid_level_func7, + UINT32_MAX), DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, UINT32_MAX), DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, UINT32_MAX), DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, UINT32_MAX), diff --git a/target/i386/cpu.h b/target/i386/cpu.h index ecd0ec0899..5f6e3a029a 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -479,6 +479,7 @@ typedef enum FeatureWord { FEAT_7_0_EBX, /* CPUID[EAX=7,ECX=0].EBX */ FEAT_7_0_ECX, /* CPUID[EAX=7,ECX=0].ECX */ FEAT_7_0_EDX, /* CPUID[EAX=7,ECX=0].EDX */ + FEAT_7_1_EAX, /* CPUID[EAX=7,ECX=1].EAX */ FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */ FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */ FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */ @@ -692,6 +693,8 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_EDX_CORE_CAPABILITY (1U << 30) /*Core Capability*/ #define CPUID_7_0_EDX_SPEC_CTRL_SSBD (1U << 31) /* Speculative Store Bypass Disable */ +#define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) /* AVX512 BFloat16 Instruction */ + #define CPUID_8000_0008_EBX_WBNOINVD (1U << 9) /* Write back and do not invalidate cache */ #define CPUID_8000_0008_EBX_IBPB (1U << 12) /* Indirect Branch Prediction Barrier */ @@ -1260,6 +1263,7 @@ typedef struct CPUX86State { uint64_t steal_time_msr; uint64_t async_pf_en_msr; uint64_t pv_eoi_en_msr; + uint64_t poll_control_msr; /* Partition-wide HV MSRs, will be updated only on the first vcpu */ uint64_t msr_hv_hypercall; @@ -1322,6 +1326,10 @@ typedef struct CPUX86State { /* Fields after this point are preserved across CPU reset. */ /* processor features (e.g. for CPUID insn) */ + /* Minimum cpuid leaf 7 value */ + uint32_t cpuid_level_func7; + /* Actual cpuid leaf 7 value */ + uint32_t cpuid_min_level_func7; /* Minimum level/xlevel/xlevel2, based on CPU model + features */ uint32_t cpuid_min_level, cpuid_min_xlevel, cpuid_min_xlevel2; /* Maximum level/xlevel/xlevel2 value for auto-assignment: */ diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 2abc881324..8023c679ea 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -193,6 +193,7 @@ static int kvm_get_tsc(CPUState *cs) return 0; } + memset(&msr_data, 0, sizeof(msr_data)); msr_data.info.nmsrs = 1; msr_data.entries[0].index = MSR_IA32_TSC; env->tsc_valid = !runstate_is_running(); @@ -1500,6 +1501,7 @@ int kvm_arch_init_vcpu(CPUState *cs) c = &cpuid_data.entries[cpuid_i++]; } break; + case 0x7: case 0x14: { uint32_t times; @@ -1512,7 +1514,7 @@ int kvm_arch_init_vcpu(CPUState *cs) for (j = 1; j <= times; ++j) { if (cpuid_i == KVM_MAX_CPUID_ENTRIES) { fprintf(stderr, "cpuid_data is full, no space for " - "cpuid(eax:0x14,ecx:0x%x)\n", j); + "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); abort(); } c = &cpuid_data.entries[cpuid_i++]; @@ -1709,6 +1711,7 @@ int kvm_arch_init_vcpu(CPUState *cs) if (has_xsave) { env->xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave)); + memset(env->xsave_buf, 0, sizeof(struct kvm_xsave)); } max_nested_state_len = kvm_max_nested_state_length(); @@ -1785,6 +1788,8 @@ void kvm_arch_reset_vcpu(X86CPU *cpu) hyperv_x86_synic_reset(cpu); } + /* enabled by default */ + env->poll_control_msr = 1; } void kvm_arch_do_init_vcpu(X86CPU *cpu) @@ -1840,108 +1845,105 @@ static int kvm_get_supported_feature_msrs(KVMState *s) static int kvm_get_supported_msrs(KVMState *s) { - static int kvm_supported_msrs; int ret = 0; + struct kvm_msr_list msr_list, *kvm_msr_list; - /* first time */ - if (kvm_supported_msrs == 0) { - struct kvm_msr_list msr_list, *kvm_msr_list; + /* + * Obtain MSR list from KVM. These are the MSRs that we must + * save/restore. + */ + msr_list.nmsrs = 0; + ret = kvm_ioctl(s, KVM_GET_MSR_INDEX_LIST, &msr_list); + if (ret < 0 && ret != -E2BIG) { + return ret; + } + /* + * Old kernel modules had a bug and could write beyond the provided + * memory. Allocate at least a safe amount of 1K. + */ + kvm_msr_list = g_malloc0(MAX(1024, sizeof(msr_list) + + msr_list.nmsrs * + sizeof(msr_list.indices[0]))); - kvm_supported_msrs = -1; + kvm_msr_list->nmsrs = msr_list.nmsrs; + ret = kvm_ioctl(s, KVM_GET_MSR_INDEX_LIST, kvm_msr_list); + if (ret >= 0) { + int i; - /* Obtain MSR list from KVM. These are the MSRs that we must - * save/restore */ - msr_list.nmsrs = 0; - ret = kvm_ioctl(s, KVM_GET_MSR_INDEX_LIST, &msr_list); - if (ret < 0 && ret != -E2BIG) { - return ret; - } - /* Old kernel modules had a bug and could write beyond the provided - memory. Allocate at least a safe amount of 1K. */ - kvm_msr_list = g_malloc0(MAX(1024, sizeof(msr_list) + - msr_list.nmsrs * - sizeof(msr_list.indices[0]))); - - kvm_msr_list->nmsrs = msr_list.nmsrs; - ret = kvm_ioctl(s, KVM_GET_MSR_INDEX_LIST, kvm_msr_list); - if (ret >= 0) { - int i; - - for (i = 0; i < kvm_msr_list->nmsrs; i++) { - switch (kvm_msr_list->indices[i]) { - case MSR_STAR: - has_msr_star = true; - break; - case MSR_VM_HSAVE_PA: - has_msr_hsave_pa = true; - break; - case MSR_TSC_AUX: - has_msr_tsc_aux = true; - break; - case MSR_TSC_ADJUST: - has_msr_tsc_adjust = true; - break; - case MSR_IA32_TSCDEADLINE: - has_msr_tsc_deadline = true; - break; - case MSR_IA32_SMBASE: - has_msr_smbase = true; - break; - case MSR_SMI_COUNT: - has_msr_smi_count = true; - break; - case MSR_IA32_MISC_ENABLE: - has_msr_misc_enable = true; - break; - case MSR_IA32_BNDCFGS: - has_msr_bndcfgs = true; - break; - case MSR_IA32_XSS: - has_msr_xss = true; - break; - case HV_X64_MSR_CRASH_CTL: - has_msr_hv_crash = true; - break; - case HV_X64_MSR_RESET: - has_msr_hv_reset = true; - break; - case HV_X64_MSR_VP_INDEX: - has_msr_hv_vpindex = true; - break; - case HV_X64_MSR_VP_RUNTIME: - has_msr_hv_runtime = true; - break; - case HV_X64_MSR_SCONTROL: - has_msr_hv_synic = true; - break; - case HV_X64_MSR_STIMER0_CONFIG: - has_msr_hv_stimer = true; - break; - case HV_X64_MSR_TSC_FREQUENCY: - has_msr_hv_frequencies = true; - break; - case HV_X64_MSR_REENLIGHTENMENT_CONTROL: - has_msr_hv_reenlightenment = true; - break; - case MSR_IA32_SPEC_CTRL: - has_msr_spec_ctrl = true; - break; - case MSR_VIRT_SSBD: - has_msr_virt_ssbd = true; - break; - case MSR_IA32_ARCH_CAPABILITIES: - has_msr_arch_capabs = true; - break; - case MSR_IA32_CORE_CAPABILITY: - has_msr_core_capabs = true; - break; - } + for (i = 0; i < kvm_msr_list->nmsrs; i++) { + switch (kvm_msr_list->indices[i]) { + case MSR_STAR: + has_msr_star = true; + break; + case MSR_VM_HSAVE_PA: + has_msr_hsave_pa = true; + break; + case MSR_TSC_AUX: + has_msr_tsc_aux = true; + break; + case MSR_TSC_ADJUST: + has_msr_tsc_adjust = true; + break; + case MSR_IA32_TSCDEADLINE: + has_msr_tsc_deadline = true; + break; + case MSR_IA32_SMBASE: + has_msr_smbase = true; + break; + case MSR_SMI_COUNT: + has_msr_smi_count = true; + break; + case MSR_IA32_MISC_ENABLE: + has_msr_misc_enable = true; + break; + case MSR_IA32_BNDCFGS: + has_msr_bndcfgs = true; + break; + case MSR_IA32_XSS: + has_msr_xss = true; + break; + case HV_X64_MSR_CRASH_CTL: + has_msr_hv_crash = true; + break; + case HV_X64_MSR_RESET: + has_msr_hv_reset = true; + break; + case HV_X64_MSR_VP_INDEX: + has_msr_hv_vpindex = true; + break; + case HV_X64_MSR_VP_RUNTIME: + has_msr_hv_runtime = true; + break; + case HV_X64_MSR_SCONTROL: + has_msr_hv_synic = true; + break; + case HV_X64_MSR_STIMER0_CONFIG: + has_msr_hv_stimer = true; + break; + case HV_X64_MSR_TSC_FREQUENCY: + has_msr_hv_frequencies = true; + break; + case HV_X64_MSR_REENLIGHTENMENT_CONTROL: + has_msr_hv_reenlightenment = true; + break; + case MSR_IA32_SPEC_CTRL: + has_msr_spec_ctrl = true; + break; + case MSR_VIRT_SSBD: + has_msr_virt_ssbd = true; + break; + case MSR_IA32_ARCH_CAPABILITIES: + has_msr_arch_capabs = true; + break; + case MSR_IA32_CORE_CAPABILITY: + has_msr_core_capabs = true; + break; } } - - g_free(kvm_msr_list); } + g_free(kvm_msr_list); + return ret; } @@ -2493,6 +2495,11 @@ static int kvm_put_msrs(X86CPU *cpu, int level) if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_STEAL_TIME)) { kvm_msr_entry_add(cpu, MSR_KVM_STEAL_TIME, env->steal_time_msr); } + + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_POLL_CONTROL)) { + kvm_msr_entry_add(cpu, MSR_KVM_POLL_CONTROL, env->poll_control_msr); + } + if (has_architectural_pmu_version > 0) { if (has_architectural_pmu_version > 1) { /* Stop the counter. */ @@ -2878,6 +2885,9 @@ static int kvm_get_msrs(X86CPU *cpu) if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_STEAL_TIME)) { kvm_msr_entry_add(cpu, MSR_KVM_STEAL_TIME, 0); } + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_POLL_CONTROL)) { + kvm_msr_entry_add(cpu, MSR_KVM_POLL_CONTROL, 1); + } if (has_architectural_pmu_version > 0) { if (has_architectural_pmu_version > 1) { kvm_msr_entry_add(cpu, MSR_CORE_PERF_FIXED_CTR_CTRL, 0); @@ -3112,6 +3122,10 @@ static int kvm_get_msrs(X86CPU *cpu) case MSR_KVM_STEAL_TIME: env->steal_time_msr = msrs[i].data; break; + case MSR_KVM_POLL_CONTROL: { + env->poll_control_msr = msrs[i].data; + break; + } case MSR_CORE_PERF_FIXED_CTR_CTRL: env->msr_fixed_ctr_ctrl = msrs[i].data; break; @@ -3480,6 +3494,7 @@ static int kvm_put_debugregs(X86CPU *cpu) return 0; } + memset(&dbgregs, 0, sizeof(dbgregs)); for (i = 0; i < 4; i++) { dbgregs.db[i] = env->dr[i]; } diff --git a/target/i386/machine.c b/target/i386/machine.c index ce55755f0f..2767b3096d 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -437,6 +437,14 @@ static const VMStateDescription vmstate_exception_info = { } }; +/* Poll control MSR enabled by default */ +static bool poll_control_msr_needed(void *opaque) +{ + X86CPU *cpu = opaque; + + return cpu->env.poll_control_msr != 1; +} + static const VMStateDescription vmstate_steal_time_msr = { .name = "cpu/steal_time_msr", .version_id = 1, @@ -470,6 +478,17 @@ static const VMStateDescription vmstate_pv_eoi_msr = { } }; +static const VMStateDescription vmstate_poll_control_msr = { + .name = "cpu/poll_control_msr", + .version_id = 1, + .minimum_version_id = 1, + .needed = poll_control_msr_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.poll_control_msr, X86CPU), + VMSTATE_END_OF_LIST() + } +}; + static bool fpop_ip_dp_needed(void *opaque) { X86CPU *cpu = opaque; @@ -1354,6 +1373,7 @@ VMStateDescription vmstate_x86_cpu = { &vmstate_async_pf_msr, &vmstate_pv_eoi_msr, &vmstate_steal_time_msr, + &vmstate_poll_control_msr, &vmstate_fpop_ip_dp, &vmstate_msr_tsc_adjust, &vmstate_msr_tscdeadline, diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h index ed05989768..ec1ec745d0 100644 --- a/target/i386/ops_sse.h +++ b/target/i386/ops_sse.h @@ -710,102 +710,134 @@ void helper_cvtsq2sd(CPUX86State *env, ZMMReg *d, uint64_t val) #endif /* float to integer */ + +/* + * x86 mandates that we return the indefinite integer value for the result + * of any float-to-integer conversion that raises the 'invalid' exception. + * Wrap the softfloat functions to get this behaviour. + */ +#define WRAP_FLOATCONV(RETTYPE, FN, FLOATTYPE, INDEFVALUE) \ + static inline RETTYPE x86_##FN(FLOATTYPE a, float_status *s) \ + { \ + int oldflags, newflags; \ + RETTYPE r; \ + \ + oldflags = get_float_exception_flags(s); \ + set_float_exception_flags(0, s); \ + r = FN(a, s); \ + newflags = get_float_exception_flags(s); \ + if (newflags & float_flag_invalid) { \ + r = INDEFVALUE; \ + } \ + set_float_exception_flags(newflags | oldflags, s); \ + return r; \ + } + +WRAP_FLOATCONV(int32_t, float32_to_int32, float32, INT32_MIN) +WRAP_FLOATCONV(int32_t, float32_to_int32_round_to_zero, float32, INT32_MIN) +WRAP_FLOATCONV(int32_t, float64_to_int32, float64, INT32_MIN) +WRAP_FLOATCONV(int32_t, float64_to_int32_round_to_zero, float64, INT32_MIN) +WRAP_FLOATCONV(int64_t, float32_to_int64, float32, INT64_MIN) +WRAP_FLOATCONV(int64_t, float32_to_int64_round_to_zero, float32, INT64_MIN) +WRAP_FLOATCONV(int64_t, float64_to_int64, float64, INT64_MIN) +WRAP_FLOATCONV(int64_t, float64_to_int64_round_to_zero, float64, INT64_MIN) + void helper_cvtps2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s) { - d->ZMM_L(0) = float32_to_int32(s->ZMM_S(0), &env->sse_status); - d->ZMM_L(1) = float32_to_int32(s->ZMM_S(1), &env->sse_status); - d->ZMM_L(2) = float32_to_int32(s->ZMM_S(2), &env->sse_status); - d->ZMM_L(3) = float32_to_int32(s->ZMM_S(3), &env->sse_status); + d->ZMM_L(0) = x86_float32_to_int32(s->ZMM_S(0), &env->sse_status); + d->ZMM_L(1) = x86_float32_to_int32(s->ZMM_S(1), &env->sse_status); + d->ZMM_L(2) = x86_float32_to_int32(s->ZMM_S(2), &env->sse_status); + d->ZMM_L(3) = x86_float32_to_int32(s->ZMM_S(3), &env->sse_status); } void helper_cvtpd2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s) { - d->ZMM_L(0) = float64_to_int32(s->ZMM_D(0), &env->sse_status); - d->ZMM_L(1) = float64_to_int32(s->ZMM_D(1), &env->sse_status); + d->ZMM_L(0) = x86_float64_to_int32(s->ZMM_D(0), &env->sse_status); + d->ZMM_L(1) = x86_float64_to_int32(s->ZMM_D(1), &env->sse_status); d->ZMM_Q(1) = 0; } void helper_cvtps2pi(CPUX86State *env, MMXReg *d, ZMMReg *s) { - d->MMX_L(0) = float32_to_int32(s->ZMM_S(0), &env->sse_status); - d->MMX_L(1) = float32_to_int32(s->ZMM_S(1), &env->sse_status); + d->MMX_L(0) = x86_float32_to_int32(s->ZMM_S(0), &env->sse_status); + d->MMX_L(1) = x86_float32_to_int32(s->ZMM_S(1), &env->sse_status); } void helper_cvtpd2pi(CPUX86State *env, MMXReg *d, ZMMReg *s) { - d->MMX_L(0) = float64_to_int32(s->ZMM_D(0), &env->sse_status); - d->MMX_L(1) = float64_to_int32(s->ZMM_D(1), &env->sse_status); + d->MMX_L(0) = x86_float64_to_int32(s->ZMM_D(0), &env->sse_status); + d->MMX_L(1) = x86_float64_to_int32(s->ZMM_D(1), &env->sse_status); } int32_t helper_cvtss2si(CPUX86State *env, ZMMReg *s) { - return float32_to_int32(s->ZMM_S(0), &env->sse_status); + return x86_float32_to_int32(s->ZMM_S(0), &env->sse_status); } int32_t helper_cvtsd2si(CPUX86State *env, ZMMReg *s) { - return float64_to_int32(s->ZMM_D(0), &env->sse_status); + return x86_float64_to_int32(s->ZMM_D(0), &env->sse_status); } #ifdef TARGET_X86_64 int64_t helper_cvtss2sq(CPUX86State *env, ZMMReg *s) { - return float32_to_int64(s->ZMM_S(0), &env->sse_status); + return x86_float32_to_int64(s->ZMM_S(0), &env->sse_status); } int64_t helper_cvtsd2sq(CPUX86State *env, ZMMReg *s) { - return float64_to_int64(s->ZMM_D(0), &env->sse_status); + return x86_float64_to_int64(s->ZMM_D(0), &env->sse_status); } #endif /* float to integer truncated */ void helper_cvttps2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s) { - d->ZMM_L(0) = float32_to_int32_round_to_zero(s->ZMM_S(0), &env->sse_status); - d->ZMM_L(1) = float32_to_int32_round_to_zero(s->ZMM_S(1), &env->sse_status); - d->ZMM_L(2) = float32_to_int32_round_to_zero(s->ZMM_S(2), &env->sse_status); - d->ZMM_L(3) = float32_to_int32_round_to_zero(s->ZMM_S(3), &env->sse_status); + d->ZMM_L(0) = x86_float32_to_int32_round_to_zero(s->ZMM_S(0), &env->sse_status); + d->ZMM_L(1) = x86_float32_to_int32_round_to_zero(s->ZMM_S(1), &env->sse_status); + d->ZMM_L(2) = x86_float32_to_int32_round_to_zero(s->ZMM_S(2), &env->sse_status); + d->ZMM_L(3) = x86_float32_to_int32_round_to_zero(s->ZMM_S(3), &env->sse_status); } void helper_cvttpd2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s) { - d->ZMM_L(0) = float64_to_int32_round_to_zero(s->ZMM_D(0), &env->sse_status); - d->ZMM_L(1) = float64_to_int32_round_to_zero(s->ZMM_D(1), &env->sse_status); + d->ZMM_L(0) = x86_float64_to_int32_round_to_zero(s->ZMM_D(0), &env->sse_status); + d->ZMM_L(1) = x86_float64_to_int32_round_to_zero(s->ZMM_D(1), &env->sse_status); d->ZMM_Q(1) = 0; } void helper_cvttps2pi(CPUX86State *env, MMXReg *d, ZMMReg *s) { - d->MMX_L(0) = float32_to_int32_round_to_zero(s->ZMM_S(0), &env->sse_status); - d->MMX_L(1) = float32_to_int32_round_to_zero(s->ZMM_S(1), &env->sse_status); + d->MMX_L(0) = x86_float32_to_int32_round_to_zero(s->ZMM_S(0), &env->sse_status); + d->MMX_L(1) = x86_float32_to_int32_round_to_zero(s->ZMM_S(1), &env->sse_status); } void helper_cvttpd2pi(CPUX86State *env, MMXReg *d, ZMMReg *s) { - d->MMX_L(0) = float64_to_int32_round_to_zero(s->ZMM_D(0), &env->sse_status); - d->MMX_L(1) = float64_to_int32_round_to_zero(s->ZMM_D(1), &env->sse_status); + d->MMX_L(0) = x86_float64_to_int32_round_to_zero(s->ZMM_D(0), &env->sse_status); + d->MMX_L(1) = x86_float64_to_int32_round_to_zero(s->ZMM_D(1), &env->sse_status); } int32_t helper_cvttss2si(CPUX86State *env, ZMMReg *s) { - return float32_to_int32_round_to_zero(s->ZMM_S(0), &env->sse_status); + return x86_float32_to_int32_round_to_zero(s->ZMM_S(0), &env->sse_status); } int32_t helper_cvttsd2si(CPUX86State *env, ZMMReg *s) { - return float64_to_int32_round_to_zero(s->ZMM_D(0), &env->sse_status); + return x86_float64_to_int32_round_to_zero(s->ZMM_D(0), &env->sse_status); } #ifdef TARGET_X86_64 int64_t helper_cvttss2sq(CPUX86State *env, ZMMReg *s) { - return float32_to_int64_round_to_zero(s->ZMM_S(0), &env->sse_status); + return x86_float32_to_int64_round_to_zero(s->ZMM_S(0), &env->sse_status); } int64_t helper_cvttsd2sq(CPUX86State *env, ZMMReg *s) { - return float64_to_int64_round_to_zero(s->ZMM_D(0), &env->sse_status); + return x86_float64_to_int64_round_to_zero(s->ZMM_D(0), &env->sse_status); } #endif diff --git a/target/i386/translate.c b/target/i386/translate.c index 03150a86e2..5cd74ad639 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -5381,7 +5381,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_op_mov_reg_v(s, dflag, rm, s->T0); set_cc_op(s, CC_OP_EFLAGS); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; @@ -6443,7 +6442,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_op_mov_reg_v(s, ot, R_EAX, s->T1); gen_bpt_io(s, s->tmp2_i32, ot); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; @@ -6464,7 +6462,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32); gen_bpt_io(s, s->tmp2_i32, ot); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; @@ -6482,7 +6479,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_op_mov_reg_v(s, ot, R_EAX, s->T1); gen_bpt_io(s, s->tmp2_i32, ot); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; @@ -6502,7 +6498,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32); gen_bpt_io(s, s->tmp2_i32, ot); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; @@ -7206,7 +7201,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } gen_helper_rdtsc(cpu_env); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; @@ -7666,7 +7660,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } gen_helper_rdtscp(cpu_env); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); gen_jmp(s, s->pc - s->cs_base); } break; @@ -8036,9 +8029,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_op_mov_v_reg(s, ot, s->T0, rm); gen_helper_write_crN(cpu_env, tcg_const_i32(reg), s->T0); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } gen_jmp_im(s, s->pc - s->cs_base); gen_eob(s); } else { diff --git a/target/lm32/translate.c b/target/lm32/translate.c index b9f2f2c4a7..778cae1e81 100644 --- a/target/lm32/translate.c +++ b/target/lm32/translate.c @@ -885,9 +885,6 @@ static void dec_wcsr(DisasContext *dc) } gen_helper_wcsr_im(cpu_env, cpu_R[dc->r1]); tcg_gen_movi_tl(cpu_pc, dc->pc + 4); - if (tb_cflags(dc->tb) & CF_USE_ICOUNT) { - gen_io_end(); - } dc->is_jmp = DISAS_UPDATE; break; case CSR_IP: @@ -897,9 +894,6 @@ static void dec_wcsr(DisasContext *dc) } gen_helper_wcsr_ip(cpu_env, cpu_R[dc->r1]); tcg_gen_movi_tl(cpu_pc, dc->pc + 4); - if (tb_cflags(dc->tb) & CF_USE_ICOUNT) { - gen_io_end(); - } dc->is_jmp = DISAS_UPDATE; break; case CSR_ICC: @@ -1111,9 +1105,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) && (dc->pc - page_start < TARGET_PAGE_SIZE) && num_insns < max_insns); - if (tb_cflags(tb) & CF_LAST_IO) { - gen_io_end(); - } if (unlikely(cs->singlestep_enabled)) { if (dc->is_jmp == DISAS_NEXT) { diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 9ce65f3bcf..95ff663292 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1724,8 +1724,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) npc = dc->jmp_pc; } - if (tb_cflags(tb) & CF_LAST_IO) - gen_io_end(); /* Force an update if the per-tb cpu state has changed. */ if (dc->is_jmp == DISAS_NEXT && (dc->cpustate_changed || org_flags != dc->tb_flags)) { diff --git a/target/mips/cpu.h b/target/mips/cpu.h index d235117dab..1fd4a180e1 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1,8 +1,6 @@ #ifndef MIPS_CPU_H #define MIPS_CPU_H -#define ALIGNED_ONLY - #include "cpu-qom.h" #include "exec/cpu-defs.h" #include "fpu/softfloat-types.h" diff --git a/target/mips/translate.c b/target/mips/translate.c index 1c50e5a8c4..8ebde6ffee 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -7129,9 +7129,6 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_io_start(); } gen_helper_mfc0_count(arg, cpu_env); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } /* * Break the TB to be able to take timer interrupts immediately * after reading count. DISAS_STOP isn't sufficient, we need to @@ -8296,7 +8293,6 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) /* For simplicity assume that all writes can cause interrupts. */ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); /* * DISAS_STOP isn't sufficient, we need to ensure we break out of * translated code to check for pending interrupts. @@ -8607,9 +8603,6 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_io_start(); } gen_helper_mfc0_count(arg, cpu_env); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } /* * Break the TB to be able to take timer interrupts immediately * after reading count. DISAS_STOP isn't sufficient, we need to @@ -9748,7 +9741,6 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) /* For simplicity assume that all writes can cause interrupts. */ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); /* * DISAS_STOP isn't sufficient, we need to ensure we break out of * translated code to check for pending interrupts. @@ -12817,9 +12809,6 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel) gen_io_start(); } gen_helper_rdhwr_cc(t0, cpu_env); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } gen_store_gpr(t0, rt); /* * Break the TB to be able to take timer interrupts immediately diff --git a/target/nios2/translate.c b/target/nios2/translate.c index 17d8f1877c..e17656e66f 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -862,10 +862,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) !tcg_op_buf_full() && num_insns < max_insns); - if (tb_cflags(tb) & CF_LAST_IO) { - gen_io_end(); - } - /* Indicate where the next block should start */ switch (dc->is_jmp) { case DISAS_NEXT: diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h index a2f202f021..5769fb78a9 100644 --- a/target/ppc/cpu-qom.h +++ b/target/ppc/cpu-qom.h @@ -201,6 +201,7 @@ typedef struct PowerPCCPUClass { typedef struct PPCTimebase { uint64_t guest_timebase; int64_t time_of_the_day_ns; + bool runstate_paused; } PPCTimebase; extern const VMStateDescription vmstate_ppc_timebase; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 4ea33cf696..eaee1a5575 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -591,7 +591,7 @@ enum { #define FPSCR_XE 3 /* Floating-point inexact exception enable */ #define FPSCR_NI 2 /* Floating-point non-IEEE mode */ #define FPSCR_RN1 1 -#define FPSCR_RN 0 /* Floating-point rounding control */ +#define FPSCR_RN0 0 /* Floating-point rounding control */ #define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1) #define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1) #define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1) @@ -614,7 +614,7 @@ enum { #define fpscr_ze (((env->fpscr) >> FPSCR_ZE) & 0x1) #define fpscr_xe (((env->fpscr) >> FPSCR_XE) & 0x1) #define fpscr_ni (((env->fpscr) >> FPSCR_NI) & 0x1) -#define fpscr_rn (((env->fpscr) >> FPSCR_RN) & 0x3) +#define fpscr_rn (((env->fpscr) >> FPSCR_RN0) & 0x3) /* Invalid operation exception summary */ #define fpscr_ix ((env->fpscr) & ((1 << FPSCR_VXSNAN) | (1 << FPSCR_VXISI) | \ (1 << FPSCR_VXIDI) | (1 << FPSCR_VXZDZ) | \ @@ -640,7 +640,7 @@ enum { #define FP_VXZDZ (1ull << FPSCR_VXZDZ) #define FP_VXIMZ (1ull << FPSCR_VXIMZ) #define FP_VXVC (1ull << FPSCR_VXVC) -#define FP_FR (1ull << FSPCR_FR) +#define FP_FR (1ull << FPSCR_FR) #define FP_FI (1ull << FPSCR_FI) #define FP_C (1ull << FPSCR_C) #define FP_FL (1ull << FPSCR_FL) @@ -648,7 +648,7 @@ enum { #define FP_FE (1ull << FPSCR_FE) #define FP_FU (1ull << FPSCR_FU) #define FP_FPCC (FP_FL | FP_FG | FP_FE | FP_FU) -#define FP_FPRF (FP_C | FP_FL | FP_FG | FP_FE | FP_FU) +#define FP_FPRF (FP_C | FP_FPCC) #define FP_VXSOFT (1ull << FPSCR_VXSOFT) #define FP_VXSQRT (1ull << FPSCR_VXSQRT) #define FP_VXCVI (1ull << FPSCR_VXCVI) @@ -659,7 +659,12 @@ enum { #define FP_XE (1ull << FPSCR_XE) #define FP_NI (1ull << FPSCR_NI) #define FP_RN1 (1ull << FPSCR_RN1) -#define FP_RN (1ull << FPSCR_RN) +#define FP_RN0 (1ull << FPSCR_RN0) +#define FP_RN (FP_RN1 | FP_RN0) + +#define FP_MODE FP_RN +#define FP_ENABLES (FP_VE | FP_OE | FP_UE | FP_ZE | FP_XE) +#define FP_STATUS (FP_FR | FP_FI | FP_FPRF) /* the exception bits which can be cleared by mcrfs - includes FX */ #define FP_EX_CLEAR_BITS (FP_FX | FP_OX | FP_UX | FP_ZX | \ @@ -1104,10 +1109,6 @@ struct CPUPPCState { bool resume_as_sreset; #endif - /* Those resources are used only during code translation */ - /* opcode handlers */ - opc_handler_t *opcodes[PPC_CPU_OPCODES_LEN]; - /* Those resources are used only in QEMU core */ target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */ target_ulong hflags_nmsr; /* specific hflags, not coming from MSR */ @@ -1191,6 +1192,10 @@ struct PowerPCCPU { int32_t node_id; /* NUMA node this CPU belongs to */ PPCHash64Options *hash64_opts; + /* Those resources are used only during code translation */ + /* opcode handlers */ + opc_handler_t *opcodes[PPC_CPU_OPCODES_LEN]; + /* Fields related to migration compatibility hacks */ bool pre_2_8_migration; target_ulong mig_msr_mask; @@ -1224,6 +1229,10 @@ struct PPCVirtualHypervisorClass { void (*hpte_set_r)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte1); void (*get_pate)(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry); target_ulong (*encode_hpt_for_kvm_pr)(PPCVirtualHypervisor *vhyp); +#ifndef CONFIG_USER_ONLY + void (*cpu_exec_enter)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu); + void (*cpu_exec_exit)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu); +#endif }; #define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor" @@ -1462,6 +1471,7 @@ typedef PowerPCCPU ArchCPU; #define SPR_MPC_ICTRL (0x09E) #define SPR_MPC_BAR (0x09F) #define SPR_PSPB (0x09F) +#define SPR_DPDES (0x0B0) #define SPR_DAWR (0x0B4) #define SPR_RPR (0x0BA) #define SPR_CIABR (0x0BB) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index f437c88aad..07bc9051b0 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -58,19 +58,35 @@ uint64_t helper_todouble(uint32_t arg) uint64_t ret; if (likely(abs_arg >= 0x00800000)) { - /* Normalized operand, or Inf, or NaN. */ - ret = (uint64_t)extract32(arg, 30, 2) << 62; - ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59; - ret |= (uint64_t)extract32(arg, 0, 30) << 29; + if (unlikely(extract32(arg, 23, 8) == 0xff)) { + /* Inf or NAN. */ + ret = (uint64_t)extract32(arg, 31, 1) << 63; + ret |= (uint64_t)0x7ff << 52; + ret |= (uint64_t)extract32(arg, 0, 23) << 29; + } else { + /* Normalized operand. */ + ret = (uint64_t)extract32(arg, 30, 2) << 62; + ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59; + ret |= (uint64_t)extract32(arg, 0, 30) << 29; + } } else { /* Zero or Denormalized operand. */ ret = (uint64_t)extract32(arg, 31, 1) << 63; if (unlikely(abs_arg != 0)) { - /* Denormalized operand. */ - int shift = clz32(abs_arg) - 9; - int exp = -126 - shift + 1023; + /* + * Denormalized operand. + * Shift fraction so that the msb is in the implicit bit position. + * Thus, shift is in the range [1:23]. + */ + int shift = clz32(abs_arg) - 8; + /* + * The first 3 terms compute the float64 exponent. We then bias + * this result by -1 so that we can swallow the implicit bit below. + */ + int exp = -126 - shift + 1023 - 1; + ret |= (uint64_t)exp << 52; - ret |= abs_arg << (shift + 29); + ret += (uint64_t)abs_arg << (52 - 23 + shift); } } return ret; @@ -403,7 +419,7 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit) if (prev == 1) { switch (bit) { case FPSCR_RN1: - case FPSCR_RN: + case FPSCR_RN0: fpscr_set_rounding_mode(env); break; case FPSCR_VXSNAN: @@ -557,7 +573,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) } break; case FPSCR_RN1: - case FPSCR_RN: + case FPSCR_RN0: fpscr_set_rounding_mode(env); break; default: @@ -2871,10 +2887,14 @@ void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode, uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) { + uint64_t result; + float_status tstat = env->fp_status; set_float_exception_flags(0, &tstat); - return (uint64_t)float64_to_float32(xb, &tstat) << 32; + result = (uint64_t)float64_to_float32(xb, &tstat); + /* hardware replicates result to both words of the doubleword result. */ + return (result << 32) | result; } uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 380c9b1e2a..54ea9b9500 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -193,8 +193,6 @@ DEF_HELPER_2(vprtybw, void, avr, avr) DEF_HELPER_2(vprtybd, void, avr, avr) DEF_HELPER_2(vprtybq, void, avr, avr) DEF_HELPER_3(vsubcuw, void, avr, avr, avr) -DEF_HELPER_2(lvsl, void, avr, tl) -DEF_HELPER_2(lvsr, void, avr, tl) DEF_HELPER_FLAGS_5(vaddsbs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddshs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddsws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) @@ -219,8 +217,6 @@ DEF_HELPER_3(vrlb, void, avr, avr, avr) DEF_HELPER_3(vrlh, void, avr, avr, avr) DEF_HELPER_3(vrlw, void, avr, avr, avr) DEF_HELPER_3(vrld, void, avr, avr, avr) -DEF_HELPER_3(vsl, void, avr, avr, avr) -DEF_HELPER_3(vsr, void, avr, avr, avr) DEF_HELPER_4(vsldoi, void, avr, avr, avr, i32) DEF_HELPER_3(vextractub, void, avr, avr, i32) DEF_HELPER_3(vextractuh, void, avr, avr, i32) @@ -314,8 +310,6 @@ DEF_HELPER_4(vctsxs, void, env, avr, avr, i32) DEF_HELPER_2(vclzb, void, avr, avr) DEF_HELPER_2(vclzh, void, avr, avr) -DEF_HELPER_2(vclzw, void, avr, avr) -DEF_HELPER_2(vclzd, void, avr, avr) DEF_HELPER_2(vctzb, void, avr, avr) DEF_HELPER_2(vctzh, void, avr, avr) DEF_HELPER_2(vctzw, void, avr, avr) @@ -328,7 +322,6 @@ DEF_HELPER_1(vclzlsbb, tl, avr) DEF_HELPER_1(vctzlsbb, tl, avr) DEF_HELPER_3(vbpermd, void, avr, avr, avr) DEF_HELPER_3(vbpermq, void, avr, avr, avr) -DEF_HELPER_2(vgbbd, void, avr, avr) DEF_HELPER_3(vpmsumb, void, avr, avr, avr) DEF_HELPER_3(vpmsumh, void, avr, avr, avr) DEF_HELPER_3(vpmsumw, void, avr, avr, avr) diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 8f037af956..46deb57a34 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -459,24 +459,6 @@ SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX) #undef SATCVT #undef SATCVTU -void helper_lvsl(ppc_avr_t *r, target_ulong sh) -{ - int i, j = (sh & 0xf); - - for (i = 0; i < ARRAY_SIZE(r->u8); i++) { - r->VsrB(i) = j++; - } -} - -void helper_lvsr(ppc_avr_t *r, target_ulong sh) -{ - int i, j = 0x10 - (sh & 0xf); - - for (i = 0; i < ARRAY_SIZE(r->u8); i++) { - r->VsrB(i) = j++; - } -} - void helper_mtvscr(CPUPPCState *env, uint32_t vscr) { env->vscr = vscr & ~(1u << VSCR_SAT); @@ -1205,282 +1187,6 @@ void helper_vbpermq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) #undef VBPERMQ_INDEX #undef VBPERMQ_DW -static const uint64_t VGBBD_MASKS[256] = { - 0x0000000000000000ull, /* 00 */ - 0x0000000000000080ull, /* 01 */ - 0x0000000000008000ull, /* 02 */ - 0x0000000000008080ull, /* 03 */ - 0x0000000000800000ull, /* 04 */ - 0x0000000000800080ull, /* 05 */ - 0x0000000000808000ull, /* 06 */ - 0x0000000000808080ull, /* 07 */ - 0x0000000080000000ull, /* 08 */ - 0x0000000080000080ull, /* 09 */ - 0x0000000080008000ull, /* 0A */ - 0x0000000080008080ull, /* 0B */ - 0x0000000080800000ull, /* 0C */ - 0x0000000080800080ull, /* 0D */ - 0x0000000080808000ull, /* 0E */ - 0x0000000080808080ull, /* 0F */ - 0x0000008000000000ull, /* 10 */ - 0x0000008000000080ull, /* 11 */ - 0x0000008000008000ull, /* 12 */ - 0x0000008000008080ull, /* 13 */ - 0x0000008000800000ull, /* 14 */ - 0x0000008000800080ull, /* 15 */ - 0x0000008000808000ull, /* 16 */ - 0x0000008000808080ull, /* 17 */ - 0x0000008080000000ull, /* 18 */ - 0x0000008080000080ull, /* 19 */ - 0x0000008080008000ull, /* 1A */ - 0x0000008080008080ull, /* 1B */ - 0x0000008080800000ull, /* 1C */ - 0x0000008080800080ull, /* 1D */ - 0x0000008080808000ull, /* 1E */ - 0x0000008080808080ull, /* 1F */ - 0x0000800000000000ull, /* 20 */ - 0x0000800000000080ull, /* 21 */ - 0x0000800000008000ull, /* 22 */ - 0x0000800000008080ull, /* 23 */ - 0x0000800000800000ull, /* 24 */ - 0x0000800000800080ull, /* 25 */ - 0x0000800000808000ull, /* 26 */ - 0x0000800000808080ull, /* 27 */ - 0x0000800080000000ull, /* 28 */ - 0x0000800080000080ull, /* 29 */ - 0x0000800080008000ull, /* 2A */ - 0x0000800080008080ull, /* 2B */ - 0x0000800080800000ull, /* 2C */ - 0x0000800080800080ull, /* 2D */ - 0x0000800080808000ull, /* 2E */ - 0x0000800080808080ull, /* 2F */ - 0x0000808000000000ull, /* 30 */ - 0x0000808000000080ull, /* 31 */ - 0x0000808000008000ull, /* 32 */ - 0x0000808000008080ull, /* 33 */ - 0x0000808000800000ull, /* 34 */ - 0x0000808000800080ull, /* 35 */ - 0x0000808000808000ull, /* 36 */ - 0x0000808000808080ull, /* 37 */ - 0x0000808080000000ull, /* 38 */ - 0x0000808080000080ull, /* 39 */ - 0x0000808080008000ull, /* 3A */ - 0x0000808080008080ull, /* 3B */ - 0x0000808080800000ull, /* 3C */ - 0x0000808080800080ull, /* 3D */ - 0x0000808080808000ull, /* 3E */ - 0x0000808080808080ull, /* 3F */ - 0x0080000000000000ull, /* 40 */ - 0x0080000000000080ull, /* 41 */ - 0x0080000000008000ull, /* 42 */ - 0x0080000000008080ull, /* 43 */ - 0x0080000000800000ull, /* 44 */ - 0x0080000000800080ull, /* 45 */ - 0x0080000000808000ull, /* 46 */ - 0x0080000000808080ull, /* 47 */ - 0x0080000080000000ull, /* 48 */ - 0x0080000080000080ull, /* 49 */ - 0x0080000080008000ull, /* 4A */ - 0x0080000080008080ull, /* 4B */ - 0x0080000080800000ull, /* 4C */ - 0x0080000080800080ull, /* 4D */ - 0x0080000080808000ull, /* 4E */ - 0x0080000080808080ull, /* 4F */ - 0x0080008000000000ull, /* 50 */ - 0x0080008000000080ull, /* 51 */ - 0x0080008000008000ull, /* 52 */ - 0x0080008000008080ull, /* 53 */ - 0x0080008000800000ull, /* 54 */ - 0x0080008000800080ull, /* 55 */ - 0x0080008000808000ull, /* 56 */ - 0x0080008000808080ull, /* 57 */ - 0x0080008080000000ull, /* 58 */ - 0x0080008080000080ull, /* 59 */ - 0x0080008080008000ull, /* 5A */ - 0x0080008080008080ull, /* 5B */ - 0x0080008080800000ull, /* 5C */ - 0x0080008080800080ull, /* 5D */ - 0x0080008080808000ull, /* 5E */ - 0x0080008080808080ull, /* 5F */ - 0x0080800000000000ull, /* 60 */ - 0x0080800000000080ull, /* 61 */ - 0x0080800000008000ull, /* 62 */ - 0x0080800000008080ull, /* 63 */ - 0x0080800000800000ull, /* 64 */ - 0x0080800000800080ull, /* 65 */ - 0x0080800000808000ull, /* 66 */ - 0x0080800000808080ull, /* 67 */ - 0x0080800080000000ull, /* 68 */ - 0x0080800080000080ull, /* 69 */ - 0x0080800080008000ull, /* 6A */ - 0x0080800080008080ull, /* 6B */ - 0x0080800080800000ull, /* 6C */ - 0x0080800080800080ull, /* 6D */ - 0x0080800080808000ull, /* 6E */ - 0x0080800080808080ull, /* 6F */ - 0x0080808000000000ull, /* 70 */ - 0x0080808000000080ull, /* 71 */ - 0x0080808000008000ull, /* 72 */ - 0x0080808000008080ull, /* 73 */ - 0x0080808000800000ull, /* 74 */ - 0x0080808000800080ull, /* 75 */ - 0x0080808000808000ull, /* 76 */ - 0x0080808000808080ull, /* 77 */ - 0x0080808080000000ull, /* 78 */ - 0x0080808080000080ull, /* 79 */ - 0x0080808080008000ull, /* 7A */ - 0x0080808080008080ull, /* 7B */ - 0x0080808080800000ull, /* 7C */ - 0x0080808080800080ull, /* 7D */ - 0x0080808080808000ull, /* 7E */ - 0x0080808080808080ull, /* 7F */ - 0x8000000000000000ull, /* 80 */ - 0x8000000000000080ull, /* 81 */ - 0x8000000000008000ull, /* 82 */ - 0x8000000000008080ull, /* 83 */ - 0x8000000000800000ull, /* 84 */ - 0x8000000000800080ull, /* 85 */ - 0x8000000000808000ull, /* 86 */ - 0x8000000000808080ull, /* 87 */ - 0x8000000080000000ull, /* 88 */ - 0x8000000080000080ull, /* 89 */ - 0x8000000080008000ull, /* 8A */ - 0x8000000080008080ull, /* 8B */ - 0x8000000080800000ull, /* 8C */ - 0x8000000080800080ull, /* 8D */ - 0x8000000080808000ull, /* 8E */ - 0x8000000080808080ull, /* 8F */ - 0x8000008000000000ull, /* 90 */ - 0x8000008000000080ull, /* 91 */ - 0x8000008000008000ull, /* 92 */ - 0x8000008000008080ull, /* 93 */ - 0x8000008000800000ull, /* 94 */ - 0x8000008000800080ull, /* 95 */ - 0x8000008000808000ull, /* 96 */ - 0x8000008000808080ull, /* 97 */ - 0x8000008080000000ull, /* 98 */ - 0x8000008080000080ull, /* 99 */ - 0x8000008080008000ull, /* 9A */ - 0x8000008080008080ull, /* 9B */ - 0x8000008080800000ull, /* 9C */ - 0x8000008080800080ull, /* 9D */ - 0x8000008080808000ull, /* 9E */ - 0x8000008080808080ull, /* 9F */ - 0x8000800000000000ull, /* A0 */ - 0x8000800000000080ull, /* A1 */ - 0x8000800000008000ull, /* A2 */ - 0x8000800000008080ull, /* A3 */ - 0x8000800000800000ull, /* A4 */ - 0x8000800000800080ull, /* A5 */ - 0x8000800000808000ull, /* A6 */ - 0x8000800000808080ull, /* A7 */ - 0x8000800080000000ull, /* A8 */ - 0x8000800080000080ull, /* A9 */ - 0x8000800080008000ull, /* AA */ - 0x8000800080008080ull, /* AB */ - 0x8000800080800000ull, /* AC */ - 0x8000800080800080ull, /* AD */ - 0x8000800080808000ull, /* AE */ - 0x8000800080808080ull, /* AF */ - 0x8000808000000000ull, /* B0 */ - 0x8000808000000080ull, /* B1 */ - 0x8000808000008000ull, /* B2 */ - 0x8000808000008080ull, /* B3 */ - 0x8000808000800000ull, /* B4 */ - 0x8000808000800080ull, /* B5 */ - 0x8000808000808000ull, /* B6 */ - 0x8000808000808080ull, /* B7 */ - 0x8000808080000000ull, /* B8 */ - 0x8000808080000080ull, /* B9 */ - 0x8000808080008000ull, /* BA */ - 0x8000808080008080ull, /* BB */ - 0x8000808080800000ull, /* BC */ - 0x8000808080800080ull, /* BD */ - 0x8000808080808000ull, /* BE */ - 0x8000808080808080ull, /* BF */ - 0x8080000000000000ull, /* C0 */ - 0x8080000000000080ull, /* C1 */ - 0x8080000000008000ull, /* C2 */ - 0x8080000000008080ull, /* C3 */ - 0x8080000000800000ull, /* C4 */ - 0x8080000000800080ull, /* C5 */ - 0x8080000000808000ull, /* C6 */ - 0x8080000000808080ull, /* C7 */ - 0x8080000080000000ull, /* C8 */ - 0x8080000080000080ull, /* C9 */ - 0x8080000080008000ull, /* CA */ - 0x8080000080008080ull, /* CB */ - 0x8080000080800000ull, /* CC */ - 0x8080000080800080ull, /* CD */ - 0x8080000080808000ull, /* CE */ - 0x8080000080808080ull, /* CF */ - 0x8080008000000000ull, /* D0 */ - 0x8080008000000080ull, /* D1 */ - 0x8080008000008000ull, /* D2 */ - 0x8080008000008080ull, /* D3 */ - 0x8080008000800000ull, /* D4 */ - 0x8080008000800080ull, /* D5 */ - 0x8080008000808000ull, /* D6 */ - 0x8080008000808080ull, /* D7 */ - 0x8080008080000000ull, /* D8 */ - 0x8080008080000080ull, /* D9 */ - 0x8080008080008000ull, /* DA */ - 0x8080008080008080ull, /* DB */ - 0x8080008080800000ull, /* DC */ - 0x8080008080800080ull, /* DD */ - 0x8080008080808000ull, /* DE */ - 0x8080008080808080ull, /* DF */ - 0x8080800000000000ull, /* E0 */ - 0x8080800000000080ull, /* E1 */ - 0x8080800000008000ull, /* E2 */ - 0x8080800000008080ull, /* E3 */ - 0x8080800000800000ull, /* E4 */ - 0x8080800000800080ull, /* E5 */ - 0x8080800000808000ull, /* E6 */ - 0x8080800000808080ull, /* E7 */ - 0x8080800080000000ull, /* E8 */ - 0x8080800080000080ull, /* E9 */ - 0x8080800080008000ull, /* EA */ - 0x8080800080008080ull, /* EB */ - 0x8080800080800000ull, /* EC */ - 0x8080800080800080ull, /* ED */ - 0x8080800080808000ull, /* EE */ - 0x8080800080808080ull, /* EF */ - 0x8080808000000000ull, /* F0 */ - 0x8080808000000080ull, /* F1 */ - 0x8080808000008000ull, /* F2 */ - 0x8080808000008080ull, /* F3 */ - 0x8080808000800000ull, /* F4 */ - 0x8080808000800080ull, /* F5 */ - 0x8080808000808000ull, /* F6 */ - 0x8080808000808080ull, /* F7 */ - 0x8080808080000000ull, /* F8 */ - 0x8080808080000080ull, /* F9 */ - 0x8080808080008000ull, /* FA */ - 0x8080808080008080ull, /* FB */ - 0x8080808080800000ull, /* FC */ - 0x8080808080800080ull, /* FD */ - 0x8080808080808000ull, /* FE */ - 0x8080808080808080ull, /* FF */ -}; - -void helper_vgbbd(ppc_avr_t *r, ppc_avr_t *b) -{ - int i; - uint64_t t[2] = { 0, 0 }; - - VECTOR_FOR_INORDER_I(i, u8) { -#if defined(HOST_WORDS_BIGENDIAN) - t[i >> 3] |= VGBBD_MASKS[b->u8[i]] >> (i & 7); -#else - t[i >> 3] |= VGBBD_MASKS[b->u8[i]] >> (7 - (i & 7)); -#endif - } - - r->u64[0] = t[0]; - r->u64[1] = t[1]; -} - #define PMSUM(name, srcfld, trgfld, trgtyp) \ void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ @@ -1758,41 +1464,6 @@ VEXTU_X_DO(vextuhrx, 16, 0) VEXTU_X_DO(vextuwrx, 32, 0) #undef VEXTU_X_DO -/* - * The specification says that the results are undefined if all of the - * shift counts are not identical. We check to make sure that they - * are to conform to what real hardware appears to do. - */ -#define VSHIFT(suffix, leftp) \ - void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int shift = b->VsrB(15) & 0x7; \ - int doit = 1; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \ - doit = doit && ((b->u8[i] & 0x7) == shift); \ - } \ - if (doit) { \ - if (shift == 0) { \ - *r = *a; \ - } else if (leftp) { \ - uint64_t carry = a->VsrD(1) >> (64 - shift); \ - \ - r->VsrD(0) = (a->VsrD(0) << shift) | carry; \ - r->VsrD(1) = a->VsrD(1) << shift; \ - } else { \ - uint64_t carry = a->VsrD(0) << (64 - shift); \ - \ - r->VsrD(1) = (a->VsrD(1) >> shift) | carry; \ - r->VsrD(0) = a->VsrD(0) >> shift; \ - } \ - } \ - } -VSHIFT(l, 1) -VSHIFT(r, 0) -#undef VSHIFT - void helper_vslv(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i; @@ -2148,18 +1819,12 @@ VUPK(lsw, s64, s32, UPKLO) #define clzb(v) ((v) ? clz32((uint32_t)(v) << 24) : 8) #define clzh(v) ((v) ? clz32((uint32_t)(v) << 16) : 16) -#define clzw(v) clz32((v)) -#define clzd(v) clz64((v)) VGENERIC_DO(clzb, u8) VGENERIC_DO(clzh, u16) -VGENERIC_DO(clzw, u32) -VGENERIC_DO(clzd, u64) #undef clzb #undef clzh -#undef clzw -#undef clzd #define ctzb(v) ((v) ? ctz32(v) : 8) #define ctzh(v) ((v) ? ctz32(v) : 16) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 6162a903fa..8c5b1f25cc 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -58,7 +58,6 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { }; static int cap_interrupt_unset; -static int cap_interrupt_level; static int cap_segstate; static int cap_booke_sregs; static int cap_ppc_smt; @@ -90,25 +89,6 @@ static int cap_large_decr; static uint32_t debug_inst_opcode; /* - * XXX We have a race condition where we actually have a level triggered - * interrupt, but the infrastructure can't expose that yet, so the guest - * takes but ignores it, goes to sleep and never gets notified that there's - * still an interrupt pending. - * - * As a quick workaround, let's just wake up again 20 ms after we injected - * an interrupt. That way we can assure that we're always reinjecting - * interrupts in case the guest swallowed them. - */ -static QEMUTimer *idle_timer; - -static void kvm_kick_cpu(void *opaque) -{ - PowerPCCPU *cpu = opaque; - - qemu_cpu_kick(CPU(cpu)); -} - -/* * Check whether we are running with KVM-PR (instead of KVM-HV). This * should only be used for fallback tests - generally we should use * explicit capabilities for the features we want, rather than @@ -127,7 +107,6 @@ static int kvmppc_get_dec_bits(void); int kvm_arch_init(MachineState *ms, KVMState *s) { cap_interrupt_unset = kvm_check_extension(s, KVM_CAP_PPC_UNSET_IRQ); - cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL); cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE); cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); cap_ppc_smt_possible = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT_POSSIBLE); @@ -163,9 +142,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s) */ cap_ppc_pvr_compat = false; - if (!cap_interrupt_level) { - fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " - "VM to stall at times!\n"); + if (!kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL)) { + error_report("KVM: Host kernel doesn't have level irq capability"); + exit(1); } kvm_ppc_register_host_cpu_type(ms); @@ -493,8 +472,6 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } - idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, kvm_kick_cpu, cpu); - switch (cenv->mmu_model) { case POWERPC_MMU_BOOKE206: /* This target supports access to KVM's guest TLB */ @@ -1334,7 +1311,7 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level) return 0; } - if (!kvm_enabled() || !cap_interrupt_unset || !cap_interrupt_level) { + if (!kvm_enabled() || !cap_interrupt_unset) { return 0; } @@ -1351,49 +1328,7 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level) void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - int r; - unsigned irq; - - qemu_mutex_lock_iothread(); - - /* - * PowerPC QEMU tracks the various core input pins (interrupt, - * critical interrupt, reset, etc) in PPC-specific - * env->irq_input_state. - */ - if (!cap_interrupt_level && - run->ready_for_interrupt_injection && - (cs->interrupt_request & CPU_INTERRUPT_HARD) && - (env->irq_input_state & (1 << PPC_INPUT_INT))) - { - /* - * For now KVM disregards the 'irq' argument. However, in the - * future KVM could cache it in-kernel to avoid a heavyweight - * exit when reading the UIC. - */ - irq = KVM_INTERRUPT_SET; - - trace_kvm_injected_interrupt(irq); - r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &irq); - if (r < 0) { - printf("cpu %d fail inject %x\n", cs->cpu_index, irq); - } - - /* Always wake up soon in case the interrupt was level based */ - timer_mod(idle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - (NANOSECONDS_PER_SECOND / 50)); - } - - /* - * We don't know if there are more interrupts pending after - * this. However, the guest will return to userspace in the course - * of handling this one anyways, so we will get a chance to - * deliver the rest. - */ - - qemu_mutex_unlock_iothread(); + return; } MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 9f9553afb4..0cf3f979e2 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -1861,7 +1861,6 @@ static void gen_darn(DisasContext *ctx) gen_helper_darn64(cpu_gpr[rD(ctx->opcode)]); } if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); gen_stop_exception(ctx); } } @@ -3991,9 +3990,6 @@ static void gen_rfi(DisasContext *ctx) gen_update_cfar(ctx, ctx->base.pc_next - 4); gen_helper_rfi(cpu_env); gen_sync_exception(ctx); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } #endif } @@ -4011,9 +4007,6 @@ static void gen_rfid(DisasContext *ctx) gen_update_cfar(ctx, ctx->base.pc_next - 4); gen_helper_rfid(cpu_env); gen_sync_exception(ctx); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } #endif } @@ -4389,9 +4382,6 @@ static void gen_mtmsrd(DisasContext *ctx) /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ gen_stop_exception(ctx); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } } #endif /* !defined(CONFIG_USER_ONLY) */ } @@ -4429,9 +4419,6 @@ static void gen_mtmsr(DisasContext *ctx) tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]); #endif gen_helper_store_msr(cpu_env, msr); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } tcg_temp_free(msr); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ @@ -7858,6 +7845,7 @@ static bool ppc_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); + PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = cs->env_ptr; opc_handler_t **table, *handler; @@ -7875,7 +7863,7 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) opc3(ctx->opcode), opc4(ctx->opcode), ctx->le_mode ? "little" : "big"); ctx->base.pc_next += 4; - table = env->opcodes; + table = cpu->opcodes; handler = table[opc1(ctx->opcode)]; if (is_indirect_opcode(handler)) { table = ind_table(handler); diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c index 9dcff947c0..7cd9d8db05 100644 --- a/target/ppc/translate/fp-impl.inc.c +++ b/target/ppc/translate/fp-impl.inc.c @@ -617,6 +617,28 @@ static void gen_mffs(DisasContext *ctx) tcg_temp_free_i64(t0); } +/* mffsl */ +static void gen_mffsl(DisasContext *ctx) +{ + TCGv_i64 t0; + + if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { + return gen_mffs(ctx); + } + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + t0 = tcg_temp_new_i64(); + gen_reset_fpstatus(); + tcg_gen_extu_tl_i64(t0, cpu_fpscr); + /* Mask everything except mode, status, and enables. */ + tcg_gen_andi_i64(t0, t0, FP_MODE | FP_STATUS | FP_ENABLES); + set_fpr(rD(ctx->opcode), t0); + tcg_temp_free_i64(t0); +} + /* mtfsb0 */ static void gen_mtfsb0(DisasContext *ctx) { diff --git a/target/ppc/translate/fp-ops.inc.c b/target/ppc/translate/fp-ops.inc.c index 621f6bfe0c..88ebc2526c 100644 --- a/target/ppc/translate/fp-ops.inc.c +++ b/target/ppc/translate/fp-ops.inc.c @@ -104,7 +104,9 @@ GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), -GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT), +GEN_HANDLER_E_2(mffs, 0x3F, 0x07, 0x12, 0x00, 0x00000000, PPC_FLOAT, PPC_NONE), +GEN_HANDLER_E_2(mffsl, 0x3F, 0x07, 0x12, 0x18, 0x00000000, PPC_FLOAT, + PPC2_ISA300), GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT), diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c index 663275b729..0d71c10428 100644 --- a/target/ppc/translate/vmx-impl.inc.c +++ b/target/ppc/translate/vmx-impl.inc.c @@ -142,38 +142,6 @@ GEN_VR_STVE(bx, 0x07, 0x04, 1); GEN_VR_STVE(hx, 0x07, 0x05, 2); GEN_VR_STVE(wx, 0x07, 0x06, 4); -static void gen_lvsl(DisasContext *ctx) -{ - TCGv_ptr rd; - TCGv EA; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - rd = gen_avr_ptr(rD(ctx->opcode)); - gen_helper_lvsl(rd, EA); - tcg_temp_free(EA); - tcg_temp_free_ptr(rd); -} - -static void gen_lvsr(DisasContext *ctx) -{ - TCGv_ptr rd; - TCGv EA; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - rd = gen_avr_ptr(rD(ctx->opcode)); - gen_helper_lvsr(rd, EA); - tcg_temp_free(EA); - tcg_temp_free_ptr(rd); -} - static void gen_mfvscr(DisasContext *ctx) { TCGv_i32 t; @@ -316,6 +284,16 @@ static void glue(gen_, name)(DisasContext *ctx) \ tcg_temp_free_ptr(rd); \ } +#define GEN_VXFORM_TRANS(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + trans_##name(ctx); \ +} + #define GEN_VXFORM_ENV(name, opc2, opc3) \ static void glue(gen_, name)(DisasContext *ctx) \ { \ @@ -515,6 +493,307 @@ static void gen_vmrgow(DisasContext *ctx) tcg_temp_free_i64(avr); } +/* + * lvsl VRT,RA,RB - Load Vector for Shift Left + * + * Let the EA be the sum (rA|0)+(rB). Let sh=EA[28–31]. + * Let X be the 32-byte value 0x00 || 0x01 || 0x02 || ... || 0x1E || 0x1F. + * Bytes sh:sh+15 of X are placed into vD. + */ +static void trans_lvsl(DisasContext *ctx) +{ + int VT = rD(ctx->opcode); + TCGv_i64 result = tcg_temp_new_i64(); + TCGv_i64 sh = tcg_temp_new_i64(); + TCGv EA = tcg_temp_new(); + + /* Get sh(from description) by anding EA with 0xf. */ + gen_addr_reg_index(ctx, EA); + tcg_gen_extu_tl_i64(sh, EA); + tcg_gen_andi_i64(sh, sh, 0xfULL); + + /* + * Create bytes sh:sh+7 of X(from description) and place them in + * higher doubleword of vD. + */ + tcg_gen_muli_i64(sh, sh, 0x0101010101010101ULL); + tcg_gen_addi_i64(result, sh, 0x0001020304050607ull); + set_avr64(VT, result, true); + /* + * Create bytes sh+8:sh+15 of X(from description) and place them in + * lower doubleword of vD. + */ + tcg_gen_addi_i64(result, sh, 0x08090a0b0c0d0e0fULL); + set_avr64(VT, result, false); + + tcg_temp_free_i64(result); + tcg_temp_free_i64(sh); + tcg_temp_free(EA); +} + +/* + * lvsr VRT,RA,RB - Load Vector for Shift Right + * + * Let the EA be the sum (rA|0)+(rB). Let sh=EA[28–31]. + * Let X be the 32-byte value 0x00 || 0x01 || 0x02 || ... || 0x1E || 0x1F. + * Bytes (16-sh):(31-sh) of X are placed into vD. + */ +static void trans_lvsr(DisasContext *ctx) +{ + int VT = rD(ctx->opcode); + TCGv_i64 result = tcg_temp_new_i64(); + TCGv_i64 sh = tcg_temp_new_i64(); + TCGv EA = tcg_temp_new(); + + + /* Get sh(from description) by anding EA with 0xf. */ + gen_addr_reg_index(ctx, EA); + tcg_gen_extu_tl_i64(sh, EA); + tcg_gen_andi_i64(sh, sh, 0xfULL); + + /* + * Create bytes (16-sh):(23-sh) of X(from description) and place them in + * higher doubleword of vD. + */ + tcg_gen_muli_i64(sh, sh, 0x0101010101010101ULL); + tcg_gen_subfi_i64(result, 0x1011121314151617ULL, sh); + set_avr64(VT, result, true); + /* + * Create bytes (24-sh):(32-sh) of X(from description) and place them in + * lower doubleword of vD. + */ + tcg_gen_subfi_i64(result, 0x18191a1b1c1d1e1fULL, sh); + set_avr64(VT, result, false); + + tcg_temp_free_i64(result); + tcg_temp_free_i64(sh); + tcg_temp_free(EA); +} + +/* + * vsl VRT,VRA,VRB - Vector Shift Left + * + * Shifting left 128 bit value of vA by value specified in bits 125-127 of vB. + * Lowest 3 bits in each byte element of register vB must be identical or + * result is undefined. + */ +static void trans_vsl(DisasContext *ctx) +{ + int VT = rD(ctx->opcode); + int VA = rA(ctx->opcode); + int VB = rB(ctx->opcode); + TCGv_i64 avrA = tcg_temp_new_i64(); + TCGv_i64 avrB = tcg_temp_new_i64(); + TCGv_i64 sh = tcg_temp_new_i64(); + TCGv_i64 shifted = tcg_temp_new_i64(); + TCGv_i64 tmp = tcg_temp_new_i64(); + + /* Place bits 125-127 of vB in sh. */ + get_avr64(avrB, VB, false); + tcg_gen_andi_i64(sh, avrB, 0x07ULL); + + /* + * Save highest sh bits of lower doubleword element of vA in variable + * shifted and perform shift on lower doubleword. + */ + get_avr64(avrA, VA, false); + tcg_gen_subfi_i64(tmp, 64, sh); + tcg_gen_shr_i64(shifted, avrA, tmp); + tcg_gen_andi_i64(shifted, shifted, 0x7fULL); + tcg_gen_shl_i64(avrA, avrA, sh); + set_avr64(VT, avrA, false); + + /* + * Perform shift on higher doubleword element of vA and replace lowest + * sh bits with shifted. + */ + get_avr64(avrA, VA, true); + tcg_gen_shl_i64(avrA, avrA, sh); + tcg_gen_or_i64(avrA, avrA, shifted); + set_avr64(VT, avrA, true); + + tcg_temp_free_i64(avrA); + tcg_temp_free_i64(avrB); + tcg_temp_free_i64(sh); + tcg_temp_free_i64(shifted); + tcg_temp_free_i64(tmp); +} + +/* + * vsr VRT,VRA,VRB - Vector Shift Right + * + * Shifting right 128 bit value of vA by value specified in bits 125-127 of vB. + * Lowest 3 bits in each byte element of register vB must be identical or + * result is undefined. + */ +static void trans_vsr(DisasContext *ctx) +{ + int VT = rD(ctx->opcode); + int VA = rA(ctx->opcode); + int VB = rB(ctx->opcode); + TCGv_i64 avrA = tcg_temp_new_i64(); + TCGv_i64 avrB = tcg_temp_new_i64(); + TCGv_i64 sh = tcg_temp_new_i64(); + TCGv_i64 shifted = tcg_temp_new_i64(); + TCGv_i64 tmp = tcg_temp_new_i64(); + + /* Place bits 125-127 of vB in sh. */ + get_avr64(avrB, VB, false); + tcg_gen_andi_i64(sh, avrB, 0x07ULL); + + /* + * Save lowest sh bits of higher doubleword element of vA in variable + * shifted and perform shift on higher doubleword. + */ + get_avr64(avrA, VA, true); + tcg_gen_subfi_i64(tmp, 64, sh); + tcg_gen_shl_i64(shifted, avrA, tmp); + tcg_gen_andi_i64(shifted, shifted, 0xfe00000000000000ULL); + tcg_gen_shr_i64(avrA, avrA, sh); + set_avr64(VT, avrA, true); + /* + * Perform shift on lower doubleword element of vA and replace highest + * sh bits with shifted. + */ + get_avr64(avrA, VA, false); + tcg_gen_shr_i64(avrA, avrA, sh); + tcg_gen_or_i64(avrA, avrA, shifted); + set_avr64(VT, avrA, false); + + tcg_temp_free_i64(avrA); + tcg_temp_free_i64(avrB); + tcg_temp_free_i64(sh); + tcg_temp_free_i64(shifted); + tcg_temp_free_i64(tmp); +} + +/* + * vgbbd VRT,VRB - Vector Gather Bits by Bytes by Doubleword + * + * All ith bits (i in range 1 to 8) of each byte of doubleword element in source + * register are concatenated and placed into ith byte of appropriate doubleword + * element in destination register. + * + * Following solution is done for both doubleword elements of source register + * in parallel, in order to reduce the number of instructions needed(that's why + * arrays are used): + * First, both doubleword elements of source register vB are placed in + * appropriate element of array avr. Bits are gathered in 2x8 iterations(2 for + * loops). In first iteration bit 1 of byte 1, bit 2 of byte 2,... bit 8 of + * byte 8 are in their final spots so avr[i], i={0,1} can be and-ed with + * tcg_mask. For every following iteration, both avr[i] and tcg_mask variables + * have to be shifted right for 7 and 8 places, respectively, in order to get + * bit 1 of byte 2, bit 2 of byte 3.. bit 7 of byte 8 in their final spots so + * shifted avr values(saved in tmp) can be and-ed with new value of tcg_mask... + * After first 8 iteration(first loop), all the first bits are in their final + * places, all second bits but second bit from eight byte are in their places... + * only 1 eight bit from eight byte is in it's place). In second loop we do all + * operations symmetrically, in order to get other half of bits in their final + * spots. Results for first and second doubleword elements are saved in + * result[0] and result[1] respectively. In the end those results are saved in + * appropriate doubleword element of destination register vD. + */ +static void trans_vgbbd(DisasContext *ctx) +{ + int VT = rD(ctx->opcode); + int VB = rB(ctx->opcode); + TCGv_i64 tmp = tcg_temp_new_i64(); + uint64_t mask = 0x8040201008040201ULL; + int i, j; + + TCGv_i64 result[2]; + result[0] = tcg_temp_new_i64(); + result[1] = tcg_temp_new_i64(); + TCGv_i64 avr[2]; + avr[0] = tcg_temp_new_i64(); + avr[1] = tcg_temp_new_i64(); + TCGv_i64 tcg_mask = tcg_temp_new_i64(); + + tcg_gen_movi_i64(tcg_mask, mask); + for (j = 0; j < 2; j++) { + get_avr64(avr[j], VB, j); + tcg_gen_and_i64(result[j], avr[j], tcg_mask); + } + for (i = 1; i < 8; i++) { + tcg_gen_movi_i64(tcg_mask, mask >> (i * 8)); + for (j = 0; j < 2; j++) { + tcg_gen_shri_i64(tmp, avr[j], i * 7); + tcg_gen_and_i64(tmp, tmp, tcg_mask); + tcg_gen_or_i64(result[j], result[j], tmp); + } + } + for (i = 1; i < 8; i++) { + tcg_gen_movi_i64(tcg_mask, mask << (i * 8)); + for (j = 0; j < 2; j++) { + tcg_gen_shli_i64(tmp, avr[j], i * 7); + tcg_gen_and_i64(tmp, tmp, tcg_mask); + tcg_gen_or_i64(result[j], result[j], tmp); + } + } + for (j = 0; j < 2; j++) { + set_avr64(VT, result[j], j); + } + + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(tcg_mask); + tcg_temp_free_i64(result[0]); + tcg_temp_free_i64(result[1]); + tcg_temp_free_i64(avr[0]); + tcg_temp_free_i64(avr[1]); +} + +/* + * vclzw VRT,VRB - Vector Count Leading Zeros Word + * + * Counting the number of leading zero bits of each word element in source + * register and placing result in appropriate word element of destination + * register. + */ +static void trans_vclzw(DisasContext *ctx) +{ + int VT = rD(ctx->opcode); + int VB = rB(ctx->opcode); + TCGv_i32 tmp = tcg_temp_new_i32(); + int i; + + /* Perform count for every word element using tcg_gen_clzi_i32. */ + for (i = 0; i < 4; i++) { + tcg_gen_ld_i32(tmp, cpu_env, + offsetof(CPUPPCState, vsr[32 + VB].u64[0]) + i * 4); + tcg_gen_clzi_i32(tmp, tmp, 32); + tcg_gen_st_i32(tmp, cpu_env, + offsetof(CPUPPCState, vsr[32 + VT].u64[0]) + i * 4); + } + + tcg_temp_free_i32(tmp); +} + +/* + * vclzd VRT,VRB - Vector Count Leading Zeros Doubleword + * + * Counting the number of leading zero bits of each doubleword element in source + * register and placing result in appropriate doubleword element of destination + * register. + */ +static void trans_vclzd(DisasContext *ctx) +{ + int VT = rD(ctx->opcode); + int VB = rB(ctx->opcode); + TCGv_i64 avr = tcg_temp_new_i64(); + + /* high doubleword */ + get_avr64(avr, VB, true); + tcg_gen_clzi_i64(avr, avr, 64); + set_avr64(VT, avr, true); + + /* low doubleword */ + get_avr64(avr, VB, false); + tcg_gen_clzi_i64(avr, avr, 64); + set_avr64(VT, avr, false); + + tcg_temp_free_i64(avr); +} + GEN_VXFORM(vmuloub, 4, 0); GEN_VXFORM(vmulouh, 4, 1); GEN_VXFORM(vmulouw, 4, 2); @@ -627,11 +906,11 @@ GEN_VXFORM(vrld, 2, 3); GEN_VXFORM(vrldmi, 2, 3); GEN_VXFORM_DUAL(vrld, PPC_NONE, PPC2_ALTIVEC_207, \ vrldmi, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vsl, 2, 7); +GEN_VXFORM_TRANS(vsl, 2, 7); GEN_VXFORM(vrldnm, 2, 7); GEN_VXFORM_DUAL(vsl, PPC_ALTIVEC, PPC_NONE, \ vrldnm, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vsr, 2, 11); +GEN_VXFORM_TRANS(vsr, 2, 11); GEN_VXFORM_ENV(vpkuhum, 7, 0); GEN_VXFORM_ENV(vpkuwum, 7, 1); GEN_VXFORM_ENV(vpkudum, 7, 17); @@ -662,6 +941,8 @@ GEN_VXFORM_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207, GEN_VXFORM_HETRO(vextubrx, 6, 28) GEN_VXFORM_HETRO(vextuhrx, 6, 29) GEN_VXFORM_HETRO(vextuwrx, 6, 30) +GEN_VXFORM_TRANS(lvsl, 6, 31) +GEN_VXFORM_TRANS(lvsr, 6, 32) GEN_VXFORM_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207, \ vextuwrx, PPC_NONE, PPC2_ISA300) @@ -1028,8 +1309,8 @@ GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) GEN_VXFORM_NOA(vclzb, 1, 28) GEN_VXFORM_NOA(vclzh, 1, 29) -GEN_VXFORM_NOA(vclzw, 1, 30) -GEN_VXFORM_NOA(vclzd, 1, 31) +GEN_VXFORM_TRANS(vclzw, 1, 30) +GEN_VXFORM_TRANS(vclzd, 1, 31) GEN_VXFORM_NOA_2(vnegw, 1, 24, 6) GEN_VXFORM_NOA_2(vnegd, 1, 24, 7) GEN_VXFORM_NOA_2(vextsb2w, 1, 24, 16) @@ -1057,7 +1338,7 @@ GEN_VXFORM_DUAL(vclzd, PPC_NONE, PPC2_ALTIVEC_207, \ vpopcntd, PPC_NONE, PPC2_ALTIVEC_207) GEN_VXFORM(vbpermd, 6, 23); GEN_VXFORM(vbpermq, 6, 21); -GEN_VXFORM_NOA(vgbbd, 6, 20); +GEN_VXFORM_TRANS(vgbbd, 6, 20); GEN_VXFORM(vpmsumb, 4, 16) GEN_VXFORM(vpmsumh, 4, 17) GEN_VXFORM(vpmsumw, 4, 18) diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index 86fc8f2e31..4a21ed7289 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -189,7 +189,6 @@ static void spr_read_decr(DisasContext *ctx, int gprn, int sprn) } gen_helper_load_decr(cpu_gpr[gprn], cpu_env); if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); gen_stop_exception(ctx); } } @@ -201,7 +200,6 @@ static void spr_write_decr(DisasContext *ctx, int sprn, int gprn) } gen_helper_store_decr(cpu_env, cpu_gpr[gprn]); if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); gen_stop_exception(ctx); } } @@ -8198,6 +8196,18 @@ static void gen_spr_power8_pspb(CPUPPCState *env) KVM_REG_PPC_PSPB, 0); } +static void gen_spr_power8_dpdes(CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + /* Directed Privileged Door-bell Exception State, used for IPI */ + spr_register_kvm_hv(env, SPR_DPDES, "DPDES", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DPDES, 0x00000000); +#endif +} + static void gen_spr_power8_ic(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) @@ -8629,6 +8639,7 @@ static void init_proc_POWER8(CPUPPCState *env) gen_spr_power8_pmu_user(env); gen_spr_power8_tm(env); gen_spr_power8_pspb(env); + gen_spr_power8_dpdes(env); gen_spr_vtb(env); gen_spr_power8_ic(env); gen_spr_power8_book4(env); @@ -8817,6 +8828,7 @@ static void init_proc_POWER9(CPUPPCState *env) gen_spr_power8_pmu_user(env); gen_spr_power8_tm(env); gen_spr_power8_pspb(env); + gen_spr_power8_dpdes(env); gen_spr_vtb(env); gen_spr_power8_ic(env); gen_spr_power8_book4(env); @@ -9440,14 +9452,13 @@ static void fix_opcode_tables(opc_handler_t **ppc_opcodes) static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp) { PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - CPUPPCState *env = &cpu->env; opcode_t *opc; - fill_new_table(env->opcodes, PPC_CPU_OPCODES_LEN); + fill_new_table(cpu->opcodes, PPC_CPU_OPCODES_LEN); for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) { if (((opc->handler.type & pcc->insns_flags) != 0) || ((opc->handler.type2 & pcc->insns_flags2) != 0)) { - if (register_insn(env->opcodes, opc) < 0) { + if (register_insn(cpu->opcodes, opc) < 0) { error_setg(errp, "ERROR initializing PowerPC instruction " "0x%02x 0x%02x 0x%02x", opc->opc1, opc->opc2, opc->opc3); @@ -9455,7 +9466,7 @@ static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp) } } } - fix_opcode_tables(env->opcodes); + fix_opcode_tables(cpu->opcodes); fflush(stdout); fflush(stderr); } @@ -10023,7 +10034,6 @@ static void ppc_cpu_unrealize(DeviceState *dev, Error **errp) { PowerPCCPU *cpu = POWERPC_CPU(dev); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - CPUPPCState *env = &cpu->env; Error *local_err = NULL; opc_handler_t **table, **table_2; int i, j, k; @@ -10035,11 +10045,11 @@ static void ppc_cpu_unrealize(DeviceState *dev, Error **errp) } for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) { - if (env->opcodes[i] == &invalid_handler) { + if (cpu->opcodes[i] == &invalid_handler) { continue; } - if (is_indirect_opcode(env->opcodes[i])) { - table = ind_table(env->opcodes[i]); + if (is_indirect_opcode(cpu->opcodes[i])) { + table = ind_table(cpu->opcodes[i]); for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) { if (table[j] == &invalid_handler) { continue; @@ -10057,7 +10067,7 @@ static void ppc_cpu_unrealize(DeviceState *dev, Error **errp) ~PPC_INDIRECT)); } } - g_free((opc_handler_t *)((uintptr_t)env->opcodes[i] & + g_free((opc_handler_t *)((uintptr_t)cpu->opcodes[i] & ~PPC_INDIRECT)); } } @@ -10471,6 +10481,28 @@ static bool ppc_cpu_is_big_endian(CPUState *cs) return !msr_le; } + +static void ppc_cpu_exec_enter(CPUState *cs) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + + if (cpu->vhyp) { + PPCVirtualHypervisorClass *vhc = + PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + vhc->cpu_exec_enter(cpu->vhyp, cpu); + } +} + +static void ppc_cpu_exec_exit(CPUState *cs) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + + if (cpu->vhyp) { + PPCVirtualHypervisorClass *vhc = + PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + vhc->cpu_exec_exit(cpu->vhyp, cpu); + } +} #endif static void ppc_cpu_instance_init(Object *obj) @@ -10624,6 +10656,11 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) cc->tcg_initialize = ppc_translate_init; cc->tlb_fill = ppc_cpu_tlb_fill; #endif +#ifndef CONFIG_USER_ONLY + cc->cpu_exec_enter = ppc_cpu_exec_enter; + cc->cpu_exec_exit = ppc_cpu_exec_exit; +#endif + cc->disas_set_info = ppc_disas_set_info; dc->fw_name = "PowerPC,UNKNOWN"; diff --git a/target/riscv/insn_trans/trans_rvi.inc.c b/target/riscv/insn_trans/trans_rvi.inc.c index ea6473111c..1af795e05d 100644 --- a/target/riscv/insn_trans/trans_rvi.inc.c +++ b/target/riscv/insn_trans/trans_rvi.inc.c @@ -511,7 +511,6 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a) } while (0) #define RISCV_OP_CSR_POST do {\ - gen_io_end(); \ gen_set_gpr(a->rd, dest); \ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \ exit_tb(ctx); \ diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index aee733eaaa..ecaa7a18a9 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -23,8 +23,6 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" -#define ALIGNED_ONLY - /* CPU Subtypes */ #define SH_CPU_SH7750 (1 << 0) #define SH_CPU_SH7750S (1 << 1) diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 0d5b01efe5..694d7139cf 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -5,8 +5,6 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" -#define ALIGNED_ONLY - #if !defined(TARGET_SPARC64) #define TARGET_DPREGS 16 #else diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 091bab53af..02c16128c8 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -4412,10 +4412,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_tick_set_limit(r_tickptr, cpu_tick_cmpr); tcg_temp_free_ptr(r_tickptr); - if (tb_cflags(dc->base.tb) & - CF_USE_ICOUNT) { - gen_io_end(); - } /* End TB to handle timer interrupt */ dc->base.is_jmp = DISAS_EXIT; } @@ -4440,10 +4436,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_tick_set_count(r_tickptr, cpu_tmp0); tcg_temp_free_ptr(r_tickptr); - if (tb_cflags(dc->base.tb) & - CF_USE_ICOUNT) { - gen_io_end(); - } /* End TB to handle timer interrupt */ dc->base.is_jmp = DISAS_EXIT; } @@ -4468,10 +4460,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_tick_set_limit(r_tickptr, cpu_stick_cmpr); tcg_temp_free_ptr(r_tickptr); - if (tb_cflags(dc->base.tb) & - CF_USE_ICOUNT) { - gen_io_end(); - } /* End TB to handle timer interrupt */ dc->base.is_jmp = DISAS_EXIT; } @@ -4588,10 +4576,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_tick_set_count(r_tickptr, cpu_tmp0); tcg_temp_free_ptr(r_tickptr); - if (tb_cflags(dc->base.tb) & - CF_USE_ICOUNT) { - gen_io_end(); - } /* End TB to handle timer interrupt */ dc->base.is_jmp = DISAS_EXIT; } diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c index d27451eed3..0e01f35856 100644 --- a/target/unicore32/translate.c +++ b/target/unicore32/translate.c @@ -1931,7 +1931,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) code. */ cpu_abort(cs, "IO on conditional branch instruction"); } - gen_io_end(); } /* At this stage dc->condjmp will only be set when the skipped diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 2c277134f1..0459243e6b 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -32,8 +32,6 @@ #include "exec/cpu-defs.h" #include "xtensa-isa.h" -#define ALIGNED_ONLY - /* Xtensa processors have a weak memory model */ #define TCG_GUEST_DEFAULT_MO (0) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index fa12a576b2..d20e60ce77 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -539,9 +539,6 @@ static void gen_waiti(DisasContext *dc, uint32_t imm4) gen_io_start(); } gen_helper_waiti(cpu_env, pc, intlevel); - if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } tcg_temp_free(pc); tcg_temp_free(intlevel); } @@ -2215,9 +2212,6 @@ static void translate_rsr_ccount(DisasContext *dc, const OpcodeArg arg[], } gen_helper_update_ccount(cpu_env); tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]); - if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } #endif } @@ -2607,9 +2601,6 @@ static void translate_wsr_ccompare(DisasContext *dc, const OpcodeArg arg[], tcg_gen_mov_i32(cpu_SR[par[0]], arg[0].in); gen_helper_update_ccompare(cpu_env, tmp); tcg_temp_free(tmp); - if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } #endif } @@ -2621,9 +2612,6 @@ static void translate_wsr_ccount(DisasContext *dc, const OpcodeArg arg[], gen_io_start(); } gen_helper_wsr_ccount(cpu_env, arg[0].in); - if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } #endif } @@ -2830,9 +2818,6 @@ static void translate_xsr_ccount(DisasContext *dc, const OpcodeArg arg[], tcg_gen_mov_i32(arg[0].out, tmp); tcg_temp_free(tmp); - if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } #endif } @@ -1925,7 +1925,7 @@ static const char * const ldst_name[] = }; static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = { -#ifdef ALIGNED_ONLY +#ifdef TARGET_ALIGNED_ONLY [MO_UNALN >> MO_ASHIFT] = "un+", [MO_ALIGN >> MO_ASHIFT] = "", #else @@ -333,10 +333,12 @@ typedef enum TCGMemOp { MO_TE = MO_LE, #endif - /* MO_UNALN accesses are never checked for alignment. + /* + * MO_UNALN accesses are never checked for alignment. * MO_ALIGN accesses will result in a call to the CPU's * do_unaligned_access hook if the guest address is not aligned. - * The default depends on whether the target CPU defines ALIGNED_ONLY. + * The default depends on whether the target CPU defines + * TARGET_ALIGNED_ONLY. * * Some architectures (e.g. ARMv8) need the address which is aligned * to a size more than the size of the memory access. @@ -353,7 +355,7 @@ typedef enum TCGMemOp { */ MO_ASHIFT = 4, MO_AMASK = 7 << MO_ASHIFT, -#ifdef ALIGNED_ONLY +#ifdef TARGET_ALIGNED_ONLY MO_ALIGN = 0, MO_UNALN = MO_AMASK, #else diff --git a/tests/ptimer-test-stubs.c b/tests/ptimer-test-stubs.c index 54b3fd26f6..ed393d9082 100644 --- a/tests/ptimer-test-stubs.c +++ b/tests/ptimer-test-stubs.c @@ -88,9 +88,9 @@ int64_t qemu_clock_get_ns(QEMUClockType type) return ptimer_test_time_ns; } -int64_t qemu_clock_deadline_ns_all(QEMUClockType type) +int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask) { - QEMUTimerList *timer_list = main_loop_tlg.tl[type]; + QEMUTimerList *timer_list = main_loop_tlg.tl[QEMU_CLOCK_VIRTUAL]; QEMUTimer *t = timer_list->active_timers.next; int64_t deadline = -1; diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c index b30aad0737..5b20e91599 100644 --- a/tests/ptimer-test.c +++ b/tests/ptimer-test.c @@ -50,13 +50,15 @@ static void ptimer_test_set_qemu_time_ns(int64_t ns) static void qemu_clock_step(uint64_t ns) { - int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, + QEMU_TIMER_ATTR_ALL); int64_t advanced_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns; while (deadline != -1 && deadline <= advanced_time) { ptimer_test_set_qemu_time_ns(deadline); ptimer_test_expire_qemu_timers(deadline, QEMU_CLOCK_VIRTUAL); - deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, + QEMU_TIMER_ATTR_ALL); } ptimer_test_set_qemu_time_ns(advanced_time); diff --git a/tests/test-bitmap.c b/tests/test-bitmap.c index 18aa584591..087e02a26c 100644 --- a/tests/test-bitmap.c +++ b/tests/test-bitmap.c @@ -67,6 +67,18 @@ static void bitmap_set_case(bmap_set_func set_func) bmap = bitmap_new(BMAP_SIZE); + /* Set one bit at offset in second word */ + for (offset = 0; offset <= BITS_PER_LONG; offset++) { + bitmap_clear(bmap, 0, BMAP_SIZE); + set_func(bmap, BITS_PER_LONG + offset, 1); + g_assert_cmpint(find_first_bit(bmap, 2 * BITS_PER_LONG), + ==, BITS_PER_LONG + offset); + g_assert_cmpint(find_next_zero_bit(bmap, + 3 * BITS_PER_LONG, + BITS_PER_LONG + offset), + ==, BITS_PER_LONG + offset + 1); + } + /* Both Aligned, set bits [BITS_PER_LONG, 3*BITS_PER_LONG] */ set_func(bmap, BITS_PER_LONG, 2 * BITS_PER_LONG); g_assert_cmpuint(bmap[1], ==, -1ul); diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c index 34b54dfc89..5418e085a4 100644 --- a/tests/test-string-input-visitor.c +++ b/tests/test-string-input-visitor.c @@ -444,16 +444,14 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data, char buf[10000]; for (i = 0; i < 100; i++) { - unsigned int j; + unsigned int j, k; j = g_test_rand_int_range(0, sizeof(buf) - 1); buf[j] = '\0'; - if (j != 0) { - for (j--; j != 0; j--) { - buf[j - 1] = (char)g_test_rand_int_range(0, 256); - } + for (k = 0; k != j; k++) { + buf[k] = (char)g_test_rand_int_range(0, 256); } v = visitor_input_test_init(data, buf); diff --git a/tests/test-throttle.c b/tests/test-throttle.c index 083e1f9ba8..7adb5e6652 100644 --- a/tests/test-throttle.c +++ b/tests/test-throttle.c @@ -558,6 +558,8 @@ static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */ BucketType index; int i; + throttle_config_init(&cfg); + for (i = 0; i < 3; i++) { BucketType index = to_test[is_ops][i]; cfg.buckets[index].avg = avg; diff --git a/util/qemu-timer.c b/util/qemu-timer.c index b0e40a9087..d428fec567 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -47,9 +47,6 @@ typedef struct QEMUClock { /* We rely on BQL to protect the timerlists */ QLIST_HEAD(, QEMUTimerList) timerlists; - NotifierList reset_notifiers; - int64_t last; - QEMUClockType type; bool enabled; } QEMUClock; @@ -130,9 +127,7 @@ static void qemu_clock_init(QEMUClockType type, QEMUTimerListNotifyCB *notify_cb clock->type = type; clock->enabled = (type == QEMU_CLOCK_VIRTUAL ? false : true); - clock->last = INT64_MIN; QLIST_INIT(&clock->timerlists); - notifier_list_init(&clock->reset_notifiers); main_loop_tlg.tl[type] = timerlist_new(type, notify_cb, NULL); } @@ -252,14 +247,38 @@ int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) * ignore whether or not the clock should be used in deadline * calculations. */ -int64_t qemu_clock_deadline_ns_all(QEMUClockType type) +int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask) { int64_t deadline = -1; + int64_t delta; + int64_t expire_time; + QEMUTimer *ts; QEMUTimerList *timer_list; QEMUClock *clock = qemu_clock_ptr(type); + + if (!clock->enabled) { + return -1; + } + QLIST_FOREACH(timer_list, &clock->timerlists, list) { - deadline = qemu_soonest_timeout(deadline, - timerlist_deadline_ns(timer_list)); + qemu_mutex_lock(&timer_list->active_timers_lock); + ts = timer_list->active_timers; + /* Skip all external timers */ + while (ts && (ts->attributes & ~attr_mask)) { + ts = ts->next; + } + if (!ts) { + qemu_mutex_unlock(&timer_list->active_timers_lock); + continue; + } + expire_time = ts->expire_time; + qemu_mutex_unlock(&timer_list->active_timers_lock); + + delta = expire_time - qemu_clock_get_ns(type); + if (delta <= 0) { + delta = 0; + } + deadline = qemu_soonest_timeout(deadline, delta); } return deadline; } @@ -629,9 +648,6 @@ int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg) int64_t qemu_clock_get_ns(QEMUClockType type) { - int64_t now, last; - QEMUClock *clock = qemu_clock_ptr(type); - switch (type) { case QEMU_CLOCK_REALTIME: return get_clock(); @@ -643,43 +659,12 @@ int64_t qemu_clock_get_ns(QEMUClockType type) return cpu_get_clock(); } case QEMU_CLOCK_HOST: - now = REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime()); - last = clock->last; - clock->last = now; - if (now < last || now > (last + get_max_clock_jump())) { - notifier_list_notify(&clock->reset_notifiers, &now); - } - return now; + return REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime()); case QEMU_CLOCK_VIRTUAL_RT: return REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock()); } } -uint64_t qemu_clock_get_last(QEMUClockType type) -{ - QEMUClock *clock = qemu_clock_ptr(type); - return clock->last; -} - -void qemu_clock_set_last(QEMUClockType type, uint64_t last) -{ - QEMUClock *clock = qemu_clock_ptr(type); - clock->last = last; -} - -void qemu_clock_register_reset_notifier(QEMUClockType type, - Notifier *notifier) -{ - QEMUClock *clock = qemu_clock_ptr(type); - notifier_list_add(&clock->reset_notifiers, notifier); -} - -void qemu_clock_unregister_reset_notifier(QEMUClockType type, - Notifier *notifier) -{ - notifier_remove(notifier); -} - void init_clocks(QEMUTimerListNotifyCB *notify_cb) { QEMUClockType type; @@ -1557,6 +1557,20 @@ void qemu_system_reset(ShutdownCause reason) cpu_synchronize_all_post_reset(); } +/* + * Wake the VM after suspend. + */ +static void qemu_system_wakeup(void) +{ + MachineClass *mc; + + mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; + + if (mc && mc->wakeup) { + mc->wakeup(current_machine); + } +} + void qemu_system_guest_panicked(GuestPanicInformation *info) { qemu_log_mask(LOG_GUEST_ERROR, "Guest crashed"); @@ -1765,7 +1779,7 @@ static bool main_loop_should_exit(void) } if (qemu_wakeup_requested()) { pause_all_vcpus(); - qemu_system_reset(SHUTDOWN_CAUSE_NONE); + qemu_system_wakeup(); notifier_list_notify(&wakeup_notifiers, &wakeup_reason); wakeup_reason = QEMU_WAKEUP_REASON_NONE; resume_all_vcpus(); |