use applevisor as av;
use crate::caches::*;
use crate::core::*;
use crate::crash::*;
use crate::error::*;
use crate::loader::*;
use crate::memory::*;
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum ExceptionVectorType {
SynchronousCurElSp0,
IrqCurElSp0,
FiqCurElSp0,
SerrorCurElSp0,
SynchronousCurElSpX,
IrqCurElSpX,
FiqCurElSpX,
SerrorCurElSpX,
SynchronousLowerElA64,
IrqLowerElA64,
FiqLowerElA64,
SerrorLowerElA64,
SynchronousLowerElA32,
IrqLowerElA32,
FiqLowerElA32,
SerrorLowerElA32,
Unknown(u8),
}
impl From<u8> for ExceptionVectorType {
fn from(val: u8) -> Self {
match val {
0x0 => Self::SynchronousCurElSp0,
0x1 => Self::IrqCurElSp0,
0x2 => Self::FiqCurElSp0,
0x3 => Self::SerrorCurElSp0,
0x4 => Self::SynchronousCurElSpX,
0x5 => Self::IrqCurElSpX,
0x6 => Self::FiqCurElSpX,
0x7 => Self::SerrorCurElSpX,
0x8 => Self::SynchronousLowerElA64,
0x9 => Self::IrqLowerElA64,
0xa => Self::FiqLowerElA64,
0xb => Self::SerrorLowerElA64,
0xc => Self::SynchronousLowerElA32,
0xd => Self::IrqLowerElA32,
0xe => Self::FiqLowerElA32,
0xf => Self::SerrorLowerElA32,
_ => Self::Unknown(val),
}
}
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum ExceptionClass {
Unknown(u64),
WfTrap,
McrMrcTrap0,
McrrMrrcTrap,
McrMrcTrap1,
LdcStcTrap,
SveSimdFpTrap,
Ld64St64Trap,
MrrcTrap,
BranchTargetException,
IllegalExecutionState,
SvcA32,
SvcA64,
HvcA64,
MsrMrsSysTrap,
SveTrap,
PacAuthFailure,
InsAbortLowerEl,
InsAbortCurEl,
PcALignmentFault,
DataAbortLowerEl,
DataAbortCurEl,
SpALignmentFault,
FpTrapA32,
FpTrapA64,
SerrorInterrupt,
BreakpointLowerEl,
BreakpointCurEl,
SoftwareStepLowerEL,
SoftwareStepCurEL,
WatchpointLowerEL,
WatchpointCurEL,
BkptA32,
BrkA64,
}
impl From<u64> for ExceptionClass {
fn from(val: u64) -> Self {
match val & 0x3f {
0b000001 => Self::WfTrap,
0b000011 => Self::McrMrcTrap0,
0b000100 => Self::McrrMrrcTrap,
0b000101 => Self::McrMrcTrap1,
0b000110 => Self::LdcStcTrap,
0b000111 => Self::SveSimdFpTrap,
0b001010 => Self::Ld64St64Trap,
0b001100 => Self::MrrcTrap,
0b001101 => Self::BranchTargetException,
0b001110 => Self::IllegalExecutionState,
0b010001 => Self::SvcA32,
0b010101 => Self::SvcA64,
0b010110 => Self::HvcA64,
0b011000 => Self::MsrMrsSysTrap,
0b011001 => Self::SveTrap,
0b011100 => Self::PacAuthFailure,
0b100000 => Self::InsAbortLowerEl,
0b100001 => Self::InsAbortCurEl,
0b100010 => Self::PcALignmentFault,
0b100100 => Self::DataAbortLowerEl,
0b100101 => Self::DataAbortCurEl,
0b100110 => Self::SpALignmentFault,
0b101000 => Self::FpTrapA32,
0b101100 => Self::FpTrapA64,
0b101111 => Self::SerrorInterrupt,
0b110000 => Self::BreakpointLowerEl,
0b110001 => Self::BreakpointCurEl,
0b110010 => Self::SoftwareStepLowerEL,
0b110011 => Self::SoftwareStepCurEL,
0b110100 => Self::WatchpointLowerEL,
0b110101 => Self::WatchpointCurEL,
0b111000 => Self::BkptA32,
0b111100 => Self::BrkA64,
_ => Self::Unknown(val),
}
}
}
pub const EVTABLE_ADDR: u64 = 0xffff_ffff_ffff_0000;
pub const END_ADDR: u64 = 0xdead_beef_0bad_0d0e;
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct Exceptions;
impl Exceptions {
pub fn init(vcpu: &mut av::Vcpu, vma: &mut VirtMemAllocator) -> Result<()> {
vma.map_privileged(EVTABLE_ADDR, 0x1000, av::MemPerms::RX)?;
for i in 0..16 {
let asm = format!("hvc #{}", i);
let hvc = KSE.with(|ks| ks.asm(asm, 0).expect("could not assemble"));
vma.write(EVTABLE_ADDR + i * 0x80, &hvc.bytes)?;
}
vcpu.set_sys_reg(av::SysReg::VBAR_EL1, EVTABLE_ADDR)?;
Ok(())
}
pub fn handle<L: Loader + Loader<LD = LD> + Loader<GD = GD>, LD: Clone, GD: Clone>(
executor: &mut Executor<L, LD, GD>,
) -> Result<ExitKind> {
let exit = executor.vcpu.get_exit_info();
match ExceptionClass::from(exit.exception.syndrome >> 26) {
ExceptionClass::HvcA64 => Self::handle_hvc(executor),
ExceptionClass::BrkA64 => executor.hooks.handle(
&mut executor.vcpu,
&mut executor.vma.borrow_mut(),
&executor.vma.borrow_snapshot(),
&mut executor.ldata,
&executor.gdata,
&mut executor.cdata,
&mut executor.bdata,
),
_ => Err(ExceptionError::UnimplementedException(
exit.exception.syndrome,
))?,
}
}
#[allow(clippy::single_match)]
pub fn handle_hvc<L: Loader + Loader<LD = LD> + Loader<GD = GD>, LD: Clone, GD: Clone>(
executor: &mut Executor<L, LD, GD>,
) -> Result<ExitKind> {
let exit = executor.vcpu.get_exit_info();
let mut vma = executor.vma.borrow_mut();
match exit.exception.syndrome & 0xf {
0x00 => {
let esr = executor.vcpu.get_sys_reg(av::SysReg::ESR_EL1)?;
match ExceptionClass::from(esr >> 26) {
ExceptionClass::DataAbortCurEl => {
let far = executor.vcpu.get_sys_reg(av::SysReg::FAR_EL1)?;
match vma.page_fault_dirty_state_handler(far) {
Ok(true) => {
let elr = executor.vcpu.get_sys_reg(av::SysReg::ELR_EL1)?;
executor.vcpu.set_reg(av::Reg::PC, elr)?;
Caches::tlbi_vaae1_on_fault(&mut executor.vcpu, &mut vma)?;
return Ok(ExitKind::Continue);
}
Err(Error::Memory(MemoryError::UnallocatedMemoryAccess(_))) => {}
Err(Error::Memory(MemoryError::InvalidAddress(_))) => {
if far == END_ADDR {
return Ok(ExitKind::Exit);
}
}
Err(e) => return Err(e)?,
_ => {}
}
}
_ => {}
};
executor.loader.exception_handler_sync_curel_sp0(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
)
}
0x01 => executor.loader.exception_handler_irq_curel_sp0(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x02 => executor.loader.exception_handler_fiq_curel_sp0(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x03 => executor.loader.exception_handler_serror_curel_sp0(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x04 => {
let esr = executor.vcpu.get_sys_reg(av::SysReg::ESR_EL1)?;
match ExceptionClass::from(esr >> 26) {
ExceptionClass::DataAbortCurEl => {
let far = executor.vcpu.get_sys_reg(av::SysReg::FAR_EL1)?;
match vma.page_fault_dirty_state_handler(far) {
Ok(true) => {
let elr = executor.vcpu.get_sys_reg(av::SysReg::ELR_EL1)?;
executor.vcpu.set_reg(av::Reg::PC, elr)?;
Caches::tlbi_vaae1_on_fault(&mut executor.vcpu, &mut vma)?;
return Ok(ExitKind::Continue);
}
Err(Error::Memory(MemoryError::UnallocatedMemoryAccess(_))) => {}
Err(Error::Memory(MemoryError::InvalidAddress(_))) => {
if far == END_ADDR {
return Ok(ExitKind::Exit);
}
}
Err(e) => return Err(e)?,
_ => {}
}
}
_ => {
let lr = executor.vcpu.get_reg(av::Reg::LR)?;
if lr == END_ADDR {
return Ok(ExitKind::Exit);
}
}
};
executor.loader.exception_handler_sync_curel_spx(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
)
}
0x05 => executor.loader.exception_handler_irq_curel_spx(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x06 => executor.loader.exception_handler_fiq_curel_spx(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x07 => executor.loader.exception_handler_serror_curel_spx(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x08 => {
let esr = executor.vcpu.get_sys_reg(av::SysReg::ESR_EL1)?;
match ExceptionClass::from(esr >> 26) {
ExceptionClass::DataAbortLowerEl => {
let far = executor.vcpu.get_sys_reg(av::SysReg::FAR_EL1)?;
match vma.page_fault_dirty_state_handler(far) {
Ok(true) => {
let elr = executor.vcpu.get_sys_reg(av::SysReg::ELR_EL1)?;
executor.vcpu.set_reg(av::Reg::PC, elr)?;
Caches::tlbi_vaae1_on_fault(&mut executor.vcpu, &mut vma)?;
return Ok(ExitKind::Continue);
}
Err(Error::Memory(MemoryError::UnallocatedMemoryAccess(_))) => {}
Err(Error::Memory(MemoryError::InvalidAddress(_))) => {}
Err(e) => return Err(e)?,
_ => {}
}
}
_ => {
let lr = executor.vcpu.get_reg(av::Reg::LR)?;
if lr == END_ADDR {
return Ok(ExitKind::Exit);
}
}
};
executor.loader.exception_handler_sync_lowerel_aarch64(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
)
}
0x09 => executor.loader.exception_handler_irq_lowerel_aarch64(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x0a => executor.loader.exception_handler_fiq_lowerel_aarch64(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x0b => executor.loader.exception_handler_serror_lowerel_aarch64(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x0c => executor.loader.exception_handler_sync_lowerel_aarch32(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x0d => executor.loader.exception_handler_irq_lowerel_aarch32(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x0e => executor.loader.exception_handler_fiq_lowerel_aarch32(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
0x0f => executor.loader.exception_handler_serror_lowerel_aarch32(
&mut executor.vcpu,
&mut vma,
&mut executor.ldata,
&executor.gdata,
),
_ => Ok(ExitKind::Crash("Unknown Exception".to_string())),
}
}
}