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>
This commit is contained in:
Stefan Hajnoczi
2025-04-23 09:29:12 -04:00
33 changed files with 989 additions and 792 deletions
+8
View File
@@ -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
+5 -3
View File
@@ -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)
+28 -25
View File
@@ -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 {
+24 -19
View File
@@ -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!(
+2 -2
View File
@@ -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());
+10 -3
View File
@@ -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
View File
@@ -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 */ }
}
},
};
+29 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
@@ -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 {
File diff suppressed because it is too large Load Diff
@@ -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);
@@ -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();
}
@@ -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);
@@ -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);
@@ -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 */
+6 -4
View File
@@ -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);
}
}
+2 -2
View File
@@ -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);
+42 -15
View File
@@ -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);

Some files were not shown because too many files have changed in this diff Show More