From 0034a0f239623388525c884dabf9a125eafb1acb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 14 Jan 2015 17:53:55 +0100 Subject: pc: fix KVM features in pc-1.3 and earlier machine types Due to a typo, instead of disabling KVM_FEATURE_PV_EOI (bit 6) these machine types are disabling bits 1 and 2, which are KVM_FEATURE_NOP_IO_DELAY and KVM_FEATURE_MMU_OP. Not a big deal because they aren't very important and KVM_FEATURE_MMU_OP is disabled anyway. The worst part is actually that KVM_FEATURE_PV_EOI is remaining enabled. Signed-off-by: Paolo Bonzini --- hw/i386/pc_piix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index f0a3201..97a754e 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -406,7 +406,7 @@ static void pc_compat_1_3(MachineState *machine) static void pc_compat_1_2(MachineState *machine) { pc_compat_1_3(machine); - x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, KVM_FEATURE_PV_EOI); + x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI); } static void pc_init_pci_2_2(MachineState *machine) @@ -483,7 +483,7 @@ static void pc_init_isa(MachineState *machine) if (!machine->cpu_model) { machine->cpu_model = "486"; } - x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, KVM_FEATURE_PV_EOI); + x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI); enable_compat_apic_id_mode(); pc_init1(machine, 0, 1); } -- cgit v1.1 From 43bfb507f422a642ea2893555e13ccc2557d810a Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 15 Jan 2015 12:26:42 +0100 Subject: tests/multiboot: Update reference output The changes look okay (larger PCI hole, some rounding differences), so just update the reference output of the test case. Signed-off-by: Kevin Wolf Signed-off-by: Paolo Bonzini --- tests/multiboot/mmap.out | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/tests/multiboot/mmap.out b/tests/multiboot/mmap.out index e70b6eb..003e109 100644 --- a/tests/multiboot/mmap.out +++ b/tests/multiboot/mmap.out @@ -4,14 +4,14 @@ === Running test case: mmap.elf === Lower memory: 639k -Upper memory: 130040k +Upper memory: 129920k e820 memory map: 0x0 - 0x9fc00: type 1 [entry size: 20] 0x9fc00 - 0xa0000: type 2 [entry size: 20] 0xf0000 - 0x100000: type 2 [entry size: 20] -0x100000 - 0x7ffe000: type 1 [entry size: 20] -0x7ffe000 - 0x8000000: type 2 [entry size: 20] +0x100000 - 0x7fe0000: type 1 [entry size: 20] +0x7fe0000 - 0x8000000: type 2 [entry size: 20] 0xfffc0000 - 0x100000000: type 2 [entry size: 20] mmap start: 0x9000 @@ -22,32 +22,31 @@ real mmap end: 0x9090 === Running test case: mmap.elf -m 1.1M === Lower memory: 639k -Upper memory: 96k +Upper memory: 104k e820 memory map: 0x0 - 0x9fc00: type 1 [entry size: 20] 0x9fc00 - 0xa0000: type 2 [entry size: 20] 0xf0000 - 0x100000: type 2 [entry size: 20] -0x100000 - 0x118000: type 1 [entry size: 20] -0x118000 - 0x11a000: type 2 [entry size: 20] +0x100000 - 0x11a000: type 1 [entry size: 20] 0xfffc0000 - 0x100000000: type 2 [entry size: 20] mmap start: 0x9000 -mmap end: 0x9090 -real mmap end: 0x9090 +mmap end: 0x9078 +real mmap end: 0x9078 === Running test case: mmap.elf -m 2G === Lower memory: 639k -Upper memory: 2096120k +Upper memory: 2096000k e820 memory map: 0x0 - 0x9fc00: type 1 [entry size: 20] 0x9fc00 - 0xa0000: type 2 [entry size: 20] 0xf0000 - 0x100000: type 2 [entry size: 20] -0x100000 - 0x7fffe000: type 1 [entry size: 20] -0x7fffe000 - 0x80000000: type 2 [entry size: 20] +0x100000 - 0x7ffe0000: type 1 [entry size: 20] +0x7ffe0000 - 0x80000000: type 2 [entry size: 20] 0xfffc0000 - 0x100000000: type 2 [entry size: 20] mmap start: 0x9000 @@ -58,16 +57,16 @@ real mmap end: 0x9090 === Running test case: mmap.elf -m 4G === Lower memory: 639k -Upper memory: 3668984k +Upper memory: 3144576k e820 memory map: 0x0 - 0x9fc00: type 1 [entry size: 20] 0x9fc00 - 0xa0000: type 2 [entry size: 20] 0xf0000 - 0x100000: type 2 [entry size: 20] -0x100000 - 0xdfffe000: type 1 [entry size: 20] -0xdfffe000 - 0xe0000000: type 2 [entry size: 20] +0x100000 - 0xbffe0000: type 1 [entry size: 20] +0xbffe0000 - 0xc0000000: type 2 [entry size: 20] 0xfffc0000 - 0x100000000: type 2 [entry size: 20] -0x100000000 - 0x120000000: type 1 [entry size: 20] +0x100000000 - 0x140000000: type 1 [entry size: 20] mmap start: 0x9000 mmap end: 0x90a8 @@ -77,16 +76,16 @@ real mmap end: 0x90a8 === Running test case: mmap.elf -m 8G === Lower memory: 639k -Upper memory: 3668984k +Upper memory: 3144576k e820 memory map: 0x0 - 0x9fc00: type 1 [entry size: 20] 0x9fc00 - 0xa0000: type 2 [entry size: 20] 0xf0000 - 0x100000: type 2 [entry size: 20] -0x100000 - 0xdfffe000: type 1 [entry size: 20] -0xdfffe000 - 0xe0000000: type 2 [entry size: 20] +0x100000 - 0xbffe0000: type 1 [entry size: 20] +0xbffe0000 - 0xc0000000: type 2 [entry size: 20] 0xfffc0000 - 0x100000000: type 2 [entry size: 20] -0x100000000 - 0x220000000: type 1 [entry size: 20] +0x100000000 - 0x240000000: type 1 [entry size: 20] mmap start: 0x9000 mmap end: 0x90a8 -- cgit v1.1 From b4168498f613db3d908909106146001a9279e732 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 15 Jan 2015 12:26:43 +0100 Subject: multiboot: Fix offset of bootloader name This fixes a bug introduced in commit 5eba5a66 ('Add bootloader name to multiboot implementation'). The calculation of the bootloader name offset didn't consider space occupied by module command lines, so some unlucky module got its command line partially overwritten with a "qemu" string. Signed-off-by: Kevin Wolf Signed-off-by: Paolo Bonzini --- hw/i386/multiboot.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index f86d351..1adbe9e 100644 --- a/hw/i386/multiboot.c +++ b/hw/i386/multiboot.c @@ -156,6 +156,7 @@ int load_multiboot(FWCfgState *fw_cfg, MultibootState mbs; uint8_t bootinfo[MBI_SIZE]; uint8_t *mb_bootinfo_data; + uint32_t cmdline_len; /* Ok, let's see if it is a multiboot image. The header is 12x32bit long, so the latest entry may be 8192 - 48. */ @@ -258,27 +259,28 @@ int load_multiboot(FWCfgState *fw_cfg, mbs.offset_mbinfo = mbs.mb_buf_size; /* Calculate space for cmdlines, bootloader name, and mb_mods */ - mbs.mb_buf_size += strlen(kernel_filename) + 1; - mbs.mb_buf_size += strlen(kernel_cmdline) + 1; - mbs.mb_buf_size += strlen(bootloader_name) + 1; + cmdline_len = strlen(kernel_filename) + 1; + cmdline_len += strlen(kernel_cmdline) + 1; if (initrd_filename) { const char *r = initrd_filename; - mbs.mb_buf_size += strlen(r) + 1; + cmdline_len += strlen(r) + 1; mbs.mb_mods_avail = 1; while (*(r = get_opt_value(NULL, 0, r))) { mbs.mb_mods_avail++; r++; } - mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail; } + mbs.mb_buf_size += cmdline_len; + mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail; + mbs.mb_buf_size += strlen(bootloader_name) + 1; + mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size); /* enlarge mb_buf to hold cmdlines, bootloader, mb-info structs */ mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size); mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE; - mbs.offset_bootloader = mbs.offset_cmdlines + strlen(kernel_filename) + 1 - + strlen(kernel_cmdline) + 1; + mbs.offset_bootloader = mbs.offset_cmdlines + cmdline_len; if (initrd_filename) { char *next_initrd, not_last; -- cgit v1.1 From a9c837d8ef573604328e4cb61e2e0cab61bba319 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 15 Jan 2015 12:26:44 +0100 Subject: tests/multiboot: Add test for modules This test case is meant to detect corruptions of the Multiboot modules as well as the multiboot modules list and the module command lines. Signed-off-by: Kevin Wolf Signed-off-by: Paolo Bonzini --- tests/multiboot/Makefile | 5 ++++- tests/multiboot/libc.c | 12 ++++++++++ tests/multiboot/libc.h | 1 + tests/multiboot/module.txt | 1 + tests/multiboot/modules.c | 55 +++++++++++++++++++++++++++++++++++++++++++++ tests/multiboot/modules.out | 38 +++++++++++++++++++++++++++++++ tests/multiboot/run_test.sh | 9 +++++++- 7 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 tests/multiboot/module.txt create mode 100644 tests/multiboot/modules.c create mode 100644 tests/multiboot/modules.out diff --git a/tests/multiboot/Makefile b/tests/multiboot/Makefile index 34cdd81..36f01dc 100644 --- a/tests/multiboot/Makefile +++ b/tests/multiboot/Makefile @@ -6,11 +6,14 @@ LD=ld LDFLAGS=-melf_i386 -T link.ld LIBS=$(shell $(CC) $(CCFLAGS) -print-libgcc-file-name) -all: mmap.elf +all: mmap.elf modules.elf mmap.elf: start.o mmap.o libc.o $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) +modules.elf: start.o modules.o libc.o + $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + %.o: %.c $(CC) $(CCFLAGS) -c -o $@ $^ diff --git a/tests/multiboot/libc.c b/tests/multiboot/libc.c index 05abbd9..6df9bda 100644 --- a/tests/multiboot/libc.c +++ b/tests/multiboot/libc.c @@ -22,6 +22,18 @@ #include "libc.h" +void* memcpy(void *dest, const void *src, int n) +{ + char *d = dest; + const char *s = src; + + while (n--) { + *d++ = *s++; + } + + return dest; +} + static void print_char(char c) { outb(0xe9, c); diff --git a/tests/multiboot/libc.h b/tests/multiboot/libc.h index 80eec5b..04c9922 100644 --- a/tests/multiboot/libc.h +++ b/tests/multiboot/libc.h @@ -57,5 +57,6 @@ static inline void outb(uint16_t port, uint8_t data) /* Misc functions */ void printf(const char *fmt, ...); +void* memcpy(void *dest, const void *src, int n); #endif diff --git a/tests/multiboot/module.txt b/tests/multiboot/module.txt new file mode 100644 index 0000000..54c1d27 --- /dev/null +++ b/tests/multiboot/module.txt @@ -0,0 +1 @@ +This is a test file that is used as a multiboot module. diff --git a/tests/multiboot/modules.c b/tests/multiboot/modules.c new file mode 100644 index 0000000..531601f --- /dev/null +++ b/tests/multiboot/modules.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015 Kevin Wolf + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "libc.h" +#include "multiboot.h" + +int test_main(uint32_t magic, struct mb_info *mbi) +{ + struct mb_module *mod; + unsigned int i; + + (void) magic; + + printf("Module list with %d entries at %x\n", + mbi->mods_count, mbi->mods_addr); + + for (i = 0, mod = (struct mb_module*) mbi->mods_addr; + i < mbi->mods_count; + i++, mod++) + { + char buf[1024]; + unsigned int size = mod->mod_end - mod->mod_start; + + printf("[%p] Module: %x - %x (%d bytes) '%s'\n", + mod, mod->mod_start, mod->mod_end, size, mod->string); + + /* Print test file, but remove the newline at the end */ + if (size < sizeof(buf)) { + memcpy(buf, (void*) mod->mod_start, size); + buf[size - 1] = '\0'; + printf(" Content: '%s'\n", buf); + } + } + + return 0; +} diff --git a/tests/multiboot/modules.out b/tests/multiboot/modules.out new file mode 100644 index 0000000..1636708 --- /dev/null +++ b/tests/multiboot/modules.out @@ -0,0 +1,38 @@ + + + +=== Running test case: modules.elf === + +Module list with 0 entries at 102000 + + +=== Running test case: modules.elf -initrd module.txt === + +Module list with 1 entries at 102000 +[102000] Module: 103000 - 103038 (56 bytes) 'module.txt' + Content: 'This is a test file that is used as a multiboot module.' + + +=== Running test case: modules.elf -initrd module.txt argument === + +Module list with 1 entries at 102000 +[102000] Module: 103000 - 103038 (56 bytes) 'module.txt argument' + Content: 'This is a test file that is used as a multiboot module.' + + +=== Running test case: modules.elf -initrd module.txt argument,,with,,commas === + +Module list with 1 entries at 102000 +[102000] Module: 103000 - 103038 (56 bytes) 'module.txt argument,with,commas' + Content: 'This is a test file that is used as a multiboot module.' + + +=== Running test case: modules.elf -initrd module.txt,module.txt argument,module.txt === + +Module list with 3 entries at 102000 +[102000] Module: 103000 - 103038 (56 bytes) 'module.txt' + Content: 'This is a test file that is used as a multiboot module.' +[102010] Module: 104000 - 104038 (56 bytes) 'module.txt argument' + Content: 'This is a test file that is used as a multiboot module.' +[102020] Module: 105000 - 105038 (56 bytes) 'module.txt' + Content: 'This is a test file that is used as a multiboot module.' diff --git a/tests/multiboot/run_test.sh b/tests/multiboot/run_test.sh index 97a9a49..78d7edf 100755 --- a/tests/multiboot/run_test.sh +++ b/tests/multiboot/run_test.sh @@ -48,10 +48,17 @@ mmap() { run_qemu mmap.elf -m 8G } +modules() { + run_qemu modules.elf + run_qemu modules.elf -initrd module.txt + run_qemu modules.elf -initrd "module.txt argument" + run_qemu modules.elf -initrd "module.txt argument,,with,,commas" + run_qemu modules.elf -initrd "module.txt,module.txt argument,module.txt" +} make all -for t in mmap; do +for t in mmap modules; do echo > test.log $t -- cgit v1.1 From a03c3e90e11976fb147904d537457984bb938ce2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 24 Oct 2014 10:18:38 +0200 Subject: target-i386: use vmstate_offset_sub_array for AVX registers After the next patch, each vmstate field will extract parts of a larger (32x512-bit) array, so we cannot check the vmstate field against the type of the array. While changing this, change the macros to accept the index of the first element (which will not be 0 for Hi16_ZMM_REGS) instead of the number of elements (which is always CPU_NB_REGS). Signed-off-by: Paolo Bonzini --- include/migration/vmstate.h | 10 ++++++++++ target-i386/machine.c | 28 ++++++++++++++++------------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index d712a65..6097b94 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -359,6 +359,16 @@ extern const VMStateInfo vmstate_info_bitmap; .offset = vmstate_offset_array(_s, _f, _type*, _n), \ } +#define VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, _num, _version, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .num = (_num), \ + .vmsd = &(_vmsd), \ + .size = sizeof(_type), \ + .flags = VMS_STRUCT|VMS_ARRAY, \ + .offset = vmstate_offset_sub_array(_state, _field, _type, _start), \ +} + #define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \ .name = (stringify(_field)), \ .num = (_num), \ diff --git a/target-i386/machine.c b/target-i386/machine.c index 722d62e..604a49a 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -42,8 +42,9 @@ static const VMStateDescription vmstate_xmm_reg = { } }; -#define VMSTATE_XMM_REGS(_field, _state, _n) \ - VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_xmm_reg, XMMReg) +#define VMSTATE_XMM_REGS(_field, _state, _start) \ + VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \ + vmstate_xmm_reg, XMMReg) /* YMMH format is the same as XMM */ static const VMStateDescription vmstate_ymmh_reg = { @@ -57,8 +58,9 @@ static const VMStateDescription vmstate_ymmh_reg = { } }; -#define VMSTATE_YMMH_REGS_VARS(_field, _state, _n, _v) \ - VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_ymmh_reg, XMMReg) +#define VMSTATE_YMMH_REGS_VARS(_field, _state, _start, _v) \ + VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, _v, \ + vmstate_ymmh_reg, XMMReg) static const VMStateDescription vmstate_zmmh_reg = { .name = "zmmh_reg", @@ -73,8 +75,9 @@ static const VMStateDescription vmstate_zmmh_reg = { } }; -#define VMSTATE_ZMMH_REGS_VARS(_field, _state, _n) \ - VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_zmmh_reg, YMMReg) +#define VMSTATE_ZMMH_REGS_VARS(_field, _state, _start) \ + VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \ + vmstate_zmmh_reg, YMMReg) #ifdef TARGET_X86_64 static const VMStateDescription vmstate_hi16_zmm_reg = { @@ -94,8 +97,9 @@ static const VMStateDescription vmstate_hi16_zmm_reg = { } }; -#define VMSTATE_Hi16_ZMM_REGS_VARS(_field, _state, _n) \ - VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_hi16_zmm_reg, ZMMReg) +#define VMSTATE_Hi16_ZMM_REGS_VARS(_field, _state, _start) \ + VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \ + vmstate_hi16_zmm_reg, ZMMReg) #endif static const VMStateDescription vmstate_bnd_regs = { @@ -679,9 +683,9 @@ static const VMStateDescription vmstate_avx512 = { .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_UINT64_ARRAY(env.opmask_regs, X86CPU, NB_OPMASK_REGS), - VMSTATE_ZMMH_REGS_VARS(env.zmmh_regs, X86CPU, CPU_NB_REGS), + VMSTATE_ZMMH_REGS_VARS(env.zmmh_regs, X86CPU, 0), #ifdef TARGET_X86_64 - VMSTATE_Hi16_ZMM_REGS_VARS(env.hi16_zmm_regs, X86CPU, CPU_NB_REGS), + VMSTATE_Hi16_ZMM_REGS_VARS(env.hi16_zmm_regs, X86CPU, 0), #endif VMSTATE_END_OF_LIST() } @@ -750,7 +754,7 @@ VMStateDescription vmstate_x86_cpu = { VMSTATE_INT32(env.a20_mask, X86CPU), /* XMM */ VMSTATE_UINT32(env.mxcsr, X86CPU), - VMSTATE_XMM_REGS(env.xmm_regs, X86CPU, CPU_NB_REGS), + VMSTATE_XMM_REGS(env.xmm_regs, X86CPU, 0), #ifdef TARGET_X86_64 VMSTATE_UINT64(env.efer, X86CPU), @@ -803,7 +807,7 @@ VMStateDescription vmstate_x86_cpu = { /* XSAVE related fields */ VMSTATE_UINT64_V(env.xcr0, X86CPU, 12), VMSTATE_UINT64_V(env.xstate_bv, X86CPU, 12), - VMSTATE_YMMH_REGS_VARS(env.ymmh_regs, X86CPU, CPU_NB_REGS, 12), + VMSTATE_YMMH_REGS_VARS(env.ymmh_regs, X86CPU, 0, 12), VMSTATE_END_OF_LIST() /* The above list is not sorted /wrt version numbers, watch out! */ }, -- cgit v1.1 From b7711471f551aa4419f9d46a11121f48ced422da Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 24 Oct 2014 09:50:21 +0200 Subject: target-i386: make xmm_regs 512-bit wide Right now, the AVX512 registers are split in many different fields: xmm_regs for the low 128 bits of the first 16 registers, ymmh_regs for the next 128 bits of the same first 16 registers, zmmh_regs for the next 256 bits of the same first 16 registers, and finally hi16_zmm_regs for the full 512 bits of the second 16 bit registers. This makes it simple to move data in and out of the xsave region, but would be a nightmare for a hypothetical TCG implementation and leads to a proliferation of [XYZ]MM_[BWLSQD] macros. Instead, this patch marshals data manually from the xsave region to a single 32x512-bit array, simplifying the macro jungle and clarifying which bits are in which vmstate subsection. The migration format is unaffected. Signed-off-by: Paolo Bonzini --- target-i386/cpu.h | 68 ++++++--------------------------------------------- target-i386/kvm.c | 40 ++++++++++++++++++------------ target-i386/machine.c | 55 ++++++++++++++++++++--------------------- 3 files changed, 59 insertions(+), 104 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index da33587..478450c 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -713,31 +713,13 @@ typedef struct SegmentCache { } SegmentCache; typedef union { - uint8_t _b[16]; - uint16_t _w[8]; - uint32_t _l[4]; - uint64_t _q[2]; - float32 _s[4]; - float64 _d[2]; -} XMMReg; - -typedef union { - uint8_t _b[32]; - uint16_t _w[16]; - uint32_t _l[8]; - uint64_t _q[4]; - float32 _s[8]; - float64 _d[4]; -} YMMReg; - -typedef union { uint8_t _b[64]; uint16_t _w[32]; uint32_t _l[16]; uint64_t _q[8]; float32 _s[16]; float64 _d[8]; -} ZMMReg; +} XMMReg; /* really zmm */ typedef union { uint8_t _b[8]; @@ -758,46 +740,18 @@ typedef struct BNDCSReg { } BNDCSReg; #ifdef HOST_WORDS_BIGENDIAN -#define ZMM_B(n) _b[63 - (n)] -#define ZMM_W(n) _w[31 - (n)] -#define ZMM_L(n) _l[15 - (n)] -#define ZMM_S(n) _s[15 - (n)] -#define ZMM_Q(n) _q[7 - (n)] -#define ZMM_D(n) _d[7 - (n)] - -#define YMM_B(n) _b[31 - (n)] -#define YMM_W(n) _w[15 - (n)] -#define YMM_L(n) _l[7 - (n)] -#define YMM_S(n) _s[7 - (n)] -#define YMM_Q(n) _q[3 - (n)] -#define YMM_D(n) _d[3 - (n)] - -#define XMM_B(n) _b[15 - (n)] -#define XMM_W(n) _w[7 - (n)] -#define XMM_L(n) _l[3 - (n)] -#define XMM_S(n) _s[3 - (n)] -#define XMM_Q(n) _q[1 - (n)] -#define XMM_D(n) _d[1 - (n)] +#define XMM_B(n) _b[63 - (n)] +#define XMM_W(n) _w[31 - (n)] +#define XMM_L(n) _l[15 - (n)] +#define XMM_S(n) _s[15 - (n)] +#define XMM_Q(n) _q[7 - (n)] +#define XMM_D(n) _d[7 - (n)] #define MMX_B(n) _b[7 - (n)] #define MMX_W(n) _w[3 - (n)] #define MMX_L(n) _l[1 - (n)] #define MMX_S(n) _s[1 - (n)] #else -#define ZMM_B(n) _b[n] -#define ZMM_W(n) _w[n] -#define ZMM_L(n) _l[n] -#define ZMM_S(n) _s[n] -#define ZMM_Q(n) _q[n] -#define ZMM_D(n) _d[n] - -#define YMM_B(n) _b[n] -#define YMM_W(n) _w[n] -#define YMM_L(n) _l[n] -#define YMM_S(n) _s[n] -#define YMM_Q(n) _q[n] -#define YMM_D(n) _d[n] - #define XMM_B(n) _b[n] #define XMM_W(n) _w[n] #define XMM_L(n) _l[n] @@ -896,17 +850,11 @@ typedef struct CPUX86State { float_status mmx_status; /* for 3DNow! float ops */ float_status sse_status; uint32_t mxcsr; - XMMReg xmm_regs[CPU_NB_REGS]; + XMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32]; XMMReg xmm_t0; MMXReg mmx_t0; - XMMReg ymmh_regs[CPU_NB_REGS]; - uint64_t opmask_regs[NB_OPMASK_REGS]; - YMMReg zmmh_regs[CPU_NB_REGS]; -#ifdef TARGET_X86_64 - ZMMReg hi16_zmm_regs[CPU_NB_REGS]; -#endif /* sysenter registers */ uint32_t sysenter_cs; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 36b1519..40d6a14 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1048,7 +1048,7 @@ static int kvm_put_xsave(X86CPU *cpu) CPUX86State *env = &cpu->env; struct kvm_xsave* xsave = env->kvm_xsave_buf; uint16_t cwd, swd, twd; - uint8_t *xmm; + uint8_t *xmm, *ymmh, *zmmh; int i, r; if (!kvm_has_xsave()) { @@ -1071,26 +1071,30 @@ static int kvm_put_xsave(X86CPU *cpu) sizeof env->fpregs); xsave->region[XSAVE_MXCSR] = env->mxcsr; *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV] = env->xstate_bv; - memcpy(&xsave->region[XSAVE_YMMH_SPACE], env->ymmh_regs, - sizeof env->ymmh_regs); memcpy(&xsave->region[XSAVE_BNDREGS], env->bnd_regs, sizeof env->bnd_regs); memcpy(&xsave->region[XSAVE_BNDCSR], &env->bndcs_regs, sizeof(env->bndcs_regs)); memcpy(&xsave->region[XSAVE_OPMASK], env->opmask_regs, sizeof env->opmask_regs); - memcpy(&xsave->region[XSAVE_ZMM_Hi256], env->zmmh_regs, - sizeof env->zmmh_regs); xmm = (uint8_t *)&xsave->region[XSAVE_XMM_SPACE]; - for (i = 0; i < CPU_NB_REGS; i++, xmm += 16) { + ymmh = (uint8_t *)&xsave->region[XSAVE_YMMH_SPACE]; + zmmh = (uint8_t *)&xsave->region[XSAVE_ZMM_Hi256]; + for (i = 0; i < CPU_NB_REGS; i++, xmm += 16, ymmh += 16, zmmh += 32) { stq_p(xmm, env->xmm_regs[i].XMM_Q(0)); stq_p(xmm+8, env->xmm_regs[i].XMM_Q(1)); + stq_p(ymmh, env->xmm_regs[i].XMM_Q(2)); + stq_p(ymmh+8, env->xmm_regs[i].XMM_Q(3)); + stq_p(zmmh, env->xmm_regs[i].XMM_Q(4)); + stq_p(zmmh+8, env->xmm_regs[i].XMM_Q(5)); + stq_p(zmmh+16, env->xmm_regs[i].XMM_Q(6)); + stq_p(zmmh+24, env->xmm_regs[i].XMM_Q(7)); } #ifdef TARGET_X86_64 - memcpy(&xsave->region[XSAVE_Hi16_ZMM], env->hi16_zmm_regs, - sizeof env->hi16_zmm_regs); + memcpy(&xsave->region[XSAVE_Hi16_ZMM], &env->xmm_regs[16], + 16 * sizeof env->xmm_regs[16]); #endif r = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_XSAVE, xsave); return r; @@ -1407,7 +1411,7 @@ static int kvm_get_xsave(X86CPU *cpu) CPUX86State *env = &cpu->env; struct kvm_xsave* xsave = env->kvm_xsave_buf; int ret, i; - const uint8_t *xmm; + const uint8_t *xmm, *ymmh, *zmmh; uint16_t cwd, swd, twd; if (!kvm_has_xsave()) { @@ -1435,26 +1439,30 @@ static int kvm_get_xsave(X86CPU *cpu) memcpy(env->fpregs, &xsave->region[XSAVE_ST_SPACE], sizeof env->fpregs); env->xstate_bv = *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV]; - memcpy(env->ymmh_regs, &xsave->region[XSAVE_YMMH_SPACE], - sizeof env->ymmh_regs); memcpy(env->bnd_regs, &xsave->region[XSAVE_BNDREGS], sizeof env->bnd_regs); memcpy(&env->bndcs_regs, &xsave->region[XSAVE_BNDCSR], sizeof(env->bndcs_regs)); memcpy(env->opmask_regs, &xsave->region[XSAVE_OPMASK], sizeof env->opmask_regs); - memcpy(env->zmmh_regs, &xsave->region[XSAVE_ZMM_Hi256], - sizeof env->zmmh_regs); xmm = (const uint8_t *)&xsave->region[XSAVE_XMM_SPACE]; - for (i = 0; i < CPU_NB_REGS; i++, xmm += 16) { + ymmh = (const uint8_t *)&xsave->region[XSAVE_YMMH_SPACE]; + zmmh = (const uint8_t *)&xsave->region[XSAVE_ZMM_Hi256]; + for (i = 0; i < CPU_NB_REGS; i++, xmm += 16, ymmh += 16, zmmh += 32) { env->xmm_regs[i].XMM_Q(0) = ldq_p(xmm); env->xmm_regs[i].XMM_Q(1) = ldq_p(xmm+8); + env->xmm_regs[i].XMM_Q(2) = ldq_p(ymmh); + env->xmm_regs[i].XMM_Q(3) = ldq_p(ymmh+8); + env->xmm_regs[i].XMM_Q(4) = ldq_p(zmmh); + env->xmm_regs[i].XMM_Q(5) = ldq_p(zmmh+8); + env->xmm_regs[i].XMM_Q(6) = ldq_p(zmmh+16); + env->xmm_regs[i].XMM_Q(7) = ldq_p(zmmh+24); } #ifdef TARGET_X86_64 - memcpy(env->hi16_zmm_regs, &xsave->region[XSAVE_Hi16_ZMM], - sizeof env->hi16_zmm_regs); + memcpy(&env->xmm_regs[16], &xsave->region[XSAVE_Hi16_ZMM], + 16 * sizeof env->xmm_regs[16]); #endif return 0; } diff --git a/target-i386/machine.c b/target-i386/machine.c index 604a49a..cd1ddd2 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -46,14 +46,14 @@ static const VMStateDescription vmstate_xmm_reg = { VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \ vmstate_xmm_reg, XMMReg) -/* YMMH format is the same as XMM */ +/* YMMH format is the same as XMM, but for bits 128-255 */ static const VMStateDescription vmstate_ymmh_reg = { .name = "ymmh_reg", .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT64(XMM_Q(0), XMMReg), - VMSTATE_UINT64(XMM_Q(1), XMMReg), + VMSTATE_UINT64(XMM_Q(2), XMMReg), + VMSTATE_UINT64(XMM_Q(3), XMMReg), VMSTATE_END_OF_LIST() } }; @@ -67,17 +67,17 @@ static const VMStateDescription vmstate_zmmh_reg = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT64(YMM_Q(0), YMMReg), - VMSTATE_UINT64(YMM_Q(1), YMMReg), - VMSTATE_UINT64(YMM_Q(2), YMMReg), - VMSTATE_UINT64(YMM_Q(3), YMMReg), + VMSTATE_UINT64(XMM_Q(4), XMMReg), + VMSTATE_UINT64(XMM_Q(5), XMMReg), + VMSTATE_UINT64(XMM_Q(6), XMMReg), + VMSTATE_UINT64(XMM_Q(7), XMMReg), VMSTATE_END_OF_LIST() } }; #define VMSTATE_ZMMH_REGS_VARS(_field, _state, _start) \ VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \ - vmstate_zmmh_reg, YMMReg) + vmstate_zmmh_reg, XMMReg) #ifdef TARGET_X86_64 static const VMStateDescription vmstate_hi16_zmm_reg = { @@ -85,21 +85,21 @@ static const VMStateDescription vmstate_hi16_zmm_reg = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT64(ZMM_Q(0), ZMMReg), - VMSTATE_UINT64(ZMM_Q(1), ZMMReg), - VMSTATE_UINT64(ZMM_Q(2), ZMMReg), - VMSTATE_UINT64(ZMM_Q(3), ZMMReg), - VMSTATE_UINT64(ZMM_Q(4), ZMMReg), - VMSTATE_UINT64(ZMM_Q(5), ZMMReg), - VMSTATE_UINT64(ZMM_Q(6), ZMMReg), - VMSTATE_UINT64(ZMM_Q(7), ZMMReg), + VMSTATE_UINT64(XMM_Q(0), XMMReg), + VMSTATE_UINT64(XMM_Q(1), XMMReg), + VMSTATE_UINT64(XMM_Q(2), XMMReg), + VMSTATE_UINT64(XMM_Q(3), XMMReg), + VMSTATE_UINT64(XMM_Q(4), XMMReg), + VMSTATE_UINT64(XMM_Q(5), XMMReg), + VMSTATE_UINT64(XMM_Q(6), XMMReg), + VMSTATE_UINT64(XMM_Q(7), XMMReg), VMSTATE_END_OF_LIST() } }; #define VMSTATE_Hi16_ZMM_REGS_VARS(_field, _state, _start) \ VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \ - vmstate_hi16_zmm_reg, ZMMReg) + vmstate_hi16_zmm_reg, XMMReg) #endif static const VMStateDescription vmstate_bnd_regs = { @@ -658,17 +658,16 @@ static bool avx512_needed(void *opaque) } for (i = 0; i < CPU_NB_REGS; i++) { -#define ENV_ZMMH(reg, field) (env->zmmh_regs[reg].YMM_Q(field)) - if (ENV_ZMMH(i, 0) || ENV_ZMMH(i, 1) || - ENV_ZMMH(i, 2) || ENV_ZMMH(i, 3)) { +#define ENV_XMM(reg, field) (env->xmm_regs[reg].XMM_Q(field)) + if (ENV_XMM(i, 4) || ENV_XMM(i, 6) || + ENV_XMM(i, 5) || ENV_XMM(i, 7)) { return true; } #ifdef TARGET_X86_64 -#define ENV_Hi16_ZMM(reg, field) (env->hi16_zmm_regs[reg].ZMM_Q(field)) - if (ENV_Hi16_ZMM(i, 0) || ENV_Hi16_ZMM(i, 1) || - ENV_Hi16_ZMM(i, 2) || ENV_Hi16_ZMM(i, 3) || - ENV_Hi16_ZMM(i, 4) || ENV_Hi16_ZMM(i, 5) || - ENV_Hi16_ZMM(i, 6) || ENV_Hi16_ZMM(i, 7)) { + if (ENV_XMM(i+16, 0) || ENV_XMM(i+16, 1) || + ENV_XMM(i+16, 2) || ENV_XMM(i+16, 3) || + ENV_XMM(i+16, 4) || ENV_XMM(i+16, 5) || + ENV_XMM(i+16, 6) || ENV_XMM(i+16, 7)) { return true; } #endif @@ -683,9 +682,9 @@ static const VMStateDescription vmstate_avx512 = { .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_UINT64_ARRAY(env.opmask_regs, X86CPU, NB_OPMASK_REGS), - VMSTATE_ZMMH_REGS_VARS(env.zmmh_regs, X86CPU, 0), + VMSTATE_ZMMH_REGS_VARS(env.xmm_regs, X86CPU, 0), #ifdef TARGET_X86_64 - VMSTATE_Hi16_ZMM_REGS_VARS(env.hi16_zmm_regs, X86CPU, 0), + VMSTATE_Hi16_ZMM_REGS_VARS(env.xmm_regs, X86CPU, 16), #endif VMSTATE_END_OF_LIST() } @@ -807,7 +806,7 @@ VMStateDescription vmstate_x86_cpu = { /* XSAVE related fields */ VMSTATE_UINT64_V(env.xcr0, X86CPU, 12), VMSTATE_UINT64_V(env.xstate_bv, X86CPU, 12), - VMSTATE_YMMH_REGS_VARS(env.ymmh_regs, X86CPU, 0, 12), + VMSTATE_YMMH_REGS_VARS(env.xmm_regs, X86CPU, 0, 12), VMSTATE_END_OF_LIST() /* The above list is not sorted /wrt version numbers, watch out! */ }, -- cgit v1.1 From 65a81af8df722714298f17d2b40da8e5f045e059 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 23 Dec 2014 21:40:55 +0100 Subject: qemu-timer: add timer_init and timer_init_ns/us/ms These functions for the main loop TimerListGroup will replace timer_new and timer_new_ns/us/ms. Signed-off-by: Paolo Bonzini --- include/qemu/timer.h | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 0666920..9a3504c 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -428,6 +428,79 @@ void timer_init_tl(QEMUTimer *ts, QEMUTimerCB *cb, void *opaque); /** + * timer_init: + * @type: the clock to associate with the timer + * @scale: the scale value for the timer + * @cb: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Initialize a timer with the given scale on the default timer list + * associated with the clock. + * + * You need not call an explicit deinit call. Simply make + * sure it is not on a list with timer_del. + */ +static inline void timer_init(QEMUTimer *ts, QEMUClockType type, int scale, + QEMUTimerCB *cb, void *opaque) +{ + timer_init_tl(ts, main_loop_tlg.tl[type], scale, cb, opaque); +} + +/** + * timer_init_ns: + * @type: the clock to associate with the timer + * @cb: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Initialize a timer with nanosecond scale on the default timer list + * associated with the clock. + * + * You need not call an explicit deinit call. Simply make + * sure it is not on a list with timer_del. + */ +static inline void timer_init_ns(QEMUTimer *ts, QEMUClockType type, + QEMUTimerCB *cb, void *opaque) +{ + timer_init(ts, type, SCALE_NS, cb, opaque); +} + +/** + * timer_init_us: + * @type: the clock to associate with the timer + * @cb: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Initialize a timer with microsecond scale on the default timer list + * associated with the clock. + * + * You need not call an explicit deinit call. Simply make + * sure it is not on a list with timer_del. + */ +static inline void timer_init_us(QEMUTimer *ts, QEMUClockType type, + QEMUTimerCB *cb, void *opaque) +{ + timer_init(ts, type, SCALE_US, cb, opaque); +} + +/** + * timer_init_ms: + * @type: the clock to associate with the timer + * @cb: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Initialize a timer with millisecond scale on the default timer list + * associated with the clock. + * + * You need not call an explicit deinit call. Simply make + * sure it is not on a list with timer_del. + */ +static inline void timer_init_ms(QEMUTimer *ts, QEMUClockType type, + QEMUTimerCB *cb, void *opaque) +{ + timer_init(ts, type, SCALE_MS, cb, opaque); +} + +/** * timer_new_tl: * @timer_list: the timer list to attach the timer to * @scale: the scale value for the timer -- cgit v1.1 From cd1bd53a669c88f219ca47b538889cd918605fea Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 24 Dec 2014 10:57:04 +0100 Subject: qemu-timer: introduce timer_deinit In some cases, a timer was set to NULL so that we could check if it is initialized. Use the timer_list field instead, and add a timer_deinit function that NULLs it. It then makes sense that timer_del be a no-op (instead of a crasher) on such a de-initialized timer. It avoids the need to poke at the timerlist field to check if the timers are initialized. Signed-off-by: Paolo Bonzini --- include/qemu/timer.h | 11 +++++++++++ qemu-timer.c | 14 +++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 9a3504c..ca5befb 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -595,6 +595,17 @@ static inline QEMUTimer *timer_new_ms(QEMUClockType type, QEMUTimerCB *cb, } /** + * timer_deinit: + * @ts: the timer to be de-initialised + * + * Deassociate the timer from any timerlist. You should + * call timer_del before. After this call, any further + * timer_del call cannot cause dangling pointer accesses + * even if the previously used timerlist is freed. + */ +void timer_deinit(QEMUTimer *ts); + +/** * timer_free: * @ts: the timer * diff --git a/qemu-timer.c b/qemu-timer.c index 98d9d1b..464396f 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -342,6 +342,12 @@ void timer_init_tl(QEMUTimer *ts, ts->expire_time = -1; } +void timer_deinit(QEMUTimer *ts) +{ + assert(ts->expire_time == -1); + ts->timer_list = NULL; +} + void timer_free(QEMUTimer *ts) { g_free(ts); @@ -398,9 +404,11 @@ void timer_del(QEMUTimer *ts) { QEMUTimerList *timer_list = ts->timer_list; - qemu_mutex_lock(&timer_list->active_timers_lock); - timer_del_locked(timer_list, ts); - qemu_mutex_unlock(&timer_list->active_timers_lock); + if (timer_list) { + qemu_mutex_lock(&timer_list->active_timers_lock); + timer_del_locked(timer_list, ts); + qemu_mutex_unlock(&timer_list->active_timers_lock); + } } /* modify the current timer so that it will be fired when current_time -- cgit v1.1 From e720677e32e70b1f60637ebbcf2ffb23a4607f3e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 8 Jan 2015 10:18:59 +0100 Subject: vmstate: accept QEMUTimer in VMSTATE_TIMER*, add VMSTATE_TIMER_PTR* Old users of VMSTATE_TIMER* are mechanically changed to VMSTATE_TIMER_PTR variants. Signed-off-by: Paolo Bonzini --- hw/acpi/ich9.c | 2 +- hw/acpi/piix4.c | 2 +- hw/arm/stellaris.c | 2 +- hw/block/fdc.c | 2 +- hw/char/cadence_uart.c | 2 +- hw/char/serial.c | 4 ++-- hw/core/ptimer.c | 2 +- hw/dma/pl330.c | 2 +- hw/input/lm832x.c | 2 +- hw/intc/armv7m_nvic.c | 2 +- hw/isa/vt82c686.c | 2 +- hw/misc/macio/cuda.c | 2 +- hw/net/pcnet.c | 2 +- hw/sd/sdhci.c | 4 ++-- hw/timer/a9gtimer.c | 2 +- hw/timer/arm_mptimer.c | 2 +- hw/timer/hpet.c | 2 +- hw/timer/mc146818rtc.c | 4 ++-- hw/usb/hcd-ehci.c | 2 +- hw/usb/hcd-ohci.c | 2 +- hw/usb/hcd-uhci.c | 2 +- hw/usb/hcd-xhci.c | 2 +- hw/usb/redirect.c | 2 +- hw/watchdog/wdt_i6300esb.c | 2 +- hw/watchdog/wdt_ib700.c | 2 +- include/migration/vmstate.h | 18 +++++++++++++++--- target-arm/machine.c | 4 ++-- 27 files changed, 45 insertions(+), 33 deletions(-) diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index ea991a3..43869d7 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -166,7 +166,7 @@ const VMStateDescription vmstate_ich9_pm = { VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs), VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs), VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs), - VMSTATE_TIMER(acpi_regs.tmr.timer, ICH9LPCPMRegs), + VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs), VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs), VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs), VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs), diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 481a16c..184e7e4 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -285,7 +285,7 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState), VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState), VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState), + VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState), VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState), VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE), VMSTATE_STRUCT_TEST( diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 64bd4b4..ccc3b18 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -306,7 +306,7 @@ static const VMStateDescription vmstate_stellaris_gptm = { VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2), VMSTATE_UINT32(rtc, gptm_state), VMSTATE_INT64_ARRAY(tick, gptm_state, 2), - VMSTATE_TIMER_ARRAY(timer, gptm_state, 2), + VMSTATE_TIMER_PTR_ARRAY(timer, gptm_state, 2), VMSTATE_END_OF_LIST() } }; diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 739a03e..2bf87c9 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -791,7 +791,7 @@ static const VMStateDescription vmstate_fdc_result_timer = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_TIMER(result_timer, FDCtrl), + VMSTATE_TIMER_PTR(result_timer, FDCtrl), VMSTATE_END_OF_LIST() } }; diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index a5736cb..7044b35 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -520,7 +520,7 @@ static const VMStateDescription vmstate_cadence_uart = { VMSTATE_UINT32(rx_count, UartState), VMSTATE_UINT32(tx_count, UartState), VMSTATE_UINT32(rx_wpos, UartState), - VMSTATE_TIMER(fifo_trigger_handle, UartState), + VMSTATE_TIMER_PTR(fifo_trigger_handle, UartState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/char/serial.c b/hw/char/serial.c index 3aca874..bd25c03 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -730,7 +730,7 @@ const VMStateDescription vmstate_serial_fifo_timeout_timer = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_TIMER(fifo_timeout_timer, SerialState), + VMSTATE_TIMER_PTR(fifo_timeout_timer, SerialState), VMSTATE_END_OF_LIST() } }; @@ -763,7 +763,7 @@ const VMStateDescription vmstate_serial_poll = { .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_INT32(poll_msl, SerialState), - VMSTATE_TIMER(modem_status_poll, SerialState), + VMSTATE_TIMER_PTR(modem_status_poll, SerialState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 466e543..2abad1f 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -214,7 +214,7 @@ const VMStateDescription vmstate_ptimer = { VMSTATE_INT64(period, ptimer_state), VMSTATE_INT64(last_event, ptimer_state), VMSTATE_INT64(next_event, ptimer_state), - VMSTATE_TIMER(timer, ptimer_state), + VMSTATE_TIMER_PTR(timer, ptimer_state), VMSTATE_END_OF_LIST() } }; diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c index 6b6eaae..16cf77e 100644 --- a/hw/dma/pl330.c +++ b/hw/dma/pl330.c @@ -286,7 +286,7 @@ static const VMStateDescription vmstate_pl330 = { PL330Queue), VMSTATE_STRUCT(write_queue, PL330State, 0, vmstate_pl330_queue, PL330Queue), - VMSTATE_TIMER(timer, PL330State), + VMSTATE_TIMER_PTR(timer, PL330State), VMSTATE_UINT32(inten, PL330State), VMSTATE_UINT32(int_status, PL330State), VMSTATE_UINT32(ev_status, PL330State), diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c index 9eb68e8..530a6e0 100644 --- a/hw/input/lm832x.c +++ b/hw/input/lm832x.c @@ -455,7 +455,7 @@ static const VMStateDescription vmstate_lm_kbd = { VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256), VMSTATE_UINT8(pwm.faddr, LM823KbdState), VMSTATE_BUFFER(pwm.addr, LM823KbdState), - VMSTATE_TIMER_ARRAY(pwm.tm, LM823KbdState, 3), + VMSTATE_TIMER_PTR_ARRAY(pwm.tm, LM823KbdState, 3), VMSTATE_END_OF_LIST() } }; diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index d0543d4..6ff6c7f 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -450,7 +450,7 @@ static const VMStateDescription vmstate_nvic = { VMSTATE_UINT32(systick.control, nvic_state), VMSTATE_UINT32(systick.reload, nvic_state), VMSTATE_INT64(systick.tick, nvic_state), - VMSTATE_TIMER(systick.timer, nvic_state), + VMSTATE_TIMER_PTR(systick.timer, nvic_state), VMSTATE_END_OF_LIST() } }; diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 2f53bf8..17510ce 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -234,7 +234,7 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_UINT16(ar.pm1.evt.en, VT686PMState), VMSTATE_UINT16(ar.pm1.cnt.cnt, VT686PMState), VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER(ar.tmr.timer, VT686PMState), + VMSTATE_TIMER_PTR(ar.tmr.timer, VT686PMState), VMSTATE_INT64(ar.tmr.overflow_time, VT686PMState), VMSTATE_END_OF_LIST() } diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index b4273aa..47d9771 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -631,7 +631,7 @@ static const VMStateDescription vmstate_cuda_timer = { VMSTATE_UINT16(counter_value, CUDATimer), VMSTATE_INT64(load_time, CUDATimer), VMSTATE_INT64(next_irq_time, CUDATimer), - VMSTATE_TIMER_TEST(timer, CUDATimer, cuda_timer_exist), + VMSTATE_TIMER_PTR_TEST(timer, CUDATimer, cuda_timer_exist), VMSTATE_END_OF_LIST() } }; diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c index 8a1c8f1..8486b80 100644 --- a/hw/net/pcnet.c +++ b/hw/net/pcnet.c @@ -1719,7 +1719,7 @@ const VMStateDescription vmstate_pcnet = { VMSTATE_BUFFER(buffer, PCNetState), VMSTATE_UNUSED_TEST(is_version_2, 4), VMSTATE_INT32(tx_busy, PCNetState), - VMSTATE_TIMER(poll_timer, PCNetState), + VMSTATE_TIMER_PTR(poll_timer, PCNetState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 15064d3..10e5355 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1205,8 +1205,8 @@ const VMStateDescription sdhci_vmstate = { VMSTATE_UINT64(admasysaddr, SDHCIState), VMSTATE_UINT8(stopped_state, SDHCIState), VMSTATE_VBUFFER_UINT32(fifo_buffer, SDHCIState, 1, NULL, 0, buf_maxsz), - VMSTATE_TIMER(insert_timer, SDHCIState), - VMSTATE_TIMER(transfer_timer, SDHCIState), + VMSTATE_TIMER_PTR(insert_timer, SDHCIState), + VMSTATE_TIMER_PTR(transfer_timer, SDHCIState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/timer/a9gtimer.c b/hw/timer/a9gtimer.c index a0656d5..435142a 100644 --- a/hw/timer/a9gtimer.c +++ b/hw/timer/a9gtimer.c @@ -328,7 +328,7 @@ static const VMStateDescription vmstate_a9_gtimer = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_TIMER(timer, A9GTimerState), + VMSTATE_TIMER_PTR(timer, A9GTimerState), VMSTATE_UINT64(counter, A9GTimerState), VMSTATE_UINT64(ref_counter, A9GTimerState), VMSTATE_UINT64(cpu_ref_time, A9GTimerState), diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c index 35a0a23..8b93b3c 100644 --- a/hw/timer/arm_mptimer.c +++ b/hw/timer/arm_mptimer.c @@ -246,7 +246,7 @@ static const VMStateDescription vmstate_timerblock = { VMSTATE_UINT32(control, TimerBlock), VMSTATE_UINT32(status, TimerBlock), VMSTATE_INT64(tick, TimerBlock), - VMSTATE_TIMER(timer, TimerBlock), + VMSTATE_TIMER_PTR(timer, TimerBlock), VMSTATE_END_OF_LIST() } }; diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index d8bc231..78d86be 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -299,7 +299,7 @@ static const VMStateDescription vmstate_hpet_timer = { VMSTATE_UINT64(fsb, HPETTimer), VMSTATE_UINT64(period, HPETTimer), VMSTATE_UINT8(wrap_flag, HPETTimer), - VMSTATE_TIMER(qemu_timer, HPETTimer), + VMSTATE_TIMER_PTR(qemu_timer, HPETTimer), VMSTATE_END_OF_LIST() } }; diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index f18d128..5a107fa 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -758,7 +758,7 @@ static const VMStateDescription vmstate_rtc = { VMSTATE_BUFFER(cmos_data, RTCState), VMSTATE_UINT8(cmos_index, RTCState), VMSTATE_UNUSED(7*4), - VMSTATE_TIMER(periodic_timer, RTCState), + VMSTATE_TIMER_PTR(periodic_timer, RTCState), VMSTATE_INT64(next_periodic_time, RTCState), VMSTATE_UNUSED(3*8), VMSTATE_UINT32_V(irq_coalesced, RTCState, 2), @@ -766,7 +766,7 @@ static const VMStateDescription vmstate_rtc = { VMSTATE_UINT64_V(base_rtc, RTCState, 3), VMSTATE_UINT64_V(last_update, RTCState, 3), VMSTATE_INT64_V(offset, RTCState, 3), - VMSTATE_TIMER_V(update_timer, RTCState, 3), + VMSTATE_TIMER_PTR_V(update_timer, RTCState, 3), VMSTATE_UINT64_V(next_alarm_time, RTCState, 3), VMSTATE_END_OF_LIST() }, diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 1cc0fc1..ccf54b6 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -2437,7 +2437,7 @@ const VMStateDescription vmstate_ehci = { VMSTATE_UINT32(portsc[4], EHCIState), VMSTATE_UINT32(portsc[5], EHCIState), /* frame timer */ - VMSTATE_TIMER(frame_timer, EHCIState), + VMSTATE_TIMER_PTR(frame_timer, EHCIState), VMSTATE_UINT64(last_run_ns, EHCIState), VMSTATE_UINT32(async_stepdown, EHCIState), /* schedule state */ diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 9a84eb6..a0d478e 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -2015,7 +2015,7 @@ static const VMStateDescription vmstate_ohci_eof_timer = { .minimum_version_id = 1, .pre_load = ohci_eof_timer_pre_load, .fields = (VMStateField[]) { - VMSTATE_TIMER(eof_timer, OHCIState), + VMSTATE_TIMER_PTR(eof_timer, OHCIState), VMSTATE_END_OF_LIST() }, }; diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 4a4215d..f903de7 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -419,7 +419,7 @@ static const VMStateDescription vmstate_uhci = { VMSTATE_UINT32(fl_base_addr, UHCIState), VMSTATE_UINT8(sof_timing, UHCIState), VMSTATE_UINT8(status2, UHCIState), - VMSTATE_TIMER(frame_timer, UHCIState), + VMSTATE_TIMER_PTR(frame_timer, UHCIState), VMSTATE_INT64_V(expire_time, UHCIState, 2), VMSTATE_UINT32_V(pending_int_mask, UHCIState, 3), VMSTATE_END_OF_LIST() diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 9a942cf..776699b 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -3855,7 +3855,7 @@ static const VMStateDescription vmstate_xhci = { /* Runtime Registers & state */ VMSTATE_INT64(mfindex_start, XHCIState), - VMSTATE_TIMER(mfwrap_timer, XHCIState), + VMSTATE_TIMER_PTR(mfwrap_timer, XHCIState), VMSTATE_STRUCT(cmd_ring, XHCIState, 1, vmstate_xhci_ring, XHCIRing), VMSTATE_END_OF_LIST() diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 9fbd59e..962d3f5 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -2438,7 +2438,7 @@ static const VMStateDescription usbredir_vmstate = { .post_load = usbredir_post_load, .fields = (VMStateField[]) { VMSTATE_USB_DEVICE(dev, USBRedirDevice), - VMSTATE_TIMER(attach_timer, USBRedirDevice), + VMSTATE_TIMER_PTR(attach_timer, USBRedirDevice), { .name = "parser", .version_id = 0, diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c index 687c8b1..33dd6d4 100644 --- a/hw/watchdog/wdt_i6300esb.c +++ b/hw/watchdog/wdt_i6300esb.c @@ -398,7 +398,7 @@ static const VMStateDescription vmstate_i6300esb = { VMSTATE_INT32(free_run, I6300State), VMSTATE_INT32(locked, I6300State), VMSTATE_INT32(enabled, I6300State), - VMSTATE_TIMER(timer, I6300State), + VMSTATE_TIMER_PTR(timer, I6300State), VMSTATE_UINT32(timer1_preload, I6300State), VMSTATE_UINT32(timer2_preload, I6300State), VMSTATE_INT32(stage, I6300State), diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c index 8cb9827..0917a71 100644 --- a/hw/watchdog/wdt_ib700.c +++ b/hw/watchdog/wdt_ib700.c @@ -93,7 +93,7 @@ static const VMStateDescription vmstate_ib700 = { .version_id = 0, .minimum_version_id = 0, .fields = (VMStateField[]) { - VMSTATE_TIMER(timer, IB700State), + VMSTATE_TIMER_PTR(timer, IB700State), VMSTATE_END_OF_LIST() } }; diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 6097b94..fa307a6 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -652,17 +652,29 @@ extern const VMStateInfo vmstate_info_bitmap; #define VMSTATE_FLOAT64(_f, _s) \ VMSTATE_FLOAT64_V(_f, _s, 0) -#define VMSTATE_TIMER_TEST(_f, _s, _test) \ +#define VMSTATE_TIMER_PTR_TEST(_f, _s, _test) \ VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *) -#define VMSTATE_TIMER_V(_f, _s, _v) \ +#define VMSTATE_TIMER_PTR_V(_f, _s, _v) \ VMSTATE_POINTER(_f, _s, _v, vmstate_info_timer, QEMUTimer *) +#define VMSTATE_TIMER_PTR(_f, _s) \ + VMSTATE_TIMER_PTR_V(_f, _s, 0) + +#define VMSTATE_TIMER_PTR_ARRAY(_f, _s, _n) \ + VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *) + +#define VMSTATE_TIMER_TEST(_f, _s, _test) \ + VMSTATE_SINGLE_TEST(_f, _s, _test, 0, vmstate_info_timer, QEMUTimer) + +#define VMSTATE_TIMER_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, vmstate_info_timer, QEMUTimer) + #define VMSTATE_TIMER(_f, _s) \ VMSTATE_TIMER_V(_f, _s, 0) #define VMSTATE_TIMER_ARRAY(_f, _s, _n) \ - VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *) + VMSTATE_ARRAY(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer) #define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool) diff --git a/target-arm/machine.c b/target-arm/machine.c index c29e7a2..9446e5a 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -277,8 +277,8 @@ const VMStateDescription vmstate_arm_cpu = { VMSTATE_UINT32(env.exception.syndrome, ARMCPU), VMSTATE_UINT32(env.exception.fsr, ARMCPU), VMSTATE_UINT64(env.exception.vaddress, ARMCPU), - VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU), - VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU), + VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), + VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), VMSTATE_BOOL(powered_off, ARMCPU), VMSTATE_END_OF_LIST() }, -- cgit v1.1 From b30934cb52a72a763da21dccc9994c64517d6f25 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 21 Jan 2015 17:48:33 +0100 Subject: hw: misc, add educational driver I am using qemu for teaching the Linux kernel at our university. I wrote a simple PCI device that can answer to writes/reads, generate interrupts and perform DMA. As I am dragging it locally over 2 years, I am sending it to you now. Signed-off-by: Jiri Slaby [Fix 32-bit compilation. - Paolo] Signed-off-by: Paolo Bonzini --- MAINTAINERS | 5 + default-configs/pci.mak | 1 + docs/specs/edu.txt | 110 +++++++++++++ hw/misc/Makefile.objs | 1 + hw/misc/edu.c | 408 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 525 insertions(+) create mode 100644 docs/specs/edu.txt create mode 100644 hw/misc/edu.c diff --git a/MAINTAINERS b/MAINTAINERS index 430688d..fd335a4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -599,6 +599,11 @@ F: hw/net/opencores_eth.c Devices ------- +EDU +M: Jiri Slaby +S: Maintained +F: hw/misc/edu.c + IDE M: Kevin Wolf M: Stefan Hajnoczi diff --git a/default-configs/pci.mak b/default-configs/pci.mak index a186c39..030cdc7 100644 --- a/default-configs/pci.mak +++ b/default-configs/pci.mak @@ -32,3 +32,4 @@ CONFIG_PCI_TESTDEV=y CONFIG_NVME_PCI=y CONFIG_SD=y CONFIG_SDHCI=y +CONFIG_EDU=y diff --git a/docs/specs/edu.txt b/docs/specs/edu.txt new file mode 100644 index 0000000..7f81467 --- /dev/null +++ b/docs/specs/edu.txt @@ -0,0 +1,110 @@ + +EDU device +========== + +Copyright (c) 2014-2015 Jiri Slaby + +This document is licensed under the GPLv2 (or later). + +This is an educational device for writing (kernel) drivers. Its original +intention was to support the Linux kernel lectures taught at the Masaryk +University. Students are given this virtual device and are expected to write a +driver with I/Os, IRQs, DMAs and such. + +The devices behaves very similar to the PCI bridge present in the COMBO6 cards +developed under the Liberouter wings. Both PCI device ID and PCI space is +inherited from that device. + +Command line switches: + -device edu[,dma_mask=mask] + + dma_mask makes the virtual device work with DMA addresses with the given + mask. For educational purposes, the device supports only 28 bits (256 MiB) + by default. Students shall set dma_mask for the device in the OS driver + properly. + +PCI specs +--------- + +PCI ID: 1234:11e8 + +PCI Region 0: + I/O memory, 1 MB in size. Users are supposed to communicate with the card + through this memory. + +MMIO area spec +-------------- + +Only size == 4 accesses are allowed for addresses < 0x80. size == 4 or +size == 8 for the rest. + +0x00 (RO) : identification (0xRRrr00edu) + RR -- major version + rr -- minor version + +0x04 (RW) : card liveness check + It is a simple value inversion (~ C operator). + +0x08 (RW) : factorial computation + The stored value is taken and factorial of it is put back here. + This happens only after factorial bit in the status register (0x20 + below) is cleared. + +0x20 (RW) : status register, bitwise OR + 0x01 -- computing factorial (RO) + 0x80 -- raise interrupt 0x01 after finishing factorial computation + +0x24 (RO) : interrupt status register + It contains values which raised the interrupt (see interrupt raise + register below). + +0x60 (WO) : interrupt raise register + Raise an interrupt. The value will be put to the interrupt status + register (using bitwise OR). + +0x64 (WO) : interrupt acknowledge register + Clear an interrupt. The value will be cleared from the interrupt + status register. This needs to be done from the ISR to stop + generating interrupts. + +0x80 (RW) : DMA source address + Where to perform the DMA from. + +0x88 (RW) : DMA destination address + Where to perform the DMA to. + +0x90 (RW) : DMA transfer count + The size of the area to perform the DMA on. + +0x98 (RW) : DMA command register, bitwise OR + 0x01 -- start transfer + 0x02 -- direction (0: from RAM to EDU, 1: from EDU to RAM) + 0x04 -- raise interrupt 0x100 after finishing the DMA + +IRQ controller +-------------- +An IRQ is generated when written to the interrupt raise register. The value +appears in interrupt status register when the interrupt is raised and has to +be written to the interrupt acknowledge register to lower it. + +DMA controller +-------------- +One has to specify, source, destination, size, and start the transfer. One +4096 bytes long buffer at offset 0x40000 is available in the EDU device. I.e. +one can perform DMA to/from this space when programmed properly. + +Example of transferring a 100 byte block to and from the buffer using a given +PCI address 'addr': +addr -> DMA source address +0x40000 -> DMA destination address +100 -> DMA transfer count +1 -> DMA command register +while (DMA command register & 1) + ; + +0x40000 -> DMA source address +addr+100 -> DMA destination address +100 -> DMA transfer count +3 -> DMA command register +while (DMA command register & 1) + ; diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index e47fea8..029a56f 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -40,3 +40,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o obj-$(CONFIG_ZYNQ) += zynq_slcr.o obj-$(CONFIG_PVPANIC) += pvpanic.o +obj-$(CONFIG_EDU) += edu.o diff --git a/hw/misc/edu.c b/hw/misc/edu.c new file mode 100644 index 0000000..f601069 --- /dev/null +++ b/hw/misc/edu.c @@ -0,0 +1,408 @@ +/* + * QEMU educational PCI device + * + * Copyright (c) 2012-2015 Jiri Slaby + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "hw/pci/pci.h" +#include "qemu/timer.h" +#include "qemu/main-loop.h" /* iothread mutex */ +#include "qapi/visitor.h" + +#define EDU(obj) OBJECT_CHECK(EduState, obj, "edu") + +#define FACT_IRQ 0x00000001 +#define DMA_IRQ 0x00000100 + +#define DMA_START 0x40000 +#define DMA_SIZE 4096 + +typedef struct { + PCIDevice pdev; + MemoryRegion mmio; + + QemuThread thread; + QemuMutex thr_mutex; + QemuCond thr_cond; + bool stopping; + + uint32_t addr4; + uint32_t fact; +#define EDU_STATUS_COMPUTING 0x01 +#define EDU_STATUS_IRQFACT 0x80 + uint32_t status; + + uint32_t irq_status; + +#define EDU_DMA_RUN 0x1 +#define EDU_DMA_DIR(cmd) (((cmd) & 0x2) >> 1) +# define EDU_DMA_FROM_PCI 0 +# define EDU_DMA_TO_PCI 1 +#define EDU_DMA_IRQ 0x4 + struct dma_state { + dma_addr_t src; + dma_addr_t dst; + dma_addr_t cnt; + dma_addr_t cmd; + } dma; + QEMUTimer dma_timer; + char dma_buf[DMA_SIZE]; + uint64_t dma_mask; +} EduState; + +static void edu_raise_irq(EduState *edu, uint32_t val) +{ + edu->irq_status |= val; + if (edu->irq_status) { + pci_set_irq(&edu->pdev, 1); + } +} + +static void edu_lower_irq(EduState *edu, uint32_t val) +{ + edu->irq_status &= ~val; + + if (!edu->irq_status) { + pci_set_irq(&edu->pdev, 0); + } +} + +static bool within(uint32_t addr, uint32_t start, uint32_t end) +{ + return start <= addr && addr < end; +} + +static void edu_check_range(uint32_t addr, uint32_t size1, uint32_t start, + uint32_t size2) +{ + uint32_t end1 = addr + size1; + uint32_t end2 = start + size2; + + if (within(addr, start, end2) && + end1 > addr && within(end1, start, end2)) { + return; + } + + hw_error("EDU: DMA range 0x%.8x-0x%.8x out of bounds (0x%.8x-0x%.8x)!", + addr, end1 - 1, start, end2 - 1); +} + +static dma_addr_t edu_clamp_addr(const EduState *edu, dma_addr_t addr) +{ + dma_addr_t res = addr & edu->dma_mask; + + if (addr != res) { + printf("EDU: clamping DMA %#.16"PRIx64" to %#.16"PRIx64"!\n", addr, res); + } + + return res; +} + +static void edu_dma_timer(void *opaque) +{ + EduState *edu = opaque; + bool raise_irq = false; + + if (!(edu->dma.cmd & EDU_DMA_RUN)) { + return; + } + + if (EDU_DMA_DIR(edu->dma.cmd) == EDU_DMA_FROM_PCI) { + uint32_t dst = edu->dma.dst; + edu_check_range(dst, edu->dma.cnt, DMA_START, DMA_SIZE); + dst -= DMA_START; + pci_dma_read(&edu->pdev, edu_clamp_addr(edu, edu->dma.src), + edu->dma_buf + dst, edu->dma.cnt); + } else { + uint32_t src = edu->dma.src; + edu_check_range(src, edu->dma.cnt, DMA_START, DMA_SIZE); + src -= DMA_START; + pci_dma_write(&edu->pdev, edu_clamp_addr(edu, edu->dma.dst), + edu->dma_buf + src, edu->dma.cnt); + } + + edu->dma.cmd &= ~EDU_DMA_RUN; + if (edu->dma.cmd & EDU_DMA_IRQ) { + raise_irq = true; + } + + if (raise_irq) { + edu_raise_irq(edu, DMA_IRQ); + } +} + +static void dma_rw(EduState *edu, bool write, dma_addr_t *val, dma_addr_t *dma, + bool timer) +{ + if (write && (edu->dma.cmd & EDU_DMA_RUN)) { + return; + } + + if (write) { + *dma = *val; + } else { + *val = *dma; + } + + if (timer) { + timer_mod(&edu->dma_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100); + } +} + +static uint64_t edu_mmio_read(void *opaque, hwaddr addr, unsigned size) +{ + EduState *edu = opaque; + uint64_t val = ~0ULL; + + if (size != 4) { + return val; + } + + switch (addr) { + case 0x00: + val = 0x010000edu; + break; + case 0x04: + val = edu->addr4; + break; + case 0x08: + qemu_mutex_lock(&edu->thr_mutex); + val = edu->fact; + qemu_mutex_unlock(&edu->thr_mutex); + break; + case 0x20: + val = atomic_read(&edu->status); + break; + case 0x24: + val = edu->irq_status; + break; + case 0x80: + dma_rw(edu, false, &val, &edu->dma.src, false); + break; + case 0x88: + dma_rw(edu, false, &val, &edu->dma.dst, false); + break; + case 0x90: + dma_rw(edu, false, &val, &edu->dma.cnt, false); + break; + case 0x98: + dma_rw(edu, false, &val, &edu->dma.cmd, false); + break; + } + + return val; +} + +static void edu_mmio_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + EduState *edu = opaque; + + if (addr < 0x80 && size != 4) { + return; + } + + if (addr >= 0x80 && size != 4 && size != 8) { + return; + } + + switch (addr) { + case 0x04: + edu->addr4 = ~val; + break; + case 0x08: + if (atomic_read(&edu->status) & EDU_STATUS_COMPUTING) { + break; + } + /* EDU_STATUS_COMPUTING cannot go 0->1 concurrently, because it is only + * set in this function and it is under the iothread mutex. + */ + qemu_mutex_lock(&edu->thr_mutex); + edu->fact = val; + atomic_or(&edu->status, EDU_STATUS_COMPUTING); + qemu_cond_signal(&edu->thr_cond); + qemu_mutex_unlock(&edu->thr_mutex); + break; + case 0x20: + if (val & EDU_STATUS_IRQFACT) { + atomic_or(&edu->status, EDU_STATUS_IRQFACT); + } else { + atomic_and(&edu->status, ~EDU_STATUS_IRQFACT); + } + break; + case 0x60: + edu_raise_irq(edu, val); + break; + case 0x64: + edu_lower_irq(edu, val); + break; + case 0x80: + dma_rw(edu, true, &val, &edu->dma.src, false); + break; + case 0x88: + dma_rw(edu, true, &val, &edu->dma.dst, false); + break; + case 0x90: + dma_rw(edu, true, &val, &edu->dma.cnt, false); + break; + case 0x98: + if (!(val & EDU_DMA_RUN)) { + break; + } + dma_rw(edu, true, &val, &edu->dma.cmd, true); + break; + } +} + +static const MemoryRegionOps edu_mmio_ops = { + .read = edu_mmio_read, + .write = edu_mmio_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +/* + * We purposedly use a thread, so that users are forced to wait for the status + * register. + */ +static void *edu_fact_thread(void *opaque) +{ + EduState *edu = opaque; + + while (1) { + uint32_t val, ret = 1; + + qemu_mutex_lock(&edu->thr_mutex); + while ((atomic_read(&edu->status) & EDU_STATUS_COMPUTING) == 0 && + !edu->stopping) { + qemu_cond_wait(&edu->thr_cond, &edu->thr_mutex); + } + + if (edu->stopping) { + qemu_mutex_unlock(&edu->thr_mutex); + break; + } + + val = edu->fact; + qemu_mutex_unlock(&edu->thr_mutex); + + while (val > 0) { + ret *= val--; + } + + /* + * We should sleep for a random period here, so that students are + * forced to check the status properly. + */ + + qemu_mutex_lock(&edu->thr_mutex); + edu->fact = ret; + qemu_mutex_unlock(&edu->thr_mutex); + atomic_and(&edu->status, ~EDU_STATUS_COMPUTING); + + if (atomic_read(&edu->status) & EDU_STATUS_IRQFACT) { + qemu_mutex_lock_iothread(); + edu_raise_irq(edu, FACT_IRQ); + qemu_mutex_unlock_iothread(); + } + } + + return NULL; +} + +static int pci_edu_init(PCIDevice *pdev) +{ + EduState *edu = DO_UPCAST(EduState, pdev, pdev); + uint8_t *pci_conf = pdev->config; + + timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu); + + qemu_mutex_init(&edu->thr_mutex); + qemu_cond_init(&edu->thr_cond); + qemu_thread_create(&edu->thread, "edu", edu_fact_thread, + edu, QEMU_THREAD_JOINABLE); + + pci_config_set_interrupt_pin(pci_conf, 1); + + memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu, + "edu-mmio", 1 << 20); + pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio); + + return 0; +} + +static void pci_edu_uninit(PCIDevice *pdev) +{ + EduState *edu = DO_UPCAST(EduState, pdev, pdev); + + qemu_mutex_lock(&edu->thr_mutex); + edu->stopping = true; + qemu_mutex_unlock(&edu->thr_mutex); + qemu_cond_signal(&edu->thr_cond); + qemu_thread_join(&edu->thread); + + qemu_cond_destroy(&edu->thr_cond); + qemu_mutex_destroy(&edu->thr_mutex); + + timer_del(&edu->dma_timer); +} + +static void edu_obj_uint64(Object *obj, struct Visitor *v, void *opaque, + const char *name, Error **errp) +{ + uint64_t *val = opaque; + + visit_type_uint64(v, val, name, errp); +} + +static void edu_instance_init(Object *obj) +{ + EduState *edu = EDU(obj); + + edu->dma_mask = (1UL << 28) - 1; + object_property_add(obj, "dma_mask", "uint64", edu_obj_uint64, + edu_obj_uint64, NULL, &edu->dma_mask, NULL); +} + +static void edu_class_init(ObjectClass *class, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(class); + + k->init = pci_edu_init; + k->exit = pci_edu_uninit; + k->vendor_id = PCI_VENDOR_ID_QEMU; + k->device_id = 0x11e8; + k->revision = 0x10; + k->class_id = PCI_CLASS_OTHERS; +} + +static void pci_edu_register_types(void) +{ + static const TypeInfo edu_info = { + .name = "edu", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(EduState), + .instance_init = edu_instance_init, + .class_init = edu_class_init, + }; + + type_register_static(&edu_info); +} +type_init(pci_edu_register_types) -- cgit v1.1 From edcbc401f42077f9d62713d439839201a73a5966 Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Wed, 21 Jan 2015 16:15:29 -0500 Subject: kvm_stat: Add aarch64 support This patch enables aarch64 support for kvm_stat. The platform detection is based on OS uname. Signed-off-by: Wei Huang Signed-off-by: Paolo Bonzini --- scripts/kvm/kvm_stat | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index 7b1437c..470ca08 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -204,10 +204,18 @@ def ppc_init(): } }) +def aarch64_init(): + globals().update({ + 'sc_perf_evt_open' : 241 + }) + def detect_platform(): if os.uname()[4].startswith('ppc'): ppc_init() return + elif os.uname()[4].startswith('aarch64'): + aarch64_init() + return for line in file('/proc/cpuinfo').readlines(): if line.startswith('flags'): -- cgit v1.1 From 2c9d535a2e43699de32987b76cf548a39e4d04d2 Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Wed, 21 Jan 2015 16:15:30 -0500 Subject: kvm_stat: Update exit reasons to the latest defintion This patch updates the exit reasons for x86_vmx, x86_svm, and userspace to the latest definition. Signed-off-by: Wei Huang Signed-off-by: Paolo Bonzini --- scripts/kvm/kvm_stat | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index 470ca08..95c650b 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -65,6 +65,8 @@ vmx_exit_reasons = { 49: 'EPT_MISCONFIG', 54: 'WBINVD', 55: 'XSETBV', + 56: 'APIC_WRITE', + 58: 'INVPCID', } svm_exit_reasons = { @@ -138,6 +140,7 @@ svm_exit_reasons = { 0x08a: 'MONITOR', 0x08b: 'MWAIT', 0x08c: 'MWAIT_COND', + 0x08d: 'XSETBV', 0x400: 'NPF', } @@ -167,6 +170,7 @@ userspace_exit_reasons = { 21: 'WATCHDOG', 22: 'S390_TSCH', 23: 'EPR', + 24: 'SYSTEM_EVENT', } x86_exit_reasons = { -- cgit v1.1 From 874b1cfad51e325d535f99261f91c92df444c18c Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Wed, 21 Jan 2015 16:15:31 -0500 Subject: kvm_stat: Print errno when syscall to perf_event_open() fails kvm_stat uses syscall() to call perf_event_open(). If this function call fails, the returned value is -1, which doesn't tell the details of such failure (i.e. ENOSYS or EINVAL). This patch retrieves errno and prints it when syscall() fails. The error message will look like "Exception: perf_event_open failed, errno = 38". Signed-off-by: Wei Huang Signed-off-by: Paolo Bonzini --- scripts/kvm/kvm_stat | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index 95c650b..8f6f007 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -13,6 +13,7 @@ import curses import sys, os, time, optparse, ctypes +from ctypes import * class DebugfsProvider(object): def __init__(self): @@ -247,6 +248,9 @@ import struct, array libc = ctypes.CDLL('libc.so.6') syscall = libc.syscall +get_errno = libc.__errno_location +get_errno.restype = POINTER(c_int) + class perf_event_attr(ctypes.Structure): _fields_ = [('type', ctypes.c_uint32), ('size', ctypes.c_uint32), @@ -330,7 +334,8 @@ class Event(object): group_leader = group.events[0].fd fd = _perf_event_open(attr, -1, group.cpu, group_leader, 0) if fd == -1: - raise Exception('perf_event_open failed') + err = get_errno()[0] + raise Exception('perf_event_open failed, errno = ' + err.__str__()) if filter: import fcntl fcntl.ioctl(fd, ioctl_numbers['SET_FILTER'], filter) -- cgit v1.1 From 927411fa42c5fcf16ed0fcc0447d5ee8c83b22ca Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 20 Jan 2015 11:07:09 +0100 Subject: apic: do not dereference pointer before it is checked for NULL Right now you only get to apic_init_reset if you have an APIC (do_cpu_init is reached only if CPU_INTERRUPT_INIT is set and that only happens in hw/intc/apic.c). However, this is wrong because for example a port 92 or keyboard controller reset is really an INIT, and that can happen also with no APIC. So keep the check and fix the error that Coverity reported. Reported-by: Markus Armbruster Reviewed-by: Markus Armbruster Signed-off-by: Paolo Bonzini --- hw/intc/apic_common.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index d9bb188..0858b45 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -177,13 +177,14 @@ bool apic_next_timer(APICCommonState *s, int64_t current_time) void apic_init_reset(DeviceState *dev) { - APICCommonState *s = APIC_COMMON(dev); - APICCommonClass *info = APIC_COMMON_GET_CLASS(s); + APICCommonState *s; + APICCommonClass *info; int i; - if (!s) { + if (!dev) { return; } + s = APIC_COMMON(dev); s->tpr = 0; s->spurious_vec = 0xff; s->log_dest = 0; @@ -208,6 +209,7 @@ void apic_init_reset(DeviceState *dev) } s->timer_expiry = -1; + info = APIC_COMMON_GET_CLASS(s); if (info->reset) { info->reset(s); } -- cgit v1.1 From dd858343a73c5c47019c6ade282a91681e0d7105 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 23 Jan 2015 10:43:49 +0100 Subject: .travis.yml: Add "--enable-modules" We will change the default to "--enable-modules", let's cover it before the switch. Signed-off-by: Paolo Bonzini --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index ad66e5b..0ac170b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -98,3 +98,6 @@ matrix: EXTRA_PKGS="liblttng-ust-dev liburcu-dev" EXTRA_CONFIG="--enable-trace-backends=ust" compiler: gcc + - env: TARGETS=i386-softmmu,x86_64-softmmu + EXTRA_CONFIG="--enable-modules" + compiler: gcc -- cgit v1.1 From a904c91196a9c5dbd7b9abcd3d40b0824286fb1c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 21 Jan 2015 16:18:35 +0100 Subject: exec: fix madvise of NULL pointer Coverity flags this as "dereference after null check". Not quite a dereference, since it will just EFAULT, but still nice to fix. Signed-off-by: Paolo Bonzini --- exec.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/exec.c b/exec.c index 410371d..6b79ad1 100644 --- a/exec.c +++ b/exec.c @@ -1386,12 +1386,13 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp) cpu_physical_memory_set_dirty_range(new_block->offset, new_block->used_length); - qemu_ram_setup_dump(new_block->host, new_block->max_length); - qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE); - qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK); - - if (kvm_enabled()) { - kvm_setup_guest_memory(new_block->host, new_block->max_length); + if (new_block->host) { + qemu_ram_setup_dump(new_block->host, new_block->max_length); + qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE); + qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK); + if (kvm_enabled()) { + kvm_setup_guest_memory(new_block->host, new_block->max_length); + } } return new_block->offset; -- cgit v1.1 From 80fd48df4a53d01cc5d8a41e565f81af5978121f Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 22 Jan 2015 10:53:46 +0100 Subject: sparse: Fix build with sparse on .S files rules.mak has a rule for .S files using CPP. This will result in errors like CPP s390-ccw/start.asm cc: error: unrecognized command line option '-Wbitwise' Lets also redefine CPP in case of --enable-sparse. Signed-off-by: Christian Borntraeger Signed-off-by: Paolo Bonzini --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 5ea1014..f185dd0 100755 --- a/configure +++ b/configure @@ -4938,6 +4938,7 @@ echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak if test "$sparse" = "yes" ; then echo "CC := REAL_CC=\"\$(CC)\" cgcc" >> $config_host_mak + echo "CPP := REAL_CC=\"\$(CPP)\" cgcc" >> $config_host_mak echo "CXX := REAL_CC=\"\$(CXX)\" cgcc" >> $config_host_mak echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak -- cgit v1.1 From 13704e4c455770d500d6b87b117e32f0d01252c9 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 22 Jan 2015 17:22:54 -0200 Subject: target-i386: Disable HLE and RTM on Haswell & Broadwell All Haswell CPUs and some Broadwell CPUs were updated by Intel to have the HLE and RTM features disabled. This will prevent "-cpu Haswell,enforce" and "-cpu Broadwell,enforce" from running out of the box on those CPUs. Disable those features by default on Broadwell and Haswell CPU models, starting on pc-*-2.3. Users who want to use those features can enable them explicitly on the command-line. Signed-off-by: Eduardo Habkost Signed-off-by: Paolo Bonzini --- hw/i386/pc_piix.c | 4 ++++ hw/i386/pc_q35.c | 4 ++++ target-i386/cpu.c | 9 ++++----- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 97a754e..38b42b0 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -328,6 +328,10 @@ static void pc_compat_2_2(MachineState *machine) x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C); x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); + x86_cpu_compat_set_features("Haswell", FEAT_7_0_EBX, + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0); + x86_cpu_compat_set_features("Broadwell", FEAT_7_0_EBX, + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0); } static void pc_compat_2_1(MachineState *machine) diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index a432944..63027ee 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -307,6 +307,10 @@ static void pc_compat_2_2(MachineState *machine) x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C); x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); + x86_cpu_compat_set_features("Haswell", FEAT_7_0_EBX, + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0); + x86_cpu_compat_set_features("Broadwell", FEAT_7_0_EBX, + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0); } static void pc_compat_2_1(MachineState *machine) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index b81ac5c..3a9b32e 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1100,9 +1100,8 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_EXT3_LAHF_LM, .features[FEAT_7_0_EBX] = CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | - CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | - CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | - CPUID_7_0_EBX_RTM, + CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | + CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID, .features[FEAT_XSAVE] = CPUID_XSAVE_XSAVEOPT, .xlevel = 0x8000000A, @@ -1135,9 +1134,9 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, .features[FEAT_7_0_EBX] = CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | - CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | + CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | - CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | + CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP, .features[FEAT_XSAVE] = CPUID_XSAVE_XSAVEOPT, -- cgit v1.1 From fc116efad0aadb2f8a49d51240bddbfe21b631a0 Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Fri, 23 Jan 2015 15:56:04 -0500 Subject: kvm_stat: Add RESET support for perf event ioctl While running kvm_stat using tracepoint on ARM64 hardware (e.g. "kvm_stat -1 -t"), the initial values of some kvm_userspace_exit counters were found to be very suspecious. For instance the tracing tool showed that S390_TSCH was called many times on ARM64 machine, which apparently was wrong. This patch adds RESET ioctl support for perf monitoring. Before calling ioctl to enable a perf event, this patch resets the counter first. With this patch, the init counter values become correct on ARM64 hardware. Example: ==== before patch ==== kvm_userspace_exit(S390_SIEIC) 1426 0 kvm_userspace_exit(S390_TSCH) 339 0 ==== after patch ==== kvm_userspace_exit(S390_SIEIC) 0 0 kvm_userspace_exit(S390_TSCH) 0 0 Signed-off-by: Wei Huang --- scripts/kvm/kvm_stat | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index 8f6f007..c0c4ff0 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -186,6 +186,7 @@ ioctl_numbers = { 'SET_FILTER' : 0x40082406, 'ENABLE' : 0x00002400, 'DISABLE' : 0x00002401, + 'RESET' : 0x00002403, } def x86_init(flag): @@ -346,6 +347,9 @@ class Event(object): def disable(self): import fcntl fcntl.ioctl(self.fd, ioctl_numbers['DISABLE'], 0) + def reset(self): + import fcntl + fcntl.ioctl(self.fd, ioctl_numbers['RESET'], 0) class TracepointProvider(object): def __init__(self): @@ -405,6 +409,7 @@ class TracepointProvider(object): for group in self.group_leaders: for event in group.events: if event.name in fields: + event.reset() event.enable() else: event.disable() -- cgit v1.1