Enables MMU and set PC to kernel entry point (#945)

This commit is contained in:
Putta Khunchalee 2024-08-24 00:18:04 +07:00 committed by GitHub
parent f46b182d4d
commit c44798de47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 68 additions and 3 deletions

View File

@ -131,10 +131,13 @@ impl<'a> Cpu for HfCpu<'a> {
fn states(&mut self) -> Result<Self::States<'_>, Self::GetStatesErr> {
Ok(HfStates {
cpu: self,
sctlr_el1: State::None,
tcr_el1: State::None,
ttbr0_el1: State::None,
ttbr1_el1: State::None,
sp_el1: State::None,
pc: State::None,
x0: State::None,
})
}
@ -206,6 +209,8 @@ pub struct HfStates<'a, 'b> {
#[cfg(target_arch = "x86_64")]
ss: State<usize>,
#[cfg(target_arch = "aarch64")]
sctlr_el1: State<u64>,
#[cfg(target_arch = "aarch64")]
tcr_el1: State<u64>,
#[cfg(target_arch = "aarch64")]
ttbr0_el1: State<u64>,
@ -213,6 +218,10 @@ pub struct HfStates<'a, 'b> {
ttbr1_el1: State<u64>,
#[cfg(target_arch = "aarch64")]
sp_el1: State<u64>,
#[cfg(target_arch = "aarch64")]
pc: State<u64>,
#[cfg(target_arch = "aarch64")]
x0: State<u64>,
}
impl<'a, 'b> CpuStates for HfStates<'a, 'b> {
@ -285,6 +294,13 @@ impl<'a, 'b> CpuStates for HfStates<'a, 'b> {
todo!()
}
#[cfg(target_arch = "aarch64")]
fn set_sctlr_el1(&mut self, m: bool) {
let m: u64 = m.into();
self.sctlr_el1 = State::Dirty(m);
}
#[cfg(target_arch = "aarch64")]
fn set_tcr_el1(&mut self, ips: u8, tg1: u8, a1: bool, t1sz: u8, tg0: u8, t0sz: u8) {
let ips: u64 = ips.into();
@ -325,7 +341,12 @@ impl<'a, 'b> CpuStates for HfStates<'a, 'b> {
#[cfg(target_arch = "aarch64")]
fn set_pc(&mut self, v: usize) {
todo!()
self.pc = State::Dirty(v.try_into().unwrap());
}
#[cfg(target_arch = "aarch64")]
fn set_x0(&mut self, v: usize) {
self.x0 = State::Dirty(v.try_into().unwrap());
}
#[cfg(target_arch = "x86_64")]
@ -366,10 +387,13 @@ impl<'a, 'b> CpuStates for HfStates<'a, 'b> {
#[cfg(target_arch = "aarch64")]
fn commit(self) -> Result<(), Self::Err> {
use hv_sys::{
hv_reg_t_HV_REG_PC as HV_REG_PC, hv_reg_t_HV_REG_X0 as HV_REG_X0,
hv_sys_reg_t_HV_SYS_REG_SCTLR_EL1 as HV_SYS_REG_SCTLR_EL1,
hv_sys_reg_t_HV_SYS_REG_SP_EL1 as HV_SYS_REG_SP_EL1,
hv_sys_reg_t_HV_SYS_REG_TCR_EL1 as HV_SYS_REG_TCR_EL1,
hv_sys_reg_t_HV_SYS_REG_TTBR0_EL1 as HV_SYS_REG_TTBR0_EL1,
hv_sys_reg_t_HV_SYS_REG_TTBR1_EL1 as HV_SYS_REG_TTBR1_EL1, hv_vcpu_set_sys_reg,
hv_sys_reg_t_HV_SYS_REG_TTBR1_EL1 as HV_SYS_REG_TTBR1_EL1, hv_vcpu_set_reg,
hv_vcpu_set_sys_reg,
};
// Set system registers.
@ -379,6 +403,10 @@ impl<'a, 'b> CpuStates for HfStates<'a, 'b> {
None => Ok(()),
};
if let State::Dirty(v) = self.sctlr_el1 {
set_sys(HV_SYS_REG_SCTLR_EL1, v).map_err(StatesError::SetSctlrEl1Failed)?;
}
if let State::Dirty(v) = self.tcr_el1 {
set_sys(HV_SYS_REG_TCR_EL1, v).map_err(StatesError::SetTcrEl1Failed)?;
}
@ -395,6 +423,20 @@ impl<'a, 'b> CpuStates for HfStates<'a, 'b> {
set_sys(HV_SYS_REG_SP_EL1, v).map_err(StatesError::SetSpEl1Failed)?;
}
// Set general registers.
let set_reg = |reg, val| match NonZero::new(unsafe { hv_vcpu_set_reg(cpu, reg, val) }) {
Some(v) => Err(v),
None => Ok(()),
};
if let State::Dirty(v) = self.pc {
set_reg(HV_REG_PC, v).map_err(StatesError::SetPcFailed)?;
}
if let State::Dirty(v) = self.x0 {
set_reg(HV_REG_X0, v).map_err(StatesError::SetX0Failed)?;
}
Ok(())
}
}
@ -478,6 +520,10 @@ pub enum StatesError {
#[error("couldn't set CR4")]
SetCr4Failed(NonZero<hv_sys::hv_return_t>),
#[cfg(target_arch = "aarch64")]
#[error("couldn't set SCTLR_EL1")]
SetSctlrEl1Failed(NonZero<hv_sys::hv_return_t>),
#[cfg(target_arch = "aarch64")]
#[error("couldn't set TCR_EL1")]
SetTcrEl1Failed(NonZero<hv_sys::hv_return_t>),
@ -493,4 +539,12 @@ pub enum StatesError {
#[cfg(target_arch = "aarch64")]
#[error("couldn't set SP_EL1")]
SetSpEl1Failed(NonZero<hv_sys::hv_return_t>),
#[cfg(target_arch = "aarch64")]
#[error("couldn't set PC")]
SetPcFailed(NonZero<hv_sys::hv_return_t>),
#[cfg(target_arch = "aarch64")]
#[error("couldn't set X0")]
SetX0Failed(NonZero<hv_sys::hv_return_t>),
}

View File

@ -87,6 +87,9 @@ pub trait CpuStates {
#[cfg(target_arch = "x86_64")]
fn set_ss(&mut self, p: bool);
#[cfg(target_arch = "aarch64")]
fn set_sctlr_el1(&mut self, m: bool);
/// # Panics
/// - If `ips` greater than 7.
/// - If `tg1` or `tg0` geater than 3.
@ -110,6 +113,9 @@ pub trait CpuStates {
#[cfg(target_arch = "aarch64")]
fn set_pc(&mut self, v: usize);
#[cfg(target_arch = "aarch64")]
fn set_x0(&mut self, v: usize);
fn commit(self) -> Result<(), Self::Err>;
}

View File

@ -549,10 +549,13 @@ fn setup_main_cpu(cpu: &mut impl Cpu, entry: usize, map: RamMap) -> Result<(), M
#[cfg(target_arch = "aarch64")]
fn setup_main_cpu(cpu: &mut impl Cpu, entry: usize, map: RamMap) -> Result<(), MainCpuError> {
// Enable MMU to enable virtual address.
let mut states = cpu
.states()
.map_err(|e| MainCpuError::GetCpuStatesFailed(Box::new(e)))?;
states.set_sctlr_el1(true);
// Uses 48-bit Intermediate Physical Address (ips = 0b101) and 48-bit virtual addresses
// (t?sz = 16) for both kernel space and user space. Use ASID from user space (a1 = 0).
states.set_tcr_el1(
@ -575,8 +578,10 @@ fn setup_main_cpu(cpu: &mut impl Cpu, entry: usize, map: RamMap) -> Result<(), M
states.set_ttbr0_el1(map.page_table);
states.set_ttbr1_el1(map.page_table);
// Set stack pointer to the kernel.
// Set entry point, its argument and stack pointer.
states.set_x0(map.env_vaddr);
states.set_sp_el1(map.stack_vaddr + map.stack_len); // Top-down.
states.set_pc(map.kern_vaddr + entry);
states
.commit()