mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
hypervisor: x86: share string op helpers
Move common string instruction bookkeeping into the x86 instruction emulator so MOVS, STOS, and MSHV port string I/O use one implementation for REP counts, direction-flag handling, and index advancement. This keeps existing MOVS/STOS behavior unchanged while removing the need for MSHV to open-code the same string-operation details. Signed-off-by: Wei Liu <liuwe@microsoft.com> Assisted-by: Copilot:GPT-5.5
This commit is contained in:
@@ -10,6 +10,7 @@ use iced_x86::*;
|
||||
use crate::arch::emulator::{EmulationError, PlatformEmulator, PlatformError};
|
||||
use crate::arch::x86::Exception;
|
||||
use crate::arch::x86::emulator::CpuStateManager;
|
||||
use crate::arch::x86::regs::DF;
|
||||
|
||||
pub mod cmp;
|
||||
pub mod mov;
|
||||
@@ -17,6 +18,22 @@ pub mod movs;
|
||||
pub mod or;
|
||||
pub mod stos;
|
||||
|
||||
pub fn string_op_repeat_count(has_rep_prefix: bool, rcx: u64) -> u64 {
|
||||
if has_rep_prefix { rcx } else { 1 }
|
||||
}
|
||||
|
||||
pub fn string_op_backwards(rflags: u64) -> bool {
|
||||
(rflags & DF) != 0
|
||||
}
|
||||
|
||||
pub fn advance_string_op_index(index: u64, len: usize, backwards: bool) -> u64 {
|
||||
if backwards {
|
||||
index.wrapping_sub(len as u64)
|
||||
} else {
|
||||
index.wrapping_add(len as u64)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_op<T: CpuStateManager>(
|
||||
insn: &Instruction,
|
||||
op_index: u32,
|
||||
@@ -137,3 +154,28 @@ pub trait InstructionHandler<T: CpuStateManager> {
|
||||
platform: &mut dyn PlatformEmulator<CpuState = T>,
|
||||
) -> Result<(), EmulationError<Exception>>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_string_op_repeat_count() {
|
||||
assert_eq!(string_op_repeat_count(false, 0), 1);
|
||||
assert_eq!(string_op_repeat_count(false, 7), 1);
|
||||
assert_eq!(string_op_repeat_count(true, 7), 7);
|
||||
assert_eq!(string_op_repeat_count(true, 0), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_op_backwards() {
|
||||
assert!(!string_op_backwards(0));
|
||||
assert!(string_op_backwards(DF));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_advance_string_op_index() {
|
||||
assert_eq!(advance_string_op_index(0x1000, 4, false), 0x1004);
|
||||
assert_eq!(advance_string_op_index(0x1000, 4, true), 0xffc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
use anyhow::anyhow;
|
||||
|
||||
use crate::arch::x86::emulator::instructions::*;
|
||||
use crate::arch::x86::regs::DF;
|
||||
|
||||
macro_rules! movs {
|
||||
($bound:ty) => {
|
||||
@@ -23,13 +22,14 @@ macro_rules! movs {
|
||||
state: &mut T,
|
||||
platform: &mut dyn PlatformEmulator<CpuState = T>,
|
||||
) -> Result<(), EmulationError<Exception>> {
|
||||
let mut count: u64 = if insn.has_rep_prefix() {
|
||||
let rcx = if insn.has_rep_prefix() {
|
||||
state
|
||||
.read_reg(Register::ECX)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?
|
||||
} else {
|
||||
1
|
||||
0
|
||||
};
|
||||
let mut count = string_op_repeat_count(insn.has_rep_prefix(), rcx);
|
||||
|
||||
let mut rsi = state
|
||||
.read_reg(Register::RSI)
|
||||
@@ -38,7 +38,7 @@ macro_rules! movs {
|
||||
.read_reg(Register::RDI)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
|
||||
let df = (state.flags() & DF) != 0;
|
||||
let backwards = string_op_backwards(state.flags());
|
||||
let len = std::mem::size_of::<$bound>();
|
||||
|
||||
while count > 0 {
|
||||
@@ -58,13 +58,8 @@ macro_rules! movs {
|
||||
.write_memory(dst, &memory[0..len])
|
||||
.map_err(EmulationError::PlatformEmulationError)?;
|
||||
|
||||
if df {
|
||||
rsi = rsi.wrapping_sub(len as u64);
|
||||
rdi = rdi.wrapping_sub(len as u64);
|
||||
} else {
|
||||
rsi = rsi.wrapping_add(len as u64);
|
||||
rdi = rdi.wrapping_add(len as u64);
|
||||
}
|
||||
rsi = advance_string_op_index(rsi, len, backwards);
|
||||
rdi = advance_string_op_index(rdi, len, backwards);
|
||||
count -= 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
use anyhow::anyhow;
|
||||
|
||||
use crate::arch::x86::emulator::instructions::*;
|
||||
use crate::arch::x86::regs::DF;
|
||||
|
||||
macro_rules! stos {
|
||||
($bound:ty) => {
|
||||
@@ -23,13 +22,14 @@ macro_rules! stos {
|
||||
state: &mut T,
|
||||
platform: &mut dyn PlatformEmulator<CpuState = T>,
|
||||
) -> Result<(), EmulationError<Exception>> {
|
||||
let mut count: u64 = if insn.has_rep_prefix() {
|
||||
let rcx = if insn.has_rep_prefix() {
|
||||
state
|
||||
.read_reg(Register::ECX)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?
|
||||
} else {
|
||||
1
|
||||
0
|
||||
};
|
||||
let mut count = string_op_repeat_count(insn.has_rep_prefix(), rcx);
|
||||
|
||||
let rax = state
|
||||
.read_reg(Register::RAX)
|
||||
@@ -39,7 +39,7 @@ macro_rules! stos {
|
||||
.read_reg(Register::RDI)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
|
||||
let df = (state.flags() & DF) != 0;
|
||||
let backwards = string_op_backwards(state.flags());
|
||||
let len = std::mem::size_of::<$bound>();
|
||||
let rax_bytes = rax.to_le_bytes();
|
||||
|
||||
@@ -52,11 +52,7 @@ macro_rules! stos {
|
||||
.write_memory(dst, &rax_bytes[0..len])
|
||||
.map_err(EmulationError::PlatformEmulationError)?;
|
||||
|
||||
if df {
|
||||
rdi = rdi.wrapping_sub(len as u64);
|
||||
} else {
|
||||
rdi = rdi.wrapping_add(len as u64);
|
||||
}
|
||||
rdi = advance_string_op_index(rdi, len, backwards);
|
||||
count -= 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ use crate::arch::x86::{
|
||||
|
||||
#[macro_use]
|
||||
mod instructions;
|
||||
pub use instructions::{advance_string_op_index, string_op_backwards, string_op_repeat_count};
|
||||
|
||||
/// x86 CPU modes
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
|
||||
Reference in New Issue
Block a user