* 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-----

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>
This commit is contained in:
Peter Maydell 2024-02-28 14:23:21 +00:00
commit bfe8020c81
15 changed files with 157 additions and 90 deletions

View File

@ -399,8 +399,8 @@ static int boot_device2nibble(char boot_device)
return 0; return 0;
} }
static void set_boot_dev(MC146818RtcState *s, const char *boot_device, static void set_boot_dev(PCMachineState *pcms, MC146818RtcState *s,
Error **errp) const char *boot_device, Error **errp)
{ {
#define PC_MAX_BOOT_DEVICES 3 #define PC_MAX_BOOT_DEVICES 3
int nbds, bds[3] = { 0, }; 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, 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) 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) 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, 0x5c, val >> 8);
mc146818rtc_set_cmos_data(s, 0x5d, val >> 16); 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 = 0;
val |= 0x02; /* FPU is there */ 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); 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) static bool pc_machine_get_smbus(Object *obj, Error **errp)
{ {
PCMachineState *pcms = PC_MACHINE(obj); PCMachineState *pcms = PC_MACHINE(obj);
@ -1723,6 +1747,7 @@ static void pc_machine_initfn(Object *obj)
#ifdef CONFIG_HPET #ifdef CONFIG_HPET
pcms->hpet_enabled = true; pcms->hpet_enabled = true;
#endif #endif
pcms->fd_bootchk = true;
pcms->default_bus_bypass_iommu = false; pcms->default_bus_bypass_iommu = false;
pcms->pcspk = isa_new(TYPE_PC_SPEAKER); pcms->pcspk = isa_new(TYPE_PC_SPEAKER);
@ -1869,6 +1894,10 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
NULL, NULL); NULL, NULL);
object_class_property_set_description(oc, PC_MACHINE_SMBIOS_EP, object_class_property_set_description(oc, PC_MACHINE_SMBIOS_EP,
"SMBIOS Entry Point type [32, 64]"); "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 = { static const TypeInfo pc_machine_info = {

View File

@ -1059,7 +1059,7 @@ static void ide_sector_write_cb(void *opaque, int ret)
ide_sector_write); 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 /* It seems there is a bug in the Windows 2000 installer HDD
IDE driver which fills the disk with empty logs when the IDE driver which fills the disk with empty logs when the
IDE write IRQ comes too early. This hack tries to correct 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, .resize_cb = ide_resize_cb,
}; };
int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, int ide_init_drive(IDEState *s, IDEDevice *dev, IDEDriveKind kind, Error **errp)
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)
{ {
uint64_t nb_sectors; uint64_t nb_sectors;
s->blk = blk; s->blk = dev->conf.blk;
s->drive_kind = kind; s->drive_kind = kind;
blk_get_geometry(blk, &nb_sectors); blk_get_geometry(s->blk, &nb_sectors);
s->cylinders = cylinders; s->win2k_install_hack = dev->win2k_install_hack;
s->heads = s->drive_heads = heads; s->cylinders = dev->conf.cyls;
s->sectors = s->drive_sectors = secs; s->heads = s->drive_heads = dev->conf.heads;
s->chs_trans = chs_trans; s->sectors = s->drive_sectors = dev->conf.secs;
s->chs_trans = dev->chs_trans;
s->nb_sectors = nb_sectors; s->nb_sectors = nb_sectors;
s->wwn = wwn; s->wwn = dev->wwn;
/* The SMART values should be preserved across power cycles /* The SMART values should be preserved across power cycles
but they aren't. */ but they aren't. */
s->smart_enabled = 1; s->smart_enabled = 1;
@ -2614,26 +2611,26 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
s->smart_errors = 0; s->smart_errors = 0;
s->smart_selftest_count = 0; s->smart_selftest_count = 0;
if (kind == IDE_CD) { 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 { } else {
if (!blk_is_inserted(s->blk)) { if (!blk_is_inserted(s->blk)) {
error_setg(errp, "Device needs media, but drive is empty"); error_setg(errp, "Device needs media, but drive is empty");
return -1; return -1;
} }
if (!blk_is_writable(blk)) { if (!blk_is_writable(s->blk)) {
error_setg(errp, "Can't use a read-only drive"); error_setg(errp, "Can't use a read-only drive");
return -1; 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) { if (dev->serial) {
pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), serial); pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), dev->serial);
} else { } else {
snprintf(s->drive_serial_str, sizeof(s->drive_serial_str), snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
"QM%05d", s->drive_serial); "QM%05d", s->drive_serial);
} }
if (model) { if (dev->model) {
pstrcpy(s->drive_model_str, sizeof(s->drive_model_str), model); pstrcpy(s->drive_model_str, sizeof(s->drive_model_str), dev->model);
} else { } else {
switch (kind) { switch (kind) {
case IDE_CD: case IDE_CD:
@ -2648,14 +2645,14 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
} }
} }
if (version) { if (dev->version) {
pstrcpy(s->version, sizeof(s->version), version); pstrcpy(s->version, sizeof(s->version), dev->version);
} else { } else {
pstrcpy(s->version, sizeof(s->version), qemu_hw_version()); pstrcpy(s->version, sizeof(s->version), qemu_hw_version());
} }
ide_reset(s); ide_reset(s);
blk_iostatus_enable(blk); blk_iostatus_enable(s->blk);
return 0; return 0;
} }

