396 lines
9.0 KiB
Rust
396 lines
9.0 KiB
Rust
use core::{arch::global_asm, cell::UnsafeCell, marker::PhantomData};
|
|
|
|
use kernel_arch_interface::{
|
|
mem::{KernelTableManager, PhysicalMemoryAllocator},
|
|
task::{StackBuilder, TaskContext, TaskFrame, UserContextInfo},
|
|
};
|
|
use libk_mm_interface::address::{AsPhysicalAddress, PhysicalAddress};
|
|
use tock_registers::interfaces::Writeable;
|
|
use yggdrasil_abi::{arch::SavedFrame, error::Error};
|
|
|
|
use crate::{gdt::TSS, mem::KERNEL_TABLES, registers::CR3};
|
|
|
|
#[repr(C)]
|
|
pub struct ExceptionFrame {
|
|
pub eax: u32,
|
|
pub ecx: u32,
|
|
pub edx: u32,
|
|
pub ebx: u32,
|
|
pub ebp: u32,
|
|
pub esi: u32,
|
|
pub edi: u32,
|
|
|
|
pub exc_number: u32,
|
|
pub exc_code: u32,
|
|
|
|
pub eip: u32,
|
|
pub cs: u32,
|
|
pub eflags: u32,
|
|
esp: u32,
|
|
ss: u32,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
#[repr(C)]
|
|
pub struct SyscallFrame {
|
|
pub eax: usize,
|
|
// ebx, ecx, edx, esi, edi, ebp
|
|
pub args: [usize; 6],
|
|
|
|
pub eip: u32,
|
|
pub cs: u32,
|
|
pub eflags: u32,
|
|
pub esp: u32,
|
|
pub ss: u32,
|
|
}
|
|
|
|
#[repr(C)]
|
|
pub struct InterruptFrame {
|
|
pub eax: u32,
|
|
pub ecx: u32,
|
|
pub edx: u32,
|
|
pub ebx: u32,
|
|
pub ebp: u32,
|
|
pub esi: u32,
|
|
pub edi: u32,
|
|
|
|
pub irq_number: u32,
|
|
|
|
pub eip: u32,
|
|
pub cs: u32,
|
|
pub eflags: u32,
|
|
esp: u32,
|
|
ss: u32,
|
|
}
|
|
|
|
#[repr(C, align(0x10))]
|
|
struct Inner {
|
|
// 0x00
|
|
sp: usize,
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub struct TaskContextImpl<
|
|
K: KernelTableManager,
|
|
PA: PhysicalMemoryAllocator<Address = PhysicalAddress>,
|
|
> {
|
|
inner: UnsafeCell<Inner>,
|
|
stack_base_phys: PhysicalAddress,
|
|
stack_size: usize,
|
|
|
|
cr3: u32,
|
|
tss_esp0: u32,
|
|
|
|
_pd: PhantomData<(K, PA)>,
|
|
}
|
|
|
|
impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddress>>
|
|
TaskContext<K, PA> for TaskContextImpl<K, PA>
|
|
{
|
|
const SIGNAL_STACK_EXTRA_ALIGN: usize = 0;
|
|
const USER_STACK_EXTRA_ALIGN: usize = 0;
|
|
|
|
fn user(context: UserContextInfo) -> Result<Self, Error> {
|
|
const USER_TASK_PAGES: usize = 8;
|
|
|
|
let stack_base_phys = PA::allocate_contiguous_pages(USER_TASK_PAGES)?;
|
|
let stack_base = stack_base_phys.raw_virtualize::<K>();
|
|
|
|
let mut stack = StackBuilder::new(stack_base, USER_TASK_PAGES * 0x1000);
|
|
|
|
stack.push(0x200);
|
|
stack.push(context.entry as _);
|
|
stack.push(context.stack_pointer);
|
|
|
|
setup_common_context(&mut stack, __i686_task_enter_user as _);
|
|
|
|
let sp = stack.build();
|
|
let esp0 = stack_base + USER_TASK_PAGES * 0x1000;
|
|
|
|
Ok(Self {
|
|
inner: UnsafeCell::new(Inner { sp }),
|
|
stack_base_phys,
|
|
stack_size: USER_TASK_PAGES * 0x1000,
|
|
|
|
tss_esp0: esp0 as _,
|
|
cr3: context.address_space.try_into().unwrap(),
|
|
|
|
_pd: PhantomData,
|
|
})
|
|
}
|
|
|
|
fn kernel(
|
|
entry: extern "C" fn(usize) -> !,
|
|
arg: usize,
|
|
) -> Result<Self, yggdrasil_abi::error::Error> {
|
|
const KERNEL_TASK_PAGES: usize = 32;
|
|
|
|
let stack_base_phys = PA::allocate_contiguous_pages(KERNEL_TASK_PAGES)?;
|
|
let stack_base = stack_base_phys.raw_virtualize::<K>();
|
|
|
|
let mut stack = StackBuilder::new(stack_base, KERNEL_TASK_PAGES * 0x1000);
|
|
|
|
// Entry and argument
|
|
stack.push(entry as _);
|
|
stack.push(arg);
|
|
|
|
// XXX
|
|
setup_common_context(&mut stack, __i686_task_enter_kernel as _);
|
|
|
|
let sp = stack.build();
|
|
|
|
// TODO stack is leaked
|
|
|
|
Ok(Self {
|
|
inner: UnsafeCell::new(Inner { sp }),
|
|
stack_base_phys,
|
|
stack_size: KERNEL_TASK_PAGES * 0x1000,
|
|
|
|
tss_esp0: 0,
|
|
cr3: unsafe { KERNEL_TABLES.as_physical_address() }
|
|
.try_into_u32()
|
|
.unwrap(),
|
|
|
|
_pd: PhantomData,
|
|
})
|
|
}
|
|
|
|
unsafe fn switch(&self, from: &Self) {
|
|
let dst = self.inner.get();
|
|
let src = from.inner.get();
|
|
|
|
if dst != src {
|
|
TSS.esp0 = self.tss_esp0;
|
|
CR3.set(self.cr3);
|
|
|
|
__i686_switch_task(dst, src);
|
|
}
|
|
}
|
|
|
|
unsafe fn enter(&self) -> ! {
|
|
TSS.esp0 = self.tss_esp0;
|
|
CR3.set(self.cr3);
|
|
|
|
__i686_enter_task(self.inner.get())
|
|
}
|
|
|
|
unsafe fn switch_and_drop(&self, thread: *const ()) {
|
|
TSS.esp0 = self.tss_esp0;
|
|
CR3.set(self.cr3);
|
|
|
|
__i686_switch_and_drop(self.inner.get(), thread)
|
|
}
|
|
}
|
|
|
|
fn setup_common_context(builder: &mut StackBuilder, entry: usize) {
|
|
builder.push(entry);
|
|
|
|
builder.push(0); // %edi
|
|
builder.push(0); // %esi
|
|
builder.push(0); // %ebp
|
|
builder.push(0); // %ebx
|
|
}
|
|
|
|
extern "C" {
|
|
fn __i686_task_enter_kernel();
|
|
fn __i686_task_enter_user();
|
|
fn __i686_task_enter_from_fork();
|
|
fn __i686_enter_task(to: *mut Inner) -> !;
|
|
fn __i686_switch_task(to: *mut Inner, from: *mut Inner);
|
|
fn __i686_switch_and_drop(to: *mut Inner, from: *const ());
|
|
}
|
|
|
|
impl TaskFrame for SyscallFrame {
|
|
fn store(&self) -> SavedFrame {
|
|
SavedFrame {
|
|
eax: self.eax as _,
|
|
ecx: self.args[1] as _,
|
|
edx: self.args[2] as _,
|
|
ebx: self.args[0] as _,
|
|
ebp: self.args[5] as _,
|
|
esi: self.args[3] as _,
|
|
edi: self.args[4] as _,
|
|
|
|
user_ip: self.eip,
|
|
user_sp: self.esp,
|
|
eflags: self.eflags,
|
|
}
|
|
}
|
|
|
|
fn restore(&mut self, saved: &SavedFrame) {
|
|
todo!()
|
|
}
|
|
|
|
fn user_sp(&self) -> usize {
|
|
todo!()
|
|
}
|
|
|
|
fn user_ip(&self) -> usize {
|
|
todo!()
|
|
}
|
|
|
|
fn argument(&self) -> u64 {
|
|
todo!()
|
|
}
|
|
|
|
fn set_user_sp(&mut self, value: usize) {
|
|
self.esp = value as _;
|
|
}
|
|
|
|
fn set_user_ip(&mut self, value: usize) {
|
|
self.eip = value as _;
|
|
}
|
|
|
|
fn set_argument(&mut self, value: u64) {
|
|
// TODO implement ABI for passing 64-bit values via EAX/EDX
|
|
if value & (1 << 63) != 0 {
|
|
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
|
|
}
|
|
|
|
self.eax = value as usize;
|
|
}
|
|
|
|
fn set_single_step(&mut self, step: bool) {
|
|
todo!()
|
|
}
|
|
|
|
fn set_return_value(&mut self, value: u64) {
|
|
// TODO implement ABI for returning 64-bit values via EAX/EDX
|
|
if value & (1 << 63) != 0 {
|
|
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
|
|
}
|
|
|
|
self.eax = value as usize;
|
|
}
|
|
}
|
|
|
|
impl TaskFrame for InterruptFrame {
|
|
fn store(&self) -> SavedFrame {
|
|
SavedFrame {
|
|
eax: self.eax,
|
|
ecx: self.ecx,
|
|
edx: self.edx,
|
|
ebx: self.ebx,
|
|
ebp: self.ebp,
|
|
esi: self.esi,
|
|
edi: self.edi,
|
|
|
|
user_ip: self.eip,
|
|
user_sp: self.esp,
|
|
eflags: self.eflags,
|
|
}
|
|
}
|
|
|
|
fn restore(&mut self, saved: &SavedFrame) {
|
|
todo!()
|
|
}
|
|
|
|
fn user_sp(&self) -> usize {
|
|
todo!()
|
|
}
|
|
|
|
fn user_ip(&self) -> usize {
|
|
todo!()
|
|
}
|
|
|
|
fn argument(&self) -> u64 {
|
|
todo!()
|
|
}
|
|
|
|
fn set_user_sp(&mut self, value: usize) {
|
|
self.esp = value as u32;
|
|
}
|
|
|
|
fn set_user_ip(&mut self, value: usize) {
|
|
self.eip = value as u32;
|
|
}
|
|
|
|
fn set_argument(&mut self, value: u64) {
|
|
// TODO implement ABI for returning 64-bit values via EAX/EDX
|
|
if value & (1 << 63) != 0 {
|
|
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
|
|
}
|
|
|
|
self.eax = value as u32;
|
|
}
|
|
|
|
fn set_single_step(&mut self, step: bool) {
|
|
todo!()
|
|
}
|
|
|
|
fn set_return_value(&mut self, value: u64) {
|
|
// TODO implement ABI for returning 64-bit values via EAX/EDX
|
|
if value & (1 << 63) != 0 {
|
|
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
|
|
}
|
|
|
|
self.eax = value as u32;
|
|
}
|
|
}
|
|
|
|
impl TaskFrame for ExceptionFrame {
|
|
fn store(&self) -> SavedFrame {
|
|
SavedFrame {
|
|
eax: self.eax,
|
|
ecx: self.ecx,
|
|
edx: self.edx,
|
|
ebx: self.ebx,
|
|
ebp: self.ebp,
|
|
esi: self.esi,
|
|
edi: self.edi,
|
|
|
|
user_ip: self.eip,
|
|
user_sp: self.esp,
|
|
eflags: self.eflags,
|
|
}
|
|
}
|
|
|
|
fn restore(&mut self, saved: &SavedFrame) {
|
|
todo!()
|
|
}
|
|
|
|
fn user_sp(&self) -> usize {
|
|
todo!()
|
|
}
|
|
|
|
fn user_ip(&self) -> usize {
|
|
todo!()
|
|
}
|
|
|
|
fn argument(&self) -> u64 {
|
|
todo!()
|
|
}
|
|
|
|
fn set_user_sp(&mut self, value: usize) {
|
|
self.esp = value as u32;
|
|
}
|
|
|
|
fn set_user_ip(&mut self, value: usize) {
|
|
self.eip = value as u32;
|
|
}
|
|
|
|
fn set_argument(&mut self, value: u64) {
|
|
// TODO implement ABI for returning 64-bit values via EAX/EDX
|
|
if value & (1 << 63) != 0 {
|
|
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
|
|
}
|
|
|
|
self.eax = value as u32;
|
|
}
|
|
|
|
fn set_single_step(&mut self, step: bool) {
|
|
todo!()
|
|
}
|
|
|
|
fn set_return_value(&mut self, value: u64) {
|
|
// TODO implement ABI for returning 64-bit values via EAX/EDX
|
|
if value & (1 << 63) != 0 {
|
|
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
|
|
}
|
|
|
|
self.eax = value as u32;
|
|
}
|
|
}
|
|
|
|
global_asm!(include_str!("context.S"), options(att_syntax));
|