Browse Source

* target/i386: Fix model number of Zhaoxin YongFeng vCPU template

* target/i386: Reset parked vCPUs together with the online ones
 * scsi: add conversion from ENODEV to sense
 * target/i386: tweaks to flag handling
 * target/i386: tweaks to SHLD/SHRD code generation
 * target/i386: remove some global temporaries from TCG
 * target/i386: pull emulator outside target/i386/hvf
 * host/i386: consolidate getting host CPU vendor
 * rust/hpet: preparation for migration support
 * rust/pl011: bring over more commits from C version
 -----BEGIN PGP SIGNATURE-----
 
 iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmgItXAUHHBib256aW5p
 QHJlZGhhdC5jb20ACgkQv/vSX3jHroNrwgf/TAiz0LdO9q3O9Ob2FJVdAL6jn0YH
 /yDjAOpRT9WBOoKi+fikMuX6FlxVNpb6K5xx/WMbXDiO3PLMMNYet3fnXpjGBCj0
 aLcrHxG0TUfUk2mYssBoyZ1IG5bjevRZjjRFAXGubJZp/l6oXCCPrZ4mkW9MRP9U
 GzzwhSC2U0CuZREz4YxurPZmgx9lKRcf71lVExh6AHWpPPU3tWk0F51zE+PxObWk
 WvNwVvBPPYryC88DcN9YytiNn0jLtIozf3sxTDAi6jsg5T6PzeGU+LTck3DtQJIY
 3eAoTpLW1ZEYMIcbA/upLHz+obqDCgWZUPQydHvJS/xlIcnO+RYkWobOxg==
 =06CN
 -----END PGP SIGNATURE-----

Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging

* target/i386: Fix model number of Zhaoxin YongFeng vCPU template
* target/i386: Reset parked vCPUs together with the online ones
* scsi: add conversion from ENODEV to sense
* target/i386: tweaks to flag handling
* target/i386: tweaks to SHLD/SHRD code generation
* target/i386: remove some global temporaries from TCG
* target/i386: pull emulator outside target/i386/hvf
* host/i386: consolidate getting host CPU vendor
* rust/hpet: preparation for migration support
* rust/pl011: bring over more commits from C version

# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmgItXAUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroNrwgf/TAiz0LdO9q3O9Ob2FJVdAL6jn0YH
# /yDjAOpRT9WBOoKi+fikMuX6FlxVNpb6K5xx/WMbXDiO3PLMMNYet3fnXpjGBCj0
# aLcrHxG0TUfUk2mYssBoyZ1IG5bjevRZjjRFAXGubJZp/l6oXCCPrZ4mkW9MRP9U
# GzzwhSC2U0CuZREz4YxurPZmgx9lKRcf71lVExh6AHWpPPU3tWk0F51zE+PxObWk
# WvNwVvBPPYryC88DcN9YytiNn0jLtIozf3sxTDAi6jsg5T6PzeGU+LTck3DtQJIY
# 3eAoTpLW1ZEYMIcbA/upLHz+obqDCgWZUPQydHvJS/xlIcnO+RYkWobOxg==
# =06CN
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 23 Apr 2025 05:40:00 EDT
# 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: (34 commits)
  rust/hw/char/pl011: Extract DR write logic into separate function
  rust/hw/char/pl011: Extract extract DR read logic into separate function
  rust/vmstate_test: Fix typo in test_vmstate_macro_array_of_pointer_wrapped()
  rust/hpet: Fix a clippy error
  rust/hpet: convert HPETTimer index to u8 type
  rust/hpet: convert num_timers to u8 type
  i386/cpu: Consolidate the helper to get Host's vendor
  target/i386/emulate: remove flags_mask
  MAINTAINERS: add an entry for the x86 instruction emulator
  target/i386: move x86 instruction emulator out of hvf
  target/i386/emulate: add a panic.h
  target/i386: add a directory for x86 instruction emulator
  target/i386/hvf: rename some include guards
  target/i386/hvf: drop unused headers
  target/i386: rename lazy flags field and its type
  target/i386/hvf: provide and use simulate_{wrmsr, rdmsr} in emul_ops
  target/i386/hvf: provide and use write_mem in emul_ops
  target/i386/hvf: use emul_ops->read_mem in x86_emu.c
  target/i386: rename hvf_mmio_buf to emu_mmio_buf
  target/i386/hvf: provide and use handle_io in emul_ops
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
pull/291/head
Stefan Hajnoczi 11 months ago
parent
commit
eebba0536a
  1. 8
      MAINTAINERS
  2. 8
      accel/kvm/kvm-all.c
  3. 53
      rust/hw/char/pl011/src/device.rs
  4. 43
      rust/hw/timer/hpet/src/hpet.rs
  5. 4
      rust/qemu-api/tests/vmstate_tests.rs
  6. 13
      scsi/utils.c
  7. 12
      target/i386/cpu.c
  8. 33
      target/i386/cpu.h
  9. 5
      target/i386/emulate/meson.build
  10. 45
      target/i386/emulate/panic.h
  11. 4
      target/i386/emulate/x86.h
  12. 886
      target/i386/emulate/x86_decode.c
  13. 6
      target/i386/emulate/x86_decode.h
  14. 62
      target/i386/emulate/x86_emu.c
  15. 15
      target/i386/emulate/x86_emu.h
  16. 66
      target/i386/emulate/x86_flags.c
  17. 6
      target/i386/emulate/x86_flags.h
  18. 10
      target/i386/host-cpu.c
  19. 4
      target/i386/hvf/hvf-i386.h
  20. 57
      target/i386/hvf/hvf.c
  21. 3
      target/i386/hvf/meson.build
  22. 2
      target/i386/hvf/vmx.h
  23. 4
      target/i386/hvf/x86.c
  24. 2
      target/i386/hvf/x86_cpuid.c
  25. 2
      target/i386/hvf/x86_descr.h
  26. 2
      target/i386/hvf/x86_mmu.c
  27. 6
      target/i386/hvf/x86_task.c
  28. 2
      target/i386/hvf/x86hvf.c
  29. 3
      target/i386/kvm/vmsr_energy.c
  30. 1
      target/i386/meson.build
  31. 90
      target/i386/tcg/cc_helper_template.h.inc
  32. 180
      target/i386/tcg/emit.c.inc
  33. 144
      target/i386/tcg/translate.c

8
MAINTAINERS

@ -534,6 +534,14 @@ S: Supported
F: target/i386/whpx/
F: include/system/whpx.h
X86 Instruction Emulator
M: Cameron Esfahani <dirty@apple.com>
M: Roman Bolshakov <rbolshakov@ddn.com>
R: Phil Dennis-Jordan <phil@philjordan.eu>
R: Wei Liu <wei.liu@kernel.org>
S: Maintained
F: target/i386/emulate/
Guest CPU Cores (Xen)
---------------------
X86 Xen CPUs

8
accel/kvm/kvm-all.c

@ -437,9 +437,8 @@ int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id)
return kvm_fd;
}
static void kvm_reset_parked_vcpus(void *param)
static void kvm_reset_parked_vcpus(KVMState *s)
{
KVMState *s = param;
struct KVMParkedVcpu *cpu;
QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) {
@ -2738,7 +2737,6 @@ static int kvm_init(MachineState *ms)
}
qemu_register_reset(kvm_unpoison_all, NULL);
qemu_register_reset(kvm_reset_parked_vcpus, s);
if (s->kernel_irqchip_allowed) {
kvm_irqchip_create(s);
@ -2908,6 +2906,10 @@ static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg
void kvm_cpu_synchronize_post_reset(CPUState *cpu)
{
run_on_cpu(cpu, do_kvm_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);
if (cpu == first_cpu) {
kvm_reset_parked_vcpus(kvm_state);
}
}
static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)

53
rust/hw/char/pl011/src/device.rs