View File

@ -31,6 +31,7 @@
static Property ide_props[] = { static Property ide_props[] = {
DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1), DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
DEFINE_PROP_BOOL("win2k-install-hack", IDEDevice, win2k_install_hack, false),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -118,10 +119,7 @@ void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
return; return;
} }
if (ide_init_drive(s, dev->conf.blk, kind, if (ide_init_drive(s, dev, kind, errp) < 0) {
dev->version, dev->serial, dev->model, dev->wwn,
dev->conf.cyls, dev->conf.heads, dev->conf.secs,
dev->chs_trans, errp) < 0) {
return; return;
} }

View File

@ -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); void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
uint32_t ide_data_readl(void *opaque, uint32_t addr); uint32_t ide_data_readl(void *opaque, uint32_t addr);
int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, int ide_init_drive(IDEState *s, IDEDevice *dev, IDEDriveKind kind, Error **errp);
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);
void ide_exit(IDEState *s); void ide_exit(IDEState *s);
void ide_bus_init_output_irq(IDEBus *bus, qemu_irq irq_out); void ide_bus_init_output_irq(IDEBus *bus, qemu_irq irq_out);
int ide_init_ioport(IDEBus *bus, ISADevice *isa, int iobase, int iobase2); int ide_init_ioport(IDEBus *bus, ISADevice *isa, int iobase, int iobase2);

View File

