refactor: move asm! usage to intrin module

This commit is contained in:
2022-01-26 15:15:38 +02:00
parent 01da9e7ee5
commit d45a8adc34
13 changed files with 127 additions and 151 deletions
+4 -2
View File
@@ -1,6 +1,6 @@
//! AArch64 exception handling
use crate::arch::machine;
use crate::arch::{machine, intrin};
use crate::debug::Level;
use crate::dev::irq::{IntController, IrqContext};
use crate::mem;
@@ -98,7 +98,9 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) {
let res = proc.manipulate_space(|space| {
space.try_cow_copy(far)?;
Process::invalidate_asid(asid);
unsafe {
intrin::flush_tlb_asid(asid);
}
Result::<(), Errno>::Ok(())
});
+17
View File
@@ -0,0 +1,17 @@
use core::arch::asm;
#[inline(always)]
pub unsafe fn irq_disable() {
asm!("msr daifset, {bits}", bits = const 2, options(nomem, nostack, preserves_flags));
}
#[inline(always)]
pub unsafe fn flush_tlb_virt(addr: usize) {
}
// TODO non-portable
#[inline(always)]
pub unsafe fn flush_tlb_asid(asid: usize) {
asm!("tlbi aside1, {}", in(reg) asid);
}
@@ -1,5 +1,6 @@
use crate::dev::Device;
use crate::mem::virt::DeviceMemoryIo;
use crate::arch::intrin;
use crate::sync::IrqSafeSpinLock;
use crate::util::InitOnce;
use libsys::error::Errno;
@@ -72,7 +73,7 @@ impl RWdog {
regs.CTRL.write(CTRL::KEY::Value + CTRL::RESTART::SET);
loop {
asm!("wfe");
intrin::hang();
}
}
+3 -2
View File
@@ -1,12 +1,13 @@
//! aarch64 architecture implementation
use core::arch::asm;
use cortex_a::registers::DAIF;
use tock_registers::interfaces::{Readable, Writeable};
use core::arch::asm;
pub mod boot;
pub mod context;
pub mod exception;
pub mod intrin;
pub mod irq;
pub mod reg;
pub mod timer;
@@ -35,7 +36,7 @@ cfg_if! {
#[inline(always)]
pub unsafe fn irq_mask_save() -> u64 {
let state = DAIF.get();
asm!("msr daifset, {bits}", bits = const 2, options(nomem, nostack, preserves_flags));
intrin::irq_disable();
state
}
@@ -1,50 +0,0 @@
//! CNTKCTL_EL1 register
#![allow(missing_docs)]
use core::arch::asm;
use tock_registers::{
interfaces::{Readable, Writeable},
register_bitfields,
};
register_bitfields! {
u64,
/// Counter-timer Kernel Control Register
pub CNTKCTL_EL1 [
/// If set, disables CNTPCT and CNTFRQ trapping from EL0
EL0PCTEN OFFSET(0) NUMBITS(1) []
]
}
/// CNTKCTL_EL1 register
pub struct Reg;
impl Readable for Reg {
type T = u64;
type R = CNTKCTL_EL1::Register;
#[inline(always)]
fn get(&self) -> Self::T {
let mut tmp;
unsafe {
asm!("mrs {}, cntkctl_el1", out(reg) tmp);
}
tmp
}
}
impl Writeable for Reg {
type T = u64;
type R = CNTKCTL_EL1::Register;
#[inline(always)]
fn set(&self, value: Self::T) {
unsafe {
asm!("msr cntkctl_el1, {}", in(reg) value);
}
}
}
/// CNTKCTL_EL1 register
pub const CNTKCTL_EL1: Reg = Reg;
-58
View File
@@ -1,58 +0,0 @@
//! CPACR_EL1 register
#![allow(missing_docs)]
use core::arch::asm;
use tock_registers::{
interfaces::{Readable, Writeable},
register_bitfields,
};
register_bitfields! {
u64,
/// EL1 Architectural Feature Access Control Register
pub CPACR_EL1 [
/// Enable EL0 and EL1 SIMD/FP accesses to EL1
FPEN OFFSET(20) NUMBITS(2) [
/// Trap both EL0 and EL1
TrapAll = 0,
/// Trap EL0
TrapEl0 = 1,
/// Trap EL1
TrapEl1 = 2,
/// Do not trap any SIMD/FP instructions
TrapNone = 3
]
]
}
/// CPACR_EL1 register
pub struct Reg;
impl Readable for Reg {
type T = u64;
type R = CPACR_EL1::Register;
#[inline(always)]
fn get(&self) -> Self::T {
let mut tmp;
unsafe {
asm!("mrs {}, cpacr_el1", out(reg) tmp);
}
tmp
}
}
impl Writeable for Reg {
type T = u64;
type R = CPACR_EL1::Register;
#[inline(always)]
fn set(&self, value: Self::T) {
unsafe {
asm!("msr cpacr_el1, {}", in(reg) value);
}
}
}
/// CPACR_EL1 register
pub const CPACR_EL1: Reg = Reg;
+63 -4
View File
@@ -1,7 +1,66 @@
//! AArch64 architectural registers
pub mod cpacr_el1;
pub use cpacr_el1::CPACR_EL1;
use core::arch::asm;
use tock_registers::{
interfaces::{Readable, Writeable},
register_bitfields,
};
pub mod cntkctl_el1;
pub use cntkctl_el1::CNTKCTL_EL1;
macro_rules! wrap_msr {
($struct_name:ident, $name:ident, $reg:literal, $fields:tt) => {
register_bitfields! {
u64,
pub $name $fields
}
pub struct $struct_name;
impl Readable for $struct_name {
type T = u64;
type R = $name::Register;
#[inline(always)]
fn get(&self) -> Self::T {
let mut value;
unsafe {
asm!(concat!("mrs {}, ", $reg), out(reg) value)
}
value
}
}
impl Writeable for $struct_name {
type T = u64;
type R = $name::Register;
#[inline(always)]
fn set(&self, value: Self::T) {
unsafe {
asm!(concat!("msr ", $reg, ", {}"), in(reg) value);
}
}
}
pub const $name: $struct_name = $struct_name;
};
}
/// EL1 Architectural Feature Access Control Register
wrap_msr!(CpacrEl1, CPACR_EL1, "cpacr_el1", [
/// Enable EL0 and EL1 SIMD/FP accesses to EL1
FPEN OFFSET(20) NUMBITS(2) [
/// Trap both EL0 and EL1
TrapAll = 0,
/// Trap EL0
TrapEl0 = 1,
/// Trap EL1
TrapEl1 = 2,
/// Do not trap any SIMD/FP instructions
TrapNone = 3
]
]);
wrap_msr!(CntkctlEl1, CNTKCTL_EL1, "cntkctl_el1", [
/// If set, disables CNTPCT and CNTFRQ trapping from EL0
EL0PCTEN OFFSET(0) NUMBITS(1) []
]);
+2
View File
@@ -15,6 +15,8 @@ cfg_if! {
pub use aarch64 as platform;
pub use aarch64::machine;
pub use aarch64::intrin;
}
}
+1 -1
View File
@@ -42,7 +42,7 @@ use core::arch::asm;
#[panic_handler]
fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
unsafe {
asm!("msr daifset, #2");
arch::intrin::irq_disable();
}
errorln!("Panic: {:?}", pi);
+15
View File
@@ -26,3 +26,18 @@ pub fn kernel_end_phys() -> usize {
}
unsafe { &__kernel_end as *const _ as usize - KERNEL_OFFSET }
}
// TODO cross-platform variant
#[inline(always)]
pub fn is_el0_accessible(virt: usize, write: bool) -> bool {
use core::arch::asm;
let mut res: usize;
unsafe {
if write {
asm!("at s1e0w, {}; mrs {}, par_el1", in(reg) virt, out(reg) res);
} else {
asm!("at s1e0r, {}; mrs {}, par_el1", in(reg) virt, out(reg) res);
}
}
res & 1 == 0
}
+12 -15
View File
@@ -1,15 +1,16 @@
//! Process data and control
use crate::arch::aarch64::exception::ExceptionFrame;
use crate::arch::{aarch64::exception::ExceptionFrame, intrin};
use crate::mem::{
self,
phys::{self, PageUsage},
virt::{MapAttributes, Space},
};
use crate::proc::{
wait::Wait, Context, ProcessIo, Thread, ThreadRef, ThreadState, PROCESSES, SCHED, Tid,
wait::Wait, Context, ProcessIo, Thread, ThreadRef, ThreadState, Tid, PROCESSES, SCHED,
};
use crate::sync::{IrqSafeSpinLock};
use crate::sync::IrqSafeSpinLock;
use alloc::{rc::Rc, vec::Vec};
use core::arch::asm;
use core::sync::atomic::{AtomicU32, Ordering};
use libsys::{
error::Errno,
@@ -18,7 +19,6 @@ use libsys::{
signal::Signal,
ProgramArgs,
};
use core::arch::asm;
/// Wrapper type for a process struct reference
pub type ProcessRef = Rc<Process>;
@@ -166,7 +166,8 @@ impl Process {
loop {
let state = self.signal_state.load(Ordering::Acquire);
if let Some(signal) = Self::find1(state).map(|e| Signal::try_from(e as u32).unwrap()) {
self.signal_state.fetch_and(!(1 << (signal as u32)), Ordering::Release);
self.signal_state
.fetch_and(!(1 << (signal as u32)), Ordering::Release);
main_thread.clone().enter_signal(signal, ttbr0);
} else {
break;
@@ -190,7 +191,8 @@ impl Process {
main_thread.enter_signal(signal, ttbr0);
}
ThreadState::Waiting => {
self.signal_state.fetch_or(1 << (signal as u32), Ordering::Release);
self.signal_state
.fetch_or(1 << (signal as u32), Ordering::Release);
main_thread.interrupt_wait(true);
}
ThreadState::Ready => {
@@ -289,7 +291,7 @@ impl Process {
if let Some(space) = lock.space.take() {
unsafe {
Space::release(space);
Process::invalidate_asid((lock.id.asid() as usize) << 48);
intrin::flush_tlb_asid((lock.id.asid() as usize) << 48);
}
}
@@ -466,13 +468,8 @@ impl Process {
}
pub fn invalidate_tlb(&self) {
Process::invalidate_asid(self.asid());
}
#[inline]
pub fn invalidate_asid(asid: usize) {
unsafe {
asm!("tlbi aside1, {}", in(reg) asid);
intrin::flush_tlb_asid(self.asid());
}
}
@@ -483,7 +480,7 @@ impl Process {
) -> Result<(), Errno> {
unsafe {
// Run with interrupts disabled
asm!("msr daifset, #2");
intrin::irq_disable();
}
let proc = Process::current();
@@ -540,7 +537,7 @@ impl Process {
// TODO drop old context
let ctx = thread.ctx.get();
let asid = (process_lock.id.asid() as usize) << 48;
Process::invalidate_asid(asid);
intrin::flush_tlb_asid(asid);
ctx.write(Context::user(
entry,
+3 -3
View File
@@ -1,10 +1,10 @@
//!
use crate::proc::{Thread, ThreadRef, THREADS};
use crate::sync::IrqSafeSpinLock;
use crate::arch::intrin;
use crate::util::InitOnce;
use libsys::proc::Tid;
use alloc::{collections::VecDeque, rc::Rc};
use core::arch::asm;
struct SchedulerInner {
queue: VecDeque<Tid>,
@@ -70,7 +70,7 @@ impl Scheduler {
THREADS.lock().get(&id).unwrap().clone()
};
asm!("msr daifset, #2");
intrin::irq_disable();
Thread::enter(thread)
}
@@ -122,7 +122,7 @@ impl Scheduler {
if !Rc::ptr_eq(&from, &to) {
unsafe {
asm!("msr daifset, #2");
intrin::irq_disable();
Thread::switch(from, to, discard);
}
}
+5 -15
View File
@@ -1,6 +1,7 @@
//! System call argument ABI helpers
use crate::mem;
use crate::arch::intrin;
use core::alloc::Layout;
use libsys::error::Errno;
use crate::proc::Process;
@@ -24,19 +25,6 @@ macro_rules! invalid_memory {
}
}
#[inline(always)]
fn is_el0_accessible(virt: usize, write: bool) -> bool {
let mut res: usize;
unsafe {
if write {
asm!("at s1e0w, {}; mrs {}, par_el1", in(reg) virt, out(reg) res);
} else {
asm!("at s1e0r, {}; mrs {}, par_el1", in(reg) virt, out(reg) res);
}
}
res & 1 == 0
}
/// Checks given argument and interprets it as a `T` reference
pub fn struct_ref<'a, T>(base: usize) -> Result<&'a T, Errno> {
let layout = Layout::new::<T>();
@@ -126,13 +114,15 @@ pub fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> {
let asid = process.asid();
for i in (base / mem::PAGE_SIZE)..((base + len + mem::PAGE_SIZE - 1) / mem::PAGE_SIZE) {
if !is_el0_accessible(i * mem::PAGE_SIZE, write) {
if !mem::is_el0_accessible(i * mem::PAGE_SIZE, write) {
// It's possible a CoW page hasn't yet been cloned when trying
// a write access
let res = if write {
process.manipulate_space(|space| {
space.try_cow_copy(i * mem::PAGE_SIZE)?;
Process::invalidate_asid(asid);
unsafe {
intrin::flush_tlb_asid(asid);
}
Ok(())
})
} else {