guest state
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
mod controls;
|
mod controls;
|
||||||
|
mod register;
|
||||||
pub mod vcpu;
|
pub mod vcpu;
|
||||||
mod vmcs;
|
mod vmcs;
|
||||||
mod vmxon;
|
mod vmxon;
|
||||||
|
33
nel_os_kernel/src/vmm/x86_64/intel/register.rs
Normal file
33
nel_os_kernel/src/vmm/x86_64/intel/register.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#[repr(C)]
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct GuestRegisters {
|
||||||
|
pub rax: u64,
|
||||||
|
pub rcx: u64,
|
||||||
|
pub rdx: u64,
|
||||||
|
pub rbx: u64,
|
||||||
|
pub rbp: u64,
|
||||||
|
pub rsi: u64,
|
||||||
|
pub rdi: u64,
|
||||||
|
pub r8: u64,
|
||||||
|
pub r9: u64,
|
||||||
|
pub r10: u64,
|
||||||
|
pub r11: u64,
|
||||||
|
pub r12: u64,
|
||||||
|
pub r13: u64,
|
||||||
|
pub r14: u64,
|
||||||
|
pub r15: u64,
|
||||||
|
pub xmm0: M128,
|
||||||
|
pub xmm1: M128,
|
||||||
|
pub xmm2: M128,
|
||||||
|
pub xmm3: M128,
|
||||||
|
pub xmm4: M128,
|
||||||
|
pub xmm5: M128,
|
||||||
|
pub xmm6: M128,
|
||||||
|
pub xmm7: M128,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, align(16))]
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct M128 {
|
||||||
|
pub data: u128,
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
use core::arch::naked_asm;
|
||||||
|
|
||||||
use raw_cpuid::cpuid;
|
use raw_cpuid::cpuid;
|
||||||
use x86_64::{
|
use x86_64::{
|
||||||
registers::control::Cr4Flags,
|
registers::control::Cr4Flags,
|
||||||
@ -9,19 +11,35 @@ use crate::{
|
|||||||
vmm::{
|
vmm::{
|
||||||
x86_64::{
|
x86_64::{
|
||||||
common::{self, read_msr},
|
common::{self, read_msr},
|
||||||
intel::{controls, vmcs, vmwrite, vmxon},
|
intel::{
|
||||||
|
controls,
|
||||||
|
register::GuestRegisters,
|
||||||
|
vmcs::{
|
||||||
|
self,
|
||||||
|
segment::{DescriptorType, Granularity, SegmentRights},
|
||||||
|
},
|
||||||
|
vmread, vmwrite, vmxon,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
VCpu,
|
VCpu,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
pub struct IntelVCpu {
|
pub struct IntelVCpu {
|
||||||
|
pub launch_done: bool,
|
||||||
|
pub guest_registers: GuestRegisters,
|
||||||
activated: bool,
|
activated: bool,
|
||||||
vmxon: vmxon::Vmxon,
|
vmxon: vmxon::Vmxon,
|
||||||
vmcs: vmcs::Vmcs,
|
vmcs: vmcs::Vmcs,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntelVCpu {
|
impl IntelVCpu {
|
||||||
|
#[unsafe(naked)]
|
||||||
|
unsafe extern "C" fn test_guest_code() -> ! {
|
||||||
|
naked_asm!("2: hlt; jmp 2b");
|
||||||
|
}
|
||||||
|
|
||||||
fn activate(&mut self) -> Result<(), &'static str> {
|
fn activate(&mut self) -> Result<(), &'static str> {
|
||||||
let revision_id = common::read_msr(0x480) as u32;
|
let revision_id = common::read_msr(0x480) as u32;
|
||||||
self.vmcs.write_revision_id(revision_id);
|
self.vmcs.write_revision_id(revision_id);
|
||||||
@ -30,6 +48,7 @@ impl IntelVCpu {
|
|||||||
controls::setup_entry_controls()?;
|
controls::setup_entry_controls()?;
|
||||||
controls::setup_exit_controls()?;
|
controls::setup_exit_controls()?;
|
||||||
Self::setup_host_state()?;
|
Self::setup_host_state()?;
|
||||||
|
Self::setup_guest_state()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -73,6 +92,119 @@ impl IntelVCpu {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setup_guest_state() -> Result<(), &'static str> {
|
||||||
|
use x86::{controlregs::*, vmx::vmcs};
|
||||||
|
let cr0 = (Cr0::empty()
|
||||||
|
| Cr0::CR0_PROTECTED_MODE
|
||||||
|
| Cr0::CR0_NUMERIC_ERROR
|
||||||
|
| Cr0::CR0_EXTENSION_TYPE)
|
||||||
|
& !Cr0::CR0_ENABLE_PAGING;
|
||||||
|
vmwrite(vmcs::guest::CR0, cr0.bits() as u64)?;
|
||||||
|
vmwrite(vmcs::guest::CR3, 0)?;
|
||||||
|
vmwrite(
|
||||||
|
vmcs::guest::CR4,
|
||||||
|
(vmread(vmcs::guest::CR4)? | Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits())
|
||||||
|
& !Cr4Flags::PHYSICAL_ADDRESS_EXTENSION.bits(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
vmwrite(vmcs::guest::CS_BASE, 0)?;
|
||||||
|
vmwrite(vmcs::guest::SS_BASE, 0)?;
|
||||||
|
vmwrite(vmcs::guest::DS_BASE, 0)?;
|
||||||
|
vmwrite(vmcs::guest::ES_BASE, 0)?;
|
||||||
|
vmwrite(vmcs::guest::TR_BASE, 0)?;
|
||||||
|
vmwrite(vmcs::guest::GDTR_BASE, 0)?;
|
||||||
|
vmwrite(vmcs::guest::IDTR_BASE, 0)?;
|
||||||
|
vmwrite(vmcs::guest::LDTR_BASE, 0xDEAD00)?;
|
||||||
|
|
||||||
|
vmwrite(vmcs::guest::CS_LIMIT, u32::MAX as u64)?;
|
||||||
|
vmwrite(vmcs::guest::SS_LIMIT, u32::MAX as u64)?;
|
||||||
|
vmwrite(vmcs::guest::DS_LIMIT, u32::MAX as u64)?;
|
||||||
|
vmwrite(vmcs::guest::ES_LIMIT, u32::MAX as u64)?;
|
||||||
|
vmwrite(vmcs::guest::FS_LIMIT, u32::MAX as u64)?;
|
||||||
|
vmwrite(vmcs::guest::GS_LIMIT, u32::MAX as u64)?;
|
||||||
|
vmwrite(vmcs::guest::TR_LIMIT, 0)?;
|
||||||
|
vmwrite(vmcs::guest::GDTR_LIMIT, 0)?;
|
||||||
|
vmwrite(vmcs::guest::IDTR_LIMIT, 0)?;
|
||||||
|
vmwrite(vmcs::guest::LDTR_LIMIT, 0)?;
|
||||||
|
|
||||||
|
let cs_right = SegmentRights::default()
|
||||||
|
.with_rw(true)
|
||||||
|
.with_dc(false)
|
||||||
|
.with_executable(true)
|
||||||
|
.with_desc_type(DescriptorType::Code)
|
||||||
|
.with_dpl(0)
|
||||||
|
.with_granularity(Granularity::KByte)
|
||||||
|
.with_long(false)
|
||||||
|
.with_db(true);
|
||||||
|
|
||||||
|
let ds_right = SegmentRights::default()
|
||||||
|
.with_rw(true)
|
||||||
|
.with_dc(false)
|
||||||
|
.with_executable(false)
|
||||||
|
.with_desc_type(DescriptorType::Code)
|
||||||
|
.with_dpl(0)
|
||||||
|
.with_granularity(Granularity::KByte)
|
||||||
|
.with_long(false)
|
||||||
|
.with_db(true);
|
||||||
|
|
||||||
|
let tr_right = SegmentRights::default()
|
||||||
|
.with_rw(true)
|
||||||
|
.with_dc(false)
|
||||||
|
.with_executable(true)
|
||||||
|
.with_desc_type(DescriptorType::System)
|
||||||
|
.with_dpl(0)
|
||||||
|
.with_granularity(Granularity::Byte)
|
||||||
|
.with_long(false)
|
||||||
|
.with_db(false);
|
||||||
|
|
||||||
|
let ldtr_right = SegmentRights::default()
|
||||||
|
.with_accessed(false)
|
||||||
|
.with_rw(true)
|
||||||
|
.with_dc(false)
|
||||||
|
.with_executable(false)
|
||||||
|
.with_desc_type(DescriptorType::System)
|
||||||
|
.with_dpl(0)
|
||||||
|
.with_granularity(Granularity::Byte)
|
||||||
|
.with_long(false)
|
||||||
|
.with_db(false);
|
||||||
|
|
||||||
|
vmwrite(vmcs::guest::CS_ACCESS_RIGHTS, u32::from(cs_right) as u64)?;
|
||||||
|
vmwrite(vmcs::guest::SS_ACCESS_RIGHTS, u32::from(ds_right) as u64)?;
|
||||||
|
vmwrite(vmcs::guest::DS_ACCESS_RIGHTS, u32::from(ds_right) as u64)?;
|
||||||
|
vmwrite(vmcs::guest::ES_ACCESS_RIGHTS, u32::from(ds_right) as u64)?;
|
||||||
|
vmwrite(vmcs::guest::FS_ACCESS_RIGHTS, u32::from(ds_right) as u64)?;
|
||||||
|
vmwrite(vmcs::guest::GS_ACCESS_RIGHTS, u32::from(ds_right) as u64)?;
|
||||||
|
vmwrite(vmcs::guest::TR_ACCESS_RIGHTS, u32::from(tr_right) as u64)?;
|
||||||
|
vmwrite(
|
||||||
|
vmcs::guest::LDTR_ACCESS_RIGHTS,
|
||||||
|
u32::from(ldtr_right) as u64,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
vmwrite(vmcs::guest::CS_SELECTOR, 0)?;
|
||||||
|
vmwrite(vmcs::guest::SS_SELECTOR, 0)?;
|
||||||
|
vmwrite(vmcs::guest::DS_SELECTOR, 0)?;
|
||||||
|
vmwrite(vmcs::guest::ES_SELECTOR, 0)?;
|
||||||
|
vmwrite(vmcs::guest::FS_SELECTOR, 0)?;
|
||||||
|
vmwrite(vmcs::guest::GS_SELECTOR, 0)?;
|
||||||
|
vmwrite(vmcs::guest::TR_SELECTOR, 0)?;
|
||||||
|
vmwrite(vmcs::guest::LDTR_SELECTOR, 0)?;
|
||||||
|
vmwrite(vmcs::guest::FS_BASE, 0)?;
|
||||||
|
vmwrite(vmcs::guest::GS_BASE, 0)?;
|
||||||
|
|
||||||
|
vmwrite(vmcs::guest::IA32_EFER_FULL, 0)?;
|
||||||
|
vmwrite(vmcs::guest::IA32_EFER_HIGH, 0)?;
|
||||||
|
vmwrite(vmcs::guest::RFLAGS, 0x2)?;
|
||||||
|
vmwrite(vmcs::guest::LINK_PTR_FULL, u64::MAX)?;
|
||||||
|
|
||||||
|
vmwrite(vmcs::guest::RIP, Self::test_guest_code as u64)?; // TODO: Set linux kernel base
|
||||||
|
// TODO: RSI
|
||||||
|
|
||||||
|
vmwrite(vmcs::control::CR0_READ_SHADOW, vmread(vmcs::guest::CR0)?)?;
|
||||||
|
vmwrite(vmcs::control::CR4_READ_SHADOW, vmread(vmcs::guest::CR4)?)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VCpu for IntelVCpu {
|
impl VCpu for IntelVCpu {
|
||||||
@ -110,6 +242,8 @@ impl VCpu for IntelVCpu {
|
|||||||
let vmcs = vmcs::Vmcs::new(frame_allocator)?;
|
let vmcs = vmcs::Vmcs::new(frame_allocator)?;
|
||||||
|
|
||||||
Ok(IntelVCpu {
|
Ok(IntelVCpu {
|
||||||
|
launch_done: false,
|
||||||
|
guest_registers: GuestRegisters::default(),
|
||||||
activated: false,
|
activated: false,
|
||||||
vmxon,
|
vmxon,
|
||||||
vmcs,
|
vmcs,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
pub mod controls;
|
pub mod controls;
|
||||||
pub mod err;
|
pub mod err;
|
||||||
pub mod exit_reason;
|
pub mod exit_reason;
|
||||||
|
pub mod segment;
|
||||||
|
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
|
|
||||||
|
46
nel_os_kernel/src/vmm/x86_64/intel/vmcs/segment.rs
Normal file
46
nel_os_kernel/src/vmm/x86_64/intel/vmcs/segment.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use modular_bitfield::{bitfield, prelude::*};
|
||||||
|
|
||||||
|
#[derive(Specifier, Debug, Clone, Copy)]
|
||||||
|
pub enum DescriptorType {
|
||||||
|
System = 0,
|
||||||
|
Code = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Specifier, Debug, Clone, Copy)]
|
||||||
|
pub enum Granularity {
|
||||||
|
Byte = 0,
|
||||||
|
KByte = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[repr(u32)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct SegmentRights {
|
||||||
|
pub accessed: bool,
|
||||||
|
pub rw: bool,
|
||||||
|
pub dc: bool,
|
||||||
|
pub executable: bool,
|
||||||
|
#[bits = 1]
|
||||||
|
pub desc_type: DescriptorType,
|
||||||
|
pub dpl: B2,
|
||||||
|
pub present: bool,
|
||||||
|
reserved: B4,
|
||||||
|
pub avl: bool,
|
||||||
|
pub long: bool,
|
||||||
|
pub db: bool,
|
||||||
|
#[bits = 1]
|
||||||
|
pub granularity: Granularity,
|
||||||
|
pub usable: bool,
|
||||||
|
reserved2: B15,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SegmentRights {
|
||||||
|
fn default() -> Self {
|
||||||
|
SegmentRights::new()
|
||||||
|
.with_accessed(true)
|
||||||
|
.with_present(true)
|
||||||
|
.with_avl(false)
|
||||||
|
.with_long(false)
|
||||||
|
.with_usable(false)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user