feat: working el1t multitasking

This commit is contained in:
Mark Poliakov 2021-10-15 23:47:53 +03:00
parent 3130119419
commit 4d9f2971d9
14 changed files with 413 additions and 212 deletions

View File

@ -41,4 +41,5 @@ SECTIONS {
PROVIDE(__bss_end_phys = . - KERNEL_OFFSET);
PROVIDE(__kernel_end = .);
PROVIDE(__kernel_end_phys = . - KERNEL_OFFSET);
}

View File

@ -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]

View File

@ -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

View File

@ -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);
}
}

View File

@ -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"));

View File

@ -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) };

View File

@ -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,

View File

@ -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(())
}

View File

@ -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

View File

@ -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 }
}
///

View File

@ -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);

View File

@ -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;
}

View File

@ -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(())
}

View File

@ -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(&current).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();
}