feat: working el1t multitasking
This commit is contained in:
parent
3130119419
commit
4d9f2971d9
@ -41,4 +41,5 @@ SECTIONS {
|
||||
PROVIDE(__bss_end_phys = . - KERNEL_OFFSET);
|
||||
|
||||
PROVIDE(__kernel_end = .);
|
||||
PROVIDE(__kernel_end_phys = . - KERNEL_OFFSET);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use crate::mem::{
|
||||
};
|
||||
use crate::proc;
|
||||
use cortex_a::asm::barrier::{self, dsb, isb};
|
||||
use cortex_a::registers::{DAIF, SCTLR_EL1, VBAR_EL1};
|
||||
use cortex_a::registers::{SCTLR_EL1, VBAR_EL1};
|
||||
use tock_registers::interfaces::{ReadWriteable, Writeable};
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -3,23 +3,31 @@
|
||||
.global __aa64_ctx_switch_to
|
||||
.global __aa64_ctx_enter_kernel
|
||||
|
||||
.set PT_REGS_SIZE, 16 * 6
|
||||
|
||||
__aa64_ctx_enter_kernel:
|
||||
mov x0, #5
|
||||
ldp x0, x1, [sp, #0]
|
||||
msr sp_el0, x0
|
||||
msr ttbr0_el1, x1
|
||||
|
||||
mov x0, #4
|
||||
msr spsr_el1, x0
|
||||
ldp x0, x1, [sp]
|
||||
ldp x0, x1, [sp, #16]
|
||||
msr elr_el1, x1
|
||||
add sp, sp, #16
|
||||
add sp, sp, #32
|
||||
|
||||
mov x1, xzr
|
||||
eret
|
||||
|
||||
__aa64_ctx_switch:
|
||||
sub sp, sp, #96
|
||||
sub sp, sp, #PT_REGS_SIZE
|
||||
|
||||
stp x19, x20, [sp, #0]
|
||||
stp x21, x22, [sp, #16]
|
||||
stp x23, x24, [sp, #32]
|
||||
stp x25, x26, [sp, #48]
|
||||
stp x27, x29, [sp, #64]
|
||||
stp xzr, lr, [sp, #80]
|
||||
stp x19, x20, [sp, #16 * 0]
|
||||
stp x21, x22, [sp, #16 * 1]
|
||||
stp x23, x24, [sp, #16 * 2]
|
||||
stp x25, x26, [sp, #16 * 3]
|
||||
stp x27, x28, [sp, #16 * 4]
|
||||
stp x29, x30, [sp, #16 * 5]
|
||||
|
||||
mov x19, sp
|
||||
str x19, [x1]
|
||||
@ -27,12 +35,12 @@ __aa64_ctx_switch_to:
|
||||
ldr x0, [x0]
|
||||
mov sp, x0
|
||||
|
||||
ldp x19, x20, [sp, #0]
|
||||
ldp x21, x22, [sp, #16]
|
||||
ldp x23, x24, [sp, #32]
|
||||
ldp x25, x26, [sp, #48]
|
||||
ldp x27, x29, [sp, #64]
|
||||
ldp xzr, lr, [sp, #80]
|
||||
add sp, sp, #96
|
||||
ldp x19, x20, [sp, #16 * 0]
|
||||
ldp x21, x22, [sp, #16 * 1]
|
||||
ldp x23, x24, [sp, #16 * 2]
|
||||
ldp x25, x26, [sp, #16 * 3]
|
||||
ldp x27, x28, [sp, #16 * 4]
|
||||
ldp x29, x30, [sp, #16 * 5]
|
||||
add sp, sp, #PT_REGS_SIZE
|
||||
|
||||
ret
|
||||
|
@ -10,22 +10,27 @@ struct Stack {
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Context {
|
||||
pub k_sp: usize,
|
||||
pub k_sp: usize, // 0x00
|
||||
pub ttbr0: usize, // 0x08
|
||||
|
||||
stack_base_phys: usize,
|
||||
stack_page_count: usize,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn kernel(entry: usize, arg: usize) -> Self {
|
||||
let mut stack = Stack::new(4);
|
||||
pub fn kernel(entry: usize, arg: usize, ttbr0: usize, ustack: usize) -> Self {
|
||||
let mut stack = Stack::new(8);
|
||||
|
||||
debugln!("STACK {:#x}, {:#x}", stack.bp, stack.bp + 8 * 4096);
|
||||
|
||||
stack.push(entry);
|
||||
stack.push(arg);
|
||||
stack.push(ttbr0);
|
||||
stack.push(ustack);
|
||||
|
||||
stack.push(__aa64_ctx_enter_kernel as usize); // x30/lr
|
||||
stack.push(0); // xzr
|
||||
stack.push(0); // x29
|
||||
stack.push(0); // x28
|
||||
stack.push(0); // x27
|
||||
stack.push(0); // x26
|
||||
stack.push(0); // x25
|
||||
@ -38,18 +43,19 @@ impl Context {
|
||||
|
||||
Self {
|
||||
k_sp: stack.sp,
|
||||
ttbr0,
|
||||
|
||||
stack_base_phys: stack.bp,
|
||||
stack_page_count: 4
|
||||
stack_page_count: 8
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn enter(&mut self) -> ! {
|
||||
pub unsafe extern "C" fn enter(&mut self) -> ! {
|
||||
__aa64_ctx_switch_to(self);
|
||||
panic!("This code should not run");
|
||||
}
|
||||
|
||||
pub unsafe fn switch(&mut self, to: &mut Context) {
|
||||
pub unsafe extern "C" fn switch(&mut self, to: &mut Context) {
|
||||
__aa64_ctx_switch(to, self);
|
||||
}
|
||||
}
|
||||
|
@ -2,39 +2,24 @@
|
||||
|
||||
use crate::arch::machine;
|
||||
use crate::dev::irq::{IntController, IrqContext};
|
||||
use cortex_a::registers::{ESR_EL1, FAR_EL1};
|
||||
use tock_registers::interfaces::Readable;
|
||||
|
||||
/// Trapped SIMD/FP functionality
|
||||
pub const EC_FP_TRAP: u64 = 0b000111;
|
||||
/// Data Abort at current EL
|
||||
pub const EC_DATA_ABORT_ELX: u64 = 0b100101;
|
||||
/// SVC instruction in AA64 state
|
||||
pub const EC_SVC_AA64: u64 = 0b010101;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct ExceptionFrame {
|
||||
x0: u64,
|
||||
x1: u64,
|
||||
x2: u64,
|
||||
x3: u64,
|
||||
x4: u64,
|
||||
x5: u64,
|
||||
x6: u64,
|
||||
x7: u64,
|
||||
x8: u64,
|
||||
x9: u64,
|
||||
x10: u64,
|
||||
x11: u64,
|
||||
x12: u64,
|
||||
x13: u64,
|
||||
x14: u64,
|
||||
x15: u64,
|
||||
x16: u64,
|
||||
x17: u64,
|
||||
x18: u64,
|
||||
x29: u64,
|
||||
x30: u64,
|
||||
elr: u64,
|
||||
esr: u64,
|
||||
far: u64,
|
||||
x: [u64; 32],
|
||||
spsr_el1: u64,
|
||||
elr_el1: u64,
|
||||
sp_el0: u64,
|
||||
ttbr0_el1: u64,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@ -58,42 +43,75 @@ const fn data_abort_access_size(iss: u64) -> &'static str {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn __aa64_exc_irq_handler() {
|
||||
extern "C" fn __aa64_exc_irq_handler(_exc: &mut ExceptionFrame) {
|
||||
unsafe {
|
||||
let ic = IrqContext::new();
|
||||
machine::intc().handle_pending_irqs(&ic);
|
||||
}
|
||||
}
|
||||
|
||||
fn dump_data_abort(esr: u64, far: u64) {
|
||||
let iss = esr & 0x1FFFFFF;
|
||||
debugln!("Data Abort:");
|
||||
|
||||
debug!(" Illegal {}", data_abort_access_type(iss),);
|
||||
if iss & (1 << 24) != 0 {
|
||||
debug!(" of a {}", data_abort_access_size(iss));
|
||||
}
|
||||
if iss & (1 << 10) == 0 {
|
||||
debug!(" at {:#018x}", far);
|
||||
} else {
|
||||
debug!(" at UNKNOWN");
|
||||
}
|
||||
debugln!("");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) {
|
||||
let err_code = exc.esr >> 26;
|
||||
let iss = exc.esr & 0x1FFFFFF;
|
||||
|
||||
debugln!("Unhandled exception at ELR={:#018x}", exc.elr);
|
||||
let esr = ESR_EL1.get();
|
||||
let err_code = esr >> 26;
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match err_code {
|
||||
EC_DATA_ABORT_ELX => {
|
||||
debugln!("Data Abort:");
|
||||
|
||||
debug!(" Illegal {}", data_abort_access_type(iss),);
|
||||
if iss & (1 << 24) != 0 {
|
||||
debug!(" of a {}", data_abort_access_size(iss));
|
||||
}
|
||||
if iss & (1 << 10) == 0 {
|
||||
debug!(" at {:#018x}", exc.far);
|
||||
} else {
|
||||
debug!(" at UNKNOWN");
|
||||
}
|
||||
debugln!("");
|
||||
let far = FAR_EL1.get();
|
||||
dump_data_abort(esr, far);
|
||||
}
|
||||
EC_SVC_AA64 => {
|
||||
debugln!("{:#x} {:#x}", exc.x[0], exc.x[1]);
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
debugln!("{:#018x?}", exc);
|
||||
debugln!(
|
||||
"Unhandled exception at ELR={:#018x}, ESR={:#010x}, exc ctx @ {:p}",
|
||||
exc.elr_el1,
|
||||
esr,
|
||||
exc
|
||||
);
|
||||
|
||||
if exc.sp_el0 == 0xFFFFFF50 {
|
||||
for i in 0..10 {
|
||||
debugln!("[{:#x}] {:#x}", exc.sp_el0 + i * 8, unsafe {
|
||||
core::ptr::read((exc.sp_el0 + i * 8) as *const u64)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
debugln!("{:#x?}", exc);
|
||||
|
||||
panic!("Unhandled exception");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn __aa64_exc_fiq_handler(_exc: &mut ExceptionFrame) {
|
||||
todo!();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn __aa64_exc_serror_handler(_exc: &mut ExceptionFrame) {
|
||||
todo!();
|
||||
}
|
||||
|
||||
global_asm!(include_str!("vectors.S"));
|
||||
|
@ -11,24 +11,34 @@ use crate::dev::{
|
||||
timer::TimestampSource,
|
||||
Device,
|
||||
};
|
||||
use crate::mem::phys;
|
||||
use error::Errno;
|
||||
|
||||
mod gpio;
|
||||
mod uart;
|
||||
mod rtc;
|
||||
mod uart;
|
||||
mod wdog;
|
||||
|
||||
pub use gic::IrqNumber;
|
||||
pub use gpio::PinAddress;
|
||||
use gpio::Gpio;
|
||||
use uart::Uart;
|
||||
pub use gpio::PinAddress;
|
||||
use rtc::Rtc;
|
||||
use uart::Uart;
|
||||
use wdog::RWdog;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn init_board_early() -> Result<(), Errno> {
|
||||
unsafe {
|
||||
UART0.enable()?;
|
||||
|
||||
phys::init_from_region(0x80000000, 0x10000000);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn init_board() -> Result<(), Errno> {
|
||||
unsafe {
|
||||
UART0.enable()?;
|
||||
GIC.enable()?;
|
||||
GPIO.enable()?;
|
||||
|
||||
@ -54,9 +64,11 @@ pub unsafe fn reset_board() -> ! {
|
||||
R_WDOG.reset_board()
|
||||
}
|
||||
|
||||
const LOCAL_TIMER_IRQ: IrqNumber = IrqNumber::new(30);
|
||||
const R_WDOG_BASE: usize = 0x07020400;
|
||||
const UART0_BASE: usize = 0x05000000;
|
||||
const RTC_BASE: usize = 0x07000000;
|
||||
const RTC_IRQ: IrqNumber = IrqNumber::new(133);
|
||||
const PIO_BASE: usize = 0x0300B000;
|
||||
const GICD_BASE: usize = 0x03021000;
|
||||
const GICC_BASE: usize = 0x03022000;
|
||||
@ -69,7 +81,7 @@ pub fn console() -> &'static impl SerialDevice {
|
||||
|
||||
/// Returns the timer used as CPU-local periodic IRQ source
|
||||
#[inline]
|
||||
pub fn local_timer() -> &'static impl TimestampSource {
|
||||
pub fn local_timer() -> &'static GenericTimer {
|
||||
&LOCAL_TIMER
|
||||
}
|
||||
|
||||
@ -81,7 +93,7 @@ pub fn intc() -> &'static impl IntController<IrqNumber = IrqNumber> {
|
||||
|
||||
static R_WDOG: RWdog = unsafe { RWdog::new(R_WDOG_BASE) };
|
||||
static UART0: Uart = unsafe { Uart::new(UART0_BASE, IrqNumber::new(32)) };
|
||||
static LOCAL_TIMER: GenericTimer = GenericTimer {};
|
||||
static LOCAL_TIMER: GenericTimer = GenericTimer::new(LOCAL_TIMER_IRQ);
|
||||
pub(super) static GPIO: Gpio = unsafe { Gpio::new(PIO_BASE) };
|
||||
static RTC: Rtc = unsafe { Rtc::new(RTC_BASE, IrqNumber::new(133)) };
|
||||
static GIC: Gic = unsafe { Gic::new(GICD_BASE, GICC_BASE) };
|
||||
static RTC: Rtc = unsafe { Rtc::new(RTC_BASE, RTC_IRQ) };
|
||||
static GIC: Gic = unsafe { Gic::new(GICD_BASE, GICC_BASE, LOCAL_TIMER_IRQ) };
|
||||
|
@ -4,10 +4,9 @@ use crate::arch::aarch64::{
|
||||
irq::gic::{self, Gic},
|
||||
timer::GenericTimer,
|
||||
};
|
||||
use crate::dev::timer::TimestampSource;
|
||||
use crate::dev::{
|
||||
irq::{IntController, IntSource},
|
||||
pci::{pcie::gpex::GenericPcieHost, PciHostDevice},
|
||||
pci::pcie::gpex::GenericPcieHost,
|
||||
rtc::pl031::Pl031,
|
||||
serial::{pl011::Pl011, SerialDevice},
|
||||
Device,
|
||||
|
@ -16,6 +16,9 @@ pub struct GenericTimer {
|
||||
irq: IrqNumber
|
||||
}
|
||||
|
||||
///
|
||||
pub const TIMER_TICK: u64 = 1000000;
|
||||
|
||||
impl Device for GenericTimer {
|
||||
fn name(&self) -> &'static str {
|
||||
"ARM Generic Timer"
|
||||
@ -29,7 +32,8 @@ impl Device for GenericTimer {
|
||||
|
||||
impl IntSource for GenericTimer {
|
||||
fn handle_irq(&self) -> Result<(), Errno> {
|
||||
CNTP_TVAL_EL0.set(10000);
|
||||
CNTP_TVAL_EL0.set(TIMER_TICK);
|
||||
CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET);
|
||||
use crate::proc;
|
||||
proc::switch();
|
||||
Ok(())
|
||||
@ -37,6 +41,7 @@ impl IntSource for GenericTimer {
|
||||
|
||||
fn init_irqs(&'static self) -> Result<(), Errno> {
|
||||
machine::intc().register_handler(self.irq, self)?;
|
||||
CNTP_TVAL_EL0.set(TIMER_TICK);
|
||||
machine::intc().enable_irq(self.irq)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,113 +1,126 @@
|
||||
.macro EXC_SAVE_CTX
|
||||
stp x0, x1, [sp, #0]
|
||||
stp x2, x3, [sp, #16]
|
||||
stp x4, x5, [sp, #32]
|
||||
stp x6, x7, [sp, #48]
|
||||
stp x8, x9, [sp, #64]
|
||||
stp x10, x11, [sp, #80]
|
||||
stp x12, x13, [sp, #96]
|
||||
stp x14, x15, [sp, #112]
|
||||
stp x16, x17, [sp, #128]
|
||||
stp x18, x29, [sp, #144]
|
||||
// vi:ft=a64asm:
|
||||
|
||||
mrs x0, elr_el1
|
||||
stp x30, x0, [sp, #160]
|
||||
.set PT_REGS_SIZE, (16 * 16 + 16 * 2)
|
||||
|
||||
.macro EXC_SAVE_STATE
|
||||
sub sp, sp, #PT_REGS_SIZE
|
||||
|
||||
// TODO only save all registers if doing fork()?
|
||||
stp x0, x1, [sp, #16 * 0]
|
||||
stp x2, x3, [sp, #16 * 1]
|
||||
stp x4, x5, [sp, #16 * 2]
|
||||
stp x6, x7, [sp, #16 * 3]
|
||||
stp x8, x9, [sp, #16 * 4]
|
||||
stp x10, x11, [sp, #16 * 5]
|
||||
stp x12, x13, [sp, #16 * 6]
|
||||
stp x14, x15, [sp, #16 * 7]
|
||||
stp x16, x17, [sp, #16 * 8]
|
||||
stp x18, x19, [sp, #16 * 9]
|
||||
stp x20, x21, [sp, #16 * 10]
|
||||
stp x22, x23, [sp, #16 * 11]
|
||||
stp x24, x25, [sp, #16 * 12]
|
||||
stp x26, x27, [sp, #16 * 13]
|
||||
stp x28, x29, [sp, #16 * 14]
|
||||
stp x30, x31, [sp, #16 * 15]
|
||||
|
||||
mrs x0, spsr_el1
|
||||
stp x0, xzr, [sp, #176]
|
||||
mrs x1, elr_el1
|
||||
mrs x2, sp_el0
|
||||
mrs x3, ttbr0_el1
|
||||
|
||||
stp x0, x1, [sp, #16 * 16]
|
||||
stp x2, x3, [sp, #16 * 17]
|
||||
.endm
|
||||
|
||||
.macro EXC_RESTORE_CTX
|
||||
ldp x30, x0, [sp, #160]
|
||||
msr elr_el1, x0
|
||||
ldp x0, xzr, [sp, #176]
|
||||
.macro EXC_RESTORE_STATE
|
||||
ldp x0, x1, [sp, #16 * 16]
|
||||
ldp x2, x3, [sp, #16 * 17]
|
||||
msr spsr_el1, x0
|
||||
msr elr_el1, x1
|
||||
msr sp_el0, x2
|
||||
msr ttbr0_el1, x3
|
||||
|
||||
ldp x0, x1, [sp, #0]
|
||||
ldp x2, x3, [sp, #16]
|
||||
ldp x4, x5, [sp, #32]
|
||||
ldp x6, x7, [sp, #48]
|
||||
ldp x8, x9, [sp, #64]
|
||||
ldp x10, x11, [sp, #80]
|
||||
ldp x12, x13, [sp, #96]
|
||||
ldp x14, x15, [sp, #112]
|
||||
ldp x16, x17, [sp, #128]
|
||||
ldp x18, x29, [sp, #144]
|
||||
ldp x0, x1, [sp, #16 * 0]
|
||||
ldp x2, x3, [sp, #16 * 1]
|
||||
ldp x4, x5, [sp, #16 * 2]
|
||||
ldp x6, x7, [sp, #16 * 3]
|
||||
ldp x8, x9, [sp, #16 * 4]
|
||||
ldp x10, x11, [sp, #16 * 5]
|
||||
ldp x12, x13, [sp, #16 * 6]
|
||||
ldp x14, x15, [sp, #16 * 7]
|
||||
ldp x16, x17, [sp, #16 * 8]
|
||||
ldp x18, x19, [sp, #16 * 9]
|
||||
ldp x20, x21, [sp, #16 * 10]
|
||||
ldp x22, x23, [sp, #16 * 11]
|
||||
ldp x24, x25, [sp, #16 * 12]
|
||||
ldp x26, x27, [sp, #16 * 13]
|
||||
ldp x28, x29, [sp, #16 * 14]
|
||||
ldp x30, x31, [sp, #16 * 15]
|
||||
|
||||
add sp, sp, #PT_REGS_SIZE
|
||||
.endm
|
||||
|
||||
.macro EXC_VECTOR el, ht, bits, kind
|
||||
.p2align 7
|
||||
b __aa\bits\()_el\el\ht\()_\kind
|
||||
.endm
|
||||
|
||||
.macro EXC_ENTRY_HANDLER el, ht, bits, kind
|
||||
__aa\bits\()_el\el\ht\()_\kind:
|
||||
.if \bits == 32
|
||||
// TODO AArch32?
|
||||
b .
|
||||
.endif
|
||||
|
||||
EXC_SAVE_STATE
|
||||
mov x0, sp
|
||||
mov lr, xzr
|
||||
bl __aa64_exc_\kind\()_handler
|
||||
EXC_RESTORE_STATE
|
||||
eret
|
||||
.endm
|
||||
|
||||
.section .text
|
||||
.global aa64_el1_vectors
|
||||
.p2align 12
|
||||
aa64_el1_vectors:
|
||||
.el1_sp_el0_sync:
|
||||
b .
|
||||
.p2align 7
|
||||
.el1_sp_el0_irq:
|
||||
b .
|
||||
.p2align 7
|
||||
.el1_sp_el0_fiq:
|
||||
b .
|
||||
.p2align 7
|
||||
.el1_sp_el0_serror:
|
||||
b .
|
||||
EXC_VECTOR 1, t, 64, sync
|
||||
EXC_VECTOR 1, t, 64, irq
|
||||
EXC_VECTOR 1, t, 64, fiq
|
||||
EXC_VECTOR 1, t, 64, serror
|
||||
|
||||
EXC_VECTOR 1, h, 64, sync
|
||||
EXC_VECTOR 1, h, 64, irq
|
||||
EXC_VECTOR 1, h, 64, fiq
|
||||
EXC_VECTOR 1, h, 64, serror
|
||||
|
||||
EXC_VECTOR 0, t, 64, sync
|
||||
EXC_VECTOR 0, t, 64, irq
|
||||
EXC_VECTOR 0, t, 64, fiq
|
||||
EXC_VECTOR 0, t, 64, serror
|
||||
|
||||
EXC_VECTOR 0, t, 32, sync
|
||||
EXC_VECTOR 0, t, 32, irq
|
||||
EXC_VECTOR 0, t, 32, fiq
|
||||
EXC_VECTOR 0, t, 32, serror
|
||||
|
||||
.p2align 7
|
||||
.el1_sp_el1_sync:
|
||||
sub sp, sp, #208
|
||||
EXC_ENTRY_HANDLER 1, t, 64, sync
|
||||
EXC_ENTRY_HANDLER 1, t, 64, irq
|
||||
EXC_ENTRY_HANDLER 1, t, 64, fiq
|
||||
EXC_ENTRY_HANDLER 1, t, 64, serror
|
||||
|
||||
EXC_SAVE_CTX
|
||||
EXC_ENTRY_HANDLER 1, h, 64, sync
|
||||
EXC_ENTRY_HANDLER 1, h, 64, irq
|
||||
EXC_ENTRY_HANDLER 1, h, 64, fiq
|
||||
EXC_ENTRY_HANDLER 1, h, 64, serror
|
||||
|
||||
mrs x0, esr_el1
|
||||
mrs x1, far_el1
|
||||
stp x0, x1, [sp, #192]
|
||||
EXC_ENTRY_HANDLER 0, t, 64, sync
|
||||
EXC_ENTRY_HANDLER 0, t, 64, irq
|
||||
EXC_ENTRY_HANDLER 0, t, 64, fiq
|
||||
EXC_ENTRY_HANDLER 0, t, 64, serror
|
||||
|
||||
mov x0, sp
|
||||
bl __aa64_exc_sync_handler
|
||||
|
||||
b .
|
||||
.p2align 7
|
||||
.el1_sp_el1_irq:
|
||||
sub sp, sp, #192
|
||||
|
||||
EXC_SAVE_CTX
|
||||
|
||||
mov x0, sp
|
||||
bl __aa64_exc_irq_handler
|
||||
|
||||
EXC_RESTORE_CTX
|
||||
|
||||
add sp, sp, #192
|
||||
eret
|
||||
|
||||
.p2align 7
|
||||
.el1_sp_el1_fiq:
|
||||
b .
|
||||
.p2align 7
|
||||
.el1_sp_el1_serror:
|
||||
b .
|
||||
|
||||
.p2align 7
|
||||
.el0_aa64_sync:
|
||||
b .
|
||||
.p2align 7
|
||||
.el0_aa64_irq:
|
||||
b .
|
||||
.p2align 7
|
||||
.el0_aa64_fiq:
|
||||
b .
|
||||
.p2align 7
|
||||
.el0_aa64_serror:
|
||||
b .
|
||||
|
||||
.p2align 7
|
||||
.el0_aa32_sync:
|
||||
b .
|
||||
.p2align 7
|
||||
.el0_aa32_irq:
|
||||
b .
|
||||
.p2align 7
|
||||
.el0_aa32_fiq:
|
||||
b .
|
||||
.p2align 7
|
||||
.el0_aa32_serror:
|
||||
b .
|
||||
EXC_ENTRY_HANDLER 0, t, 32, sync
|
||||
EXC_ENTRY_HANDLER 0, t, 32, irq
|
||||
EXC_ENTRY_HANDLER 0, t, 32, fiq
|
||||
EXC_ENTRY_HANDLER 0, t, 32, serror
|
||||
|
@ -16,9 +16,9 @@ pub fn virtualize(addr: usize) -> usize {
|
||||
///
|
||||
pub fn kernel_end_phys() -> usize {
|
||||
extern "C" {
|
||||
static __kernel_end_phys: u8;
|
||||
static __kernel_end: u8;
|
||||
}
|
||||
unsafe { &__kernel_end_phys as *const _ as usize }
|
||||
unsafe { &__kernel_end as *const _ as usize - KERNEL_OFFSET }
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -2,8 +2,8 @@ use crate::mem::PAGE_SIZE;
|
||||
use core::mem::size_of;
|
||||
use error::Errno;
|
||||
|
||||
mod reserved;
|
||||
mod manager;
|
||||
mod reserved;
|
||||
|
||||
use manager::{Manager, SimpleManager, MANAGER};
|
||||
pub use reserved::ReservedRegion;
|
||||
@ -17,12 +17,14 @@ pub enum PageUsage {
|
||||
Reserved,
|
||||
Available,
|
||||
Kernel,
|
||||
KernelHeap
|
||||
KernelHeap,
|
||||
Paging,
|
||||
UserStack,
|
||||
}
|
||||
|
||||
pub struct PageInfo {
|
||||
refcount: usize,
|
||||
usage: PageUsage
|
||||
usage: PageUsage,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -49,13 +51,18 @@ impl Iterator for SimpleMemoryIterator {
|
||||
}
|
||||
|
||||
pub fn alloc_contiguous_pages(pu: PageUsage, count: usize) -> Result<usize, Errno> {
|
||||
MANAGER.lock().as_mut().unwrap().alloc_contiguous_pages(pu, count)
|
||||
MANAGER
|
||||
.lock()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.alloc_contiguous_pages(pu, count)
|
||||
}
|
||||
|
||||
fn find_contiguous<T: Iterator<Item = MemoryRegion>>(
|
||||
iter: T,
|
||||
count: usize,
|
||||
) -> Option<usize> {
|
||||
pub fn alloc_page(pu: PageUsage) -> Result<usize, Errno> {
|
||||
MANAGER.lock().as_mut().unwrap().alloc_page(pu)
|
||||
}
|
||||
|
||||
fn find_contiguous<T: Iterator<Item = MemoryRegion>>(iter: T, count: usize) -> Option<usize> {
|
||||
for region in iter {
|
||||
let mut collected = 0;
|
||||
let mut base_addr = None;
|
||||
@ -84,7 +91,7 @@ pub unsafe fn init_from_iter<T: Iterator<Item = MemoryRegion> + Clone>(iter: T)
|
||||
mem_base = reg.start;
|
||||
}
|
||||
}
|
||||
debugln!("Memory base is {:?}", mem_base);
|
||||
debugln!("Memory base is {:#x}", mem_base);
|
||||
// Step 1. Count available memory
|
||||
let mut total_pages = 0usize;
|
||||
for reg in iter.clone() {
|
||||
@ -118,7 +125,7 @@ pub unsafe fn init_from_iter<T: Iterator<Item = MemoryRegion> + Clone>(iter: T)
|
||||
pub unsafe fn init_from_region(base: usize, size: usize) {
|
||||
let iter = SimpleMemoryIterator::new(MemoryRegion {
|
||||
start: base,
|
||||
end: base + size
|
||||
end: base + size,
|
||||
});
|
||||
|
||||
init_from_iter(iter);
|
||||
|
@ -35,7 +35,7 @@ static mut RESERVED_REGIONS_HEAD: *mut ReservedRegion = null_mut();
|
||||
static mut RESERVED_REGION_KERNEL: MaybeUninit<ReservedRegion> = MaybeUninit::uninit();
|
||||
static mut RESERVED_REGION_PAGES: MaybeUninit<ReservedRegion> = MaybeUninit::uninit();
|
||||
pub unsafe fn reserve(usage: &str, region: *mut ReservedRegion) {
|
||||
debugln!("Reserving {:?} region: {:?}..{:?}", usage, (*region).start, (*region).end);
|
||||
debugln!("Reserving {:?} region: {:#x}..{:#x}", usage, (*region).start, (*region).end);
|
||||
(*region).next = RESERVED_REGIONS_HEAD;
|
||||
RESERVED_REGIONS_HEAD = region;
|
||||
}
|
||||
|
@ -1,21 +1,28 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use crate::mem::KERNEL_OFFSET;
|
||||
use crate::mem::{
|
||||
self,
|
||||
phys::{self, PageUsage},
|
||||
KERNEL_OFFSET,
|
||||
};
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::Deref;
|
||||
use cortex_a::asm::barrier::{self, dsb, isb};
|
||||
use cortex_a::registers::{TCR_EL1, TTBR0_EL1};
|
||||
use cortex_a::registers::TTBR0_EL1;
|
||||
use error::Errno;
|
||||
use tock_registers::interfaces::{ReadWriteable, Writeable};
|
||||
use tock_registers::interfaces::Writeable;
|
||||
|
||||
const PTE_BLOCK_AF: u64 = 1 << 10;
|
||||
const PTE_BLOCK_OSH: u64 = 2 << 8;
|
||||
const PTE_TABLE: u64 = 1 << 1;
|
||||
const PTE_PRESENT: u64 = 1 << 0;
|
||||
const PTE_ATTR1: u64 = 1 << 2;
|
||||
const PTE_BLOCK_NG: u64 = 1 << 11;
|
||||
|
||||
#[repr(C, align(0x1000))]
|
||||
struct Table([u64; 512]);
|
||||
pub struct Table([u64; 512]);
|
||||
|
||||
pub use Table as Space;
|
||||
|
||||
#[no_mangle]
|
||||
static mut KERNEL_TTBR1: Table = Table([0; 512]);
|
||||
@ -42,6 +49,100 @@ pub struct DeviceMemoryIo<T> {
|
||||
_0: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl Table {
|
||||
pub fn empty() -> Result<&'static mut Self, Errno> {
|
||||
let phys = phys::alloc_page(PageUsage::Paging)?;
|
||||
let virt = mem::virtualize(phys);
|
||||
let res = unsafe { &mut *(virt as *mut Self) };
|
||||
res.0.fill(0);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn dump(&self) {
|
||||
debugln!("Paging table dump:");
|
||||
for l0i in 0usize..512 {
|
||||
let l0e = self.0[l0i];
|
||||
if l0e & PTE_PRESENT == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let l1_phys = (l0e & 0xfffffffff000) as usize;
|
||||
let l1t = unsafe { &mut *(mem::virtualize(l1_phys) as *mut Self) };
|
||||
|
||||
for l1i in 0usize..512 {
|
||||
let l1e = l1t.0[l1i];
|
||||
if l1e & PTE_PRESENT == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let l2_phys = (l1e & 0xfffffffff000) as usize;
|
||||
let l2t = unsafe { &mut *(mem::virtualize(l2_phys) as *mut Self) };
|
||||
|
||||
for l2i in 0usize..512 {
|
||||
let l2e = l2t.0[l2i];
|
||||
if l2e & PTE_PRESENT == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let virt = (l0i << 30) | (l1i << 21) | (l2i << 12);
|
||||
debugln!("{:#x} -> {:#x}", virt, l2e & 0xfffffffff000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn map(&mut self, virt: usize, phys: usize) -> Result<(), Errno> {
|
||||
let l0i = virt >> 30;
|
||||
let l1i = (virt >> 21) & 0x1FF;
|
||||
let l2i = (virt >> 12) & 0x1FF;
|
||||
|
||||
debugln!("l0i = {}, l1i = {}, l2i = {}", l0i, l1i, l2i);
|
||||
|
||||
let l0e = self.0[l0i];
|
||||
let l1_phys = if l0e & PTE_PRESENT != 0 {
|
||||
assert!(l0e & PTE_TABLE != 0);
|
||||
(l0e & 0xfffffffff000) as usize
|
||||
} else {
|
||||
let page = phys::alloc_page(PageUsage::Paging)?;
|
||||
self.0[l0i] = (page as u64) | (PTE_PRESENT | PTE_TABLE);
|
||||
|
||||
let virt = mem::virtualize(phys);
|
||||
let res = &mut *(virt as *mut Self);
|
||||
res.0.fill(0);
|
||||
page
|
||||
};
|
||||
let l1t = &mut *(mem::virtualize(l1_phys) as *mut Self);
|
||||
|
||||
let l1e = l1t.0[l1i];
|
||||
let l2_phys = if l1e & PTE_PRESENT != 0 {
|
||||
assert!(l1e & PTE_TABLE != 0);
|
||||
(l1e & 0xfffffffff000) as usize
|
||||
} else {
|
||||
let page = phys::alloc_page(PageUsage::Paging)?;
|
||||
l1t.0[l1i] = (page as u64) | (PTE_PRESENT | PTE_TABLE);
|
||||
|
||||
let virt = mem::virtualize(phys);
|
||||
let res = &mut *(virt as *mut Self);
|
||||
res.0.fill(0);
|
||||
page
|
||||
};
|
||||
let l2t = &mut *(mem::virtualize(l2_phys) as *mut Self);
|
||||
|
||||
if l2t.0[l2i] & PTE_PRESENT != 0 {
|
||||
panic!(
|
||||
"Page is already mapped: {:#x} (tried {:#x}, got {:#x})",
|
||||
virt, phys, l2t.0[l2i]
|
||||
);
|
||||
}
|
||||
|
||||
debugln!("{:p} map {:#x} -> {:#x}", self, virt, phys);
|
||||
l2t.0[l2i] =
|
||||
(phys as u64) | (PTE_BLOCK_NG | PTE_PRESENT | PTE_TABLE | PTE_BLOCK_OSH | PTE_BLOCK_AF);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceMemory {
|
||||
#[inline(always)]
|
||||
pub const fn base(&self) -> usize {
|
||||
@ -117,7 +218,7 @@ impl DeviceMemory {
|
||||
Self {
|
||||
name: self.name,
|
||||
base: self.base,
|
||||
count: self.count
|
||||
count: self.count,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -163,7 +264,7 @@ pub fn enable() -> Result<(), Errno> {
|
||||
|
||||
// Disable lower-half translation
|
||||
TTBR0_EL1.set(0);
|
||||
TCR_EL1.modify(TCR_EL1::EPD0::SET);
|
||||
//TCR_EL1.modify(TCR_EL1::EPD0::SET);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,19 +1,25 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use crate::mem::{
|
||||
self,
|
||||
phys::{self, PageUsage},
|
||||
virt::Space,
|
||||
};
|
||||
use crate::sync::IrqSafeNullLock;
|
||||
use crate::util::InitOnce;
|
||||
use alloc::collections::{BTreeMap, VecDeque};
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::{RefCell, UnsafeCell};
|
||||
use core::mem::MaybeUninit;
|
||||
use core::cell::UnsafeCell;
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
pub use crate::arch::platform::context::{self, Context};
|
||||
|
||||
pub type ProcessRef = Rc<UnsafeCell<Process>>;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Process {
|
||||
ctx: Context,
|
||||
space: &'static mut Space,
|
||||
id: u32,
|
||||
}
|
||||
|
||||
@ -29,12 +35,35 @@ pub struct Scheduler {
|
||||
}
|
||||
|
||||
impl SchedulerInner {
|
||||
fn new_kernel(&mut self, entry: extern "C" fn(usize) -> !, arg: usize) -> u32 {
|
||||
fn new_kernel(&mut self, entry: usize, arg: usize) -> u32 {
|
||||
static LAST_PID: AtomicU32 = AtomicU32::new(0);
|
||||
const USTACK_PAGE_COUNT: usize = 8;
|
||||
const USTACK_VIRT_TOP: usize = 0x100000000;
|
||||
const USTACK_VIRT_BASE: usize = USTACK_VIRT_TOP - USTACK_PAGE_COUNT * mem::PAGE_SIZE;
|
||||
|
||||
let id = LAST_PID.fetch_add(1, Ordering::Relaxed);
|
||||
if id == 256 {
|
||||
panic!("Ran out of ASIDs (TODO FIXME)");
|
||||
}
|
||||
let space = Space::empty().unwrap();
|
||||
|
||||
unsafe {
|
||||
for i in 0..USTACK_PAGE_COUNT {
|
||||
let page = phys::alloc_page(PageUsage::Kernel).unwrap();
|
||||
space
|
||||
.map(USTACK_VIRT_BASE + i * mem::PAGE_SIZE, page)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let proc = Process {
|
||||
ctx: Context::kernel(entry as usize, arg),
|
||||
ctx: Context::kernel(
|
||||
entry,
|
||||
arg,
|
||||
((space as *mut _ as usize) - mem::KERNEL_OFFSET) | ((id as usize) << 56),
|
||||
USTACK_VIRT_TOP,
|
||||
),
|
||||
space,
|
||||
id,
|
||||
};
|
||||
debugln!("Created kernel process with PID {}", id);
|
||||
@ -55,14 +84,14 @@ impl SchedulerInner {
|
||||
current: None,
|
||||
};
|
||||
|
||||
this.idle = this.new_kernel(idle_fn, 0);
|
||||
this.idle = this.new_kernel(idle_fn as usize, 0);
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheduler {
|
||||
pub fn new_kernel(&self, entry: extern "C" fn(usize) -> !, arg: usize) -> u32 {
|
||||
pub fn new_kernel(&self, entry: usize, arg: usize) -> u32 {
|
||||
self.inner.get().lock().new_kernel(entry, arg)
|
||||
}
|
||||
|
||||
@ -74,15 +103,6 @@ impl Scheduler {
|
||||
self.inner.get().lock().queue.push_back(pid);
|
||||
}
|
||||
|
||||
pub fn current(&self) -> Option<ProcessRef> {
|
||||
let mut inner = self.inner.get().lock();
|
||||
inner
|
||||
.current
|
||||
.as_ref()
|
||||
.and_then(|id| inner.processes.get(id))
|
||||
.map(|r| r.clone())
|
||||
}
|
||||
|
||||
pub unsafe fn enter(&self) -> ! {
|
||||
let thread = {
|
||||
let mut inner = self.inner.get().lock();
|
||||
@ -114,7 +134,7 @@ impl Scheduler {
|
||||
inner.current = Some(next);
|
||||
(
|
||||
inner.processes.get(¤t).unwrap().clone(),
|
||||
inner.processes.get(&next).unwrap().clone()
|
||||
inner.processes.get(&next).unwrap().clone(),
|
||||
)
|
||||
};
|
||||
|
||||
@ -131,10 +151,21 @@ extern "C" fn idle_fn(_a: usize) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
extern "C" fn f1(u: usize) {
|
||||
let mut x = u;
|
||||
while x != 0 {
|
||||
x -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
extern "C" fn f0(a: usize) -> ! {
|
||||
debugln!("Thread #{} started", a);
|
||||
loop {
|
||||
debug!("{}", a);
|
||||
unsafe {
|
||||
asm!("svc #0", in("x0") a, in("x1") &a);
|
||||
}
|
||||
f1(1000000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,13 +174,13 @@ pub fn switch() {
|
||||
}
|
||||
|
||||
static SCHED: Scheduler = Scheduler {
|
||||
inner: InitOnce::new()
|
||||
inner: InitOnce::new(),
|
||||
};
|
||||
|
||||
pub unsafe fn enter() -> ! {
|
||||
SCHED.init();
|
||||
for i in 0..10 {
|
||||
SCHED.enqueue(SCHED.new_kernel(f0, i));
|
||||
SCHED.enqueue(SCHED.new_kernel(f0 as usize, i));
|
||||
}
|
||||
SCHED.enter();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user