diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2024-02-28 14:23:21 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2024-02-28 14:23:21 +0000 |
commit | bfe8020c814a30479a4241aaa78b63960655962b (patch) | |
tree | 61e7b433ec36c16307fad7d6a3c499bfd6002a76 | |
parent | d316f1b14615854de1bf4c0a9789e9c8951cc437 (diff) | |
parent | d13f40357b307e49a7983bd52d4ec35003b7ddc0 (diff) | |
download | qemu-bfe8020c814a30479a4241aaa78b63960655962b.zip qemu-bfe8020c814a30479a4241aaa78b63960655962b.tar.gz qemu-bfe8020c814a30479a4241aaa78b63960655962b.tar.bz2 |
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* target/i386: Fix physical address truncation on 32-bit PAE
* Remove globals for options -no-fd-bootchk and -win2k-hack
# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmXebwQUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroPozAf/Vgc9u6C+8PcPDrol6qxjI+EOHLNy
# 7M3/OFpUkwLXuOSawb6syYxHpLS38fKRcsb2ninngUmbRWA6p+KNUizlAFMj7op5
# wJmtdamCwCwXXaw20SfWxx2Ih0JS7FQsRsU94HTOdaDB17C9+hBcYwcggsOAXCmq
# gyVenEF1mov2A4jLMhdVIRX784AAoEP+QAuhBKQBrQwRLCTTyNdHl7jXdB9w+2sh
# KafokoFLcozJHz/tN3AhRKy6zjPugJyQmJwBRuj9tstCILtXpvf/ZE/3pUq5l3ZY
# A6dCI0zWAlGNTkpKRXsMFozNIVP2htnyidy29XHptlY5acfjtQ++rMu3BQ==
# =WY4H
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 27 Feb 2024 23:23:48 GMT
# gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg: issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1
# Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83
* tag 'for-upstream' of https://gitlab.com/bonzini/qemu:
ide, vl: turn -win2k-hack into a property on IDE devices
ide: collapse parameters to ide_init_drive
target/i386: leave the A20 bit set in the final NPT walk
target/i386: remove unnecessary/wrong application of the A20 mask
target/i386: Fix physical address truncation
target/i386: use separate MMU indexes for 32-bit accesses
target/i386: introduce function to query MMU indices
target/i386: check validity of VMCB addresses
target/i386: mask high bits of CR3 in 32-bit mode
vl, pc: turn -no-fd-bootchk into a machine property
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/i386/pc.c | 39 | ||||
-rw-r--r-- | hw/ide/core.c | 43 | ||||
-rw-r--r-- | hw/ide/ide-dev.c | 6 | ||||
-rw-r--r-- | hw/ide/ide-internal.h | 6 | ||||
-rw-r--r-- | include/hw/i386/pc.h | 2 | ||||
-rw-r--r-- | include/hw/ide/ide-dev.h | 2 | ||||
-rw-r--r-- | include/sysemu/sysemu.h | 1 | ||||
-rw-r--r-- | qemu-options.hx | 5 | ||||
-rw-r--r-- | system/globals.c | 2 | ||||
-rw-r--r-- | system/vl.c | 4 | ||||
-rw-r--r-- | target/i386/cpu.c | 9 | ||||
-rw-r--r-- | target/i386/cpu.h | 46 | ||||
-rw-r--r-- | target/i386/tcg/sysemu/excp_helper.c | 52 | ||||
-rw-r--r-- | target/i386/tcg/sysemu/misc_helper.c | 3 | ||||
-rw-r--r-- | target/i386/tcg/sysemu/svm_helper.c | 27 |
15 files changed, 157 insertions, 90 deletions
diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 880e95d..f5ff970 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -399,8 +399,8 @@ static int boot_device2nibble(char boot_device) return 0; } -static void set_boot_dev(MC146818RtcState *s, const char *boot_device, - Error **errp) +static void set_boot_dev(PCMachineState *pcms, MC146818RtcState *s, + const char *boot_device, Error **errp) { #define PC_MAX_BOOT_DEVICES 3 int nbds, bds[3] = { 0, }; @@ -420,12 +420,14 @@ static void set_boot_dev(MC146818RtcState *s, const char *boot_device, } } mc146818rtc_set_cmos_data(s, 0x3d, (bds[1] << 4) | bds[0]); - mc146818rtc_set_cmos_data(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1)); + mc146818rtc_set_cmos_data(s, 0x38, (bds[2] << 4) | !pcms->fd_bootchk); } static void pc_boot_set(void *opaque, const char *boot_device, Error **errp) { - set_boot_dev(opaque, boot_device, errp); + PCMachineState *pcms = PC_MACHINE(current_machine); + + set_boot_dev(pcms, opaque, boot_device, errp); } static void pc_cmos_init_floppy(MC146818RtcState *rtc_state, ISADevice *floppy) @@ -611,7 +613,15 @@ void pc_cmos_init(PCMachineState *pcms, mc146818rtc_set_cmos_data(s, 0x5c, val >> 8); mc146818rtc_set_cmos_data(s, 0x5d, val >> 16); - set_boot_dev(s, MACHINE(pcms)->boot_config.order, &error_fatal); + object_property_add_link(OBJECT(pcms), "rtc_state", + TYPE_ISA_DEVICE, + (Object **)&x86ms->rtc, + object_property_allow_set_link, + OBJ_PROP_LINK_STRONG); + object_property_set_link(OBJECT(pcms), "rtc_state", OBJECT(s), + &error_abort); + + set_boot_dev(pcms, s, MACHINE(pcms)->boot_config.order, &error_fatal); val = 0; val |= 0x02; /* FPU is there */ @@ -1535,6 +1545,20 @@ static void pc_machine_set_vmport(Object *obj, Visitor *v, const char *name, visit_type_OnOffAuto(v, name, &pcms->vmport, errp); } +static bool pc_machine_get_fd_bootchk(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + return pcms->fd_bootchk; +} + +static void pc_machine_set_fd_bootchk(Object *obj, bool value, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + pcms->fd_bootchk = value; +} + static bool pc_machine_get_smbus(Object *obj, Error **errp) { PCMachineState *pcms = PC_MACHINE(obj); @@ -1723,6 +1747,7 @@ static void pc_machine_initfn(Object *obj) #ifdef CONFIG_HPET pcms->hpet_enabled = true; #endif + pcms->fd_bootchk = true; pcms->default_bus_bypass_iommu = false; pcms->pcspk = isa_new(TYPE_PC_SPEAKER); @@ -1869,6 +1894,10 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) NULL, NULL); object_class_property_set_description(oc, PC_MACHINE_SMBIOS_EP, "SMBIOS Entry Point type [32, 64]"); + + object_class_property_add_bool(oc, "fd-bootchk", + pc_machine_get_fd_bootchk, + pc_machine_set_fd_bootchk); } static const TypeInfo pc_machine_info = { diff --git a/hw/ide/core.c b/hw/ide/core.c index 130c4d8..e8cb2da 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1059,7 +1059,7 @@ static void ide_sector_write_cb(void *opaque, int ret) ide_sector_write); } - if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { + if (s->win2k_install_hack && ((++s->irq_count % 16) == 0)) { /* It seems there is a bug in the Windows 2000 installer HDD IDE driver which fills the disk with empty logs when the IDE write IRQ comes too early. This hack tries to correct @@ -2589,24 +2589,21 @@ static const BlockDevOps ide_hd_block_ops = { .resize_cb = ide_resize_cb, }; -int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, - const char *version, const char *serial, const char *model, - uint64_t wwn, - uint32_t cylinders, uint32_t heads, uint32_t secs, - int chs_trans, Error **errp) +int ide_init_drive(IDEState *s, IDEDevice *dev, IDEDriveKind kind, Error **errp) { uint64_t nb_sectors; - s->blk = blk; + s->blk = dev->conf.blk; s->drive_kind = kind; - blk_get_geometry(blk, &nb_sectors); - s->cylinders = cylinders; - s->heads = s->drive_heads = heads; - s->sectors = s->drive_sectors = secs; - s->chs_trans = chs_trans; + blk_get_geometry(s->blk, &nb_sectors); + s->win2k_install_hack = dev->win2k_install_hack; + s->cylinders = dev->conf.cyls; + s->heads = s->drive_heads = dev->conf.heads; + s->sectors = s->drive_sectors = dev->conf.secs; + s->chs_trans = dev->chs_trans; s->nb_sectors = nb_sectors; - s->wwn = wwn; + s->wwn = dev->wwn; /* The SMART values should be preserved across power cycles but they aren't. */ s->smart_enabled = 1; @@ -2614,26 +2611,26 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, s->smart_errors = 0; s->smart_selftest_count = 0; if (kind == IDE_CD) { - blk_set_dev_ops(blk, &ide_cd_block_ops, s); + blk_set_dev_ops(s->blk, &ide_cd_block_ops, s); } else { if (!blk_is_inserted(s->blk)) { error_setg(errp, "Device needs media, but drive is empty"); return -1; } - if (!blk_is_writable(blk)) { + if (!blk_is_writable(s->blk)) { error_setg(errp, "Can't use a read-only drive"); return -1; } - blk_set_dev_ops(blk, &ide_hd_block_ops, s); + blk_set_dev_ops(s->blk, &ide_hd_block_ops, s); } - if (serial) { - pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), serial); + if (dev->serial) { + pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), dev->serial); } else { snprintf(s->drive_serial_str, sizeof(s->drive_serial_str), "QM%05d", s->drive_serial); } - if (model) { - pstrcpy(s->drive_model_str, sizeof(s->drive_model_str), model); + if (dev->model) { + pstrcpy(s->drive_model_str, sizeof(s->drive_model_str), dev->model); } else { switch (kind) { case IDE_CD: @@ -2648,14 +2645,14 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, } } - if (version) { - pstrcpy(s->version, sizeof(s->version), version); + if (dev->version) { + pstrcpy(s->version, sizeof(s->version), dev->version); } else { pstrcpy(s->version, sizeof(s->version), qemu_hw_version()); } ide_reset(s); - blk_iostatus_enable(blk); + blk_iostatus_enable(s->blk); return 0; } diff --git a/hw/ide/ide-dev.c b/hw/ide/ide-dev.c index 799bd4b..03f7967 100644 --- a/hw/ide/ide-dev.c +++ b/hw/ide/ide-dev.c @@ -31,6 +31,7 @@ static Property ide_props[] = { DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1), + DEFINE_PROP_BOOL("win2k-install-hack", IDEDevice, win2k_install_hack, false), DEFINE_PROP_END_OF_LIST(), }; @@ -118,10 +119,7 @@ void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp) return; } - if (ide_init_drive(s, dev->conf.blk, kind, - dev->version, dev->serial, dev->model, dev->wwn, - dev->conf.cyls, dev->conf.heads, dev->conf.secs, - dev->chs_trans, errp) < 0) { + if (ide_init_drive(s, dev, kind, errp) < 0) { return; } diff --git a/hw/ide/ide-internal.h b/hw/ide/ide-internal.h index 20dde37..0d64805 100644 --- a/hw/ide/ide-internal.h +++ b/hw/ide/ide-internal.h @@ -416,11 +416,7 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr); void ide_data_writel(void *opaque, uint32_t addr, uint32_t val); uint32_t ide_data_readl(void *opaque, uint32_t addr); -int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, - const char *version, const char *serial, const char *model, - uint64_t wwn, - uint32_t cylinders, uint32_t heads, uint32_t secs, - int chs_trans, Error **errp); +int ide_init_drive(IDEState *s, IDEDevice *dev, IDEDriveKind kind, Error **errp); void ide_exit(IDEState *s); void ide_bus_init_output_irq(IDEBus *bus, qemu_irq irq_out); int ide_init_ioport(IDEBus *bus, ISADevice *isa, int iobase, int iobase2); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 4bb1899..5065590 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -50,6 +50,7 @@ typedef struct PCMachineState { bool hpet_enabled; bool i8042_enabled; bool default_bus_bypass_iommu; + bool fd_bootchk; uint64_t max_fw_size; /* ACPI Memory hotplug IO base address */ @@ -146,7 +147,6 @@ OBJECT_DECLARE_TYPE(PCMachineState, PCMachineClass, PC_MACHINE) GSIState *pc_gsi_create(qemu_irq **irqs, bool pci_enabled); /* pc.c */ -extern int fd_bootchk; void pc_acpi_smi_interrupt(void *opaque, int irq, int level); diff --git a/include/hw/ide/ide-dev.h b/include/hw/ide/ide-dev.h index 708cc0f..9a0d71d 100644 --- a/include/hw/ide/ide-dev.h +++ b/include/hw/ide/ide-dev.h @@ -65,6 +65,7 @@ struct IDEState { int drive_serial; char drive_serial_str[21]; char drive_model_str[41]; + bool win2k_install_hack; uint64_t wwn; /* ide regs */ uint8_t feature; @@ -163,6 +164,7 @@ struct IDEDevice { * 0xffff - reserved */ uint16_t rotation_rate; + bool win2k_install_hack; }; typedef struct IDEDrive { diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 73a3794..eb1dc1e 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -41,7 +41,6 @@ extern int graphic_height; extern int graphic_depth; extern int display_opengl; extern const char *keyboard_layout; -extern int win2k_install_hack; extern int graphic_rotate; extern int old_param; extern uint8_t *boot_splash_filedata; diff --git a/qemu-options.hx b/qemu-options.hx index 9be1e58..9a47385 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2641,7 +2641,8 @@ SRST ``-win2k-hack`` Use it when installing Windows 2000 to avoid a disk full bug. After Windows 2000 is installed, you no longer need this option (this - option slows down the IDE transfers). + option slows down the IDE transfers). Synonym of ``-global + ide-device.win2k-install-hack=on``. ERST DEF("no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk, @@ -2650,7 +2651,7 @@ DEF("no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk, SRST ``-no-fd-bootchk`` Disable boot signature checking for floppy disks in BIOS. May be - needed to boot from old floppy disks. + needed to boot from old floppy disks. Synonym of ``-m fd-bootchk=off``. ERST DEF("acpitable", HAS_ARG, QEMU_OPTION_acpitable, diff --git a/system/globals.c b/system/globals.c index b6d4e72..e353584 100644 --- a/system/globals.c +++ b/system/globals.c @@ -40,8 +40,6 @@ int autostart = 1; int vga_interface_type = VGA_NONE; bool vga_interface_created; Chardev *parallel_hds[MAX_PARALLEL_PORTS]; -int win2k_install_hack; -int fd_bootchk = 1; int graphic_rotate; QEMUOptionRom option_rom[MAX_OPTION_ROMS]; int nb_option_roms; diff --git a/system/vl.c b/system/vl.c index b8469d9..e480afd 100644 --- a/system/vl.c +++ b/system/vl.c @@ -2927,7 +2927,7 @@ void qemu_init(int argc, char **argv) optarg, FD_OPTS); break; case QEMU_OPTION_no_fd_bootchk: - fd_bootchk = 0; + qdict_put_str(machine_opts_dict, "fd-bootchk", "off"); break; case QEMU_OPTION_netdev: default_net = 0; @@ -3265,7 +3265,7 @@ void qemu_init(int argc, char **argv) pid_file = optarg; break; case QEMU_OPTION_win2k_hack: - win2k_install_hack = 1; + object_register_sugar_prop("ide-device", "win2k-install-hack", "true", true); break; case QEMU_OPTION_acpitable: opts = qemu_opts_parse_noisily(qemu_find_opts("acpi"), diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 733254f..2666ef3 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -7735,10 +7735,13 @@ static bool x86_cpu_has_work(CPUState *cs) static int x86_cpu_mmu_index(CPUState *cs, bool ifetch) { CPUX86State *env = cpu_env(cs); + int mmu_index_32 = (env->hflags & HF_CS64_MASK) ? 1 : 0; + int mmu_index_base = + (env->hflags & HF_CPL_MASK) == 3 ? MMU_USER64_IDX : + !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP64_IDX : + (env->eflags & AC_MASK) ? MMU_KNOSMAP64_IDX : MMU_KSMAP64_IDX; - return (env->hflags & HF_CPL_MASK) == 3 ? MMU_USER_IDX : - (!(env->hflags & HF_SMAP_MASK) || (env->eflags & AC_MASK)) - ? MMU_KNOSMAP_IDX : MMU_KSMAP_IDX; + return mmu_index_base + mmu_index_32; } static void x86_disas_set_info(CPUState *cs, disassemble_info *info) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index dfe43b8..952174b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2299,17 +2299,47 @@ uint64_t cpu_get_tsc(CPUX86State *env); #define cpu_list x86_cpu_list /* MMU modes definitions */ -#define MMU_KSMAP_IDX 0 -#define MMU_USER_IDX 1 -#define MMU_KNOSMAP_IDX 2 -#define MMU_NESTED_IDX 3 -#define MMU_PHYS_IDX 4 +#define MMU_KSMAP64_IDX 0 +#define MMU_KSMAP32_IDX 1 +#define MMU_USER64_IDX 2 +#define MMU_USER32_IDX 3 +#define MMU_KNOSMAP64_IDX 4 +#define MMU_KNOSMAP32_IDX 5 +#define MMU_PHYS_IDX 6 +#define MMU_NESTED_IDX 7 + +#ifdef CONFIG_USER_ONLY +#ifdef TARGET_X86_64 +#define MMU_USER_IDX MMU_USER64_IDX +#else +#define MMU_USER_IDX MMU_USER32_IDX +#endif +#endif + +static inline bool is_mmu_index_smap(int mmu_index) +{ + return (mmu_index & ~1) == MMU_KSMAP64_IDX; +} + +static inline bool is_mmu_index_user(int mmu_index) +{ + return (mmu_index & ~1) == MMU_USER64_IDX; +} + +static inline bool is_mmu_index_32(int mmu_index) +{ + assert(mmu_index < MMU_PHYS_IDX); + return mmu_index & 1; +} static inline int cpu_mmu_index_kernel(CPUX86State *env) { - return !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP_IDX : - ((env->hflags & HF_CPL_MASK) < 3 && (env->eflags & AC_MASK)) - ? MMU_KNOSMAP_IDX : MMU_KSMAP_IDX; + int mmu_index_32 = (env->hflags & HF_LMA_MASK) ? 1 : 0; + int mmu_index_base = + !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP64_IDX : + ((env->hflags & HF_CPL_MASK) < 3 && (env->eflags & AC_MASK)) ? MMU_KNOSMAP64_IDX : MMU_KSMAP64_IDX; + + return mmu_index_base + mmu_index_32; } #define CC_DST (env->cc_dst) diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 5b86f43..8f7011d 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -134,10 +134,9 @@ static inline bool ptw_setl(const PTETranslate *in, uint32_t old, uint32_t set) static bool mmu_translate(CPUX86State *env, const TranslateParams *in, TranslateResult *out, TranslateFault *err) { - const int32_t a20_mask = x86_get_a20_mask(env); const target_ulong addr = in->addr; const int pg_mode = in->pg_mode; - const bool is_user = (in->mmu_idx == MMU_USER_IDX); + const bool is_user = is_mmu_index_user(in->mmu_idx); const MMUAccessType access_type = in->access_type; uint64_t ptep, pte, rsvd_mask; PTETranslate pte_trans = { @@ -164,8 +163,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, /* * Page table level 5 */ - pte_addr = ((in->cr3 & ~0xfff) + - (((addr >> 48) & 0x1ff) << 3)) & a20_mask; + pte_addr = (in->cr3 & ~0xfff) + (((addr >> 48) & 0x1ff) << 3); if (!ptw_translate(&pte_trans, pte_addr)) { return false; } @@ -189,8 +187,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, /* * Page table level 4 */ - pte_addr = ((pte & PG_ADDRESS_MASK) + - (((addr >> 39) & 0x1ff) << 3)) & a20_mask; + pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 39) & 0x1ff) << 3); if (!ptw_translate(&pte_trans, pte_addr)) { return false; } @@ -210,8 +207,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, /* * Page table level 3 */ - pte_addr = ((pte & PG_ADDRESS_MASK) + - (((addr >> 30) & 0x1ff) << 3)) & a20_mask; + pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3); if (!ptw_translate(&pte_trans, pte_addr)) { return false; } @@ -238,7 +234,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, /* * Page table level 3 */ - pte_addr = ((in->cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & a20_mask; + pte_addr = (in->cr3 & 0xffffffe0ULL) + ((addr >> 27) & 0x18); if (!ptw_translate(&pte_trans, pte_addr)) { return false; } @@ -260,8 +256,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, /* * Page table level 2 */ - pte_addr = ((pte & PG_ADDRESS_MASK) + - (((addr >> 21) & 0x1ff) << 3)) & a20_mask; + pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3); if (!ptw_translate(&pte_trans, pte_addr)) { return false; } @@ -287,8 +282,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, /* * Page table level 1 */ - pte_addr = ((pte & PG_ADDRESS_MASK) + - (((addr >> 12) & 0x1ff) << 3)) & a20_mask; + pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3); if (!ptw_translate(&pte_trans, pte_addr)) { return false; } @@ -306,7 +300,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, /* * Page table level 2 */ - pte_addr = ((in->cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & a20_mask; + pte_addr = (in->cr3 & 0xfffff000ULL) + ((addr >> 20) & 0xffc); if (!ptw_translate(&pte_trans, pte_addr)) { return false; } @@ -335,7 +329,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in, /* * Page table level 1 */ - pte_addr = ((pte & ~0xfffu) + ((addr >> 10) & 0xffc)) & a20_mask; + pte_addr = (pte & ~0xfffu) + ((addr >> 10) & 0xffc); if (!ptw_translate(&pte_trans, pte_addr)) { return false; } @@ -363,7 +357,7 @@ do_check_protect_pse36: } int prot = 0; - if (in->mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { + if (!is_mmu_index_smap(in->mmu_idx) || !(ptep & PG_USER_MASK)) { prot |= PAGE_READ; if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) { prot |= PAGE_WRITE; @@ -422,10 +416,13 @@ do_check_protect_pse36: } } - /* align to page_size */ - paddr = (pte & a20_mask & PG_ADDRESS_MASK & ~(page_size - 1)) - | (addr & (page_size - 1)); + /* merge offset within page */ + paddr = (pte & PG_ADDRESS_MASK & ~(page_size - 1)) | (addr & (page_size - 1)); + /* + * Note that NPT is walked (for both paging structures and final guest + * addresses) using the address with the A20 bit set. + */ if (in->ptw_idx == MMU_NESTED_IDX) { CPUTLBEntryFull *full; int flags, nested_page_size; @@ -464,7 +461,7 @@ do_check_protect_pse36: } } - out->paddr = paddr; + out->paddr = paddr & x86_get_a20_mask(env); out->prot = prot; out->page_size = page_size; return true; @@ -545,7 +542,8 @@ static bool get_physical_address(CPUX86State *env, vaddr addr, if (likely(use_stage2)) { in.cr3 = env->nested_cr3; in.pg_mode = env->nested_pg_mode; - in.mmu_idx = MMU_USER_IDX; + in.mmu_idx = + env->nested_pg_mode & PG_MODE_LMA ? MMU_USER64_IDX : MMU_USER32_IDX; in.ptw_idx = MMU_PHYS_IDX; if (!mmu_translate(env, &in, out, err)) { @@ -557,6 +555,10 @@ static bool get_physical_address(CPUX86State *env, vaddr addr, break; default: + if (is_mmu_index_32(mmu_idx)) { + addr = (uint32_t)addr; + } + if (likely(env->cr[0] & CR0_PG_MASK)) { in.cr3 = env->cr[3]; in.mmu_idx = mmu_idx; @@ -580,14 +582,8 @@ static bool get_physical_address(CPUX86State *env, vaddr addr, break; } - /* Translation disabled. */ + /* No translation needed. */ out->paddr = addr & x86_get_a20_mask(env); -#ifdef TARGET_X86_64 - if (!(env->hflags & HF_LMA_MASK)) { - /* Without long mode we can only address 32bits in real mode */ - out->paddr = (uint32_t)out->paddr; - } -#endif out->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; out->page_size = TARGET_PAGE_SIZE; return true; diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c index 7de0a6e..edb7c3d 100644 --- a/target/i386/tcg/sysemu/misc_helper.c +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -212,6 +212,9 @@ void helper_wrmsr(CPUX86State *env) tlb_flush(cs); break; case MSR_VM_HSAVE_PA: + if (val & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) { + goto error; + } env->vm_hsave = val; break; #ifdef TARGET_X86_64 diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 32ff0db..5d6de22 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -164,14 +164,19 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) uint64_t new_cr3; uint64_t new_cr4; - cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC()); - if (aflag == 2) { addr = env->regs[R_EAX]; } else { addr = (uint32_t)env->regs[R_EAX]; } + /* Exceptions are checked before the intercept. */ + if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) { + raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); + } + + cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC()); + qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr); env->vm_vmcb = addr; @@ -463,14 +468,19 @@ void helper_vmload(CPUX86State *env, int aflag) int mmu_idx = MMU_PHYS_IDX; target_ulong addr; - cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC()); - if (aflag == 2) { addr = env->regs[R_EAX]; } else { addr = (uint32_t)env->regs[R_EAX]; } + /* Exceptions are checked before the intercept. */ + if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) { + raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); + } + + cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC()); + if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) { mmu_idx = MMU_NESTED_IDX; } @@ -519,14 +529,19 @@ void helper_vmsave(CPUX86State *env, int aflag) int mmu_idx = MMU_PHYS_IDX; target_ulong addr; - cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC()); - if (aflag == 2) { addr = env->regs[R_EAX]; } else { addr = (uint32_t)env->regs[R_EAX]; } + /* Exceptions are checked before the intercept. */ + if (addr & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) { + raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); + } + + cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC()); + if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) { mmu_idx = MMU_NESTED_IDX; } |