Context switch
This commit is contained in:
@@ -107,6 +107,11 @@ impl<T: AddressSpace> VirtualAddress<T> {
|
||||
core::slice::from_raw_parts_mut(self.0 as *mut _, count)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn as_mut_ptr<U>(self) -> *mut U {
|
||||
self.0 as *mut U
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn as_mut<U>(self) -> &'static mut U {
|
||||
&mut *(self.0 as *mut U)
|
||||
|
||||
+1
-1
@@ -2,5 +2,5 @@
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum Errno {
|
||||
|
||||
OutOfMemory
|
||||
}
|
||||
|
||||
@@ -30,5 +30,7 @@ struct ExceptionContext {
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn exc_handler(context: ExceptionContext) -> ! {
|
||||
debug!("Unhandled exception");
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
+2
-7
@@ -8,11 +8,10 @@ pub mod debug;
|
||||
pub mod arch;
|
||||
pub mod boot;
|
||||
pub mod mem;
|
||||
pub mod proc;
|
||||
|
||||
pub use mem::KernelSpace;
|
||||
|
||||
use core::fmt::{self, Write};
|
||||
|
||||
use address::PhysicalAddress;
|
||||
use mem::phys::UsableMemory;
|
||||
#[derive(Clone)]
|
||||
@@ -45,11 +44,7 @@ extern "C" fn kernel_main() -> ! {
|
||||
mem::phys::initialize(iter);
|
||||
}
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
llvm_asm!("wfe");
|
||||
}
|
||||
}
|
||||
proc::enter();
|
||||
}
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
use super::{PageInfo, PageUsage};
|
||||
use crate::KernelSpace;
|
||||
use crate::{KernelSpace, mem::PAGE_SIZE};
|
||||
use address::{PhysicalAddress, VirtualAddress};
|
||||
use core::mem::{self, MaybeUninit};
|
||||
use error::Errno;
|
||||
use spin::Mutex;
|
||||
|
||||
pub unsafe trait Manager {
|
||||
fn alloc_page(&mut self) -> Result<PhysicalAddress, Errno>;
|
||||
fn alloc_contiguous_pages(&mut self, count: usize) -> Result<PhysicalAddress, Errno>;
|
||||
fn alloc_page(&mut self, pu: PageUsage) -> Result<PhysicalAddress, Errno>;
|
||||
fn alloc_contiguous_pages(
|
||||
&mut self,
|
||||
pu: PageUsage,
|
||||
count: usize,
|
||||
) -> Result<PhysicalAddress, Errno>;
|
||||
fn free_page(&mut self, page: PhysicalAddress) -> Result<(), Errno>;
|
||||
|
||||
// TODO status()
|
||||
@@ -48,11 +52,40 @@ impl SimpleManager {
|
||||
}
|
||||
|
||||
unsafe impl Manager for SimpleManager {
|
||||
fn alloc_page(&mut self) -> Result<PhysicalAddress, Errno> {
|
||||
todo!()
|
||||
fn alloc_page(&mut self, pu: PageUsage) -> Result<PhysicalAddress, Errno> {
|
||||
for index in 0..self.pages.len() {
|
||||
let mut page = self.pages[index].lock();
|
||||
|
||||
if page.usage == PageUsage::Available {
|
||||
page.usage = pu;
|
||||
page.refcount = 1;
|
||||
return Ok(PhysicalAddress::from(index * PAGE_SIZE));
|
||||
}
|
||||
}
|
||||
Err(Errno::OutOfMemory)
|
||||
}
|
||||
fn alloc_contiguous_pages(&mut self, _count: usize) -> Result<PhysicalAddress, Errno> {
|
||||
todo!()
|
||||
fn alloc_contiguous_pages(
|
||||
&mut self,
|
||||
pu: PageUsage,
|
||||
count: usize,
|
||||
) -> Result<PhysicalAddress, Errno> {
|
||||
'l0: for i in 0..self.pages.len() {
|
||||
for j in 0..count {
|
||||
if self.pages[i + j].lock().usage != PageUsage::Available {
|
||||
continue 'l0;
|
||||
}
|
||||
}
|
||||
|
||||
for j in 0..count {
|
||||
let mut page = self.pages[i + j].lock();
|
||||
assert!(page.usage == PageUsage::Available);
|
||||
page.usage = pu;
|
||||
page.refcount = 1;
|
||||
}
|
||||
|
||||
return Ok(PhysicalAddress::from(i * PAGE_SIZE));
|
||||
}
|
||||
Err(Errno::OutOfMemory)
|
||||
}
|
||||
fn free_page(&mut self, _page: PhysicalAddress) -> Result<(), Errno> {
|
||||
todo!()
|
||||
|
||||
@@ -14,7 +14,7 @@ pub use pbox::PhysBox;
|
||||
|
||||
type ManagerImpl = SimpleManager;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum PageUsage {
|
||||
Reserved,
|
||||
Available,
|
||||
@@ -34,16 +34,16 @@ pub struct UsableMemory {
|
||||
|
||||
const MAX_PAGES: usize = 1024;
|
||||
|
||||
pub fn alloc_page() -> Result<PhysicalAddress, Errno> {
|
||||
MANAGER.lock().as_mut().unwrap().alloc_page()
|
||||
pub fn alloc_page(pu: PageUsage) -> Result<PhysicalAddress, Errno> {
|
||||
MANAGER.lock().as_mut().unwrap().alloc_page(pu)
|
||||
}
|
||||
|
||||
pub fn alloc_contiguous_pages(count: usize) -> Result<PhysicalAddress, Errno> {
|
||||
pub fn alloc_contiguous_pages(pu: PageUsage, count: usize) -> Result<PhysicalAddress, Errno> {
|
||||
MANAGER
|
||||
.lock()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.alloc_contiguous_pages(count)
|
||||
.alloc_contiguous_pages(pu, count)
|
||||
}
|
||||
|
||||
pub fn free_page(page: PhysicalAddress) -> Result<(), Errno> {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use super::PageUsage;
|
||||
use address::PhysicalAddress;
|
||||
use error::Errno;
|
||||
|
||||
@@ -7,10 +8,10 @@ pub struct PhysBox {
|
||||
}
|
||||
|
||||
impl PhysBox {
|
||||
pub fn new() -> Result<Self, Errno> {
|
||||
pub fn new(pu: PageUsage) -> Result<Self, Errno> {
|
||||
Ok(Self {
|
||||
base: super::alloc_page()?,
|
||||
count: 1
|
||||
base: super::alloc_page(pu)?,
|
||||
count: 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
.section .text
|
||||
context_enter_kernel:
|
||||
ldp x0, xzr, [sp, #0]
|
||||
ldp lr, x1, [sp, #16]
|
||||
mov sp, x1
|
||||
ret
|
||||
|
||||
context_switch:
|
||||
// Store old callee-saved regs on stack
|
||||
sub sp, sp, #96
|
||||
|
||||
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]
|
||||
|
||||
// Store old stack pointer
|
||||
mov x19, sp
|
||||
str x19, [x1]
|
||||
context_switch_to:
|
||||
// Load new stack
|
||||
ldr x0, [x0]
|
||||
mov sp, x0
|
||||
|
||||
// Load new callee-saved regs on stack
|
||||
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
|
||||
|
||||
// Simulate/perform a return
|
||||
ret
|
||||
@@ -0,0 +1,101 @@
|
||||
use crate::{
|
||||
mem::phys::{self, PageUsage},
|
||||
KernelSpace,
|
||||
};
|
||||
use address::VirtualAddress;
|
||||
use core::mem::{size_of, MaybeUninit};
|
||||
|
||||
global_asm!(include_str!("context.S"));
|
||||
|
||||
#[repr(C)]
|
||||
struct Context {
|
||||
kernel_sp: VirtualAddress<KernelSpace>,
|
||||
}
|
||||
|
||||
struct Stack {
|
||||
bp: VirtualAddress<KernelSpace>,
|
||||
sp: VirtualAddress<KernelSpace>,
|
||||
tp: VirtualAddress<KernelSpace>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
fn new_kernel(entry: usize, arg: usize) -> Context {
|
||||
let kstack_phys = phys::alloc_contiguous_pages(PageUsage::Kernel, 4).unwrap();
|
||||
let mut stack = unsafe { Stack::new(kstack_phys.into(), 4096 * 4) };
|
||||
|
||||
stack.push(stack.tp); // popped into stack register before ERET
|
||||
stack.push(entry); // ELR before ERET
|
||||
stack.push(0usize); // padding
|
||||
stack.push(arg);
|
||||
|
||||
stack.push(context_enter_kernel as usize); // x30 LR
|
||||
stack.push(0usize); // padding
|
||||
stack.push(0usize); // x29
|
||||
stack.push(0usize); // x27
|
||||
stack.push(0usize); // x26
|
||||
stack.push(0usize); // x25
|
||||
stack.push(0usize); // x24
|
||||
stack.push(0usize); // x23
|
||||
stack.push(0usize); // x22
|
||||
stack.push(0usize); // x21
|
||||
stack.push(0usize); // x20
|
||||
stack.push(0usize); // x19
|
||||
|
||||
Context {
|
||||
kernel_sp: stack.sp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
pub unsafe fn new(bp: VirtualAddress<KernelSpace>, size: usize) -> Stack {
|
||||
Stack {
|
||||
bp,
|
||||
sp: bp + size,
|
||||
tp: bp + size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push<A: Into<usize>>(&mut self, value: A) {
|
||||
if self.sp == self.bp {
|
||||
panic!("Stack overflow");
|
||||
}
|
||||
self.sp -= size_of::<usize>();
|
||||
unsafe {
|
||||
core::ptr::write(self.sp.as_mut_ptr(), value.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn context_switch_to(dst: *mut Context);
|
||||
fn context_switch(dst: *mut Context, src: *mut Context);
|
||||
|
||||
fn context_enter_kernel();
|
||||
}
|
||||
|
||||
fn f0(arg: usize) {
|
||||
loop {
|
||||
unsafe {
|
||||
debug!("{}", arg);
|
||||
if arg == 0 {
|
||||
context_switch(C1.as_mut_ptr(), C0.as_mut_ptr());
|
||||
} else {
|
||||
context_switch(C0.as_mut_ptr(), C1.as_mut_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static mut C0: MaybeUninit<Context> = MaybeUninit::uninit();
|
||||
static mut C1: MaybeUninit<Context> = MaybeUninit::uninit();
|
||||
|
||||
pub fn enter() -> ! {
|
||||
unsafe {
|
||||
C0.write(Context::new_kernel(f0 as usize, 0));
|
||||
C1.write(Context::new_kernel(f0 as usize, 1));
|
||||
|
||||
context_switch_to(C0.as_mut_ptr());
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
Reference in New Issue
Block a user