Skip to content

Commit a324985

Browse files
committed
[feat] introduce vcpu id, maintain cs and ss access rights
1 parent 066abfe commit a324985

File tree

1 file changed

+116
-33
lines changed

1 file changed

+116
-33
lines changed

src/vmx/vcpu.rs

+116-33
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use super::vmcs::{
3232
use crate::LinuxContext;
3333
use crate::page_table::GuestPageTable64;
3434
use crate::page_table::GuestPageWalkInfo;
35-
use crate::segmentation::Segment;
35+
use crate::segmentation::{Segment, SegmentAccessRights};
3636
use crate::xstate::XState;
3737
use crate::{msr::Msr, regs::GeneralRegisters};
3838

@@ -70,11 +70,13 @@ pub struct VmxVcpu<H: AxVCpuHal> {
7070
cur_xstate: XState,
7171
entry: Option<GuestPhysAddr>,
7272
ept_root: Option<HostPhysAddr>,
73+
74+
id: usize,
7375
}
7476

7577
impl<H: AxVCpuHal> VmxVcpu<H> {
7678
/// Create a new [`VmxVcpu`].
77-
pub fn new() -> AxResult<Self> {
79+
pub fn new(id: usize) -> AxResult<Self> {
7880
let vcpu = Self {
7981
guest_regs: GeneralRegisters::default(),
8082
host_stack_top: 0,
@@ -88,6 +90,7 @@ impl<H: AxVCpuHal> VmxVcpu<H> {
8890
cur_xstate: XState::new(),
8991
entry: None,
9092
ept_root: None,
93+
id,
9194
};
9295
debug!("[HV] created VmxVcpu(vmcs: {:#x})", vcpu.vmcs.phys_addr(),);
9396
Ok(vcpu)
@@ -543,6 +546,11 @@ impl<H: AxVCpuHal> VmxVcpu<H> {
543546
}};
544547
}
545548

549+
debug!(
550+
"setup_vmcs_guest_from_ctx: CS access rights: {:?}",
551+
linux.cs.access_rights
552+
);
553+
546554
set_guest_segment!(linux.es, ES);
547555
set_guest_segment!(linux.cs, CS);
548556
set_guest_segment!(linux.ss, SS);
@@ -764,33 +772,42 @@ impl<H: AxVCpuHal> VmxVcpu<H> {
764772
Ok(())
765773
}
766774

767-
fn load_vmcs_guest(&self, linux: &mut LinuxContext) {
768-
linux.rip = VmcsGuestNW::RIP.read().unwrap() as _;
769-
linux.rsp = VmcsGuestNW::RSP.read().unwrap() as _;
770-
linux.cr0 = Cr0Flags::from_bits_truncate(VmcsGuestNW::CR0.read().unwrap() as _);
771-
linux.cr3 = VmcsGuestNW::CR3.read().unwrap() as _;
772-
linux.cr4 = Cr4Flags::from_bits_truncate(VmcsGuestNW::CR4.read().unwrap() as _);
773-
774-
linux.es.selector = SegmentSelector::from_raw(VmcsGuest16::ES_SELECTOR.read().unwrap());
775-
linux.cs.selector = SegmentSelector::from_raw(VmcsGuest16::CS_SELECTOR.read().unwrap());
776-
linux.ss.selector = SegmentSelector::from_raw(VmcsGuest16::SS_SELECTOR.read().unwrap());
777-
linux.ds.selector = SegmentSelector::from_raw(VmcsGuest16::DS_SELECTOR.read().unwrap());
778-
linux.fs.selector = SegmentSelector::from_raw(VmcsGuest16::FS_SELECTOR.read().unwrap());
779-
linux.fs.base = VmcsGuestNW::FS_BASE.read().unwrap() as _;
780-
linux.gs.selector = SegmentSelector::from_raw(VmcsGuest16::GS_SELECTOR.read().unwrap());
781-
linux.gs.base = VmcsGuestNW::GS_BASE.read().unwrap() as _;
782-
linux.tss.selector = SegmentSelector::from_raw(VmcsGuest16::TR_SELECTOR.read().unwrap());
783-
784-
linux.gdt.base = VirtAddr::new(VmcsGuestNW::GDTR_BASE.read().unwrap() as _);
785-
linux.gdt.limit = VmcsGuest32::GDTR_LIMIT.read().unwrap() as _;
786-
linux.idt.base = VirtAddr::new(VmcsGuestNW::IDTR_BASE.read().unwrap() as _);
787-
linux.idt.limit = VmcsGuest32::IDTR_LIMIT.read().unwrap() as _;
788-
789-
linux.ia32_sysenter_cs = VmcsGuest32::IA32_SYSENTER_CS.read().unwrap() as _; // 0x174
790-
linux.ia32_sysenter_esp = VmcsGuestNW::IA32_SYSENTER_ESP.read().unwrap() as _; // 0x178
791-
linux.ia32_sysenter_eip = VmcsGuestNW::IA32_SYSENTER_EIP.read().unwrap() as _; // 0x17a
775+
fn load_vmcs_guest(&self, linux: &mut LinuxContext) -> AxResult {
776+
linux.rip = VmcsGuestNW::RIP.read()? as _;
777+
linux.rsp = VmcsGuestNW::RSP.read()? as _;
778+
linux.cr0 = Cr0Flags::from_bits_truncate(VmcsGuestNW::CR0.read()? as _);
779+
linux.cr3 = VmcsGuestNW::CR3.read()? as _;
780+
linux.cr4 = Cr4Flags::from_bits_truncate(VmcsGuestNW::CR4.read()? as _);
781+
782+
linux.es.selector = SegmentSelector::from_raw(VmcsGuest16::ES_SELECTOR.read()?);
783+
784+
linux.cs.selector = SegmentSelector::from_raw(VmcsGuest16::CS_SELECTOR.read()?);
785+
// CS:
786+
// If the Type is 9 or 11 (non-conforming code segment), the DPL must equal the DPL in the access-rights field for SS.
787+
linux.cs.access_rights =
788+
SegmentAccessRights::from_bits_truncate(VmcsGuest32::CS_ACCESS_RIGHTS.read()?);
789+
linux.ss.selector = SegmentSelector::from_raw(VmcsGuest16::SS_SELECTOR.read()?);
790+
linux.ss.access_rights =
791+
SegmentAccessRights::from_bits_truncate(VmcsGuest32::SS_ACCESS_RIGHTS.read()?);
792+
793+
linux.ds.selector = SegmentSelector::from_raw(VmcsGuest16::DS_SELECTOR.read()?);
794+
linux.fs.selector = SegmentSelector::from_raw(VmcsGuest16::FS_SELECTOR.read()?);
795+
linux.fs.base = VmcsGuestNW::FS_BASE.read()? as _;
796+
linux.gs.selector = SegmentSelector::from_raw(VmcsGuest16::GS_SELECTOR.read()?);
797+
linux.gs.base = VmcsGuestNW::GS_BASE.read()? as _;
798+
linux.tss.selector = SegmentSelector::from_raw(VmcsGuest16::TR_SELECTOR.read()?);
799+
800+
linux.gdt.base = VirtAddr::new(VmcsGuestNW::GDTR_BASE.read()? as _);
801+
linux.gdt.limit = VmcsGuest32::GDTR_LIMIT.read()? as _;
802+
linux.idt.base = VirtAddr::new(VmcsGuestNW::IDTR_BASE.read()? as _);
803+
linux.idt.limit = VmcsGuest32::IDTR_LIMIT.read()? as _;
804+
805+
linux.ia32_sysenter_cs = VmcsGuest32::IA32_SYSENTER_CS.read()? as _; // 0x174
806+
linux.ia32_sysenter_esp = VmcsGuestNW::IA32_SYSENTER_ESP.read()? as _; // 0x178
807+
linux.ia32_sysenter_eip = VmcsGuestNW::IA32_SYSENTER_EIP.read()? as _; // 0x17a
792808

793809
linux.load_guest_regs(self.regs());
810+
Ok(())
794811
}
795812

796813
fn get_paging_level(&self) -> usize {
@@ -1260,6 +1277,33 @@ fn get_tr_base(tr: SegmentSelector, gdt: &DescriptorTablePointer<u64>) -> u64 {
12601277
impl<H: AxVCpuHal> Debug for VmxVcpu<H> {
12611278
fn fmt(&self, f: &mut Formatter) -> Result {
12621279
(|| -> AxResult<Result> {
1280+
let cs_selector = SegmentSelector::from_raw(VmcsGuest16::CS_SELECTOR.read()?);
1281+
let cs_access_rights_raw = VmcsGuest32::CS_ACCESS_RIGHTS.read()?;
1282+
let cs_access_rights = SegmentAccessRights::from_bits_truncate(cs_access_rights_raw);
1283+
let ss_selector = SegmentSelector::from_raw(VmcsGuest16::SS_SELECTOR.read()?);
1284+
let ss_access_rights_raw = VmcsGuest32::SS_ACCESS_RIGHTS.read()?;
1285+
let ss_access_rights = SegmentAccessRights::from_bits_truncate(ss_access_rights_raw);
1286+
let ds_selector = SegmentSelector::from_raw(VmcsGuest16::DS_SELECTOR.read()?);
1287+
let ds_access_rights =
1288+
SegmentAccessRights::from_bits_truncate(VmcsGuest32::DS_ACCESS_RIGHTS.read()?);
1289+
let fs_selector = SegmentSelector::from_raw(VmcsGuest16::FS_SELECTOR.read()?);
1290+
let fs_access_rights =
1291+
SegmentAccessRights::from_bits_truncate(VmcsGuest32::FS_ACCESS_RIGHTS.read()?);
1292+
let gs_selector = SegmentSelector::from_raw(VmcsGuest16::GS_SELECTOR.read()?);
1293+
let gs_access_rights =
1294+
SegmentAccessRights::from_bits_truncate(VmcsGuest32::GS_ACCESS_RIGHTS.read()?);
1295+
let tr_selector = SegmentSelector::from_raw(VmcsGuest16::TR_SELECTOR.read()?);
1296+
let tr_access_rights =
1297+
SegmentAccessRights::from_bits_truncate(VmcsGuest32::TR_ACCESS_RIGHTS.read()?);
1298+
let gdt_base = VirtAddr::new(VmcsGuestNW::GDTR_BASE.read()? as _);
1299+
let gdt_limit = VmcsGuest32::GDTR_LIMIT.read()?;
1300+
let idt_base = VirtAddr::new(VmcsGuestNW::IDTR_BASE.read()? as _);
1301+
let idt_limit = VmcsGuest32::IDTR_LIMIT.read()?;
1302+
1303+
let ia32_sysenter_cs = VmcsGuest32::IA32_SYSENTER_CS.read()?;
1304+
let ia32_sysenter_esp = VmcsGuestNW::IA32_SYSENTER_ESP.read()?;
1305+
let ia32_sysenter_eip = VmcsGuestNW::IA32_SYSENTER_EIP.read()?;
1306+
12631307
Ok(f.debug_struct("VmxVcpu")
12641308
.field("guest_regs", &self.guest_regs)
12651309
.field("rip", &VmcsGuestNW::RIP.read()?)
@@ -1268,29 +1312,53 @@ impl<H: AxVCpuHal> Debug for VmxVcpu<H> {
12681312
.field("cr0", &VmcsGuestNW::CR0.read()?)
12691313
.field("cr3", &VmcsGuestNW::CR3.read()?)
12701314
.field("cr4", &VmcsGuestNW::CR4.read()?)
1271-
.field("cs", &VmcsGuest16::CS_SELECTOR.read()?)
1315+
.field("cs_base", &VmcsGuestNW::CS_BASE.read()?)
1316+
.field("cs_selector", &cs_selector)
1317+
.field("cs_access_rights", &cs_access_rights)
1318+
.field("cs_access_rights_raw", &cs_access_rights_raw)
1319+
.field("ss_base", &VmcsGuestNW::SS_BASE.read()?)
1320+
.field("ss_selector", &ss_selector)
1321+
.field("ss_access_rights_raw", &ss_access_rights_raw)
1322+
.field("ss_access_rights", &ss_access_rights)
1323+
.field("ds_base", &VmcsGuestNW::DS_BASE.read()?)
1324+
.field("ds_selector", &ds_selector)
1325+
.field("ds_access_rights", &ds_access_rights)
12721326
.field("fs_base", &VmcsGuestNW::FS_BASE.read()?)
1327+
.field("fs_selector", &fs_selector)
1328+
.field("fs_access_rights", &fs_access_rights)
12731329
.field("gs_base", &VmcsGuestNW::GS_BASE.read()?)
1274-
.field("tss", &VmcsGuest16::TR_SELECTOR.read()?)
1330+
.field("gs_selector", &gs_selector)
1331+
.field("gs_access_rights", &gs_access_rights)
1332+
.field("tr_selector", &tr_selector)
1333+
.field("tr_access_rights", &tr_access_rights)
1334+
.field("gdt_base", &gdt_base)
1335+
.field("gdt_limit", &gdt_limit)
1336+
.field("idt_base", &idt_base)
1337+
.field("idt_limit", &idt_limit)
1338+
.field("ia32_sysenter_cs", &ia32_sysenter_cs)
1339+
.field("ia32_sysenter_esp", &ia32_sysenter_esp)
1340+
.field("ia32_sysenter_eip", &ia32_sysenter_eip)
12751341
.finish())
12761342
})()
12771343
.unwrap()
12781344
}
12791345
}
12801346

12811347
impl<H: AxVCpuHal> AxArchVCpu for VmxVcpu<H> {
1282-
type CreateConfig = ();
1348+
type CreateConfig = usize;
12831349

12841350
type SetupConfig = ();
12851351

12861352
type HostContext = crate::context::LinuxContext;
12871353

1288-
fn new(_config: Self::CreateConfig) -> AxResult<Self> {
1289-
Self::new()
1354+
fn new(id: Self::CreateConfig) -> AxResult<Self> {
1355+
Self::new(id)
12901356
}
12911357

12921358
fn load_context(&self, config: &mut Self::HostContext) -> AxResult {
1293-
self.load_vmcs_guest(config);
1359+
info!("Loading context {:#x?}", self);
1360+
1361+
self.load_vmcs_guest(config)?;
12941362
Ok(())
12951363
}
12961364

@@ -1315,8 +1383,23 @@ impl<H: AxVCpuHal> AxArchVCpu for VmxVcpu<H> {
13151383
}
13161384

13171385
fn run(&mut self) -> AxResult<AxVCpuExitReason> {
1386+
if self.id == 3 {
1387+
warn!("Instance vcpu run {:#x?}", self);
1388+
}
1389+
13181390
match self.inner_run() {
13191391
Some(exit_info) => Ok(if exit_info.entry_failure {
1392+
match exit_info.exit_reason {
1393+
VmxExitReason::INVALID_GUEST_STATE
1394+
| VmxExitReason::MCE_DURING_VMENTRY
1395+
| VmxExitReason::MSR_LOAD_FAIL => {}
1396+
_ => {
1397+
error!("Invalid exit reasion when entry failure: {:#x?}", exit_info);
1398+
}
1399+
};
1400+
1401+
warn!("VMX entry failure: {:#x?}", exit_info);
1402+
13201403
AxVCpuExitReason::FailEntry {
13211404
// Todo: get `hardware_entry_failure_reason` somehow.
13221405
hardware_entry_failure_reason: 0,

0 commit comments

Comments
 (0)