Skip to content

Commit

Permalink
Rename vm_context into guest_system_registers
Browse files Browse the repository at this point in the history
  • Loading branch information
hky1999 committed Sep 20, 2024
1 parent 25ede6c commit cc86daf
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 200 deletions.
185 changes: 46 additions & 139 deletions src/context_frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,15 @@ impl Aarch64ContextFrame {

/// Represents the VM context for a guest virtual machine in a hypervisor environment.
///
/// The `VmContext` structure contains various registers and states needed to manage
/// The `GuestSystemRegisters` structure contains various registers and states needed to manage
/// and restore the context of a virtual machine (VM). This includes timer registers,
/// system control registers, exception registers, and hypervisor-specific registers.
///
/// The structure is aligned to 16 bytes to ensure proper memory alignment for efficient access.
#[repr(C)]
#[repr(align(16))]
#[derive(Debug, Clone, Copy, Default)]
pub struct VmContext {
pub struct GuestSystemRegisters {
// generic timer
pub cntvoff_el2: u64,
cntp_cval_el0: u64,
Expand Down Expand Up @@ -234,161 +234,68 @@ pub struct VmContext {
hpfar_el2: u64,
}

impl VmContext {
/// Creates a new `VmContext` with all registers initialized to zero.
///
/// This method returns a `VmContext` instance with default values,
/// ensuring that all fields are set to zero.
pub fn default() -> VmContext {
VmContext {
// generic timer
cntvoff_el2: 0,
cntp_cval_el0: 0,
cntv_cval_el0: 0,
cntkctl_el1: 0,
cntvct_el0: 0,
cntp_ctl_el0: 0,
cntv_ctl_el0: 0,
cntp_tval_el0: 0,
cntv_tval_el0: 0,

// vpidr and vmpidr
vpidr_el2: 0,
vmpidr_el2: 0,

// 64bit EL1/EL0 register
sp_el0: 0,
sp_el1: 0,
elr_el1: 0,
spsr_el1: 0,
sctlr_el1: 0,
actlr_el1: 0,
cpacr_el1: 0,
ttbr0_el1: 0,
ttbr1_el1: 0,
tcr_el1: 0,
esr_el1: 0,
far_el1: 0,
par_el1: 0,
mair_el1: 0,
amair_el1: 0,
vbar_el1: 0,
contextidr_el1: 0,
tpidr_el0: 0,
tpidr_el1: 0,
tpidrro_el0: 0,

// hypervisor context
hcr_el2: 0,
cptr_el2: 0,
hstr_el2: 0,

// exception
pmcr_el0: 0,
vtcr_el2: 0,
vttbr_el2: 0,
far_el2: 0,
hpfar_el2: 0,
}
}

impl GuestSystemRegisters {
/// Resets the VM context by setting all registers to zero.
///
/// This method allows the `VmContext` instance to be reused by resetting
/// This method allows the `GuestSystemRegisters` instance to be reused by resetting
/// its state to the default values (all zeros).
pub fn reset(&mut self) {
self.cntvoff_el2 = 0;
self.cntp_cval_el0 = 0;
self.cntv_cval_el0 = 0;
self.cntp_tval_el0 = 0;
self.cntv_tval_el0 = 0;
self.cntkctl_el1 = 0;
self.cntvct_el0 = 0;
self.cntp_ctl_el0 = 0;
self.vpidr_el2 = 0;
self.vmpidr_el2 = 0;
self.sp_el0 = 0;
self.sp_el1 = 0;
self.elr_el1 = 0;
self.spsr_el1 = 0;
self.sctlr_el1 = 0;
self.actlr_el1 = 0;
self.cpacr_el1 = 0;
self.ttbr0_el1 = 0;
self.ttbr1_el1 = 0;
self.tcr_el1 = 0;
self.esr_el1 = 0;
self.far_el1 = 0;
self.par_el1 = 0;
self.mair_el1 = 0;
self.amair_el1 = 0;
self.vbar_el1 = 0;
self.contextidr_el1 = 0;
self.tpidr_el0 = 0;
self.tpidr_el1 = 0;
self.tpidrro_el0 = 0;
self.hcr_el2 = 0;
self.cptr_el2 = 0;
self.hstr_el2 = 0;
self.far_el2 = 0;
self.hpfar_el2 = 0;
*self = GuestSystemRegisters::default()
}

/// Stores the current values of all relevant registers into the `VmContext` structure.
/// Stores the current values of all relevant registers into the `GuestSystemRegisters` structure.
///
/// This method uses inline assembly to read the values of various system registers
/// and stores them in the corresponding fields of the `VmContext` structure.
pub fn ext_regs_store(&mut self) {
unsafe {
asm!("mrs {0}, CNTVOFF_EL2", out(reg) self.cntvoff_el2);
asm!("mrs {0}, CNTV_CVAL_EL0", out(reg) self.cntv_cval_el0);
asm!("mrs {0:x}, CNTKCTL_EL1", out(reg) self.cntkctl_el1);
asm!("mrs {0:x}, CNTP_CTL_EL0", out(reg) self.cntp_ctl_el0);
asm!("mrs {0:x}, CNTV_CTL_EL0", out(reg) self.cntv_ctl_el0);
asm!("mrs {0:x}, CNTP_TVAL_EL0", out(reg) self.cntp_tval_el0);
asm!("mrs {0:x}, CNTV_TVAL_EL0", out(reg) self.cntv_tval_el0);
asm!("mrs {0}, CNTVCT_EL0", out(reg) self.cntvct_el0);
// MRS!("self.vpidr_el2, VPIDR_EL2, "x");
asm!("mrs {0}, VMPIDR_EL2", out(reg) self.vmpidr_el2);
/// and stores them in the corresponding fields of the `GuestSystemRegisters` structure.
pub unsafe fn store(&mut self) {
asm!("mrs {0}, CNTVOFF_EL2", out(reg) self.cntvoff_el2);
asm!("mrs {0}, CNTV_CVAL_EL0", out(reg) self.cntv_cval_el0);
asm!("mrs {0:x}, CNTKCTL_EL1", out(reg) self.cntkctl_el1);
asm!("mrs {0:x}, CNTP_CTL_EL0", out(reg) self.cntp_ctl_el0);
asm!("mrs {0:x}, CNTV_CTL_EL0", out(reg) self.cntv_ctl_el0);
asm!("mrs {0:x}, CNTP_TVAL_EL0", out(reg) self.cntp_tval_el0);
asm!("mrs {0:x}, CNTV_TVAL_EL0", out(reg) self.cntv_tval_el0);
asm!("mrs {0}, CNTVCT_EL0", out(reg) self.cntvct_el0);
// MRS!("self.vpidr_el2, VPIDR_EL2, "x");
asm!("mrs {0}, VMPIDR_EL2", out(reg) self.vmpidr_el2);

asm!("mrs {0}, SP_EL0", out(reg) self.sp_el0);
asm!("mrs {0}, SP_EL1", out(reg) self.sp_el1);
asm!("mrs {0}, ELR_EL1", out(reg) self.elr_el1);
asm!("mrs {0:x}, SPSR_EL1", out(reg) self.spsr_el1);
asm!("mrs {0:x}, SCTLR_EL1", out(reg) self.sctlr_el1);
asm!("mrs {0:x}, CPACR_EL1", out(reg) self.cpacr_el1);
asm!("mrs {0}, TTBR0_EL1", out(reg) self.ttbr0_el1);
asm!("mrs {0}, TTBR1_EL1", out(reg) self.ttbr1_el1);
asm!("mrs {0}, TCR_EL1", out(reg) self.tcr_el1);
asm!("mrs {0:x}, ESR_EL1", out(reg) self.esr_el1);
asm!("mrs {0}, FAR_EL1", out(reg) self.far_el1);
asm!("mrs {0}, PAR_EL1", out(reg) self.par_el1);
asm!("mrs {0}, MAIR_EL1", out(reg) self.mair_el1);
asm!("mrs {0}, AMAIR_EL1", out(reg) self.amair_el1);
asm!("mrs {0}, VBAR_EL1", out(reg) self.vbar_el1);
asm!("mrs {0:x}, CONTEXTIDR_EL1", out(reg) self.contextidr_el1);
asm!("mrs {0}, TPIDR_EL0", out(reg) self.tpidr_el0);
asm!("mrs {0}, TPIDR_EL1", out(reg) self.tpidr_el1);
asm!("mrs {0}, TPIDRRO_EL0", out(reg) self.tpidrro_el0);
asm!("mrs {0}, SP_EL0", out(reg) self.sp_el0);
asm!("mrs {0}, SP_EL1", out(reg) self.sp_el1);
asm!("mrs {0}, ELR_EL1", out(reg) self.elr_el1);
asm!("mrs {0:x}, SPSR_EL1", out(reg) self.spsr_el1);
asm!("mrs {0:x}, SCTLR_EL1", out(reg) self.sctlr_el1);
asm!("mrs {0:x}, CPACR_EL1", out(reg) self.cpacr_el1);
asm!("mrs {0}, TTBR0_EL1", out(reg) self.ttbr0_el1);
asm!("mrs {0}, TTBR1_EL1", out(reg) self.ttbr1_el1);
asm!("mrs {0}, TCR_EL1", out(reg) self.tcr_el1);
asm!("mrs {0:x}, ESR_EL1", out(reg) self.esr_el1);
asm!("mrs {0}, FAR_EL1", out(reg) self.far_el1);
asm!("mrs {0}, PAR_EL1", out(reg) self.par_el1);
asm!("mrs {0}, MAIR_EL1", out(reg) self.mair_el1);
asm!("mrs {0}, AMAIR_EL1", out(reg) self.amair_el1);
asm!("mrs {0}, VBAR_EL1", out(reg) self.vbar_el1);
asm!("mrs {0:x}, CONTEXTIDR_EL1", out(reg) self.contextidr_el1);
asm!("mrs {0}, TPIDR_EL0", out(reg) self.tpidr_el0);
asm!("mrs {0}, TPIDR_EL1", out(reg) self.tpidr_el1);
asm!("mrs {0}, TPIDRRO_EL0", out(reg) self.tpidrro_el0);

asm!("mrs {0}, PMCR_EL0", out(reg) self.pmcr_el0);
asm!("mrs {0}, VTCR_EL2", out(reg) self.vtcr_el2);
asm!("mrs {0}, VTTBR_EL2", out(reg) self.vttbr_el2);
asm!("mrs {0}, HCR_EL2", out(reg) self.hcr_el2);
asm!("mrs {0}, ACTLR_EL1", out(reg) self.actlr_el1);
}
asm!("mrs {0}, PMCR_EL0", out(reg) self.pmcr_el0);
asm!("mrs {0}, VTCR_EL2", out(reg) self.vtcr_el2);
asm!("mrs {0}, VTTBR_EL2", out(reg) self.vttbr_el2);
asm!("mrs {0}, HCR_EL2", out(reg) self.hcr_el2);
asm!("mrs {0}, ACTLR_EL1", out(reg) self.actlr_el1);
// println!("save sctlr {:x}", self.sctlr_el1);
}

/// Restores the values of all relevant system registers from the `VmContext` structure.
/// Restores the values of all relevant system registers from the `GuestSystemRegisters` structure.
///
/// This method uses inline assembly to write the values stored in the `VmContext` structure
/// This method uses inline assembly to write the values stored in the `GuestSystemRegisters` structure
/// back to the system registers. This is essential for restoring the state of a virtual machine
/// or thread during context switching.
///
/// Each system register is restored with its corresponding value from the `VmContext`, ensuring
/// Each system register is restored with its corresponding value from the `GuestSystemRegisters`, ensuring
/// that the virtual machine or thread resumes execution with the correct context.
pub unsafe fn ext_regs_restore(&self) {
pub unsafe fn restore(&self) {
asm!("msr CNTV_CVAL_EL0, {0}", in(reg) self.cntv_cval_el0);
asm!("msr CNTKCTL_EL1, {0:x}", in (reg) self.cntkctl_el1);
asm!("msr CNTV_CTL_EL0, {0:x}", in (reg) self.cntv_ctl_el0);
Expand Down
Loading

0 comments on commit cc86daf

Please sign in to comment.