@ -190,25 +190,7 @@ impl PL011Registers {
let mut update = false;
let result = match offset {
DR => {
self.flags.set_receive_fifo_full(false);
let c = self.read_fifo[self.read_pos];
if self.read_count > 0 {
self.read_count -= 1;
self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1);
}
if self.read_count == 0 {
self.flags.set_receive_fifo_empty(true);
}
if self.read_count + 1 == self.read_trigger {
self.int_level &= !Interrupt::RX.0;
}
// Update error bits.
self.receive_status_error_clear.set_from_data(c);
// Must call qemu_chr_fe_accept_input
update = true;
u32::from(c)
}
DR => self.read_data_register(&mut update),
RSR => u32::from(self.receive_status_error_clear),
FR => u32::from(self.flags),
FBRD => self.fbrd,
@ -239,12 +221,7 @@ impl PL011Registers {
// eprintln!("write offset {offset} value {value}");
use RegisterOffset::*;
match offset {
DR => {
// interrupts always checked
let _ = self.loopback_tx(value.into());
self.int_level |= Interrupt::TX.0;
return true;
}
DR => return self.write_data_register(value),
RSR => {
self.receive_status_error_clear = 0.into();
}
@ -306,6 +283,32 @@ impl PL011Registers {
false
}
fn read_data_register(&mut self, update: &mut bool) -> u32 {
self.flags.set_receive_fifo_full(false);
let c = self.read_fifo[self.read_pos];
if self.read_count > 0 {
self.read_count -= 1;
self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1);
}
if self.read_count == 0 {
self.flags.set_receive_fifo_empty(true);
}
if self.read_count + 1 == self.read_trigger {
self.int_level &= !Interrupt::RX.0;
}
self.receive_status_error_clear.set_from_data(c);
*update = true;
u32::from(c)
}
fn write_data_register(&mut self, value: u32) -> bool {
// interrupts always checked
let _ = self.loopback_tx(value.into());
self.int_level |= Interrupt::TX.0;
true
}
#[inline]
#[must_use]
fn loopback_tx(&mut self, value: registers::Data) -> bool {

43
rust/hw/timer/hpet/src/hpet.rs

@ -12,7 +12,7 @@ use std::{
use qemu_api::{
bindings::{
address_space_memory, address_space_stl_le, qdev_prop_bit, qdev_prop_bool,
qdev_prop_uint32, qdev_prop_usize,
qdev_prop_uint32, qdev_prop_uint8,
},
c_str,
cell::{BqlCell, BqlRefCell},
@ -34,9 +34,9 @@ use crate::fw_cfg::HPETFwConfig;
const HPET_REG_SPACE_LEN: u64 = 0x400; // 1024 bytes
/// Minimum recommended hardware implementation.
const HPET_MIN_TIMERS: usize = 3;
const HPET_MIN_TIMERS: u8 = 3;
/// Maximum timers in each timer block.
const HPET_MAX_TIMERS: usize = 32;
const HPET_MAX_TIMERS: u8 = 32;
/// Flags that HPETState.flags supports.
const HPET_FLAG_MSI_SUPPORT_SHIFT: usize = 0;
@ -184,7 +184,7 @@ fn timer_handler(timer_cell: &BqlRefCell<HPETTimer>) {
pub struct HPETTimer {
/// timer N index within the timer block (`HPETState`)
#[doc(alias = "tn")]
index: usize,
index: u8,
qemu_timer: Timer,
/// timer block abstraction containing this timer
state: NonNull<HPETState>,
@ -210,7 +210,7 @@ pub struct HPETTimer {
}
impl HPETTimer {
fn init(&mut self, index: usize, state: &HPETState) {
fn init(&mut self, index: u8, state: &HPETState) {
*self = HPETTimer {
index,
// SAFETY: the HPETTimer will only be used after the timer
@ -235,7 +235,7 @@ impl HPETTimer {
Timer::NS,
0,
timer_handler,
&state.timers[self.index],
&state.timers[self.index as usize],
)
}
@ -246,7 +246,7 @@ impl HPETTimer {
}
fn is_int_active(&self) -> bool {
self.get_state().is_timer_int_active(self.index)
self.get_state().is_timer_int_active(self.index.into())
}
const fn is_fsb_route_enabled(&self) -> bool {
@ -353,7 +353,7 @@ impl HPETTimer {
// still operate and generate appropriate status bits, but
// will not cause an interrupt"
self.get_state()
.update_int_status(self.index as u32, set && self.is_int_level_triggered());
.update_int_status(self.index.into(), set && self.is_int_level_triggered());
self.set_irq(set);
}
@ -559,14 +559,19 @@ pub struct HPETState {
/// HPET timer array managed by this timer block.
#[doc(alias = "timer")]
timers: [BqlRefCell<HPETTimer>; HPET_MAX_TIMERS],
num_timers: BqlCell<usize>,
timers: [BqlRefCell<HPETTimer>; HPET_MAX_TIMERS as usize],
num_timers: BqlCell<u8>,
/// Instance id (HPET timer block ID).
hpet_id: BqlCell<usize>,
}
impl HPETState {
// Get num_timers with `usize` type, which is useful to play with array index.
fn get_num_timers(&self) -> usize {
self.num_timers.get().into()
}
const fn has_msi_flag(&self) -> bool {
self.flags & (1 << HPET_FLAG_MSI_SUPPORT_SHIFT) != 0
}
@ -606,7 +611,7 @@ impl HPETState {
fn init_timer(&self) {
for (index, timer) in self.timers.iter().enumerate() {
timer.borrow_mut().init(index, self);
timer.borrow_mut().init(index.try_into().unwrap(), self);
}
}
@ -628,7 +633,7 @@ impl HPETState {
self.hpet_offset
.set(ticks_to_ns(self.counter.get()) - CLOCK_VIRTUAL.get_ns());
for timer in self.timers.iter().take(self.num_timers.get()) {
for timer in self.timers.iter().take(self.get_num_timers()) {
let mut t = timer.borrow_mut();
if t.is_int_enabled() && t.is_int_active() {
@ -640,7 +645,7 @@ impl HPETState {
// Halt main counter and disable interrupt generation.
self.counter.set(self.get_ticks());
for timer in self.timers.iter().take(self.num_timers.get()) {
for timer in self.timers.iter().take(self.get_num_timers()) {
timer.borrow_mut().del_timer();
}
}
@ -663,7 +668,7 @@ impl HPETState {
let new_val = val << shift;
let cleared = new_val & self.int_status.get();
for (index, timer) in self.timers.iter().take(self.num_timers.get()).enumerate() {
for (index, timer) in self.timers.iter().take(self.get_num_timers()).enumerate() {
if cleared & (1 << index) != 0 {
timer.borrow_mut().update_irq(false);
}
@ -737,7 +742,7 @@ impl HPETState {
1 << HPET_CAP_COUNT_SIZE_CAP_SHIFT |
1 << HPET_CAP_LEG_RT_CAP_SHIFT |
HPET_CAP_VENDER_ID_VALUE << HPET_CAP_VENDER_ID_SHIFT |
((self.num_timers.get() - 1) as u64) << HPET_CAP_NUM_TIM_SHIFT | // indicate the last timer
((self.get_num_timers() - 1) as u64) << HPET_CAP_NUM_TIM_SHIFT | // indicate the last timer
(HPET_CLK_PERIOD * FS_PER_NS) << HPET_CAP_CNT_CLK_PERIOD_SHIFT, // 10 ns
);
@ -746,7 +751,7 @@ impl HPETState {
}
fn reset_hold(&self, _type: ResetType) {
for timer in self.timers.iter().take(self.num_timers.get()) {
for timer in self.timers.iter().take(self.get_num_timers()) {
timer.borrow_mut().reset();
}
@ -774,7 +779,7 @@ impl HPETState {
GlobalRegister::try_from(addr).map(HPETRegister::Global)
} else {
let timer_id: usize = ((addr - 0x100) / 0x20) as usize;
if timer_id <= self.num_timers.get() {
if timer_id <= self.get_num_timers() {
// TODO: Add trace point - trace_hpet_ram_[read|write]_timer_id(timer_id)
TimerRegister::try_from(addr & 0x18)
.map(|reg| HPETRegister::Timer(&self.timers[timer_id], reg))
@ -859,8 +864,8 @@ qemu_api::declare_properties! {
c_str!("timers"),
HPETState,
num_timers,
unsafe { &qdev_prop_usize },
usize,
unsafe { &qdev_prop_uint8 },
u8,
default = HPET_MIN_TIMERS
),
qemu_api::define_property!(

4
rust/qemu-api/tests/vmstate_tests.rs

@ -383,12 +383,12 @@ fn test_vmstate_macro_array_of_pointer_wrapped() {
);
assert_eq!(foo_fields[3].offset, (FOO_ARRAY_MAX + 2) * PTR_SIZE);
assert_eq!(foo_fields[3].num_offset, 0);
assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_uint8 });
assert_eq!(foo_fields[3].version_id, 0);
assert_eq!(foo_fields[3].size, PTR_SIZE);
assert_eq!(foo_fields[3].num, FOO_ARRAY_MAX as i32);
assert_eq!(
foo_fields[2].flags.0,
foo_fields[3].flags.0,
VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0
);
assert!(foo_fields[3].vmsd.is_null());

13
scsi/utils.c

@ -587,20 +587,27 @@ int scsi_sense_from_errno(int errno_value, SCSISense *sense)
return GOOD;
case EDOM:
return TASK_SET_FULL;
#if ENODEV != ENOMEDIUM
case ENODEV:
/*
* Some of the BSDs have ENODEV and ENOMEDIUM as synonyms. For
* everyone else, give a more severe sense code for ENODEV.
*/
#endif
#ifdef CONFIG_LINUX
/* These errno mapping are specific to Linux. For more information:
* - scsi_check_sense and scsi_decide_disposition in drivers/scsi/scsi_error.c
* - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c
* - blk_errors[] in block/blk-core.c
*/
case EREMOTEIO:
*sense = SENSE_CODE(TARGET_FAILURE);
return CHECK_CONDITION;
case EBADE:
return RESERVATION_CONFLICT;
case ENODATA:
*sense = SENSE_CODE(READ_ERROR);
return CHECK_CONDITION;
case EREMOTEIO:
*sense = SENSE_CODE(TARGET_FAILURE);
return CHECK_CONDITION;
#endif
case ENOMEDIUM:
*sense = SENSE_CODE(NO_MEDIUM);

12
target/i386/cpu.c

@ -5621,6 +5621,18 @@ static const X86CPUDefinition builtin_x86_defs[] = {
.features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING,
.xlevel = 0x80000008,
.model_id = "Zhaoxin YongFeng Processor",
.versions = (X86CPUVersionDefinition[]) {
{ .version = 1 },
{
.version = 2,
.note = "with the correct model number",
.props = (PropValue[]) {
{ "model", "0x5b" },
{ /* end of list */ }
}
},
{ /* end of list */ }
}
},
};

33
target/i386/cpu.h

@ -1811,10 +1811,10 @@ typedef struct CPUCaches {
CPUCacheInfo *l3_cache;
} CPUCaches;
typedef struct HVFX86LazyFlags {
typedef struct X86LazyFlags {
target_ulong result;
target_ulong auxbits;
} HVFX86LazyFlags;
} X86LazyFlags;
typedef struct CPUArchState {
/* standard registers */
@ -2108,8 +2108,8 @@ typedef struct CPUArchState {
QemuMutex xen_timers_lock;
#endif
#if defined(CONFIG_HVF)
HVFX86LazyFlags hvf_lflags;
void *hvf_mmio_buf;
X86LazyFlags lflags;
void *emu_mmio_buf;
#endif
uint64_t mcg_cap;
@ -2843,4 +2843,29 @@ static inline bool ctl_has_irq(CPUX86State *env)
# define TARGET_VSYSCALL_PAGE (UINT64_C(-10) << 20)
#endif
/* majority(NOT a, b, c) = (a ^ b) ? b : c */
#define MAJ_INV1(a, b, c) ((((a) ^ (b)) & ((b) ^ (c))) ^ (c))
/*
* ADD_COUT_VEC(x, y) = majority((x + y) ^ x ^ y, x, y)
*
* If two corresponding bits in x and y are the same, that's the carry
* independent of the value (x+y)^x^y. Hence x^y can be replaced with
* 1 in (x+y)^x^y, resulting in majority(NOT (x+y), x, y)
*/
#define ADD_COUT_VEC(op1, op2, result) \
MAJ_INV1(result, op1, op2)
/*
* SUB_COUT_VEC(x, y) = NOT majority(x, NOT y, (x - y) ^ x ^ NOT y)
* = majority(NOT x, y, (x - y) ^ x ^ y)
*
* Note that the carry out is actually a borrow, i.e. it is inverted.
* If two corresponding bits in x and y are different, the value of the
* bit in (x-y)^x^y likewise does not matter. Hence, x^y can be replaced
* with 0 in (x-y)^x^y, resulting in majority(NOT x, y, x-y)
*/
#define SUB_COUT_VEC(op1, op2, result) \
MAJ_INV1(op1, op2, result)
#endif /* I386_CPU_H */

5
target/i386/emulate/meson.build

@ -0,0 +1,5 @@
i386_system_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: files(
'x86_decode.c',
'x86_emu.c',
'x86_flags.c',
))

45
target/i386/emulate/panic.h

@ -0,0 +1,45 @@
/*
* Copyright (C) 2016 Veertu Inc,
* Copyright (C) 2017 Google Inc,
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef X86_EMU_PANIC_H
#define X86_EMU_PANIC_H
#define VM_PANIC(x) {\
printf("%s\n", x); \
abort(); \
}
#define VM_PANIC_ON(x) {\
if (x) { \
printf("%s\n", #x); \
abort(); \
} \
}
#define VM_PANIC_EX(...) {\
printf(__VA_ARGS__); \
abort(); \
}
#define VM_PANIC_ON_EX(x, ...) {\
if (x) { \
printf(__VA_ARGS__); \
abort(); \
} \
}
#endif

4
target/i386/hvf/x86.h → target/i386/emulate/x86.h

@ -16,8 +16,8 @@
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HVF_X86_H
#define HVF_X86_H
#ifndef X86_EMU_DEFS_H
#define X86_EMU_DEFS_H
typedef struct x86_register {
union {

886
target/i386/hvf/x86_decode.c → target/i386/emulate/x86_decode.c

File diff suppressed because it is too large

6
target/i386/hvf/x86_decode.h → target/i386/emulate/x86_decode.h

@ -15,8 +15,8 @@
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HVF_X86_DECODE_H
#define HVF_X86_DECODE_H
#ifndef X86_EMU_DECODE_H
#define X86_EMU_DECODE_H
#include "cpu.h"
#include "x86.h"
@ -295,8 +295,6 @@ typedef struct x86_decode {
struct x86_modrm modrm;
struct x86_decode_op op[4];
bool is_fpu;
uint32_t flags_mask;
} x86_decode;
uint64_t sign(uint64_t val, int size);

62
target/i386/hvf/x86_emu.c → target/i386/emulate/x86_emu.c

@ -40,11 +40,7 @@
#include "x86_decode.h"
#include "x86.h"
#include "x86_emu.h"
#include "x86_mmu.h"
#include "x86_flags.h"
#include "vmcs.h"
#include "vmx.h"
#include "hvf-i386.h"
#define EXEC_2OP_FLAGS_CMD(env, decode, cmd, FLAGS_FUNC, save_res) \
{ \
@ -179,13 +175,13 @@ void write_val_ext(CPUX86State *env, target_ulong ptr, target_ulong val, int siz
write_val_to_reg(ptr, val, size);
return;
}
vmx_write_mem(env_cpu(env), ptr, &val, size);
emul_ops->write_mem(env_cpu(env), &val, ptr, size);
}
uint8_t *read_mmio(CPUX86State *env, target_ulong ptr, int bytes)
{
vmx_read_mem(env_cpu(env), env->hvf_mmio_buf, ptr, bytes);
return env->hvf_mmio_buf;
emul_ops->read_mem(env_cpu(env), env->emu_mmio_buf, ptr, bytes);
return env->emu_mmio_buf;
}
@ -396,18 +392,18 @@ static void exec_out(CPUX86State *env, struct x86_decode *decode)
{
switch (decode->opcode[0]) {
case 0xe6:
hvf_handle_io(env_cpu(env), decode->op[0].val, &AL(env), 1, 1, 1);
emul_ops->handle_io(env_cpu(env), decode->op[0].val, &AL(env), 1, 1, 1);
break;
case 0xe7:
hvf_handle_io(env_cpu(env), decode->op[0].val, &RAX(env), 1,
decode->operand_size, 1);
emul_ops->handle_io(env_cpu(env), decode->op[0].val, &RAX(env), 1,
decode->operand_size, 1);
break;
case 0xee:
hvf_handle_io(env_cpu(env), DX(env), &AL(env), 1, 1, 1);
emul_ops->handle_io(env_cpu(env), DX(env), &AL(env), 1, 1, 1);
break;
case 0xef:
hvf_handle_io(env_cpu(env), DX(env), &RAX(env), 1,
decode->operand_size, 1);
emul_ops->handle_io(env_cpu(env), DX(env), &RAX(env), 1,
decode->operand_size, 1);
break;
default:
VM_PANIC("Bad out opcode\n");
@ -421,10 +417,10 @@ static void exec_in(CPUX86State *env, struct x86_decode *decode)
target_ulong val = 0;
switch (decode->opcode[0]) {
case 0xe4:
hvf_handle_io(env_cpu(env), decode->op[0].val, &AL(env), 0, 1, 1);
emul_ops->handle_io(env_cpu(env), decode->op[0].val, &AL(env), 0, 1, 1);
break;
case 0xe5:
hvf_handle_io(env_cpu(env), decode->op[0].val, &val, 0,
emul_ops->handle_io(env_cpu(env), decode->op[0].val, &val, 0,
decode->operand_size, 1);
if (decode->operand_size == 2) {
AX(env) = val;
@ -433,10 +429,11 @@ static void exec_in(CPUX86State *env, struct x86_decode *decode)
}
break;
case 0xec:
hvf_handle_io(env_cpu(env), DX(env), &AL(env), 0, 1, 1);
emul_ops->handle_io(env_cpu(env), DX(env), &AL(env), 0, 1, 1);
break;
case 0xed:
hvf_handle_io(env_cpu(env), DX(env), &val, 0, decode->operand_size, 1);
emul_ops->handle_io(env_cpu(env), DX(env), &val, 0,
decode->operand_size, 1);
if (decode->operand_size == 2) {
AX(env) = val;
} else {
@ -486,10 +483,10 @@ static void exec_ins_single(CPUX86State *env, struct x86_decode *decode)
target_ulong addr = linear_addr_size(env_cpu(env), RDI(env),
decode->addressing_size, R_ES);
hvf_handle_io(env_cpu(env), DX(env), env->hvf_mmio_buf, 0,
decode->operand_size, 1);
vmx_write_mem(env_cpu(env), addr, env->hvf_mmio_buf,
decode->operand_size);
emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 0,
decode->operand_size, 1);
emul_ops->write_mem(env_cpu(env), env->emu_mmio_buf, addr,
decode->operand_size);
string_increment_reg(env, R_EDI, decode);
}
@ -509,10 +506,10 @@ static void exec_outs_single(CPUX86State *env, struct x86_decode *decode)
{
target_ulong addr = decode_linear_addr(env, decode, RSI(env), R_DS);
vmx_read_mem(env_cpu(env), env->hvf_mmio_buf, addr,
decode->operand_size);
hvf_handle_io(env_cpu(env), DX(env), env->hvf_mmio_buf, 1,
decode->operand_size, 1);
emul_ops->read_mem(env_cpu(env), env->emu_mmio_buf, addr,
decode->operand_size);
emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 1,
decode->operand_size, 1);
string_increment_reg(env, R_ESI, decode);
}
@ -595,7 +592,7 @@ static void exec_stos_single(CPUX86State *env, struct x86_decode *decode)
addr = linear_addr_size(env_cpu(env), RDI(env),
decode->addressing_size, R_ES);
val = read_reg(env, R_EAX, decode->operand_size);
vmx_write_mem(env_cpu(env), addr, &val, decode->operand_size);
emul_ops->write_mem(env_cpu(env), &val, addr, decode->operand_size);
string_increment_reg(env, R_EDI, decode);
}
@ -619,7 +616,7 @@ static void exec_scas_single(CPUX86State *env, struct x86_decode *decode)
addr = linear_addr_size(env_cpu(env), RDI(env),
decode->addressing_size, R_ES);
decode->op[1].type = X86_VAR_IMMEDIATE;
vmx_read_mem(env_cpu(env), &decode->op[1].val, addr, decode->operand_size);
emul_ops->read_mem(env_cpu(env), &decode->op[1].val, addr, decode->operand_size);
EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false);
string_increment_reg(env, R_EDI, decode);
@ -644,7 +641,7 @@ static void exec_lods_single(CPUX86State *env, struct x86_decode *decode)
target_ulong val = 0;
addr = decode_linear_addr(env, decode, RSI(env), R_DS);
vmx_read_mem(env_cpu(env), &val, addr, decode->operand_size);
emul_ops->read_mem(env_cpu(env), &val, addr, decode->operand_size);
write_reg(env, R_EAX, val, decode->operand_size);
string_increment_reg(env, R_ESI, decode);
@ -671,13 +668,13 @@ void x86_emul_raise_exception(CPUX86State *env, int exception_index, int error_c
static void exec_rdmsr(CPUX86State *env, struct x86_decode *decode)
{
hvf_simulate_rdmsr(env);
emul_ops->simulate_rdmsr(env_cpu(env));
env->eip += decode->len;
}
static void exec_wrmsr(CPUX86State *env, struct x86_decode *decode)
{
hvf_simulate_wrmsr(env);
emul_ops->simulate_wrmsr(env_cpu(env));
env->eip += decode->len;
}
@ -1231,6 +1228,8 @@ static struct cmd_handler {
static struct cmd_handler _cmd_handler[X86_DECODE_CMD_LAST];
const struct x86_emul_ops *emul_ops;
static void init_cmd_handler(void)
{
int i;
@ -1253,7 +1252,8 @@ bool exec_instruction(CPUX86State *env, struct x86_decode *ins)
return true;
}
void init_emu(void)
void init_emu(const struct x86_emul_ops *o)
{
emul_ops = o;
init_cmd_handler();
}

15
target/i386/hvf/x86_emu.h → target/i386/emulate/x86_emu.h

@ -23,7 +23,20 @@
#include "x86_decode.h"
#include "cpu.h"
void init_emu(void);
struct x86_emul_ops {
void (*read_mem)(CPUState *cpu, void *data, target_ulong addr, int bytes);
void (*write_mem)(CPUState *cpu, void *data, target_ulong addr, int bytes);
void (*read_segment_descriptor)(CPUState *cpu, struct x86_segment_descriptor *desc,
enum X86Seg seg);
void (*handle_io)(CPUState *cpu, uint16_t port, void *data, int direction,
int size, int count);
void (*simulate_rdmsr)(CPUState *cs);
void (*simulate_wrmsr)(CPUState *cs);
};
extern const struct x86_emul_ops *emul_ops;
void init_emu(const struct x86_emul_ops *ops);
bool exec_instruction(CPUX86State *env, struct x86_decode *ins);
void x86_emul_raise_exception(CPUX86State *env, int exception_index, int error_code);

66
target/i386/hvf/x86_flags.c → target/i386/emulate/x86_flags.c

@ -45,15 +45,6 @@
#define LF_MASK_CF (0x01 << LF_BIT_CF)
#define LF_MASK_PO (0x01 << LF_BIT_PO)
#define ADD_COUT_VEC(op1, op2, result) \
(((op1) & (op2)) | (((op1) | (op2)) & (~(result))))
#define SUB_COUT_VEC(op1, op2, result) \
(((~(op1)) & (op2)) | (((~(op1)) ^ (op2)) & (result)))
#define GET_ADD_OVERFLOW(op1, op2, result, mask) \
((((op1) ^ (result)) & ((op2) ^ (result))) & (mask))
/* ******************* */
/* OSZAPC */
/* ******************* */
@ -62,7 +53,7 @@
#define SET_FLAGS_OSZAPC_SIZE(size, lf_carries, lf_result) { \
target_ulong temp = ((lf_carries) & (LF_MASK_AF)) | \
(((lf_carries) >> (size - 2)) << LF_BIT_PO); \
env->hvf_lflags.result = (target_ulong)(int##size##_t)(lf_result); \
env->lflags.result = (target_ulong)(int##size##_t)(lf_result); \
if ((size) == 32) { \
temp = ((lf_carries) & ~(LF_MASK_PDB | LF_MASK_SD)); \
} else if ((size) == 16) { \
@ -72,7 +63,7 @@
} else { \
VM_PANIC("unimplemented"); \
} \
env->hvf_lflags.auxbits = (target_ulong)(uint32_t)temp; \
env->lflags.auxbits = (target_ulong)(uint32_t)temp; \
}
/* carries, result */
@ -99,10 +90,10 @@
} else { \
VM_PANIC("unimplemented"); \
} \
env->hvf_lflags.result = (target_ulong)(int##size##_t)(lf_result); \
target_ulong delta_c = (env->hvf_lflags.auxbits ^ temp) & LF_MASK_CF; \
env->lflags.result = (target_ulong)(int##size##_t)(lf_result); \
target_ulong delta_c = (env->lflags.auxbits ^ temp) & LF_MASK_CF; \
delta_c ^= (delta_c >> 1); \
env->hvf_lflags.auxbits = (target_ulong)(uint32_t)(temp ^ delta_c); \
env->lflags.auxbits = (target_ulong)(uint32_t)(temp ^ delta_c); \
}
/* carries, result */
@ -116,8 +107,8 @@
void SET_FLAGS_OxxxxC(CPUX86State *env, uint32_t new_of, uint32_t new_cf)
{
uint32_t temp_po = new_of ^ new_cf;
env->hvf_lflags.auxbits &= ~(LF_MASK_PO | LF_MASK_CF);
env->hvf_lflags.auxbits |= (temp_po << LF_BIT_PO) | (new_cf << LF_BIT_CF);
env->lflags.auxbits &= ~(LF_MASK_PO | LF_MASK_CF);
env->lflags.auxbits |= (temp_po << LF_BIT_PO) | (new_cf << LF_BIT_CF);
}
void SET_FLAGS_OSZAPC_SUB32(CPUX86State *env, uint32_t v1, uint32_t v2,
@ -213,27 +204,27 @@ void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t v1, uint8_t v2,
bool get_PF(CPUX86State *env)
{
uint32_t temp = (255 & env->hvf_lflags.result);
temp = temp ^ (255 & (env->hvf_lflags.auxbits >> LF_BIT_PDB));
uint32_t temp = (255 & env->lflags.result);
temp = temp ^ (255 & (env->lflags.auxbits >> LF_BIT_PDB));
temp = (temp ^ (temp >> 4)) & 0x0F;
return (0x9669U >> temp) & 1;
}
void set_PF(CPUX86State *env, bool val)
{
uint32_t temp = (255 & env->hvf_lflags.result) ^ (!val);
env->hvf_lflags.auxbits &= ~(LF_MASK_PDB);
env->hvf_lflags.auxbits |= (temp << LF_BIT_PDB);
uint32_t temp = (255 & env->lflags.result) ^ (!val);
env->lflags.auxbits &= ~(LF_MASK_PDB);
env->lflags.auxbits |= (temp << LF_BIT_PDB);
}
bool get_OF(CPUX86State *env)
{
return ((env->hvf_lflags.auxbits + (1U << LF_BIT_PO)) >> LF_BIT_CF) & 1;
return ((env->lflags.auxbits + (1U << LF_BIT_PO)) >> LF_BIT_CF) & 1;
}
bool get_CF(CPUX86State *env)
{
return (env->hvf_lflags.auxbits >> LF_BIT_CF) & 1;
return (env->lflags.auxbits >> LF_BIT_CF) & 1;
}
void set_OF(CPUX86State *env, bool val)
@ -250,49 +241,50 @@ void set_CF(CPUX86State *env, bool val)
bool get_AF(CPUX86State *env)
{
return (env->hvf_lflags.auxbits >> LF_BIT_AF) & 1;
return (env->lflags.auxbits >> LF_BIT_AF) & 1;
}
void set_AF(CPUX86State *env, bool val)
{
env->hvf_lflags.auxbits &= ~(LF_MASK_AF);
env->hvf_lflags.auxbits |= val << LF_BIT_AF;
env->lflags.auxbits &= ~(LF_MASK_AF);
env->lflags.auxbits |= val << LF_BIT_AF;
}
bool get_ZF(CPUX86State *env)
{
return !env->hvf_lflags.result;
return !env->lflags.result;
}
void set_ZF(CPUX86State *env, bool val)
{
if (val) {
env->hvf_lflags.auxbits ^=
(((env->hvf_lflags.result >> LF_SIGN_BIT) & 1) << LF_BIT_SD);
env->lflags.auxbits ^=
(((env->lflags.result >> LF_SIGN_BIT) & 1) << LF_BIT_SD);
/* merge the parity bits into the Parity Delta Byte */
uint32_t temp_pdb = (255 & env->hvf_lflags.result);
env->hvf_lflags.auxbits ^= (temp_pdb << LF_BIT_PDB);
uint32_t temp_pdb = (255 & env->lflags.result);
env->lflags.auxbits ^= (temp_pdb << LF_BIT_PDB);
/* now zero the .result value */
env->hvf_lflags.result = 0;
env->lflags.result = 0;
} else {
env->hvf_lflags.result |= (1 << 8);
env->lflags.result |= (1 << 8);
}
}
bool get_SF(CPUX86State *env)
{
return ((env->hvf_lflags.result >> LF_SIGN_BIT) ^
(env->hvf_lflags.auxbits >> LF_BIT_SD)) & 1;
return ((env->lflags.result >> LF_SIGN_BIT) ^
(env->lflags.auxbits >> LF_BIT_SD)) & 1;
}
void set_SF(CPUX86State *env, bool val)
{
bool temp_sf = get_SF(env);
env->hvf_lflags.auxbits ^= (temp_sf ^ val) << LF_BIT_SD;
env->lflags.auxbits ^= (temp_sf ^ val) << LF_BIT_SD;
}
void lflags_to_rflags(CPUX86State *env)
{
env->eflags &= ~(CC_C|CC_P|CC_A|CC_Z|CC_S|CC_O);
env->eflags |= get_CF(env) ? CC_C : 0;
env->eflags |= get_PF(env) ? CC_P : 0;
env->eflags |= get_AF(env) ? CC_A : 0;
@ -303,7 +295,7 @@ void lflags_to_rflags(CPUX86State *env)
void rflags_to_lflags(CPUX86State *env)
{
env->hvf_lflags.auxbits = env->hvf_lflags.result = 0;
env->lflags.auxbits = env->lflags.result = 0;
set_OF(env, env->eflags & CC_O);
set_SF(env, env->eflags & CC_S);
set_ZF(env, env->eflags & CC_Z);

6
target/i386/hvf/x86_flags.h → target/i386/emulate/x86_flags.h

@ -21,8 +21,8 @@
* x86 eflags functions
*/
#ifndef X86_FLAGS_H
#define X86_FLAGS_H
#ifndef X86_EMU_FLAGS_H
#define X86_EMU_FLAGS_H
#include "cpu.h"
void lflags_to_rflags(CPUX86State *env);
@ -78,4 +78,4 @@ void SET_FLAGS_OSZAPC_LOGIC16(CPUX86State *env, uint16_t v1, uint16_t v2,
void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t v1, uint8_t v2,
uint8_t diff);
#endif /* X86_FLAGS_H */
#endif /* X86_EMU_FLAGS_H */

10
target/i386/host-cpu.c

@ -109,9 +109,13 @@ void host_cpu_vendor_fms(char *vendor, int *family, int *model, int *stepping)
{
uint32_t eax, ebx, ecx, edx;
host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
host_cpuid(0x0, 0, NULL, &ebx, &ecx, &edx);
x86_cpu_vendor_words2str(vendor, ebx, edx, ecx);
if (!family && !model && !stepping) {
return;
}
host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
if (family) {
*family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
@ -129,11 +133,9 @@ void host_cpu_instance_init(X86CPU *cpu)
X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu);
if (xcc->model) {
uint32_t ebx = 0, ecx = 0, edx = 0;
char vendor[CPUID_VENDOR_SZ + 1];
host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
x86_cpu_vendor_words2str(vendor, ebx, edx, ecx);
host_cpu_vendor_fms(vendor, NULL, NULL, NULL);
object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort);
}
}

4
target/i386/hvf/hvf-i386.h

@ -19,8 +19,8 @@
uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, int reg);
void hvf_handle_io(CPUState *, uint16_t, void *, int, int, int);
void hvf_simulate_rdmsr(CPUX86State *env);
void hvf_simulate_wrmsr(CPUX86State *env);
void hvf_simulate_rdmsr(CPUState *cpu);
void hvf_simulate_wrmsr(CPUState *cpu);
/* Host specific functions */
int hvf_inject_interrupt(CPUArchState *env, int vector);

57
target/i386/hvf/hvf.c

@ -59,12 +59,12 @@
#include "hvf-i386.h"
#include "vmcs.h"
#include "vmx.h"
#include "x86.h"
#include "emulate/x86.h"
#include "x86_descr.h"
#include "x86_flags.h"
#include "emulate/x86_flags.h"
#include "x86_mmu.h"
#include "x86_decode.h"
#include "x86_emu.h"
#include "emulate/x86_decode.h"
#include "emulate/x86_emu.h"
#include "x86_task.h"
#include "x86hvf.h"
@ -168,7 +168,7 @@ void hvf_arch_vcpu_destroy(CPUState *cpu)
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
g_free(env->hvf_mmio_buf);
g_free(env->emu_mmio_buf);
}
static void init_tsc_freq(CPUX86State *env)
@ -229,6 +229,33 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
return hv_vm_create(HV_VM_DEFAULT);
}
static void hvf_read_segment_descriptor(CPUState *s, struct x86_segment_descriptor *desc,
X86Seg seg)
{
struct vmx_segment vmx_segment;
vmx_read_segment_descriptor(s, &vmx_segment, seg);
vmx_segment_to_x86_descriptor(s, &vmx_segment, desc);
}
static void hvf_read_mem(CPUState *cpu, void *data, target_ulong gva, int bytes)
{
vmx_read_mem(cpu, data, gva, bytes);
}
static void hvf_write_mem(CPUState *cpu, void *data, target_ulong gva, int bytes)
{
vmx_write_mem(cpu, gva, data, bytes);
}
static const struct x86_emul_ops hvf_x86_emul_ops = {
.read_mem = hvf_read_mem,
.write_mem = hvf_write_mem,
.read_segment_descriptor = hvf_read_segment_descriptor,
.handle_io = hvf_handle_io,
.simulate_rdmsr = hvf_simulate_rdmsr,
.simulate_wrmsr = hvf_simulate_wrmsr,
};
int hvf_arch_init_vcpu(CPUState *cpu)
{
X86CPU *x86cpu = X86_CPU(cpu);
@ -237,13 +264,13 @@ int hvf_arch_init_vcpu(CPUState *cpu)
int r;
uint64_t reqCap;
init_emu();
init_emu(&hvf_x86_emul_ops);
init_decoder();
if (hvf_state->hvf_caps == NULL) {
hvf_state->hvf_caps = g_new0(struct hvf_vcpu_caps, 1);
}
env->hvf_mmio_buf = g_new(char, 4096);
env->emu_mmio_buf = g_new(char, 4096);
if (x86cpu->vmware_cpuid_freq) {
init_tsc_freq(env);
@ -481,10 +508,10 @@ void hvf_store_regs(CPUState *cs)
macvm_set_rip(cs, env->eip);
}
void hvf_simulate_rdmsr(CPUX86State *env)
void hvf_simulate_rdmsr(CPUState *cs)
{
X86CPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
uint32_t msr = ECX(env);
uint64_t val = 0;
@ -586,10 +613,10 @@ void hvf_simulate_rdmsr(CPUX86State *env)
RDX(env) = (uint32_t)(val >> 32);
}
void hvf_simulate_wrmsr(CPUX86State *env)
void hvf_simulate_wrmsr(CPUState *cs)
{
X86CPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
uint32_t msr = ECX(env);
uint64_t data = ((uint64_t)EDX(env) << 32) | EAX(env);
@ -875,9 +902,9 @@ int hvf_vcpu_exec(CPUState *cpu)
{
hvf_load_regs(cpu);
if (exit_reason == EXIT_REASON_RDMSR) {
hvf_simulate_rdmsr(env);
hvf_simulate_rdmsr(cpu);
} else {
hvf_simulate_wrmsr(env);
hvf_simulate_wrmsr(cpu);
}
env->eip += ins_len;
hvf_store_regs(cpu);

3
target/i386/hvf/meson.build

@ -2,10 +2,7 @@ i386_system_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: files(
'hvf.c',
'x86.c',
'x86_cpuid.c',
'x86_decode.c',
'x86_descr.c',
'x86_emu.c',
'x86_flags.c',
'x86_mmu.c',
'x86_task.c',
'x86hvf.c',

2
target/i386/hvf/vmx.h

@ -29,7 +29,7 @@
#include <Hypervisor/hv_vmx.h>
#include "vmcs.h"
#include "cpu.h"
#include "x86.h"
#include "emulate/x86.h"
#include "system/hvf.h"
#include "system/hvf_int.h"

4
target/i386/hvf/x86.c

@ -19,8 +19,8 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "x86_decode.h"
#include "x86_emu.h"
#include "emulate/x86_decode.h"
#include "emulate/x86_emu.h"
#include "vmcs.h"
#include "vmx.h"
#include "x86_mmu.h"

2
target/i386/hvf/x86_cpuid.c

@ -24,7 +24,7 @@
#include "qemu/cpuid.h"
#include "host/cpuinfo.h"
#include "cpu.h"
#include "x86.h"
#include "emulate/x86.h"
#include "vmx.h"
#include "system/hvf.h"
#include "hvf-i386.h"

2
target/i386/hvf/x86_descr.h

@ -19,7 +19,7 @@
#ifndef HVF_X86_DESCR_H
#define HVF_X86_DESCR_H
#include "x86.h"
#include "emulate/x86.h"
typedef struct vmx_segment {
uint16_t sel;

2
target/i386/hvf/x86_mmu.c

@ -19,7 +19,7 @@
#include "qemu/osdep.h"
#include "panic.h"
#include "cpu.h"
#include "x86.h"
#include "emulate/x86.h"
#include "x86_mmu.h"
#include "vmcs.h"
#include "vmx.h"

6
target/i386/hvf/x86_task.c

@ -14,11 +14,11 @@
#include "hvf-i386.h"
#include "vmcs.h"
#include "vmx.h"
#include "x86.h"
#include "emulate/x86.h"
#include "x86_descr.h"
#include "x86_mmu.h"
#include "x86_decode.h"
#include "x86_emu.h"
#include "emulate/x86_decode.h"
#include "emulate/x86_emu.h"
#include "x86_task.h"
#include "x86hvf.h"

2
target/i386/hvf/x86hvf.c

@ -24,7 +24,7 @@
#include "vmcs.h"
#include "cpu.h"
#include "x86_descr.h"
#include "x86_decode.h"
#include "emulate/x86_decode.h"
#include "system/hw_accel.h"
#include "hw/i386/apic_internal.h"

3
target/i386/kvm/vmsr_energy.c

@ -29,10 +29,9 @@ char *vmsr_compute_default_paths(void)
bool is_host_cpu_intel(void)
{
int family, model, stepping;
char vendor[CPUID_VENDOR_SZ + 1];
host_cpu_vendor_fms(vendor, &family, &model, &stepping);
host_cpu_vendor_fms(vendor, NULL, NULL, NULL);
return g_str_equal(vendor, CPUID_VENDOR_INTEL);
}

1
target/i386/meson.build

@ -31,6 +31,7 @@ subdir('whpx')
subdir('nvmm')
subdir('hvf')
subdir('tcg')
subdir('emulate')
target_arch += {'i386': i386_ss}
target_system_arch += {'i386': i386_system_ss}

90
target/i386/tcg/cc_helper_template.h.inc

@ -44,18 +44,32 @@
/* dynamic flags computation */
static uint32_t glue(compute_all_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
static uint32_t glue(compute_all_cout, SUFFIX)(DATA_TYPE dst, DATA_TYPE carries)
{
uint32_t cf, pf, af, zf, sf, of;
DATA_TYPE src2 = dst - src1;
uint32_t af_cf, pf, zf, sf, of;
cf = dst < src1;
/* PF, ZF, SF computed from result. */
pf = compute_pf(dst);
af = (dst ^ src1 ^ src2) & CC_A;
zf = (dst == 0) * CC_Z;
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
return cf + pf + af + zf + sf + of;
/*
* AF, CF, OF computed from carry out vector. To compute AF and CF, rotate it
* left by one so cout(DATA_BITS - 1) is in bit 0 and cout(3) in bit 4.
*
* To compute OF, place the highest two carry bits into OF and the bit
* immediately to the right of it; then, adding CC_O / 2 XORs them.
*/
af_cf = ((carries << 1) | (carries >> (DATA_BITS - 1))) & (CC_A | CC_C);
of = (lshift(carries, 12 - DATA_BITS) + CC_O / 2) & CC_O;
return pf + zf + sf + af_cf + of;
}
static uint32_t glue(compute_all_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
DATA_TYPE src2 = dst - src1;
DATA_TYPE carries = ADD_COUT_VEC(src1, src2, dst);
return glue(compute_all_cout, SUFFIX)(dst, carries);
}
static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
@ -66,25 +80,9 @@ static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
static uint32_t glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
DATA_TYPE src3)
{
uint32_t cf, pf, af, zf, sf, of;
#ifdef WIDER_TYPE
WIDER_TYPE src13 = (WIDER_TYPE) src1 + (WIDER_TYPE) src3;
DATA_TYPE src2 = dst - src13;
cf = dst < src13;
#else
DATA_TYPE src2 = dst - src1 - src3;
cf = (src3 ? dst <= src1 : dst < src1);
#endif
pf = compute_pf(dst);
af = (dst ^ src1 ^ src2) & 0x10;
zf = (dst == 0) << 6;
sf = lshift(dst, 8 - DATA_BITS) & 0x80;
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
return cf + pf + af + zf + sf + of;
DATA_TYPE carries = ADD_COUT_VEC(src1, src2, dst);
return glue(compute_all_cout, SUFFIX)(dst, carries);
}
static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
@ -101,16 +99,9 @@ static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1,
static uint32_t glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2)
{
uint32_t cf, pf, af, zf, sf, of;
DATA_TYPE src1 = dst + src2;
cf = src1 < src2;
pf = compute_pf(dst);
af = (dst ^ src1 ^ src2) & CC_A;
zf = (dst == 0) * CC_Z;
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
return cf + pf + af + zf + sf + of;
DATA_TYPE carries = SUB_COUT_VEC(src1, src2, dst);
return glue(compute_all_cout, SUFFIX)(dst, carries);
}
static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2)
@ -123,25 +114,9 @@ static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2)
static uint32_t glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2,
DATA_TYPE src3)
{
uint32_t cf, pf, af, zf, sf, of;
#ifdef WIDER_TYPE
WIDER_TYPE src23 = (WIDER_TYPE) src2 + (WIDER_TYPE) src3;
DATA_TYPE src1 = dst + src23;
cf = src1 < src23;
#else
DATA_TYPE src1 = dst + src2 + src3;
cf = (src3 ? src1 <= src2 : src1 < src2);
#endif
pf = compute_pf(dst);
af = (dst ^ src1 ^ src2) & 0x10;
zf = (dst == 0) << 6;
sf = lshift(dst, 8 - DATA_BITS) & 0x80;
of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O;
return cf + pf + af + zf + sf + of;
DATA_TYPE carries = SUB_COUT_VEC(src1, src2, dst);
return glue(compute_all_cout, SUFFIX)(dst, carries);
}
static int glue(compute_c_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2,
@ -175,13 +150,10 @@ static uint32_t glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
static uint32_t glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
uint32_t cf, pf, af, zf, sf, of;
DATA_TYPE src2;
cf = src1;
src1 = dst - 1;
src2 = 1;
pf = compute_pf(dst);
af = (dst ^ src1 ^ src2) & CC_A;
af = (dst ^ (dst - 1)) & CC_A; /* bits 0..3 are all clear */
zf = (dst == 0) * CC_Z;
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
of = (dst == SIGN_MASK) * CC_O;
@ -191,13 +163,10 @@ static uint32_t glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
static uint32_t glue(compute_all_dec, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
{
uint32_t cf, pf, af, zf, sf, of;
DATA_TYPE src2;
cf = src1;
src1 = dst + 1;
src2 = 1;
pf = compute_pf(dst);
af = (dst ^ src1 ^ src2) & CC_A;
af = (dst ^ (dst + 1)) & CC_A; /* bits 0..3 are all set */
zf = (dst == 0) * CC_Z;
sf = lshift(dst, 8 - DATA_BITS) & CC_S;
of = (dst == SIGN_MASK - 1) * CC_O;
@ -292,6 +261,5 @@ static int glue(compute_c_blsi, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
#undef DATA_BITS
#undef SIGN_MASK
#undef DATA_TYPE
#undef DATA_MASK
#undef SUFFIX
#undef WIDER_TYPE

180
target/i386/tcg/emit.c.inc

@ -1170,11 +1170,28 @@ static void gen_AAS(DisasContext *s, X86DecodedInsn *decode)
assume_cc_op(s, CC_OP_EFLAGS);
}
static void gen_ADD(DisasContext *s, X86DecodedInsn *decode);
static void gen_ADC(DisasContext *s, X86DecodedInsn *decode)
{
MemOp ot = decode->op[1].ot;
TCGv c_in = tcg_temp_new();
TCGv c_in;
/*
* Try to avoid CC_OP_ADC by transforming as follows:
* CC_ADC: src1 = dst + c_in, src2 = 0, src3 = c_in
* CC_ADD: src1 = dst + c_in, src2 = c_in (no src3)
*
* In general src2 vs. src3 matters when computing AF and OF, but not here:
* - AF is bit 4 of dst^src1^src2, which is bit 4 of dst^src1 in both cases
* - OF is a function of the two MSBs, and in both cases they are zero for src2
*/
if (decode->e.op2 == X86_TYPE_I && decode->immediate == 0) {
gen_compute_eflags_c(s, s->T1);
gen_ADD(s, decode);
return;
}
c_in = tcg_temp_new();
gen_compute_eflags_c(s, c_in);
if (s->prefix & PREFIX_LOCK) {
tcg_gen_add_tl(s->T0, c_in, s->T1);
@ -1693,22 +1710,22 @@ static void gen_CMPccXADD(DisasContext *s, X86DecodedInsn *decode)
switch (jcc_op) {
case JCC_O:
/* (src1 ^ src2) & (src1 ^ dst). newv is only used here for a moment */
cmp_lhs = tcg_temp_new(), cmp_rhs = tcg_constant_tl(0);
tcg_gen_xor_tl(newv, s->cc_srcT, s->T0);
tcg_gen_xor_tl(s->tmp0, s->cc_srcT, cmpv);
tcg_gen_and_tl(s->tmp0, s->tmp0, newv);
tcg_gen_sextract_tl(s->tmp0, s->tmp0, 0, 8 << ot);
cmp_lhs = s->tmp0, cmp_rhs = tcg_constant_tl(0);
tcg_gen_xor_tl(cmp_lhs, s->cc_srcT, cmpv);
tcg_gen_and_tl(cmp_lhs, cmp_lhs, newv);
tcg_gen_sextract_tl(cmp_lhs, cmp_lhs, 0, 8 << ot);
break;
case JCC_P:
tcg_gen_ext8u_tl(s->tmp0, s->T0);
tcg_gen_ctpop_tl(s->tmp0, s->tmp0);
cmp_lhs = s->tmp0, cmp_rhs = tcg_constant_tl(1);
cmp_lhs = tcg_temp_new(), cmp_rhs = tcg_constant_tl(1);
tcg_gen_ext8u_tl(cmp_lhs, s->T0);
tcg_gen_ctpop_tl(cmp_lhs, cmp_lhs);
break;
case JCC_S:
tcg_gen_sextract_tl(s->tmp0, s->T0, 0, 8 << ot);
cmp_lhs = s->tmp0, cmp_rhs = tcg_constant_tl(0);
cmp_lhs = tcg_temp_new(), cmp_rhs = tcg_constant_tl(0);
tcg_gen_sextract_tl(cmp_lhs, s->T0, 0, 8 << ot);
break;
default:
@ -1859,7 +1876,7 @@ static void gen_CMPXCHG8B(DisasContext *s, X86DecodedInsn *decode)
s->mem_index, MO_TEUQ);
}
/* Set tmp0 to match the required value of Z. */
/* Compute the required value of Z. */
tcg_gen_setcond_i64(TCG_COND_EQ, cmp, old, cmp);
Z = tcg_temp_new();
tcg_gen_trunc_i64_tl(Z, cmp);
@ -1899,9 +1916,10 @@ static void gen_CPUID(DisasContext *s, X86DecodedInsn *decode)
static void gen_CRC32(DisasContext *s, X86DecodedInsn *decode)
{
MemOp ot = decode->op[2].ot;
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
gen_helper_crc32(s->T0, s->tmp2_i32, s->T1, tcg_constant_i32(8 << ot));
tcg_gen_trunc_tl_i32(tmp, s->T0);
gen_helper_crc32(s->T0, tmp, s->T1, tcg_constant_i32(8 << ot));
}
static void gen_CVTPI2Px(DisasContext *s, X86DecodedInsn *decode)
@ -2359,8 +2377,10 @@ static void gen_LAR(DisasContext *s, X86DecodedInsn *decode)
static void gen_LDMXCSR(DisasContext *s, X86DecodedInsn *decode)
{
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
gen_helper_ldmxcsr(tcg_env, s->tmp2_i32);
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(tmp, s->T0);
gen_helper_ldmxcsr(tcg_env, tmp);
}
static void gen_lxx_seg(DisasContext *s, X86DecodedInsn *decode, int seg)
@ -2573,11 +2593,13 @@ static void gen_MOVDQ(DisasContext *s, X86DecodedInsn *decode)
static void gen_MOVMSK(DisasContext *s, X86DecodedInsn *decode)
{
typeof(gen_helper_movmskps_ymm) *ps, *pd, *fn;
TCGv_i32 tmp = tcg_temp_new_i32();
ps = s->vex_l ? gen_helper_movmskps_ymm : gen_helper_movmskps_xmm;
pd = s->vex_l ? gen_helper_movmskpd_ymm : gen_helper_movmskpd_xmm;
fn = s->prefix & PREFIX_DATA ? pd : ps;
fn(s->tmp2_i32, tcg_env, OP_PTR2);
tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32);
fn(tmp, tcg_env, OP_PTR2);
tcg_gen_extu_i32_tl(s->T0, tmp);
}
static void gen_MOVQ(DisasContext *s, X86DecodedInsn *decode)
@ -2674,13 +2696,17 @@ static void gen_MULX(DisasContext *s, X86DecodedInsn *decode)
switch (ot) {
case MO_32:
#ifdef TARGET_X86_64
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
tcg_gen_mulu2_i32(s->tmp2_i32, s->tmp3_i32,
s->tmp2_i32, s->tmp3_i32);
tcg_gen_extu_i32_tl(cpu_regs[s->vex_v], s->tmp2_i32);
tcg_gen_extu_i32_tl(s->T0, s->tmp3_i32);
break;
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(t0, s->T0);
tcg_gen_trunc_tl_i32(t1, s->T1);
tcg_gen_mulu2_i32(t0, t1, t0, t1);
tcg_gen_extu_i32_tl(cpu_regs[s->vex_v], t0);
tcg_gen_extu_i32_tl(s->T0, t1);
break;
}
case MO_64:
#endif
@ -3724,10 +3750,14 @@ static void gen_RORX(DisasContext *s, X86DecodedInsn *decode)
switch (ot) {
case MO_32:
#ifdef TARGET_X86_64
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
tcg_gen_rotri_i32(s->tmp2_i32, s->tmp2_i32, b);
tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32);
break;
{
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(tmp, s->T0);
tcg_gen_rotri_i32(tmp, tmp, b);
tcg_gen_extu_i32_tl(s->T0, tmp);
break;
}
case MO_64:
#endif
@ -3830,22 +3860,64 @@ static void gen_SARX(DisasContext *s, X86DecodedInsn *decode)
tcg_gen_sar_tl(s->T0, s->T0, s->T1);
}
static void gen_SUB(DisasContext *s, X86DecodedInsn *decode);
static void gen_SBB(DisasContext *s, X86DecodedInsn *decode)
{
MemOp ot = decode->op[0].ot;
TCGv c_in = tcg_temp_new();
TCGv c_in;
/*
* Try to avoid CC_OP_SBB by transforming as follows:
* CC_SBB: src1 = dst + c_in, src2 = 0, src3 = c_in
* CC_SUB: src1 = dst + c_in, src2 = c_in (no src3)
*
* In general src2 vs. src3 matters when computing AF and OF, but not here:
* - AF is bit 4 of dst^src1^src2, which is bit 4 of dst^src1 in both cases
* - OF is a function of the two MSBs, and in both cases they are zero for src2
*/
if (decode->e.op2 == X86_TYPE_I && decode->immediate == 0) {
gen_compute_eflags_c(s, s->T1);
gen_SUB(s, decode);
return;
}
c_in = tcg_temp_new();
gen_compute_eflags_c(s, c_in);
/*
* Here the change is as follows:
* CC_SBB: src1 = T0, src2 = T0, src3 = c_in
* CC_SUB: src1 = 0, src2 = c_in (no src3)
*
* The difference also does not matter:
* - AF is bit 4 of dst^src1^src2, but bit 4 of src1^src2 is zero in both cases
* therefore AF comes straight from dst (in fact it is c_in)
* - for OF, src1 and src2 have the same sign in both cases, meaning there
* can be no overflow
*/
if (decode->e.op2 != X86_TYPE_I && !decode->op[0].has_ea && decode->op[0].n == decode->op[2].n) {
if (s->cc_op == CC_OP_DYNAMIC) {
tcg_gen_neg_tl(s->T0, c_in);
} else {
/*
* Do not negate c_in because it will often be dead and only the
* instruction generated by negsetcond will survive.
*/
gen_neg_setcc(s, JCC_B << 1, s->T0);
}
tcg_gen_movi_tl(s->cc_srcT, 0);
decode->cc_src = c_in;
decode->cc_dst = s->T0;
decode->cc_op = CC_OP_SUBB + ot;
return;
}
if (s->prefix & PREFIX_LOCK) {
tcg_gen_add_tl(s->T0, s->T1, c_in);
tcg_gen_neg_tl(s->T0, s->T0);
tcg_gen_atomic_add_fetch_tl(s->T0, s->A0, s->T0,
s->mem_index, ot | MO_LE);
} else {
/*
* TODO: SBB reg, reg could use gen_prepare_eflags_c followed by
* negsetcond, and CC_OP_SUBB as the cc_op.
*/
tcg_gen_sub_tl(s->T0, s->T0, s->T1);
tcg_gen_sub_tl(s->T0, s->T0, c_in);
}
@ -3956,8 +4028,7 @@ static void gen_SHLD(DisasContext *s, X86DecodedInsn *decode)
}
decode->cc_dst = s->T0;
decode->cc_src = s->tmp0;
gen_shiftd_rm_T1(s, ot, false, count);
decode->cc_src = gen_shiftd_rm_T1(s, ot, false, count);
if (can_be_zero) {
gen_shift_dynamic_flags(s, decode, count, CC_OP_SHLB + ot);
} else {
@ -4009,8 +4080,7 @@ static void gen_SHRD(DisasContext *s, X86DecodedInsn *decode)
}
decode->cc_dst = s->T0;
decode->cc_src = s->tmp0;
gen_shiftd_rm_T1(s, ot, true, count);
decode->cc_src = gen_shiftd_rm_T1(s, ot, true, count);
if (can_be_zero) {
gen_shift_dynamic_flags(s, decode, count, CC_OP_SARB + ot);
} else {
@ -4277,7 +4347,7 @@ static void gen_VCVTSI2Sx(DisasContext *s, X86DecodedInsn *decode)
}
return;
}
in = s->tmp2_i32;
in = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(in, s->T1);
#else
in = s->T1;
@ -4307,7 +4377,7 @@ static inline void gen_VCVTtSx2SI(DisasContext *s, X86DecodedInsn *decode,
return;
}
out = s->tmp2_i32;
out = tcg_temp_new_i32();
#else
out = s->T0;
#endif
@ -4359,7 +4429,7 @@ static void gen_VEXTRACTPS(DisasContext *s, X86DecodedInsn *decode)
gen_pextr(s, decode, MO_32);
}
static void gen_vinsertps(DisasContext *s, X86DecodedInsn *decode)
static void gen_vinsertps(DisasContext *s, X86DecodedInsn *decode, TCGv_i32 tmp)
{
int val = decode->immediate;
int dest_word = (val >> 4) & 3;
@ -4376,7 +4446,7 @@ static void gen_vinsertps(DisasContext *s, X86DecodedInsn *decode)
}
if (new_mask != (val & 15)) {
tcg_gen_st_i32(s->tmp2_i32, tcg_env,
tcg_gen_st_i32(tmp, tcg_env,
vector_elem_offset(&decode->op[0], MO_32, dest_word));
}
@ -4395,15 +4465,19 @@ static void gen_vinsertps(DisasContext *s, X86DecodedInsn *decode)
static void gen_VINSERTPS_r(DisasContext *s, X86DecodedInsn *decode)
{
int val = decode->immediate;
tcg_gen_ld_i32(s->tmp2_i32, tcg_env,
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_ld_i32(tmp, tcg_env,
vector_elem_offset(&decode->op[2], MO_32, (val >> 6) & 3));
gen_vinsertps(s, decode);
gen_vinsertps(s, decode, tmp);
}
static void gen_VINSERTPS_m(DisasContext *s, X86DecodedInsn *decode)
{
tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL);
gen_vinsertps(s, decode);
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_qemu_ld_i32(tmp, s->A0, s->mem_index, MO_LEUL);
gen_vinsertps(s, decode, tmp);
}
static void gen_VINSERTx128(DisasContext *s, X86DecodedInsn *decode)
@ -4524,25 +4598,29 @@ static void gen_VMOVSD_ld(DisasContext *s, X86DecodedInsn *decode)
static void gen_VMOVSS(DisasContext *s, X86DecodedInsn *decode)
{
int vec_len = vector_len(s, decode);
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_ld_i32(s->tmp2_i32, OP_PTR2, offsetof(ZMMReg, ZMM_L(0)));
tcg_gen_ld_i32(tmp, OP_PTR2, offsetof(ZMMReg, ZMM_L(0)));
tcg_gen_gvec_mov(MO_64, decode->op[0].offset, decode->op[1].offset, vec_len, vec_len);
tcg_gen_st_i32(s->tmp2_i32, OP_PTR0, offsetof(ZMMReg, ZMM_L(0)));
tcg_gen_st_i32(tmp, OP_PTR0, offsetof(ZMMReg, ZMM_L(0)));
}
static void gen_VMOVSS_ld(DisasContext *s, X86DecodedInsn *decode)
{
int vec_len = vector_len(s, decode);
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL);
tcg_gen_qemu_ld_i32(tmp, s->A0, s->mem_index, MO_LEUL);
tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0);
tcg_gen_st_i32(s->tmp2_i32, OP_PTR0, offsetof(ZMMReg, ZMM_L(0)));
tcg_gen_st_i32(tmp, OP_PTR0, offsetof(ZMMReg, ZMM_L(0)));
}
static void gen_VMOVSS_st(DisasContext *s, X86DecodedInsn *decode)
{
tcg_gen_ld_i32(s->tmp2_i32, OP_PTR2, offsetof(ZMMReg, ZMM_L(0)));
tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL);
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_ld_i32(tmp, OP_PTR2, offsetof(ZMMReg, ZMM_L(0)));
tcg_gen_qemu_st_i32(tmp, s->A0, s->mem_index, MO_LEUL);
}
static void gen_VPMASKMOV_st(DisasContext *s, X86DecodedInsn *decode)

144
target/i386/tcg/translate.c

@ -134,10 +134,7 @@ typedef struct DisasContext {
TCGv T1;
/* TCG local register indexes (only used inside old micro ops) */
TCGv tmp0;
TCGv tmp4;
TCGv_i32 tmp2_i32;
TCGv_i32 tmp3_i32;
TCGv_i64 tmp1_i64;
sigjmp_buf jmpbuf;
@ -1183,6 +1180,26 @@ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg)
return cc;
}
static void gen_neg_setcc(DisasContext *s, int b, TCGv reg)
{
CCPrepare cc = gen_prepare_cc(s, b, reg);
if (cc.no_setcond) {
if (cc.cond == TCG_COND_EQ) {
tcg_gen_addi_tl(reg, cc.reg, -1);
} else {
tcg_gen_neg_tl(reg, cc.reg);
}
return;
}
if (cc.use_reg2) {
tcg_gen_negsetcond_tl(cc.cond, reg, cc.reg, cc.reg2);
} else {
tcg_gen_negsetcondi_tl(cc.cond, reg, cc.reg, cc.imm);
}
}
static void gen_setcc(DisasContext *s, int b, TCGv reg)
{
CCPrepare cc = gen_prepare_cc(s, b, reg);
@ -1300,30 +1317,35 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot)
static void gen_ins(DisasContext *s, MemOp ot, TCGv dshift)
{
TCGv_i32 port = tcg_temp_new_i32();
gen_string_movl_A0_EDI(s);
/* Note: we must do this dummy write first to be restartable in
case of page fault. */
tcg_gen_movi_tl(s->T0, 0);
gen_op_st_v(s, ot, s->T0, s->A0);
tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
tcg_gen_andi_i32(s->tmp2_i32, s->tmp2_i32, 0xffff);
gen_helper_in_func(ot, s->T0, s->tmp2_i32);
tcg_gen_trunc_tl_i32(port, cpu_regs[R_EDX]);
tcg_gen_andi_i32(port, port, 0xffff);
gen_helper_in_func(ot, s->T0, port);
gen_op_st_v(s, ot, s->T0, s->A0);
gen_op_add_reg(s, s->aflag, R_EDI, dshift);
gen_bpt_io(s, s->tmp2_i32, ot);
gen_bpt_io(s, port, ot);
}
static void gen_outs(DisasContext *s, MemOp ot, TCGv dshift)
{
TCGv_i32 port = tcg_temp_new_i32();
TCGv_i32 value = tcg_temp_new_i32();
gen_string_movl_A0_ESI(s);
gen_op_ld_v(s, ot, s->T0, s->A0);
tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
tcg_gen_andi_i32(s->tmp2_i32, s->tmp2_i32, 0xffff);
tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T0);
gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32);
tcg_gen_trunc_tl_i32(port, cpu_regs[R_EDX]);
tcg_gen_andi_i32(port, port, 0xffff);
tcg_gen_trunc_tl_i32(value, s->T0);
gen_helper_out_func(ot, port, value);
gen_op_add_reg(s, s->aflag, R_ESI, dshift);
gen_bpt_io(s, s->tmp2_i32, ot);
gen_bpt_io(s, port, ot);
}
#define REP_MAX 65535
@ -1560,10 +1582,13 @@ static bool check_cpl0(DisasContext *s)
}
/* XXX: add faster immediate case */
static void gen_shiftd_rm_T1(DisasContext *s, MemOp ot,
static TCGv gen_shiftd_rm_T1(DisasContext *s, MemOp ot,
bool is_right, TCGv count)
{
target_ulong mask = (ot == MO_64 ? 63 : 31);
TCGv cc_src = tcg_temp_new();
TCGv tmp = tcg_temp_new();
TCGv hishift;
switch (ot) {
case MO_16:
@ -1571,9 +1596,9 @@ static void gen_shiftd_rm_T1(DisasContext *s, MemOp ot,
This means "shrdw C, B, A" shifts A:B:A >> C. Build the B:A
portion by constructing it as a 32-bit value. */
if (is_right) {
tcg_gen_deposit_tl(s->tmp0, s->T0, s->T1, 16, 16);
tcg_gen_deposit_tl(tmp, s->T0, s->T1, 16, 16);
tcg_gen_mov_tl(s->T1, s->T0);
tcg_gen_mov_tl(s->T0, s->tmp0);
tcg_gen_mov_tl(s->T0, tmp);
} else {
tcg_gen_deposit_tl(s->T1, s->T0, s->T1, 16, 16);
}
@ -1584,47 +1609,52 @@ static void gen_shiftd_rm_T1(DisasContext *s, MemOp ot,
case MO_32:
#ifdef TARGET_X86_64
/* Concatenate the two 32-bit values and use a 64-bit shift. */
tcg_gen_subi_tl(s->tmp0, count, 1);
tcg_gen_subi_tl(tmp, count, 1);
if (is_right) {
tcg_gen_concat_tl_i64(s->T0, s->T0, s->T1);
tcg_gen_shr_i64(s->tmp0, s->T0, s->tmp0);
tcg_gen_shr_i64(cc_src, s->T0, tmp);
tcg_gen_shr_i64(s->T0, s->T0, count);
} else {
tcg_gen_concat_tl_i64(s->T0, s->T1, s->T0);
tcg_gen_shl_i64(s->tmp0, s->T0, s->tmp0);
tcg_gen_shl_i64(cc_src, s->T0, tmp);
tcg_gen_shl_i64(s->T0, s->T0, count);
tcg_gen_shri_i64(s->tmp0, s->tmp0, 32);
tcg_gen_shri_i64(cc_src, cc_src, 32);
tcg_gen_shri_i64(s->T0, s->T0, 32);
}
break;
#endif
default:
tcg_gen_subi_tl(s->tmp0, count, 1);
hishift = tcg_temp_new();
tcg_gen_subi_tl(tmp, count, 1);
if (is_right) {
tcg_gen_shr_tl(s->tmp0, s->T0, s->tmp0);
tcg_gen_shr_tl(cc_src, s->T0, tmp);
tcg_gen_subfi_tl(s->tmp4, mask + 1, count);
/* mask + 1 - count = mask - tmp = mask ^ tmp */
tcg_gen_xori_tl(hishift, tmp, mask);
tcg_gen_shr_tl(s->T0, s->T0, count);
tcg_gen_shl_tl(s->T1, s->T1, s->tmp4);
tcg_gen_shl_tl(s->T1, s->T1, hishift);
} else {
tcg_gen_shl_tl(s->tmp0, s->T0, s->tmp0);
tcg_gen_shl_tl(cc_src, s->T0, tmp);
/* mask + 1 - count = mask - tmp = mask ^ tmp */
tcg_gen_xori_tl(hishift, tmp, mask);
tcg_gen_shl_tl(s->T0, s->T0, count);
tcg_gen_shr_tl(s->T1, s->T1, hishift);
if (ot == MO_16) {
/* Only needed if count > 16, for Intel behaviour. */
tcg_gen_subfi_tl(s->tmp4, 33, count);
tcg_gen_shr_tl(s->tmp4, s->T1, s->tmp4);
tcg_gen_or_tl(s->tmp0, s->tmp0, s->tmp4);
tcg_gen_shri_tl(tmp, s->T1, 1);
tcg_gen_or_tl(cc_src, cc_src, tmp);
}
tcg_gen_subfi_tl(s->tmp4, mask + 1, count);
tcg_gen_shl_tl(s->T0, s->T0, count);
tcg_gen_shr_tl(s->T1, s->T1, s->tmp4);
}
tcg_gen_movi_tl(s->tmp4, 0);
tcg_gen_movcond_tl(TCG_COND_EQ, s->T1, count, s->tmp4,
s->tmp4, s->T1);
tcg_gen_movcond_tl(TCG_COND_EQ, s->T1,
count, tcg_constant_tl(0),
tcg_constant_tl(0), s->T1);
tcg_gen_or_tl(s->T0, s->T0, s->T1);
break;
}
return cc_src;
}
#define X86_MAX_INSN_LENGTH 15
@ -1843,14 +1873,16 @@ static void gen_bndck(DisasContext *s, X86DecodedInsn *decode,
TCGCond cond, TCGv_i64 bndv)
{
TCGv ea = gen_lea_modrm_1(s, decode->mem, false);
TCGv_i32 t32 = tcg_temp_new_i32();
TCGv_i64 t64 = tcg_temp_new_i64();
tcg_gen_extu_tl_i64(s->tmp1_i64, ea);
tcg_gen_extu_tl_i64(t64, ea);
if (!CODE64(s)) {
tcg_gen_ext32u_i64(s->tmp1_i64, s->tmp1_i64);
tcg_gen_ext32u_i64(t64, t64);
}
tcg_gen_setcond_i64(cond, s->tmp1_i64, s->tmp1_i64, bndv);
tcg_gen_extrl_i64_i32(s->tmp2_i32, s->tmp1_i64);
gen_helper_bndck(tcg_env, s->tmp2_i32);
tcg_gen_setcond_i64(cond, t64, t64, bndv);
tcg_gen_extrl_i64_i32(t32, t64);
gen_helper_bndck(tcg_env, t32);
}
/* generate modrm load of memory or register. */
@ -1995,8 +2027,10 @@ static void gen_op_movl_seg_real(DisasContext *s, X86Seg seg_reg, TCGv seg)
static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src)
{
if (PE(s) && !VM86(s)) {
tcg_gen_trunc_tl_i32(s->tmp2_i32, src);
gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), s->tmp2_i32);
TCGv_i32 sel = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(sel, src);
gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), sel);
/* abort translation because the addseg value may change or
because ss32 may change. For R_SS, translation must always
stop as a special handling must be done to disable hardware
@ -2148,14 +2182,17 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
level &= 31;
if (level != 0) {
int i;
if (level > 1) {
TCGv fp = tcg_temp_new();
/* Copy level-1 pointers from the previous frame. */
for (i = 1; i < level; ++i) {
gen_lea_ss_ofs(s, s->A0, cpu_regs[R_EBP], -size * i);
gen_op_ld_v(s, d_ot, s->tmp0, s->A0);
/* Copy level-1 pointers from the previous frame. */
for (i = 1; i < level; ++i) {
gen_lea_ss_ofs(s, s->A0, cpu_regs[R_EBP], -size * i);
gen_op_ld_v(s, d_ot, fp, s->A0);
gen_lea_ss_ofs(s, s->A0, s->T1, -size * i);
gen_op_st_v(s, d_ot, s->tmp0, s->A0);
gen_lea_ss_ofs(s, s->A0, s->T1, -size * i);
gen_op_st_v(s, d_ot, fp, s->A0);
}
}
/* Push the current FrameTemp as the last level. */
@ -2378,10 +2415,11 @@ static void gen_ldy_env_A0(DisasContext *s, int offset, bool align)
int mem_index = s->mem_index;
TCGv_i128 t0 = tcg_temp_new_i128();
TCGv_i128 t1 = tcg_temp_new_i128();
TCGv a0_hi = tcg_temp_new();
tcg_gen_qemu_ld_i128(t0, s->A0, mem_index, mop | (align ? MO_ALIGN_32 : 0));
tcg_gen_addi_tl(s->tmp0, s->A0, 16);
tcg_gen_qemu_ld_i128(t1, s->tmp0, mem_index, mop);
tcg_gen_addi_tl(a0_hi, s->A0, 16);
tcg_gen_qemu_ld_i128(t1, a0_hi, mem_index, mop);
tcg_gen_st_i128(t0, tcg_env, offset + offsetof(YMMReg, YMM_X(0)));
tcg_gen_st_i128(t1, tcg_env, offset + offsetof(YMMReg, YMM_X(1)));
@ -2392,12 +2430,13 @@ static void gen_sty_env_A0(DisasContext *s, int offset, bool align)
MemOp mop = MO_128 | MO_LE | MO_ATOM_IFALIGN_PAIR;
int mem_index = s->mem_index;
TCGv_i128 t = tcg_temp_new_i128();
TCGv a0_hi = tcg_temp_new();
tcg_gen_ld_i128(t, tcg_env, offset + offsetof(YMMReg, YMM_X(0)));
tcg_gen_qemu_st_i128(t, s->A0, mem_index, mop | (align ? MO_ALIGN_32 : 0));
tcg_gen_addi_tl(s->tmp0, s->A0, 16);
tcg_gen_addi_tl(a0_hi, s->A0, 16);
tcg_gen_ld_i128(t, tcg_env, offset + offsetof(YMMReg, YMM_X(1)));
tcg_gen_qemu_st_i128(t, s->tmp0, mem_index, mop);
tcg_gen_qemu_st_i128(t, a0_hi, mem_index, mop);
}
#include "emit.c.inc"
@ -3744,11 +3783,8 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
dc->T1 = tcg_temp_new();
dc->A0 = tcg_temp_new();
dc->tmp0 = tcg_temp_new();
dc->tmp1_i64 = tcg_temp_new_i64();
dc->tmp2_i32 = tcg_temp_new_i32();
dc->tmp3_i32 = tcg_temp_new_i32();
dc->tmp4 = tcg_temp_new();
dc->cc_srcT = tcg_temp_new();
}

Loading…
Cancel
Save