use aarch64_cpu::{asm::barrier, registers::*};
#[unsafe(naked)]
pub unsafe extern "C" fn jump_to(_entry: crate::VirtAddr, _stack: crate::VirtAddr) -> ! {
core::arch::naked_asm!("mov sp, x1", "br x0");
}
impl super::mmu::El1 {
pub unsafe fn init_trap() {
#[cfg(feature = "uspace")]
CNTKCTL_EL1.modify(CNTKCTL_EL1::EL0VCTEN::TrappedNone + CNTKCTL_EL1::EL0PCTEN::TrappedNone);
unsafe extern "C" {
fn __ax_cpu_vector_el1();
}
VBAR_EL1.set(__ax_cpu_vector_el1 as *const () as u64);
TTBR0_EL1.set(0);
barrier::isb(barrier::SY);
}
}
impl super::mmu::El2 {
pub unsafe fn init_trap() {
unsafe extern "C" {
fn __ax_cpu_vector_el2();
}
VBAR_EL2.set(__ax_cpu_vector_el2 as *const () as u64);
barrier::isb(barrier::SY);
}
}
impl super::mmu::El1 {
pub unsafe fn init_boot_trap() {
unsafe extern "C" {
fn __ax_cpu_boot_vector_el1();
}
VBAR_EL1.set(__ax_cpu_boot_vector_el1 as *const () as u64);
barrier::isb(barrier::SY);
}
pub fn vector_base() -> crate::VirtAddr {
crate::VirtAddr::from_usize(VBAR_EL1.get() as usize)
}
}
impl super::mmu::El2 {
pub unsafe fn init_boot_trap() {
unsafe extern "C" {
fn __ax_cpu_boot_vector_el2();
}
VBAR_EL2.set(__ax_cpu_boot_vector_el2 as *const () as u64);
barrier::isb(barrier::SY);
}
pub fn vector_base() -> crate::VirtAddr {
crate::VirtAddr::from_usize(VBAR_EL2.get() as usize)
}
}
pub unsafe fn select_privileged_stack() {
SPSel.write(SPSel::SP::ELx);
SP_EL0.set(0);
}
unsafe fn exception_return(argument: usize) -> ! {
unsafe {
core::arch::asm!("isb", "eret", in("x0") argument, options(noreturn, nostack));
}
}
impl super::mmu::El1 {
pub unsafe fn enter(entry: crate::VirtAddr, stack: crate::VirtAddr, argument: usize) -> ! {
CNTHCTL_EL2.modify(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET);
CNTVOFF_EL2.set(0);
HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64);
SP_EL1.set(stack.as_usize() as u64);
if CurrentEL.read(CurrentEL::EL) == 3 {
SCR_EL3.write(
SCR_EL3::NS::NonSecure + SCR_EL3::HCE::HvcEnabled + SCR_EL3::RW::NextELIsAarch64,
);
SPSR_EL3.write(
SPSR_EL3::M::EL1h
+ SPSR_EL3::D::Masked
+ SPSR_EL3::A::Masked
+ SPSR_EL3::I::Masked
+ SPSR_EL3::F::Masked,
);
ELR_EL3.set(entry.as_usize() as u64);
} else {
SPSR_EL2.write(
SPSR_EL2::M::EL1h
+ SPSR_EL2::D::Masked
+ SPSR_EL2::A::Masked
+ SPSR_EL2::I::Masked
+ SPSR_EL2::F::Masked,
);
ELR_EL2.set(entry.as_usize() as u64);
}
unsafe { exception_return(argument) }
}
}
impl super::mmu::El2 {
pub unsafe fn enter(entry: crate::VirtAddr, stack: crate::VirtAddr, argument: usize) -> ! {
SCR_EL3.write(
SCR_EL3::NS::NonSecure + SCR_EL3::HCE::HvcEnabled + SCR_EL3::RW::NextELIsAarch64,
);
SPSR_EL3.write(
SPSR_EL3::M::EL2h
+ SPSR_EL3::D::Masked
+ SPSR_EL3::A::Masked
+ SPSR_EL3::I::Masked
+ SPSR_EL3::F::Masked,
);
ELR_EL3.set(entry.as_usize() as u64);
SP_EL2.set(stack.as_usize() as u64);
unsafe { exception_return(argument) }
}
}