@ -50,6 +50,7 @@ typedef struct PCMachineState {
bool hpet_enabled; bool hpet_enabled;
bool i8042_enabled; bool i8042_enabled;
bool default_bus_bypass_iommu; bool default_bus_bypass_iommu;
bool fd_bootchk;
uint64_t max_fw_size; uint64_t max_fw_size;
/* ACPI Memory hotplug IO base address */ /* 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); GSIState *pc_gsi_create(qemu_irq **irqs, bool pci_enabled);
/* pc.c */ /* pc.c */
extern int fd_bootchk;
void pc_acpi_smi_interrupt(void *opaque, int irq, int level); void pc_acpi_smi_interrupt(void *opaque, int irq, int level);

View File

@ -65,6 +65,7 @@ struct IDEState {
int drive_serial; int drive_serial;
char drive_serial_str[21]; char drive_serial_str[21];
char drive_model_str[41]; char drive_model_str[41];
bool win2k_install_hack;
uint64_t wwn; uint64_t wwn;
/* ide regs */ /* ide regs */
uint8_t feature; uint8_t feature;
@ -163,6 +164,7 @@ struct IDEDevice {
* 0xffff - reserved * 0xffff - reserved
*/ */
uint16_t rotation_rate; uint16_t rotation_rate;
bool win2k_install_hack;
}; };
typedef struct IDEDrive { typedef struct IDEDrive {

View File

@ -41,7 +41,6 @@ extern int graphic_height;
extern int graphic_depth; extern int graphic_depth;
extern int display_opengl; extern int display_opengl;
extern const char *keyboard_layout; extern const char *keyboard_layout;
extern int win2k_install_hack;
extern int graphic_rotate; extern int graphic_rotate;
extern int old_param; extern int old_param;
extern uint8_t *boot_splash_filedata; extern uint8_t *boot_splash_filedata;

View File

@ -2641,7 +2641,8 @@ SRST
``-win2k-hack`` ``-win2k-hack``
Use it when installing Windows 2000 to avoid a disk full bug. After Use it when installing Windows 2000 to avoid a disk full bug. After
Windows 2000 is installed, you no longer need this option (this 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 ERST
DEF("no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk, 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 SRST
``-no-fd-bootchk`` ``-no-fd-bootchk``
Disable boot signature checking for floppy disks in BIOS. May be 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 ERST
DEF("acpitable", HAS_ARG, QEMU_OPTION_acpitable, DEF("acpitable", HAS_ARG, QEMU_OPTION_acpitable,

View File

@ -40,8 +40,6 @@ int autostart = 1;
int vga_interface_type = VGA_NONE; int vga_interface_type = VGA_NONE;
bool vga_interface_created; bool vga_interface_created;
Chardev *parallel_hds[MAX_PARALLEL_PORTS]; Chardev *parallel_hds[MAX_PARALLEL_PORTS];
int win2k_install_hack;
int fd_bootchk = 1;
int graphic_rotate; int graphic_rotate;
QEMUOptionRom option_rom[MAX_OPTION_ROMS]; QEMUOptionRom option_rom[MAX_OPTION_ROMS];
int nb_option_roms; int nb_option_roms;

View File

@ -2927,7 +2927,7 @@ void qemu_init(int argc, char **argv)
optarg, FD_OPTS); optarg, FD_OPTS);
break; break;
case QEMU_OPTION_no_fd_bootchk: case QEMU_OPTION_no_fd_bootchk:
fd_bootchk = 0; qdict_put_str(machine_opts_dict, "fd-bootchk", "off");
break; break;
case QEMU_OPTION_netdev: case QEMU_OPTION_netdev:
default_net = 0; default_net = 0;
@ -3265,7 +3265,7 @@ void qemu_init(int argc, char **argv)
pid_file = optarg; pid_file = optarg;
break; break;
case QEMU_OPTION_win2k_hack: case QEMU_OPTION_win2k_hack:
win2k_install_hack = 1; object_register_sugar_prop("ide-device", "win2k-install-hack", "true", true);
break; break;
case QEMU_OPTION_acpitable: case QEMU_OPTION_acpitable:
opts = qemu_opts_parse_noisily(qemu_find_opts("acpi"), opts = qemu_opts_parse_noisily(qemu_find_opts("acpi"),

View File

@ -7735,10 +7735,13 @@ static bool x86_cpu_has_work(CPUState *cs)
static int x86_cpu_mmu_index(CPUState *cs, bool ifetch) static int x86_cpu_mmu_index(CPUState *cs, bool ifetch)
{ {
CPUX86State *env = cpu_env(cs); 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 : return mmu_index_base + mmu_index_32;
(!(env->hflags & HF_SMAP_MASK) || (env->eflags & AC_MASK))
? MMU_KNOSMAP_IDX : MMU_KSMAP_IDX;
} }
static void x86_disas_set_info(CPUState *cs, disassemble_info *info) static void x86_disas_set_info(CPUState *cs, disassemble_info *info)

View File

@ -2299,17 +2299,47 @@ uint64_t cpu_get_tsc(CPUX86State *env);
#define cpu_list x86_cpu_list #define cpu_list x86_cpu_list
/* MMU modes definitions */ /* MMU modes definitions */
#define MMU_KSMAP_IDX 0 #define MMU_KSMAP64_IDX 0
#define MMU_USER_IDX 1 #define MMU_KSMAP32_IDX 1
#define MMU_KNOSMAP_IDX 2 #define MMU_USER64_IDX 2
#define MMU_NESTED_IDX 3 #define MMU_USER32_IDX 3
#define MMU_PHYS_IDX 4 #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) static inline int cpu_mmu_index_kernel(CPUX86State *env)
{ {
return !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP_IDX : int mmu_index_32 = (env->hflags & HF_LMA_MASK) ? 1 : 0;
((env->hflags & HF_CPL_MASK) < 3 && (env->eflags & AC_MASK)) int mmu_index_base =
? MMU_KNOSMAP_IDX : MMU_KSMAP_IDX; !(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) #define CC_DST (env->cc_dst)

View File

@ -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, static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
TranslateResult *out, TranslateFault *err) TranslateResult *out, TranslateFault *err)
{ {
const int32_t a20_mask = x86_get_a20_mask(env);
const target_ulong addr = in->addr; const target_ulong addr = in->addr;
const int pg_mode = in->pg_mode; 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; const MMUAccessType access_type = in->access_type;
uint64_t ptep, pte, rsvd_mask; uint64_t ptep, pte, rsvd_mask;
PTETranslate pte_trans = { PTETranslate pte_trans = {
@ -164,8 +163,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
/* /*
* Page table level 5 * Page table level 5
*/ */
pte_addr = ((in->cr3 & ~0xfff) + pte_addr = (in->cr3 & ~0xfff) + (((addr >> 48) & 0x1ff) << 3);
(((addr >> 48) & 0x1ff) << 3)) & a20_mask;
if (!ptw_translate(&pte_trans, pte_addr)) { if (!ptw_translate(&pte_trans, pte_addr)) {
return false; return false;
} }
@ -189,8 +187,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
/* /*
* Page table level 4 * Page table level 4
*/ */
pte_addr = ((pte & PG_ADDRESS_MASK) + pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 39) & 0x1ff) << 3);
(((addr >> 39) & 0x1ff) << 3)) & a20_mask;
if (!ptw_translate(&pte_trans, pte_addr)) { if (!ptw_translate(&pte_trans, pte_addr)) {
return false; return false;
} }
@ -210,8 +207,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
/* /*
* Page table level 3 * Page table level 3
*/ */
pte_addr = ((pte & PG_ADDRESS_MASK) + pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3);
(((addr >> 30) & 0x1ff) << 3)) & a20_mask;
if (!ptw_translate(&pte_trans, pte_addr)) { if (!ptw_translate(&pte_trans, pte_addr)) {
return false; return false;
} }
@ -238,7 +234,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
/* /*
* Page table level 3 * 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)) { if (!ptw_translate(&pte_trans, pte_addr)) {
return false; return false;
} }
@ -260,8 +256,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
/* /*
* Page table level 2 * Page table level 2
*/ */
pte_addr = ((pte & PG_ADDRESS_MASK) + pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3);
(((addr >> 21) & 0x1ff) << 3)) & a20_mask;
if (!ptw_translate(&pte_trans, pte_addr)) { if (!ptw_translate(&pte_trans, pte_addr)) {
return false; return false;
} }
@ -287,8 +282,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
/* /*
* Page table level 1 * Page table level 1
*/ */
pte_addr = ((pte & PG_ADDRESS_MASK) + pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3);
(((addr >> 12) & 0x1ff) << 3)) & a20_mask;
if (!ptw_translate(&pte_trans, pte_addr)) { if (!ptw_translate(&pte_trans, pte_addr)) {
return false; return false;
} }
@ -306,7 +300,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
/* /*
* Page table level 2 * 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)) { if (!ptw_translate(&pte_trans, pte_addr)) {
return false; return false;
} }
@ -335,7 +329,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
/* /*
* Page table level 1 * 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)) { if (!ptw_translate(&pte_trans, pte_addr)) {
return false; return false;
} }
@ -363,7 +357,7 @@ do_check_protect_pse36:
} }
int prot = 0; 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; prot |= PAGE_READ;
if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) { if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) {
prot |= PAGE_WRITE; prot |= PAGE_WRITE;
@ -422,10 +416,13 @@ do_check_protect_pse36:
} }
} }
/* align to page_size */ /* merge offset within page */
paddr = (pte & a20_mask & PG_ADDRESS_MASK & ~(page_size - 1)) paddr = (pte & PG_ADDRESS_MASK & ~(page_size - 1)) | (addr & (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) { if (in->ptw_idx == MMU_NESTED_IDX) {
CPUTLBEntryFull *full; CPUTLBEntryFull *full;
int flags, nested_page_size; 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->prot = prot;
out->page_size = page_size; out->page_size = page_size;
return true; return true;
@ -545,7 +542,8 @@ static bool get_physical_address(CPUX86State *env, vaddr addr,
if (likely(use_stage2)) { if (likely(use_stage2)) {
in.cr3 = env->nested_cr3; in.cr3 = env->nested_cr3;
in.pg_mode = env->nested_pg_mode; 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; in.ptw_idx = MMU_PHYS_IDX;
if (!mmu_translate(env, &in, out, err)) { if (!mmu_translate(env, &in, out, err)) {
@ -557,6 +555,10 @@ static bool get_physical_address(CPUX86State *env, vaddr addr,
break; break;
default: default:
if (is_mmu_index_32(mmu_idx)) {
addr = (uint32_t)addr;
}
if (likely(env->cr[0] & CR0_PG_MASK)) { if (likely(env->cr[0] & CR0_PG_MASK)) {
in.cr3 = env->cr[3]; in.cr3 = env->cr[3];
in.mmu_idx = mmu_idx; in.mmu_idx = mmu_idx;
@ -580,14 +582,8 @@ static bool get_physical_address(CPUX86State *env, vaddr addr,
break; break;
} }
/* Translation disabled. */ /* No translation needed. */
out->paddr = addr & x86_get_a20_mask(env); 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->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
out->page_size = TARGET_PAGE_SIZE; out->page_size = TARGET_PAGE_SIZE;
return true; return true;

View File

@ -212,6 +212,9 @@ void helper_wrmsr(CPUX86State *env)
tlb_flush(cs); tlb_flush(cs);
break; break;
case MSR_VM_HSAVE_PA: case MSR_VM_HSAVE_PA:
if (val & (0xfff | ((~0ULL) << env_archcpu(env)->phys_bits))) {
goto error;
}
env->vm_hsave = val; env->vm_hsave = val;
break; break;
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64

View File

@ -164,14 +164,19 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
uint64_t new_cr3; uint64_t new_cr3;
uint64_t new_cr4; uint64_t new_cr4;
cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC());
if (aflag == 2) { if (aflag == 2) {
addr = env->regs[R_EAX]; addr = env->regs[R_EAX];
} else { } else {
addr = (uint32_t)env->regs[R_EAX]; 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); qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
env->vm_vmcb = addr; env->vm_vmcb = addr;
@ -463,14 +468,19 @@ void helper_vmload(CPUX86State *env, int aflag)
int mmu_idx = MMU_PHYS_IDX; int mmu_idx = MMU_PHYS_IDX;
target_ulong addr; target_ulong addr;
cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC());
if (aflag == 2) { if (aflag == 2) {
addr = env->regs[R_EAX]; addr = env->regs[R_EAX];
} else { } else {
addr = (uint32_t)env->regs[R_EAX]; 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())) { if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) {
mmu_idx = MMU_NESTED_IDX; mmu_idx = MMU_NESTED_IDX;
} }
@ -519,14 +529,19 @@ void helper_vmsave(CPUX86State *env, int aflag)
int mmu_idx = MMU_PHYS_IDX; int mmu_idx = MMU_PHYS_IDX;
target_ulong addr; target_ulong addr;
cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC());
if (aflag == 2) { if (aflag == 2) {
addr = env->regs[R_EAX]; addr = env->regs[R_EAX];
} else { } else {
addr = (uint32_t)env->regs[R_EAX]; 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())) { if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) {
mmu_idx = MMU_NESTED_IDX; mmu_idx = MMU_NESTED_IDX;
} }