feat: tasks
This commit is contained in:
+4
-1
@@ -5,4 +5,7 @@ mod x86_64;
|
|||||||
pub use x86_64::*;
|
pub use x86_64::*;
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub(crate) use x86_64::{PageTableCreateError, PageTableMapError, PageTableUnmapError};
|
pub(crate) use x86_64::{
|
||||||
|
PageTableCreateError, PageTableMapError, PageTableUnmapError, ThreadContext, set_kernel_stack,
|
||||||
|
switch_context,
|
||||||
|
};
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ use crate::{
|
|||||||
memory::{
|
memory::{
|
||||||
AddressSpace, CachePolicy, FrameAllocator, PagePermissions, PhysicalAddr, VirtualAddr,
|
AddressSpace, CachePolicy, FrameAllocator, PagePermissions, PhysicalAddr, VirtualAddr,
|
||||||
},
|
},
|
||||||
println,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const APIC_ID: u32 = 0x20;
|
const APIC_ID: u32 = 0x20;
|
||||||
|
|||||||
+109
-1
@@ -1,8 +1,104 @@
|
|||||||
use core::arch::asm;
|
use core::arch::{asm, naked_asm};
|
||||||
|
|
||||||
|
use crate::memory::VirtualAddr;
|
||||||
|
|
||||||
|
#[repr(C, align(64))]
|
||||||
|
pub struct CpuLocal {
|
||||||
|
pub kernel_stack_top: usize,
|
||||||
|
pub user_rsp_scratch: usize,
|
||||||
|
pub cpu_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static mut BOOT_CPU: CpuLocal = CpuLocal {
|
||||||
|
kernel_stack_top: 0,
|
||||||
|
user_rsp_scratch: 0,
|
||||||
|
cpu_id: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ThreadContext {
|
||||||
|
rsp: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ThreadContext {
|
||||||
|
pub fn new(
|
||||||
|
user_entry: VirtualAddr,
|
||||||
|
user_stack: VirtualAddr,
|
||||||
|
kernel_stack_top: VirtualAddr,
|
||||||
|
) -> Self {
|
||||||
|
// Stack layout (grows downwards from kernel_stack_top):
|
||||||
|
// [top - 8] = user_thread_entry (popped by `ret`)
|
||||||
|
// [top - 16] = rbp (0)
|
||||||
|
// [top - 24] = rbx (user_stack)
|
||||||
|
// [top - 32] = r12 (user_entry)
|
||||||
|
// [top - 40] = r13 (0)
|
||||||
|
// [top - 48] = r14 (0)
|
||||||
|
// [top - 56] = r15 (0) <- initial rsp
|
||||||
|
|
||||||
|
let stack_ptr = (kernel_stack_top.as_usize() - 56) as *mut usize;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
stack_ptr.add(0).write(0); // r15
|
||||||
|
stack_ptr.add(1).write(0); // r14
|
||||||
|
stack_ptr.add(2).write(0); // r13
|
||||||
|
stack_ptr.add(3).write(user_entry.as_usize()); // r12 (user_entry)
|
||||||
|
stack_ptr.add(4).write(user_stack.as_usize()); // rbx (user_stack)
|
||||||
|
stack_ptr.add(5).write(0); // rbp (0)
|
||||||
|
stack_ptr
|
||||||
|
.add(6)
|
||||||
|
.write(user_thread_entry as *const () as usize); // return address
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
rsp: kernel_stack_top.as_usize() - 56,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self { rsp: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(naked)]
|
||||||
|
unsafe extern "C" fn user_thread_entry() -> ! {
|
||||||
|
naked_asm!(
|
||||||
|
// r12 = user_entry, rbx = user_stack
|
||||||
|
"mov rdi, r12",
|
||||||
|
"mov rsi, rbx",
|
||||||
|
"call {enter_user}",
|
||||||
|
enter_user = sym crate::arch::enter_user,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(naked)]
|
||||||
|
pub unsafe extern "C" fn switch_context(prev: *mut ThreadContext, next: *const ThreadContext) {
|
||||||
|
naked_asm!(
|
||||||
|
"push rbp",
|
||||||
|
"push rbx",
|
||||||
|
"push r12",
|
||||||
|
"push r13",
|
||||||
|
"push r14",
|
||||||
|
"push r15",
|
||||||
|
"",
|
||||||
|
// save current rsp into prev.rsp
|
||||||
|
"mov [rdi], rsp",
|
||||||
|
// load next rsp into rsp
|
||||||
|
"mov rsp, [rsi]",
|
||||||
|
"",
|
||||||
|
"pop r15",
|
||||||
|
"pop r14",
|
||||||
|
"pop r13",
|
||||||
|
"pop r12",
|
||||||
|
"pop rbx",
|
||||||
|
"pop rbp",
|
||||||
|
"ret",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CpuFeaturesError {
|
pub enum CpuFeaturesError {
|
||||||
CpuidFeaturesNotSupported,
|
CpuidFeaturesNotSupported,
|
||||||
|
SyscallNotSupported,
|
||||||
InvalidPhysicalAddressWidth,
|
InvalidPhysicalAddressWidth,
|
||||||
InvalidVirtualAddressWidth,
|
InvalidVirtualAddressWidth,
|
||||||
}
|
}
|
||||||
@@ -40,6 +136,18 @@ pub fn detect_features_and_enable() -> Result<CpuFeatures, CpuFeaturesError> {
|
|||||||
|
|
||||||
features.nx_supported = cpuid_result.edx & (1 << 20) != 0;
|
features.nx_supported = cpuid_result.edx & (1 << 20) != 0;
|
||||||
|
|
||||||
|
// TODO: on AMD K6 *only*, this bit is bit 10, should we consider that edge case?
|
||||||
|
let syscall_supported = cpuid_result.edx & (1 << 11) != 0;
|
||||||
|
if !syscall_supported {
|
||||||
|
return Err(CpuFeaturesError::SyscallNotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let efer = read_msr(IA32_EFER);
|
||||||
|
let value = efer | 1;
|
||||||
|
write_msr(IA32_EFER, value);
|
||||||
|
};
|
||||||
|
|
||||||
let cpuid_result = core::arch::x86_64::__cpuid(0x80000008);
|
let cpuid_result = core::arch::x86_64::__cpuid(0x80000008);
|
||||||
|
|
||||||
features.physical_address_bits = (cpuid_result.eax & 0xFF) as u8;
|
features.physical_address_bits = (cpuid_result.eax & 0xFF) as u8;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ use core::arch::asm;
|
|||||||
use crate::memory::VirtualAddr;
|
use crate::memory::VirtualAddr;
|
||||||
|
|
||||||
#[repr(C, align(8))]
|
#[repr(C, align(8))]
|
||||||
struct Gdt {
|
pub(super) struct Gdt {
|
||||||
entries: [u64; 7],
|
pub entries: [u64; 7],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gdt {
|
impl Gdt {
|
||||||
@@ -49,12 +49,12 @@ const DOUBLE_FAULT_STACK_SIZE: usize = 16 * 1024;
|
|||||||
|
|
||||||
pub(super) const KERNEL_CODE_SELECTOR: u16 = 1 * 8;
|
pub(super) const KERNEL_CODE_SELECTOR: u16 = 1 * 8;
|
||||||
pub(super) const KERNEL_DATA_SELECTOR: u16 = 2 * 8;
|
pub(super) const KERNEL_DATA_SELECTOR: u16 = 2 * 8;
|
||||||
pub(super) const USER_CODE_SELECTOR: u16 = (3 * 8) | 3;
|
pub(super) const USER_DATA_SELECTOR: u16 = (3 * 8) | 3;
|
||||||
pub(super) const USER_DATA_SELECTOR: u16 = (4 * 8) | 3;
|
pub(super) const USER_CODE_SELECTOR: u16 = (4 * 8) | 3;
|
||||||
pub(super) const TSS_SELECTOR: u16 = 5 * 8;
|
pub(super) const TSS_SELECTOR: u16 = 5 * 8;
|
||||||
|
|
||||||
#[repr(align(16))]
|
#[repr(align(16))]
|
||||||
#[allow(dead_code)] // field 0 is read, rust just cant tell
|
#[allow(unused)] // field 0 is read, rust just cant tell
|
||||||
struct ExceptionStack([u8; DOUBLE_FAULT_STACK_SIZE]);
|
struct ExceptionStack([u8; DOUBLE_FAULT_STACK_SIZE]);
|
||||||
|
|
||||||
static mut GDT: Gdt = Gdt::new();
|
static mut GDT: Gdt = Gdt::new();
|
||||||
@@ -78,8 +78,10 @@ pub fn init() {
|
|||||||
0,
|
0,
|
||||||
kernel_code_descriptor(),
|
kernel_code_descriptor(),
|
||||||
kernel_data_descriptor(),
|
kernel_data_descriptor(),
|
||||||
user_code_descriptor(),
|
// In Long Mode, userland CS will be loaded from STAR 63:48 + 16
|
||||||
|
// and userland SS from STAR 63:48 + 8 on SYSRET.
|
||||||
user_data_descriptor(),
|
user_data_descriptor(),
|
||||||
|
user_code_descriptor(),
|
||||||
tss_low,
|
tss_low,
|
||||||
tss_high,
|
tss_high,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -6,6 +6,33 @@ mod idt;
|
|||||||
|
|
||||||
pub use idt::idt_init as init;
|
pub use idt::idt_init as init;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn disable_interrupts_and_save() -> u64 {
|
||||||
|
let flags: u64;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
asm!("
|
||||||
|
pushfq",
|
||||||
|
"pop {flags}",
|
||||||
|
"cli",
|
||||||
|
flags = out(reg) flags,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
flags
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn restore_interrupts(flags: u64) {
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"push {flags}",
|
||||||
|
"popfq",
|
||||||
|
flags = in(reg) flags,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn disable_interrupts() {
|
pub fn disable_interrupts() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use crate::{
|
|||||||
AddressSpace, CachePolicy, FrameAllocator, PagePermissions, PhysicalAddr, VirtualAddr,
|
AddressSpace, CachePolicy, FrameAllocator, PagePermissions, PhysicalAddr, VirtualAddr,
|
||||||
},
|
},
|
||||||
platform::acpi::{InterruptPolarity, TriggerMode},
|
platform::acpi::{InterruptPolarity, TriggerMode},
|
||||||
println,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const IOWIN: usize = 0x10;
|
const IOWIN: usize = 0x10;
|
||||||
|
|||||||
+41
-14
@@ -1,16 +1,18 @@
|
|||||||
pub mod apic;
|
pub(super) mod apic;
|
||||||
mod cpu;
|
mod cpu;
|
||||||
mod gdt;
|
mod gdt;
|
||||||
mod interrupts;
|
mod interrupts;
|
||||||
pub mod io_apic;
|
pub(super) mod io_apic;
|
||||||
mod paging;
|
mod paging;
|
||||||
mod pit;
|
mod pit;
|
||||||
pub mod port;
|
pub mod port;
|
||||||
|
mod syscall;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
|
|
||||||
pub use interrupts::disable_interrupts;
|
pub use cpu::{ThreadContext, switch_context};
|
||||||
|
pub use interrupts::{disable_interrupts, disable_interrupts_and_save, restore_interrupts};
|
||||||
pub(crate) use paging::{
|
pub(crate) use paging::{
|
||||||
MapError as PageTableMapError, PageTableCreateError, UnmapError as PageTableUnmapError,
|
MapError as PageTableMapError, PageTableCreateError, UnmapError as PageTableUnmapError,
|
||||||
};
|
};
|
||||||
@@ -22,11 +24,7 @@ pub struct ArchState {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
KernelHandoff,
|
KernelHandoff,
|
||||||
arch::{
|
arch::x86_64::cpu::BOOT_CPU,
|
||||||
apic::LocalApic,
|
|
||||||
io_apic::{IOAPIC_VIRTUAL_ADDRESS, IoApic},
|
|
||||||
x86_64::interrupts::apic_vectors::PIT_CALIBRATION_VECTOR,
|
|
||||||
},
|
|
||||||
memory::{AddressSpace, FrameAllocator, VirtualAddr},
|
memory::{AddressSpace, FrameAllocator, VirtualAddr},
|
||||||
platform::acpi::Madt,
|
platform::acpi::Madt,
|
||||||
println,
|
println,
|
||||||
@@ -45,6 +43,14 @@ pub fn init() -> ArchState {
|
|||||||
ArchState { paging }
|
ArchState { paging }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_kernel_stack(stack_top: VirtualAddr) {
|
||||||
|
gdt::set_kernel_stack(stack_top);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
BOOT_CPU.kernel_stack_top = stack_top.as_usize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub enum InterruptInitError {
|
pub enum InterruptInitError {
|
||||||
@@ -60,8 +66,8 @@ pub enum InterruptInitError {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InterruptController {
|
pub struct InterruptController {
|
||||||
local_apic: LocalApic,
|
local_apic: apic::LocalApic,
|
||||||
io_apic: IoApic,
|
io_apic: io_apic::IoApic,
|
||||||
local_timer_frequency: u64,
|
local_timer_frequency: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +95,7 @@ pub fn init_interrupt_controller(
|
|||||||
io_apic_info.id,
|
io_apic_info.id,
|
||||||
io_apic_info.apic_address,
|
io_apic_info.apic_address,
|
||||||
io_apic_info.global_system_interrupt_base,
|
io_apic_info.global_system_interrupt_base,
|
||||||
IOAPIC_VIRTUAL_ADDRESS,
|
io_apic::IOAPIC_VIRTUAL_ADDRESS,
|
||||||
allocator,
|
allocator,
|
||||||
address_space,
|
address_space,
|
||||||
)
|
)
|
||||||
@@ -107,7 +113,7 @@ pub fn init_interrupt_controller(
|
|||||||
.configure_masked(
|
.configure_masked(
|
||||||
pit_route.gsi,
|
pit_route.gsi,
|
||||||
io_apic::RedirectionConfig {
|
io_apic::RedirectionConfig {
|
||||||
vector: PIT_CALIBRATION_VECTOR,
|
vector: interrupts::apic_vectors::PIT_CALIBRATION_VECTOR,
|
||||||
destination,
|
destination,
|
||||||
polarity: pit_route.polarity,
|
polarity: pit_route.polarity,
|
||||||
trigger: pit_route.trigger,
|
trigger: pit_route.trigger,
|
||||||
@@ -165,6 +171,9 @@ pub unsafe fn enter_kernel(stack_top: VirtualAddr, handoff: *mut KernelHandoff)
|
|||||||
unsafe {
|
unsafe {
|
||||||
gdt::set_kernel_stack(stack_top);
|
gdt::set_kernel_stack(stack_top);
|
||||||
|
|
||||||
|
BOOT_CPU.kernel_stack_top = stack_top.as_usize();
|
||||||
|
syscall::init(&raw const BOOT_CPU);
|
||||||
|
|
||||||
asm!(
|
asm!(
|
||||||
"mov rsp, {stack_top}",
|
"mov rsp, {stack_top}",
|
||||||
"xor rbp, rbp",
|
"xor rbp, rbp",
|
||||||
@@ -193,13 +202,31 @@ pub unsafe fn enter_user(
|
|||||||
"mov ds, {user_data_selector:x}",
|
"mov ds, {user_data_selector:x}",
|
||||||
"mov es, {user_data_selector:x}",
|
"mov es, {user_data_selector:x}",
|
||||||
"mov fs, {user_data_selector:x}",
|
"mov fs, {user_data_selector:x}",
|
||||||
"mov gs, {user_data_selector:x}", // ss is handled by iretq
|
"mov gs, {user_data_selector:x}",
|
||||||
|
|
||||||
"push {user_data_selector}",
|
"push {user_data_selector}",
|
||||||
"push {user_stack_pointer}",
|
"push {user_stack_pointer}",
|
||||||
"pushfq",
|
"push 0x202", // RFLAGS (IF=1, bit 1 reserved=1)
|
||||||
"push {user_code_selector}",
|
"push {user_code_selector}",
|
||||||
"push {user_instruction_pointer}",
|
"push {user_instruction_pointer}",
|
||||||
|
|
||||||
|
// clear GPRs
|
||||||
|
"xor rax, rax",
|
||||||
|
"xor rbx, rbx",
|
||||||
|
"xor rcx, rcx",
|
||||||
|
"xor rdx, rdx",
|
||||||
|
"xor rsi, rsi",
|
||||||
|
"xor rdi, rdi",
|
||||||
|
"xor rbp, rbp",
|
||||||
|
"xor r8, r8",
|
||||||
|
"xor r9, r9",
|
||||||
|
"xor r10, r10",
|
||||||
|
"xor r11, r11",
|
||||||
|
"xor r12, r12",
|
||||||
|
"xor r13, r13",
|
||||||
|
"xor r14, r14",
|
||||||
|
"xor r15, r15",
|
||||||
|
|
||||||
"iretq",
|
"iretq",
|
||||||
user_data_selector = in(reg) gdt::USER_DATA_SELECTOR as usize,
|
user_data_selector = in(reg) gdt::USER_DATA_SELECTOR as usize,
|
||||||
user_code_selector = in(reg) gdt::USER_CODE_SELECTOR as usize,
|
user_code_selector = in(reg) gdt::USER_CODE_SELECTOR as usize,
|
||||||
|
|||||||
@@ -264,12 +264,21 @@ pub(crate) enum PageTableCreateError {
|
|||||||
OutOfFrames,
|
OutOfFrames,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct PageTable {
|
pub struct PageTable {
|
||||||
pub direct_map: DirectMap,
|
pub direct_map: DirectMap,
|
||||||
config: PagingConfig,
|
config: PagingConfig,
|
||||||
frame: OwnedFrame,
|
frame: OwnedFrame,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for PageTable {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.frame.frame_address() == other.frame.frame_address()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for PageTable {}
|
||||||
|
|
||||||
impl PageTable {
|
impl PageTable {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
direct_map: DirectMap,
|
direct_map: DirectMap,
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
use core::arch::{asm, naked_asm};
|
||||||
|
|
||||||
|
use crate::arch::x86_64::{
|
||||||
|
cpu::{CpuLocal, write_msr},
|
||||||
|
gdt::{KERNEL_CODE_SELECTOR, KERNEL_DATA_SELECTOR},
|
||||||
|
};
|
||||||
|
|
||||||
|
const IA32_STAR: u32 = 0xC000_0081;
|
||||||
|
const IA32_LSTAR: u32 = 0xC000_0082;
|
||||||
|
const IA32_CSTAR: u32 = 0xC000_0083;
|
||||||
|
const IA32_FMASK: u32 = 0xC000_0084;
|
||||||
|
const IA32_GS_BASE: u32 = 0xC000_0101;
|
||||||
|
const IA32_KERNEL_GS_BASE: u32 = 0xC000_0102;
|
||||||
|
|
||||||
|
const RFLAGS_MASK: u64 = 0x257FD5; // Clear IF, TF, DF, IOPL, NT, AC
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct SyscallFrame {
|
||||||
|
pub r15: u64,
|
||||||
|
pub r14: u64,
|
||||||
|
pub r13: u64,
|
||||||
|
pub r12: u64,
|
||||||
|
pub rbp: u64,
|
||||||
|
pub rbx: u64,
|
||||||
|
pub r9: u64, // arg5
|
||||||
|
pub r8: u64, // arg4
|
||||||
|
pub r10: u64, // arg3
|
||||||
|
pub rdx: u64, // arg2
|
||||||
|
pub rsi: u64, // arg1
|
||||||
|
pub rdi: u64, // arg0
|
||||||
|
pub rax: u64, // syscall number on entry / return value on exit
|
||||||
|
pub user_rip: u64, // rcx
|
||||||
|
pub user_rflags: u64, // r11
|
||||||
|
pub user_rsp: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(cpu_local: *const CpuLocal) {
|
||||||
|
unsafe {
|
||||||
|
let star = ((KERNEL_DATA_SELECTOR as u64) << 48) | ((KERNEL_CODE_SELECTOR as u64) << 32);
|
||||||
|
write_msr(IA32_STAR, star);
|
||||||
|
write_msr(IA32_LSTAR, syscall_entry as *const () as u64);
|
||||||
|
write_msr(IA32_CSTAR, 0);
|
||||||
|
write_msr(IA32_FMASK, RFLAGS_MASK);
|
||||||
|
write_msr(IA32_GS_BASE, 0);
|
||||||
|
write_msr(IA32_KERNEL_GS_BASE, cpu_local as u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(naked)]
|
||||||
|
unsafe extern "C" fn syscall_entry() {
|
||||||
|
naked_asm!(
|
||||||
|
"swapgs",
|
||||||
|
"mov gs:[8], rsp", // user_rsp_scratch
|
||||||
|
"mov rsp, gs:[0]", // kernel_stack_top
|
||||||
|
"",
|
||||||
|
// build the syscall frame
|
||||||
|
"push qword ptr gs:[8]", // user_rsp
|
||||||
|
"push r11", // user_rflags
|
||||||
|
"push rcx", // user_rip
|
||||||
|
"push rax",
|
||||||
|
"push rdi",
|
||||||
|
"push rsi",
|
||||||
|
"push rdx",
|
||||||
|
"push r10",
|
||||||
|
"push r8",
|
||||||
|
"push r9",
|
||||||
|
"push rbx",
|
||||||
|
"push rbp",
|
||||||
|
"push r12",
|
||||||
|
"push r13",
|
||||||
|
"push r14",
|
||||||
|
"push r15",
|
||||||
|
"",
|
||||||
|
// Syscall calling convention:
|
||||||
|
// Syscall number in rax, args in rdi, rsi, rdx, r10, r8, r9
|
||||||
|
"mov rdi, rsp",
|
||||||
|
"call {dispatch}",
|
||||||
|
"",
|
||||||
|
// restore the syscall frame
|
||||||
|
"pop r15",
|
||||||
|
"pop r14",
|
||||||
|
"pop r13",
|
||||||
|
"pop r12",
|
||||||
|
"pop rbp",
|
||||||
|
"pop rbx",
|
||||||
|
"pop r9",
|
||||||
|
"pop r8",
|
||||||
|
"pop r10",
|
||||||
|
"pop rdx",
|
||||||
|
"pop rsi",
|
||||||
|
"pop rdi",
|
||||||
|
"pop rax", // return value
|
||||||
|
"pop rcx", // user_rip for sysret
|
||||||
|
"pop r11", // user_rflags for sysret
|
||||||
|
"pop qword ptr gs:[8]", // user_rsp
|
||||||
|
"",
|
||||||
|
"mov rsp, gs:[8]", // switch to user stack
|
||||||
|
"swapgs",
|
||||||
|
"sysretq",
|
||||||
|
dispatch = sym syscall_dispatch,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn syscall_dispatch(frame: &mut SyscallFrame) {
|
||||||
|
let ret = crate::task::syscall::handle(
|
||||||
|
frame.rax, frame.rdi, frame.rsi, frame.rdx, frame.r10, frame.r8, frame.r9,
|
||||||
|
);
|
||||||
|
|
||||||
|
frame.rax = ret;
|
||||||
|
}
|
||||||
+53
-10
@@ -8,12 +8,14 @@ mod boot;
|
|||||||
mod debug;
|
mod debug;
|
||||||
mod memory;
|
mod memory;
|
||||||
mod platform;
|
mod platform;
|
||||||
|
mod task;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
debug::serial,
|
debug::serial,
|
||||||
memory::{
|
memory::{
|
||||||
AddressSpace, KernelStack, MemoryRegionKind, PagePermissions, UserStack, VirtualAddr,
|
AddressSpace, KernelStackPool, MemoryRegionKind, PagePermissions, UserStack, VirtualAddr,
|
||||||
},
|
},
|
||||||
|
task::tcb::Tcb,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct KernelHandoff {
|
pub struct KernelHandoff {
|
||||||
@@ -21,6 +23,7 @@ pub struct KernelHandoff {
|
|||||||
address_space: AddressSpace,
|
address_space: AddressSpace,
|
||||||
direct_map: memory::DirectMap,
|
direct_map: memory::DirectMap,
|
||||||
boot_info: boot::BootInfo,
|
boot_info: boot::BootInfo,
|
||||||
|
kernel_stack_pool: KernelStackPool,
|
||||||
handoff_frame: memory::OwnedFrame,
|
handoff_frame: memory::OwnedFrame,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +52,10 @@ pub extern "C" fn _start() -> ! {
|
|||||||
|
|
||||||
println!("Entering kernel main...");
|
println!("Entering kernel main...");
|
||||||
|
|
||||||
let bootstrap_stack = KernelStack::allocate(&mut address_space, &mut allocator)
|
let mut kernel_stack_pool = KernelStackPool::new();
|
||||||
|
|
||||||
|
let kernel_stack = kernel_stack_pool
|
||||||
|
.allocate(&mut address_space, &mut allocator)
|
||||||
.expect("failed to allocate bootstrap stack");
|
.expect("failed to allocate bootstrap stack");
|
||||||
|
|
||||||
let handoff_frame = allocator
|
let handoff_frame = allocator
|
||||||
@@ -59,12 +65,13 @@ pub extern "C" fn _start() -> ! {
|
|||||||
.to_virtual(handoff_frame.frame_address().start_address())
|
.to_virtual(handoff_frame.frame_address().start_address())
|
||||||
.expect("failed to map kernel handoff");
|
.expect("failed to map kernel handoff");
|
||||||
|
|
||||||
let bootstrap_stack_top = bootstrap_stack.top();
|
let bootstrap_stack_top = kernel_stack.top();
|
||||||
let handoff = KernelHandoff {
|
let handoff = KernelHandoff {
|
||||||
allocator,
|
allocator,
|
||||||
address_space,
|
address_space,
|
||||||
direct_map,
|
direct_map,
|
||||||
boot_info,
|
boot_info,
|
||||||
|
kernel_stack_pool,
|
||||||
handoff_frame,
|
handoff_frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,13 +89,21 @@ pub extern "C" fn _start() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern "C" fn kernel_main(handoff: *mut KernelHandoff) -> ! {
|
pub unsafe extern "C" fn kernel_main(handoff: *mut KernelHandoff) -> ! {
|
||||||
let (mut allocator, mut address_space, direct_map, boot_info, handoff_frame) = unsafe {
|
let (
|
||||||
|
mut allocator,
|
||||||
|
mut address_space,
|
||||||
|
direct_map,
|
||||||
|
boot_info,
|
||||||
|
mut kernel_stack_pool,
|
||||||
|
handoff_frame,
|
||||||
|
) = unsafe {
|
||||||
let handoff = handoff.read();
|
let handoff = handoff.read();
|
||||||
(
|
(
|
||||||
handoff.allocator,
|
handoff.allocator,
|
||||||
handoff.address_space,
|
handoff.address_space,
|
||||||
handoff.direct_map,
|
handoff.direct_map,
|
||||||
handoff.boot_info,
|
handoff.boot_info,
|
||||||
|
handoff.kernel_stack_pool,
|
||||||
handoff.handoff_frame,
|
handoff.handoff_frame,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@@ -106,19 +121,31 @@ pub unsafe extern "C" fn kernel_main(handoff: *mut KernelHandoff) -> ! {
|
|||||||
|
|
||||||
let acpi = platform::acpi::init(&boot_info, direct_map).expect("failed to initialize ACPI");
|
let acpi = platform::acpi::init(&boot_info, direct_map).expect("failed to initialize ACPI");
|
||||||
|
|
||||||
|
println!("Parsing MADT...");
|
||||||
|
|
||||||
let madt = acpi
|
let madt = acpi
|
||||||
.madt()
|
.madt()
|
||||||
.expect("failed to parse ACPI")
|
.expect("failed to parse ACPI")
|
||||||
.expect("MADT not found");
|
.expect("MADT not found");
|
||||||
|
|
||||||
|
println!("Initializing interrupt controller...");
|
||||||
|
|
||||||
let interrupt_controller =
|
let interrupt_controller =
|
||||||
arch::init_interrupt_controller(&madt, &mut allocator, &mut address_space)
|
arch::init_interrupt_controller(&madt, &mut allocator, &mut address_space)
|
||||||
.expect("failed to initialize interrupt controller");
|
.expect("failed to initialize interrupt controller");
|
||||||
|
|
||||||
|
println!("Creating user address space...");
|
||||||
|
|
||||||
|
let task_kernel_stack = kernel_stack_pool
|
||||||
|
.allocate(&mut address_space, &mut allocator)
|
||||||
|
.expect("failed to allocate user task stack");
|
||||||
|
|
||||||
let mut user_addr_space = address_space
|
let mut user_addr_space = address_space
|
||||||
.new_user(&mut allocator)
|
.new_user(&mut allocator)
|
||||||
.expect("failed to create user address space");
|
.expect("failed to create user address space");
|
||||||
|
|
||||||
|
println!("Allocating user stack...");
|
||||||
|
|
||||||
let user_stack = UserStack::allocate(&mut user_addr_space, &mut allocator)
|
let user_stack = UserStack::allocate(&mut user_addr_space, &mut allocator)
|
||||||
.expect("failed to allocate user stack");
|
.expect("failed to allocate user stack");
|
||||||
|
|
||||||
@@ -138,21 +165,37 @@ pub unsafe extern "C" fn kernel_main(handoff: *mut KernelHandoff) -> ! {
|
|||||||
.expect("failed to map user code page");
|
.expect("failed to map user code page");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
user_addr_space.activate();
|
let user_code: &[u8] = &[
|
||||||
|
|
||||||
let user_code: [u8; 5] = [
|
|
||||||
0xCC, // INT3
|
0xCC, // INT3
|
||||||
0xCD, 0x80, // INT 0x80
|
0x0F, 0x05, // SYSCALL
|
||||||
0xEB, 0xFE, // JMP -2 (loop forever if exit returns)
|
0xEB, 0xFE, // JMP -2 (loop forever if exit returns)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let user_code_virtual = direct_map
|
||||||
|
.translate(user_code_page.start_address())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("Copying user code to {:#X}", user_code_virtual.as_usize());
|
||||||
|
|
||||||
core::ptr::copy_nonoverlapping(
|
core::ptr::copy_nonoverlapping(
|
||||||
user_code.as_ptr(),
|
user_code.as_ptr(),
|
||||||
user_instruction_pointer.as_mut_ptr::<u8>(),
|
user_code_virtual.as_mut_ptr::<u8>(),
|
||||||
user_code.len(),
|
user_code.len(),
|
||||||
);
|
);
|
||||||
|
|
||||||
arch::enter_user(user_instruction_pointer, user_stack.top());
|
println!("Activating user address space...");
|
||||||
|
|
||||||
|
let user_tcb = Tcb::new_user(
|
||||||
|
0,
|
||||||
|
user_addr_space,
|
||||||
|
task_kernel_stack,
|
||||||
|
user_instruction_pointer,
|
||||||
|
user_stack.top(),
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("Running first user task {user_tcb:?}...");
|
||||||
|
|
||||||
|
task::tcb::run_first_user(&user_tcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
hcf();
|
hcf();
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ enum AddressSpaceKind {
|
|||||||
User,
|
User,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct AddressSpace {
|
pub struct AddressSpace {
|
||||||
root: PageTable,
|
root: PageTable,
|
||||||
kind: AddressSpaceKind,
|
kind: AddressSpaceKind,
|
||||||
|
|||||||
+3
-2
@@ -1,11 +1,12 @@
|
|||||||
mod address_space;
|
mod address_space;
|
||||||
mod frame;
|
mod frame;
|
||||||
pub mod stack;
|
mod stack;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub use address_space::{AddressSpace, AddressSpaceCreateError, MapError, UnmapError};
|
pub use address_space::{AddressSpace, AddressSpaceCreateError, MapError, UnmapError};
|
||||||
pub use frame::{FRAME_SIZE, FrameAddr, FrameAllocator, OwnedFrame};
|
pub use frame::{FRAME_SIZE, FrameAddr, FrameAllocator, OwnedFrame};
|
||||||
pub use stack::{KernelStack, StackCreateError, UserStack};
|
#[allow(unused)]
|
||||||
|
pub use stack::{KernelStack, KernelStackPool, StackCreateError, UserStack};
|
||||||
|
|
||||||
pub struct KernelSegment {
|
pub struct KernelSegment {
|
||||||
pub physical_base: PhysicalAddr,
|
pub physical_base: PhysicalAddr,
|
||||||
|
|||||||
+55
-7
@@ -3,10 +3,16 @@ use crate::memory::{
|
|||||||
VirtualAddr,
|
VirtualAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
const STACK_PAGES: usize = 16;
|
const GUARD_PAGES: usize = 1; // 4KiB
|
||||||
const STACK_SIZE: usize = STACK_PAGES * FRAME_SIZE;
|
const KERNEL_STACK_PAGES: usize = 8; // 32KiB
|
||||||
|
const USER_STACK_PAGES: usize = 16; // 64KiB
|
||||||
|
const KERNEL_STACK_SIZE: usize = KERNEL_STACK_PAGES * FRAME_SIZE;
|
||||||
|
const USER_STACK_SIZE: usize = USER_STACK_PAGES * FRAME_SIZE;
|
||||||
|
|
||||||
|
const KERNEL_SLOT_SIZE: usize = (KERNEL_STACK_PAGES + GUARD_PAGES) * FRAME_SIZE;
|
||||||
|
const MAX_KERNEL_STACKS: usize = 64;
|
||||||
|
const KERNEL_STACK_BASE: usize = 0xFFFF_FFFE_0000_0000;
|
||||||
|
|
||||||
const KERNEL_STACK_TOP: VirtualAddr = VirtualAddr::new(0xFFFF_FFFE_0000_0000);
|
|
||||||
const USER_STACK_TOP: VirtualAddr = VirtualAddr::new(0x0000_7FFF_FFFF_F000);
|
const USER_STACK_TOP: VirtualAddr = VirtualAddr::new(0x0000_7FFF_FFFF_F000);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -14,13 +20,16 @@ pub enum StackCreateError {
|
|||||||
AddressOverflow,
|
AddressOverflow,
|
||||||
UnalignedStackTop,
|
UnalignedStackTop,
|
||||||
OutOfFrames,
|
OutOfFrames,
|
||||||
|
OutOfStacks,
|
||||||
GuardPageMapped,
|
GuardPageMapped,
|
||||||
Map(MapError),
|
Map(MapError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct StackMapping {
|
struct StackMapping {
|
||||||
guard_page: VirtualAddr,
|
guard_page: VirtualAddr,
|
||||||
mapped_start: VirtualAddr,
|
mapped_start: VirtualAddr,
|
||||||
|
stack_size: usize,
|
||||||
top: VirtualAddr,
|
top: VirtualAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +37,7 @@ impl StackMapping {
|
|||||||
fn allocate(
|
fn allocate(
|
||||||
address_space: &mut AddressSpace,
|
address_space: &mut AddressSpace,
|
||||||
allocator: &mut FrameAllocator,
|
allocator: &mut FrameAllocator,
|
||||||
|
stack_size: usize,
|
||||||
top: VirtualAddr,
|
top: VirtualAddr,
|
||||||
permissions: PagePermissions,
|
permissions: PagePermissions,
|
||||||
) -> Result<Self, StackCreateError> {
|
) -> Result<Self, StackCreateError> {
|
||||||
@@ -37,7 +47,7 @@ impl StackMapping {
|
|||||||
|
|
||||||
let mapped_start = VirtualAddr::new(
|
let mapped_start = VirtualAddr::new(
|
||||||
top.as_usize()
|
top.as_usize()
|
||||||
.checked_sub(STACK_SIZE)
|
.checked_sub(stack_size)
|
||||||
.ok_or(StackCreateError::AddressOverflow)?,
|
.ok_or(StackCreateError::AddressOverflow)?,
|
||||||
);
|
);
|
||||||
let guard_page = VirtualAddr::new(
|
let guard_page = VirtualAddr::new(
|
||||||
@@ -53,7 +63,7 @@ impl StackMapping {
|
|||||||
|
|
||||||
let mut mapped_pages = 0;
|
let mut mapped_pages = 0;
|
||||||
|
|
||||||
while mapped_pages < STACK_PAGES {
|
while mapped_pages < stack_size / FRAME_SIZE {
|
||||||
let virtual_address = VirtualAddr::new(
|
let virtual_address = VirtualAddr::new(
|
||||||
mapped_start
|
mapped_start
|
||||||
.as_usize()
|
.as_usize()
|
||||||
@@ -89,6 +99,7 @@ impl StackMapping {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
guard_page,
|
guard_page,
|
||||||
mapped_start,
|
mapped_start,
|
||||||
|
stack_size,
|
||||||
top,
|
top,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -115,7 +126,7 @@ impl StackMapping {
|
|||||||
/// The caller must ensure this stack is not active on any CPU and cannot be accessed by any
|
/// The caller must ensure this stack is not active on any CPU and cannot be accessed by any
|
||||||
/// kernel operation while it is being destroyed.
|
/// kernel operation while it is being destroyed.
|
||||||
unsafe fn destroy(self, address_space: &mut AddressSpace, allocator: &mut FrameAllocator) {
|
unsafe fn destroy(self, address_space: &mut AddressSpace, allocator: &mut FrameAllocator) {
|
||||||
for page in (0..STACK_PAGES).rev() {
|
for page in (0..self.stack_size / FRAME_SIZE).rev() {
|
||||||
let virtual_address =
|
let virtual_address =
|
||||||
VirtualAddr::new(self.mapped_start.as_usize() + page * FRAME_SIZE);
|
VirtualAddr::new(self.mapped_start.as_usize() + page * FRAME_SIZE);
|
||||||
let frame = unsafe {
|
let frame = unsafe {
|
||||||
@@ -130,6 +141,7 @@ impl StackMapping {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct KernelStack {
|
pub struct KernelStack {
|
||||||
mapping: StackMapping,
|
mapping: StackMapping,
|
||||||
}
|
}
|
||||||
@@ -137,12 +149,14 @@ pub struct KernelStack {
|
|||||||
impl KernelStack {
|
impl KernelStack {
|
||||||
pub fn allocate(
|
pub fn allocate(
|
||||||
address_space: &mut AddressSpace,
|
address_space: &mut AddressSpace,
|
||||||
|
top: usize,
|
||||||
allocator: &mut FrameAllocator,
|
allocator: &mut FrameAllocator,
|
||||||
) -> Result<Self, StackCreateError> {
|
) -> Result<Self, StackCreateError> {
|
||||||
let mapping = StackMapping::allocate(
|
let mapping = StackMapping::allocate(
|
||||||
address_space,
|
address_space,
|
||||||
allocator,
|
allocator,
|
||||||
KERNEL_STACK_TOP,
|
KERNEL_STACK_SIZE,
|
||||||
|
VirtualAddr::new(top),
|
||||||
PagePermissions::new(true, false, false),
|
PagePermissions::new(true, false, false),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -175,6 +189,7 @@ impl UserStack {
|
|||||||
let mapping = StackMapping::allocate(
|
let mapping = StackMapping::allocate(
|
||||||
address_space,
|
address_space,
|
||||||
allocator,
|
allocator,
|
||||||
|
USER_STACK_SIZE,
|
||||||
top,
|
top,
|
||||||
PagePermissions::new(true, false, true),
|
PagePermissions::new(true, false, true),
|
||||||
)?;
|
)?;
|
||||||
@@ -194,3 +209,36 @@ impl UserStack {
|
|||||||
unsafe { self.mapping.destroy(address_space, allocator) };
|
unsafe { self.mapping.destroy(address_space, allocator) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct KernelStackPool {
|
||||||
|
free_slots: u64, // bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KernelStackPool {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { free_slots: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate(
|
||||||
|
&mut self,
|
||||||
|
address_space: &mut AddressSpace,
|
||||||
|
allocator: &mut FrameAllocator,
|
||||||
|
) -> Result<KernelStack, StackCreateError> {
|
||||||
|
let mut slot = 0;
|
||||||
|
while slot < MAX_KERNEL_STACKS {
|
||||||
|
if self.free_slots & (1 << slot) == 0 {
|
||||||
|
self.free_slots |= 1 << slot;
|
||||||
|
let top = KERNEL_STACK_BASE + ((slot + 1) * KERNEL_SLOT_SIZE);
|
||||||
|
return KernelStack::allocate(address_space, top, allocator);
|
||||||
|
}
|
||||||
|
slot += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(StackCreateError::OutOfStacks)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free(&mut self, stack: &KernelStack) {
|
||||||
|
let slot = (stack.top().as_usize() - KERNEL_STACK_BASE) / KERNEL_SLOT_SIZE - 1;
|
||||||
|
self.free_slots &= !(1 << slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod syscall;
|
||||||
|
pub mod tcb;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
use crate::{hcf, println};
|
||||||
|
|
||||||
|
pub fn handle(
|
||||||
|
syscall_num: u64,
|
||||||
|
arg0: u64,
|
||||||
|
arg1: u64,
|
||||||
|
arg2: u64,
|
||||||
|
arg3: u64,
|
||||||
|
arg4: u64,
|
||||||
|
arg5: u64,
|
||||||
|
) -> u64 {
|
||||||
|
println!(
|
||||||
|
"Syscall nr={:#X} args=({:#X}, {:#X}, {:#X}, {:#X}, {:#X}, {:#X})",
|
||||||
|
syscall_num, arg0, arg1, arg2, arg3, arg4, arg5
|
||||||
|
);
|
||||||
|
hcf();
|
||||||
|
0
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
use crate::{
|
||||||
|
arch::ThreadContext,
|
||||||
|
memory::{AddressSpace, KernelStack, VirtualAddr},
|
||||||
|
println,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Thread Control Block
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum ThreadState {
|
||||||
|
Ready,
|
||||||
|
Running,
|
||||||
|
Blocked,
|
||||||
|
Dead,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Tcb {
|
||||||
|
pub id: usize,
|
||||||
|
pub state: ThreadState,
|
||||||
|
pub kernel_stack: KernelStack,
|
||||||
|
pub context: ThreadContext,
|
||||||
|
pub address_space: AddressSpace,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tcb {
|
||||||
|
pub fn new_user(
|
||||||
|
id: usize,
|
||||||
|
address_space: AddressSpace,
|
||||||
|
kernel_stack: KernelStack,
|
||||||
|
user_entry: VirtualAddr,
|
||||||
|
user_stack: VirtualAddr,
|
||||||
|
) -> Self {
|
||||||
|
let context = ThreadContext::new(user_entry, user_stack, kernel_stack.top());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
state: ThreadState::Ready,
|
||||||
|
kernel_stack,
|
||||||
|
context,
|
||||||
|
address_space,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn run_first_user(user_tcb: &Tcb) {
|
||||||
|
let previous_interrupts = crate::arch::disable_interrupts_and_save();
|
||||||
|
|
||||||
|
let mut boot_thread_ctx = ThreadContext::empty();
|
||||||
|
unsafe {
|
||||||
|
user_tcb.address_space.activate();
|
||||||
|
crate::arch::set_kernel_stack(user_tcb.kernel_stack.top());
|
||||||
|
crate::arch::switch_context(&mut boot_thread_ctx, &user_tcb.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::arch::restore_interrupts(previous_interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn switch(prev: &mut Tcb, next: &Tcb) {
|
||||||
|
let previous_interrupts = crate::arch::disable_interrupts_and_save();
|
||||||
|
|
||||||
|
if prev.address_space != next.address_space {
|
||||||
|
unsafe { next.address_space.activate() };
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::arch::set_kernel_stack(next.kernel_stack.top());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
crate::arch::switch_context(&mut prev.context, &next.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::arch::restore_interrupts(previous_interrupts);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user