use applevisor as av;
use crate::core::*;
use crate::error::*;
use crate::memory::*;
pub const HANDLER_SIZE: usize = 0x80;
pub const HANDLERS_MEM_SIZE: usize = 0x1000;
pub const HANDLERS_COUNT: usize = HANDLERS_MEM_SIZE / HANDLER_SIZE;
pub const HANDLERS_ADDR: u64 = 0xffff_ffff_fffe_0000;
pub const STACK_SIZE: usize = 0x1000;
pub const STACK_ADDR: u64 = 0xffff_ffff_fffe_1000;
pub struct Caches;
impl Caches {
pub fn init(vcpu: &mut av::Vcpu, vma: &mut VirtMemAllocator) -> Result<()> {
vma.map_privileged(STACK_ADDR, STACK_SIZE, av::MemPerms::RW)?;
vcpu.set_sys_reg(av::SysReg::SP_EL1, STACK_ADDR)?;
vma.map_privileged(HANDLERS_ADDR, HANDLERS_MEM_SIZE, av::MemPerms::RX)?;
let handlers = vec![
String::from(
"msr tpidr_el1, x0
mov x0, 1
msr spsel, x0
ldr x0, [sp, #0x8]
msr spsr_el1, x0
ldr x0, [sp]
msr elr_el1, x0
ic ivau, x0
dsb ish
isb
mrs x0, tpidr_el1
eret",
),
String::from(
"tlbi vmalle1
dsb ish
ic ialluis
dsb ish
isb
msr tpidr_el1, x0
mov x0, 1
msr spsel, x0
ldr x0, [sp, #0x8]
msr spsr_el1, x0
ldr x0, [sp]
msr elr_el1, x0
mrs x0, tpidr_el1
eret",
),
String::from(
"msr tpidr_el1, x0
mov x0, 1
msr spsel, x0
ldr x0, [sp, #0x8]
msr spsr_el1, x0
ldr x0, [sp]
msr elr_el1, x0
mrs x0, far_el1
lsr x0, x0, 12
dsb ishst
tlbi vaae1, x0
dsb ish
isb
mrs x0, tpidr_el1
eret",
),
String::from(
"msr tpidr_el1, x0
mov x0, 1
msr spsel, x0
ldr x0, [sp, #0x8]
msr spsr_el1, x0
ldr x0, [sp]
msr elr_el1, x0
ldr x0, [sp, #0x10]
lsr x0, x0, 12
dsb ishst
tlbi vaae1, x0
dsb ish
mrs x0, tpidr_el1
eret",
),
];
assert!(handlers.len() < HANDLERS_COUNT);
for (i, asm) in handlers.into_iter().enumerate() {
let handler = KSE.with(|ks| ks.asm(asm, 0).expect("could not assemble"));
assert!(!handler.bytes.is_empty() && handler.bytes.len() < HANDLER_SIZE);
vma.write(HANDLERS_ADDR + (i * HANDLER_SIZE) as u64, &handler.bytes)?;
}
Ok(())
}
#[inline]
pub fn ic_ivau(vcpu: &mut av::Vcpu, vma: &mut VirtMemAllocator) -> Result<()> {
vma.write_qword(STACK_ADDR, vcpu.get_reg(av::Reg::PC)?)?;
vma.write_qword(STACK_ADDR + 8, vcpu.get_reg(av::Reg::CPSR)?)?;
vcpu.set_reg(av::Reg::CPSR, 0x3c4)?;
vcpu.set_reg(av::Reg::PC, HANDLERS_ADDR)?;
Ok(())
}
#[inline]
pub fn tlbi_vmalle1_ic_ialluis(vcpu: &mut av::Vcpu, vma: &mut VirtMemAllocator) -> Result<()> {
vma.write_qword(STACK_ADDR, vcpu.get_reg(av::Reg::PC)?)?;
vma.write_qword(STACK_ADDR + 8, vcpu.get_reg(av::Reg::CPSR)?)?;
vcpu.set_reg(av::Reg::CPSR, 0x3c4)?;
vcpu.set_reg(av::Reg::PC, HANDLERS_ADDR + HANDLER_SIZE as u64)?;
Ok(())
}
#[inline]
pub fn tlbi_vaae1_on_fault(vcpu: &mut av::Vcpu, vma: &mut VirtMemAllocator) -> Result<()> {
vma.write_qword(STACK_ADDR, vcpu.get_reg(av::Reg::PC)?)?;
vma.write_qword(STACK_ADDR + 8, vcpu.get_sys_reg(av::SysReg::SPSR_EL1)?)?;
vcpu.set_reg(av::Reg::PC, HANDLERS_ADDR + (HANDLER_SIZE * 2) as u64)?;
Ok(())
}
#[inline]
pub fn tlbi_vaae1(vcpu: &mut av::Vcpu, vma: &mut VirtMemAllocator, addr: u64) -> Result<()> {
vma.write_qword(STACK_ADDR, vcpu.get_reg(av::Reg::PC)?)?;
vma.write_qword(STACK_ADDR + 8, vcpu.get_reg(av::Reg::CPSR)?)?;
vma.write_qword(STACK_ADDR + 0x10, addr)?;
vcpu.set_reg(av::Reg::CPSR, 0x3c4)?;
vcpu.set_reg(av::Reg::PC, HANDLERS_ADDR + (HANDLER_SIZE * 3) as u64)?;
Ok(())
}
}