Loads floating point registers for debugger (#1047)
Some checks are pending
Development Build / Build (push) Waiting to run
Development Build / Update PRs (push) Waiting to run

This commit is contained in:
Putta Khunchalee 2024-10-19 21:05:48 +07:00 committed by GitHub
parent ae78fd2b88
commit cc64722ef0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 179 additions and 67 deletions

View File

@ -10,11 +10,6 @@
#include <string.h>
#ifdef __x86_64__
extern "C" int kvm_get_sregs(int vcpu, kvm_sregs *regs)
{
return ioctl(vcpu, KVM_GET_SREGS, regs);
}
extern "C" int kvm_set_sregs(int vcpu, const kvm_sregs *regs)
{
return ioctl(vcpu, KVM_SET_SREGS, regs);

View File

@ -312,7 +312,16 @@ impl<H: Hypervisor, S: Screen> CpuManager<H, S> {
fs: states.get_fs().map_err(|e| error("fs", e))?.into(),
gs: states.get_gs().map_err(|e| error("gs", e))?.into(),
},
st: todo!(),
st: [
states.get_st0().map_err(|e| error("st0", e))?,
states.get_st1().map_err(|e| error("st1", e))?,
states.get_st2().map_err(|e| error("st2", e))?,
states.get_st3().map_err(|e| error("st3", e))?,
states.get_st4().map_err(|e| error("st4", e))?,
states.get_st5().map_err(|e| error("st5", e))?,
states.get_st6().map_err(|e| error("st6", e))?,
states.get_st7().map_err(|e| error("st7", e))?,
],
fpu: todo!(),
xmm: todo!(),
mxcsr: todo!(),

View File

@ -11,6 +11,10 @@ pub const KVM_RUN: c_ulong = _IO(KVMIO, 0x80);
pub const KVM_GET_REGS: c_ulong = _IOR::<KvmRegs>(KVMIO, 0x81);
#[cfg(not(target_arch = "aarch64"))]
pub const KVM_SET_REGS: c_ulong = _IOW::<KvmRegs>(KVMIO, 0x82);
#[cfg(target_arch = "x86_64")]
pub const KVM_GET_SREGS: c_ulong = _IOR::<KvmSregs>(KVMIO, 0x83);
#[cfg(target_arch = "x86_64")]
pub const KVM_GET_FPU: c_ulong = _IOR::<KvmFpu>(KVMIO, 0x8c);
pub const KVM_SET_GUEST_DEBUG: c_ulong = _IOW::<KvmGuestDebug>(KVMIO, 0x9b);
#[cfg(target_arch = "aarch64")]
pub const KVM_GET_ONE_REG: c_ulong = _IOW::<KvmOneReg<()>>(KVMIO, 0xab);
@ -22,6 +26,7 @@ pub const KVM_ARM_VCPU_INIT: c_ulong = _IOW::<KvmVcpuInit>(KVMIO, 0xae);
pub const KVM_ARM_PREFERRED_TARGET: c_ulong = _IOR::<KvmVcpuInit>(KVMIO, 0xaf);
pub const KVM_API_VERSION: c_int = 12;
pub const KVM_NR_INTERRUPTS: usize = 256;
pub const KVM_CAP_SET_GUEST_DEBUG: c_int = 23;
pub const KVM_CAP_MAX_VCPUS: c_int = 66;
@ -123,6 +128,71 @@ pub struct KvmRegs {
pub rflags: u64,
}
#[cfg(target_arch = "x86_64")]
#[repr(C)]
pub struct KvmSregs {
pub cs: KvmSegment,
pub ds: KvmSegment,
pub es: KvmSegment,
pub fs: KvmSegment,
pub gs: KvmSegment,
pub ss: KvmSegment,
pub tr: KvmSegment,
pub ldt: KvmSegment,
pub gdt: KvmDtable,
pub idt: KvmDtable,
pub cr0: u64,
pub cr2: u64,
pub cr3: u64,
pub cr4: u64,
pub cr8: u64,
pub efer: u64,
pub apic_base: u64,
pub interrupt_bitmap: [u64; (KVM_NR_INTERRUPTS + 63) / 64],
}
#[cfg(target_arch = "x86_64")]
#[repr(C)]
pub struct KvmSegment {
pub base: u64,
pub limit: u32,
pub selector: u16,
pub ty: u8,
pub present: u8,
pub dpl: u8,
pub db: u8,
pub s: u8,
pub l: u8,
pub g: u8,
pub avl: u8,
pub unusable: u8,
pub padding: u8,
}
#[cfg(target_arch = "x86_64")]
#[repr(C)]
pub struct KvmDtable {
pub base: u64,
pub limit: u16,
pub padding: [u16; 3],
}
#[cfg(target_arch = "x86_64")]
#[repr(C)]
pub struct KvmFpu {
pub fpr: [[u8; 16]; 8],
pub fcw: u16,
pub fsw: u16,
pub ftwx: u8,
pub pad1: u8,
pub last_opcode: u16,
pub last_ip: u64,
pub last_dp: u64,
pub xmm: [[u8; 16]; 16],
pub mxcsr: u32,
pub pad2: u32,
}
#[repr(C)]
pub struct KvmGuestDebug {
pub control: u32,

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use super::ffi::{KvmRegs, KVM_GET_REGS, KVM_SET_REGS};
use super::ffi::{
KvmFpu, KvmRegs, KvmSregs, KVM_GET_FPU, KVM_GET_REGS, KVM_GET_SREGS, KVM_SET_REGS,
};
use crate::vmm::hv::{CpuCommit, CpuStates, Rflags};
use libc::ioctl;
use std::ffi::c_int;
@ -12,8 +14,9 @@ pub struct KvmStates<'a> {
cpu: &'a mut OwnedFd,
gregs: KvmRegs,
gdirty: bool,
sregs: SpecialRegs,
sregs: KvmSregs,
sdirty: bool,
fregs: KvmFpu,
}
impl<'a> KvmStates<'a> {
@ -22,7 +25,7 @@ impl<'a> KvmStates<'a> {
// Load general purpose registers.
let mut gregs = MaybeUninit::uninit();
let gregs = if unsafe { ioctl(cpu.as_raw_fd(), KVM_GET_REGS, gregs.as_mut_ptr()) } < 0 {
let gregs = if unsafe { ioctl(cpu.as_raw_fd(), KVM_GET_REGS, gregs.as_mut_ptr()) < 0 } {
return Err(StatesError::GetGRegsFailed(Error::last_os_error()));
} else {
unsafe { gregs.assume_init() }
@ -30,9 +33,18 @@ impl<'a> KvmStates<'a> {
// Get special registers.
let mut sregs = MaybeUninit::uninit();
let sregs = match unsafe { kvm_get_sregs(cpu.as_raw_fd(), sregs.as_mut_ptr()) } {
0 => unsafe { sregs.assume_init() },
_ => return Err(StatesError::GetSRegsFailed(Error::last_os_error())),
let sregs = if unsafe { ioctl(cpu.as_raw_fd(), KVM_GET_SREGS, sregs.as_mut_ptr()) < 0 } {
return Err(StatesError::GetSRegsFailed(Error::last_os_error()));
} else {
unsafe { sregs.assume_init() }
};
// Get FPU registers.
let mut fregs = MaybeUninit::uninit();
let fregs = if unsafe { ioctl(cpu.as_raw_fd(), KVM_GET_FPU, fregs.as_mut_ptr()) < 0 } {
return Err(StatesError::GetFRegsFailed(Error::last_os_error()));
} else {
unsafe { fregs.assume_init() }
};
Ok(KvmStates {
@ -41,6 +53,7 @@ impl<'a> KvmStates<'a> {
gdirty: false,
sregs,
sdirty: false,
fregs,
})
}
}
@ -137,17 +150,17 @@ impl<'a> CpuStates for KvmStates<'a> {
}
fn set_cr0(&mut self, v: usize) {
self.sregs.cr0 = v;
self.sregs.cr0 = v.try_into().unwrap();
self.sdirty = true;
}
fn set_cr3(&mut self, v: usize) {
self.sregs.cr3 = v;
self.sregs.cr3 = v.try_into().unwrap();
self.sdirty = true;
}
fn set_cr4(&mut self, v: usize) {
self.sregs.cr4 = v;
self.sregs.cr4 = v.try_into().unwrap();
self.sdirty = true;
}
@ -156,7 +169,7 @@ impl<'a> CpuStates for KvmStates<'a> {
}
fn set_efer(&mut self, v: usize) {
self.sregs.efer = v;
self.sregs.efer = v.try_into().unwrap();
self.sdirty = true;
}
@ -217,6 +230,38 @@ impl<'a> CpuStates for KvmStates<'a> {
self.sregs.ss.present = p.into();
self.sdirty = true;
}
fn get_st0(&mut self) -> Result<[u8; 10], Self::Err> {
Ok(self.fregs.fpr[0][..10].try_into().unwrap())
}
fn get_st1(&mut self) -> Result<[u8; 10], Self::Err> {
Ok(self.fregs.fpr[1][..10].try_into().unwrap())
}
fn get_st2(&mut self) -> Result<[u8; 10], Self::Err> {
Ok(self.fregs.fpr[2][..10].try_into().unwrap())
}
fn get_st3(&mut self) -> Result<[u8; 10], Self::Err> {
Ok(self.fregs.fpr[3][..10].try_into().unwrap())
}
fn get_st4(&mut self) -> Result<[u8; 10], Self::Err> {
Ok(self.fregs.fpr[4][..10].try_into().unwrap())
}
fn get_st5(&mut self) -> Result<[u8; 10], Self::Err> {
Ok(self.fregs.fpr[5][..10].try_into().unwrap())
}
fn get_st6(&mut self) -> Result<[u8; 10], Self::Err> {
Ok(self.fregs.fpr[6][..10].try_into().unwrap())
}
fn get_st7(&mut self) -> Result<[u8; 10], Self::Err> {
Ok(self.fregs.fpr[7][..10].try_into().unwrap())
}
}
impl<'a> CpuCommit for KvmStates<'a> {
@ -237,55 +282,6 @@ impl<'a> CpuCommit for KvmStates<'a> {
}
}
/// Implementation of `kvm_sregs` structure.
#[repr(C)]
struct SpecialRegs {
pub cs: Segment,
pub ds: Segment,
pub es: Segment,
pub fs: Segment,
pub gs: Segment,
pub ss: Segment,
pub tr: Segment,
pub ldt: Segment,
pub gdt: DTable,
pub idt: DTable,
pub cr0: usize,
pub cr2: u64,
pub cr3: usize,
pub cr4: usize,
pub cr8: u64,
pub efer: usize,
pub apic_base: u64,
pub interrupt_bitmap: [u64; 4],
}
/// Implementation of `kvm_segment` structure.
#[repr(C)]
pub struct Segment {
pub base: u64,
pub limit: u32,
pub selector: u16,
pub ty: u8,
pub present: u8,
pub dpl: u8,
pub db: u8,
pub s: u8,
pub l: u8,
pub g: u8,
pub avl: u8,
pub unusable: u8,
pub padding: u8,
}
/// Implementation of `kvm_dtable` structure.
#[repr(C)]
struct DTable {
base: u64,
limit: u16,
padding: [u16; 3],
}
/// Implementation of [`CpuStates::Err`].
#[derive(Debug, Error)]
pub enum StatesError {
@ -295,6 +291,9 @@ pub enum StatesError {
#[error("couldn't get special registers")]
GetSRegsFailed(#[source] std::io::Error),
#[error("couldn't get floating point registers")]
GetFRegsFailed(#[source] std::io::Error),
#[error("couldn't set general purpose registers")]
SetGRegsFailed(#[source] std::io::Error),
@ -303,6 +302,5 @@ pub enum StatesError {
}
extern "C" {
fn kvm_get_sregs(vcpu: c_int, regs: *mut SpecialRegs) -> c_int;
fn kvm_set_sregs(vcpu: c_int, regs: *const SpecialRegs) -> c_int;
fn kvm_set_sregs(vcpu: c_int, regs: *const KvmSregs) -> c_int;
}

View File

@ -324,6 +324,38 @@ impl<'a, 'b> CpuStates for WhpStates<'a, 'b> {
self.dirty = true;
}
fn get_st0(&mut self) -> Result<[u8; 10], Self::Err> {
todo!()
}
fn get_st1(&mut self) -> Result<[u8; 10], Self::Err> {
todo!()
}
fn get_st2(&mut self) -> Result<[u8; 10], Self::Err> {
todo!()
}
fn get_st3(&mut self) -> Result<[u8; 10], Self::Err> {
todo!()
}
fn get_st4(&mut self) -> Result<[u8; 10], Self::Err> {
todo!()
}
fn get_st5(&mut self) -> Result<[u8; 10], Self::Err> {
todo!()
}
fn get_st6(&mut self) -> Result<[u8; 10], Self::Err> {
todo!()
}
fn get_st7(&mut self) -> Result<[u8; 10], Self::Err> {
todo!()
}
}
impl<'a, 'b> CpuCommit for WhpStates<'a, 'b> {

View File

@ -44,6 +44,14 @@ pub trait CpuStates {
fn set_gs(&mut self, p: bool);
fn get_ss(&mut self) -> Result<u16, Self::Err>;
fn set_ss(&mut self, p: bool);
fn get_st0(&mut self) -> Result<[u8; 10], Self::Err>;
fn get_st1(&mut self) -> Result<[u8; 10], Self::Err>;
fn get_st2(&mut self) -> Result<[u8; 10], Self::Err>;
fn get_st3(&mut self) -> Result<[u8; 10], Self::Err>;
fn get_st4(&mut self) -> Result<[u8; 10], Self::Err>;
fn get_st5(&mut self) -> Result<[u8; 10], Self::Err>;
fn get_st6(&mut self) -> Result<[u8; 10], Self::Err>;
fn get_st7(&mut self) -> Result<[u8; 10], Self::Err>;
}
/// Features available on a CPU.