From 5ce5c323f149b09e955955bd01b9447f6fa0e2d3 Mon Sep 17 00:00:00 2001 From: zolark173 Date: Wed, 29 May 2024 16:52:31 +0800 Subject: [PATCH 1/6] refactor shell input code for clarity --- kernel/src/os/shell.rs | 123 ++++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 52 deletions(-) diff --git a/kernel/src/os/shell.rs b/kernel/src/os/shell.rs index 738e018e7..bb63293c6 100644 --- a/kernel/src/os/shell.rs +++ b/kernel/src/os/shell.rs @@ -1,11 +1,7 @@ use super::file_system::cpio; -use super::stdio::{get_line, print, print_hex_now, println_now}; use crate::cpu::uart::recv_async; -use crate::os::timer; use crate::println; -use alloc::boxed::Box; use alloc::string::{String, ToString}; -use core::arch::asm; pub mod commands; use alloc::vec::Vec; @@ -71,62 +67,76 @@ fn get_input(commands: &Vec) -> String { loop { if let Some(c) = unsafe { recv_async() } { - if c == b'\r' { - println!(""); - break input_buffer; - } else if c == b'\t' { - let mut matched_commands = Vec::new(); - for command in commands.iter() { - let name = command.get_name(); - if name.starts_with(input_buffer.as_str()) { - matched_commands.push(command); - } + match c { + b'\r' => { + println!(""); + break input_buffer; } + b'\t' => { + let mut matched_commands = Vec::new(); + for command in commands.iter() { + let name = command.get_name(); + if name.starts_with(input_buffer.as_str()) { + matched_commands.push(command); + } + } - if matched_commands.len() == 1 { - let match_name = matched_commands[0].get_name(); - let match_name_remaining = &match_name[input_buffer.len()..]; - input_buffer.push_str(match_name_remaining); - input_buffer.push(' '); - print!("{} ", match_name_remaining); - } else { - if matched_commands.len() > 1 { - // find the common prefix - 'prefix: for idx in input_buffer.len().. { - match matched_commands[0].get_name().as_bytes().get(idx) { - Some(c) => { - for cmd in &matched_commands { - if cmd.get_name().as_bytes().get(idx).unwrap_or(&0).clone() - != *c - { - break 'prefix; - } + if matched_commands.len() == 1 { + let match_name = matched_commands[0].get_name(); + let match_name_remaining = &match_name[input_buffer.len()..]; + input_buffer.push_str(match_name_remaining); + input_buffer.push(' '); + print!("{} ", match_name_remaining); + } else { + if matched_commands.len() > 1 { + // find the common prefix + let first_command_name = matched_commands[0].get_name().as_bytes(); + for idx in input_buffer.len().. { + if let Some(c) = first_command_name.get(idx) { + let all_command_matched = matched_commands.iter().all(|cmd| { + *cmd.get_name().as_bytes().get(idx).unwrap_or(&0) == *c + }); + if !all_command_matched { + break; } + input_buffer.push(*c as char); + } else { + break; } - None => break, } } - } - let padding = commands.iter().map(|cmd| cmd.get_name().len()).max().unwrap_or(0); - - // print all matches - println!(""); - for cmd in matched_commands.iter() { - println!("{: "); + print!("{}", input_buffer); + } + } + 127 => { + if !input_buffer.is_empty() { + input_buffer.pop(); + print!("\x08 \x08"); } - print!("> "); - print!("{}", input_buffer); } - } else if c == 127 { - if !input_buffer.is_empty() { - input_buffer.pop(); - print!("\x08 \x08"); + c => { + input_buffer.push(c as char); + print!("{}", c as char); } - } else { - input_buffer.push(c as char); - print!("{}", c as char); } } } @@ -145,7 +155,7 @@ pub fn start(initrd_start: u32) { print!("> "); let input = get_input(&commands); - let mut input = input.trim().split_whitespace(); + let mut input = input.split_whitespace(); let input_command = input.next().unwrap_or(""); let input_args: Vec<&str> = input.collect(); @@ -158,9 +168,18 @@ pub fn start(initrd_start: u32) { }; if input_command == "help" { - let padding = commands.iter().map(|cmd| cmd.get_name().len()).max().unwrap_or(0); + let padding = commands + .iter() + .map(|cmd| cmd.get_name().len()) + .max() + .unwrap_or(0); for cmd in commands.iter() { - println!("{: Date: Sat, 1 Jun 2024 18:35:49 +0800 Subject: [PATCH 2/6] Add mmu kernel space support --- kernel/src/cpu.rs | 3 +- kernel/src/cpu/boot.rs | 19 +-- kernel/src/cpu/boot.s | 52 ++++---- kernel/src/cpu/device_tree.rs | 12 +- kernel/src/cpu/mmu.rs | 118 ++++++++++++++++++ kernel/src/cpu/registers.rs | 6 +- kernel/src/linker.ld | 10 +- kernel/src/os/allocator/buddy_system.rs | 5 +- kernel/src/os/exception_handler.rs | 8 +- .../os/exception_handler/exception_handler.s | 10 +- kernel/src/os/thread.rs | 18 ++- 11 files changed, 194 insertions(+), 67 deletions(-) create mode 100644 kernel/src/cpu/mmu.rs diff --git a/kernel/src/cpu.rs b/kernel/src/cpu.rs index 780b1ae8c..843b01a3c 100644 --- a/kernel/src/cpu.rs +++ b/kernel/src/cpu.rs @@ -3,4 +3,5 @@ mod registers; pub mod uart; pub mod mailbox; pub mod reboot; -mod device_tree; \ No newline at end of file +mod device_tree; +mod mmu; diff --git a/kernel/src/cpu/boot.rs b/kernel/src/cpu/boot.rs index 84db5d058..b86c7a651 100644 --- a/kernel/src/cpu/boot.rs +++ b/kernel/src/cpu/boot.rs @@ -2,7 +2,6 @@ use crate::cpu::{device_tree::DeviceTree, mailbox, uart}; use crate::os::stdio::{print_hex_now, println_now}; use crate::os::{allocator, shell, thread, timer}; use crate::println; -use alloc::boxed::Box; use core::arch::{asm, global_asm}; global_asm!(include_str!("boot.s")); @@ -13,14 +12,15 @@ pub unsafe fn _start_rust() { timer::init(); thread::init(); allocator::init(); - allocator::reserve(0x0000_0000 as *mut u8, 0x0000_1000); // Device reserved memory - allocator::reserve(0x0003_0000 as *mut u8, 0x0004_0000); // Stack - allocator::reserve(0x0007_5000 as *mut u8, 0x0000_0004); // CS counter - allocator::reserve(0x0007_5100 as *mut u8, 0x0000_0004); // device tree address - allocator::reserve(0x0008_0000 as *mut u8, 0x0008_0000); // Code - allocator::reserve(0x0800_0000 as *mut u8, 0x0010_0000); // Initramfs + allocator::reserve(0xFFFF_0000_0000_2000 as *mut u8, 0x3000); + allocator::reserve(0xFFFF_0000_0000_0000 as *mut u8, 0x0000_1000); // Device reserved memory + allocator::reserve(0xFFFF_0000_0003_0000 as *mut u8, 0x0004_0000); // Stack + allocator::reserve(0xFFFF_0000_0007_5000 as *mut u8, 0x0000_0004); // CS counter + allocator::reserve(0xFFFF_0000_0007_5100 as *mut u8, 0x0000_0004); // device tree address + allocator::reserve(0xFFFF_0000_0008_0000 as *mut u8, 0x0008_0000); // Code + allocator::reserve(0xFFFF_0000_0800_0000 as *mut u8, 0x0010_0000); // Initramfs allocator::reserve(DeviceTree::get_address(), 0x0100_0000); // Device Tree - allocator::reserve(0x0880_0000 as *mut u8, 0x0780_0000); // Simple Allocator + allocator::reserve(0xFFFF_0000_0880_0000 as *mut u8, 0x0780_0000); // Simple Allocator // Enable interrupts asm!("msr DAIFClr, 0xf"); @@ -51,7 +51,8 @@ pub unsafe fn _start_rust() { print_information(); shell::start(initrd_start); - loop {} + + panic!("Shell stoped."); } fn print_information() { diff --git a/kernel/src/cpu/boot.s b/kernel/src/cpu/boot.s index 140779445..a4a48f1f7 100644 --- a/kernel/src/cpu/boot.s +++ b/kernel/src/cpu/boot.s @@ -1,6 +1,8 @@ .section .text._start -_stack_start = 0x70000 +_STACK_START = 0xffff000000070000 +_CS_COUNTER_ADDRESS = 0x75000 +_DEVICE_TREE_ADDRESS = 0x75100 .global _start .global _bss_start @@ -12,23 +14,35 @@ _stack_start = 0x70000 .endm _start: - # Store the address of the device tree - # Should be removed when building for a real hardware - ldr x1, =0x75100 + ldr x1, =_DEVICE_TREE_ADDRESS str x0, [x1] - mrs x0, mpidr_el1 - cbz x0, .L_parking_loop + // Clear CS counter + ldr x0, =_CS_COUNTER_ADDRESS + str xzr, [x0] + + // Change EL + bl .from_el2_to_el1 - # Initailize stack pointer - ldr x0, =_stack_start + mrs x0, CurrentEL + cmp x0, #0x4 // Check if we are in EL1 + bne .from_el2_to_el1 + + // Initailize stack pointer + ldr x0, =0x70000 mov sp, x0 - # CS counter - ldr x0, =0x75000 - str xzr, [x0] + bl setup_mmu + + ldr x1, = boot_rest // indirect branch to the virtual address + br x1 + +boot_rest: + // Initailize stack pointer + ldr x0, =_STACK_START + mov sp, x0 - # Initialize bss + // Initialize bss ADR_REL x0, _bss_start ADR_REL x1, _bss_end .L_clear_bss: @@ -38,17 +52,11 @@ _start: b .L_clear_bss .L_done_clearing: - bl .from_el2_to_el1 - - mrs x0, CurrentEL - cmp x0, #0x4 // Check if we are in EL1 - bne .from_el2_to_el1 - -.set_exception_vector_table: + // Initialize exception vector table adr x0, exception_vector_table msr vbar_el1, x0 - # Call rust main function + // Call rust main function b _start_rust .from_el2_to_el1: @@ -61,9 +69,5 @@ _start: msr sp_el1, x0 eret // return to EL1 -.L_parking_loop: - wfe - b .L_parking_loop - .size _start, . - _start .type _start, function diff --git a/kernel/src/cpu/device_tree.rs b/kernel/src/cpu/device_tree.rs index 64a4552d7..e8e061a5e 100644 --- a/kernel/src/cpu/device_tree.rs +++ b/kernel/src/cpu/device_tree.rs @@ -112,7 +112,7 @@ impl Default for DeviceTree { } impl DeviceTree { - const DEVICE_TREE_ADDRESS: *const u32 = 0x75100 as *const u32; + const DEVICE_TREE_ADDRESS: *const u64 = 0x75100 as *const u64; const FDT_BEGIN_NODE: u32 = 0x00000001; const FDT_END_NODE: u32 = 0x00000002; const FDT_PROP: u32 = 0x00000003; @@ -124,12 +124,12 @@ impl DeviceTree { } pub fn get_address() -> *mut u8 { - unsafe { *(DeviceTree::DEVICE_TREE_ADDRESS) as *mut u8 } + (unsafe { *(DeviceTree::DEVICE_TREE_ADDRESS) } | 0xFFFF_0000_0000_0000) as *mut u8 } pub fn init() -> DeviceTree { let mut ret = DeviceTree { - device_tree_ptr: unsafe { *(DeviceTree::DEVICE_TREE_ADDRESS) } as *const u8, + device_tree_ptr: DeviceTree::get_address(), ..Default::default() }; @@ -194,9 +194,9 @@ impl DeviceTree { } fn construct_node(&self, now_node: &mut Node, offset: usize, depth: u32) -> usize { - // println("Constructing node"); - // print_dec(offset as u32); - // print_dec(depth); + // println_now("Constructing node"); + // print_hex_now(offset as u32); + // print_hex_now(depth); let mut i = offset; loop { // unsafe { diff --git a/kernel/src/cpu/mmu.rs b/kernel/src/cpu/mmu.rs new file mode 100644 index 000000000..993c38562 --- /dev/null +++ b/kernel/src/cpu/mmu.rs @@ -0,0 +1,118 @@ +use core::arch::asm; +use core::ptr::{read_volatile, write_volatile}; + +use crate::println; + +const TCR_CONFIG_REGION_48BIT: usize = ((64 - 48) << 0) | ((64 - 48) << 16); +const TCR_CONFIG_4KB: usize = (0b00 << 14) | (0b00 << 30); +const TCR_CONFIG_DEFAULT: usize = TCR_CONFIG_REGION_48BIT | TCR_CONFIG_4KB | (0b101usize << 32); + +const MAIR_DEVICE_NG_NR_NE: usize = 0b00000000; +const MAIR_NORMAL_NOCACHE: usize = 0b01000100; +const MAIR_IDX_DEVICE_NG_NR_NE: usize = 0; +const MAIR_IDX_NORMAL_NOCACHE: usize = 1; +const MAIR_CONFIG_DEFAULT: usize = (MAIR_DEVICE_NG_NR_NE << (MAIR_IDX_DEVICE_NG_NR_NE * 8)) + | (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8)); + +const PD_TABLE: usize = 0b11; +const PD_BLOCK: usize = 0b01; +const PD_ACCESS: usize = 1 << 10; +const AP_RW_EL0: usize = 0b01 << 6; + +const BOOT_PGD_ATTR: usize = PD_TABLE; +const BOOT_PUD_ATTR_DEVICE: usize = + PD_ACCESS | (0 << 6) | (MAIR_IDX_DEVICE_NG_NR_NE << 2) | PD_BLOCK; +const BOOT_PUD_ATTR_NORMAL: usize = + PD_ACCESS | (0 << 6) | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_BLOCK; + +const PGD_ADDRESS: usize = 0x2000; +const PUD_ADDRESS: usize = 0x3000; +const PMD_ADDRESS: usize = 0x4000; + +unsafe fn add_entry() {} + +/* +ESR_EL1 +100100 1 0 ~ 0 1 001110 +^ ^ ^ ^ +| | | | +| | | Permission fault, level2 +| | | +| | Abort caused by an instruction writing to a memory location. +| | +| 32-bit instruction trap +| +EC: Data Abort exception from a lower Exception level. +Used for MMU faults generated by data accesses, alignment faults other than those caused by Stack Pointer misalignment, and synchronous External aborts, including synchronous parity or ECC errors. Not used for debug-related exceptions. +*/ + +#[no_mangle] +unsafe extern "C" fn setup_mmu() { + // Initialize TCR + asm!( + "msr tcr_el1, {0}", + in(reg) TCR_CONFIG_DEFAULT, + ); + + // Initialize MAIR + asm!( + "msr mair_el1, {0}", + in(reg) MAIR_CONFIG_DEFAULT, + ); + + // Identity Paging + write_volatile(PGD_ADDRESS as *mut usize, PUD_ADDRESS | BOOT_PGD_ATTR); + write_volatile( + PUD_ADDRESS as *mut usize, + PMD_ADDRESS | PD_ACCESS | AP_RW_EL0 | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_TABLE, + ); + write_volatile( + (PUD_ADDRESS + 8) as *mut usize, + 0x40000000usize | BOOT_PUD_ATTR_DEVICE, + ); + + const PMD_SIZE: usize = 1024 * 1024 * 2; + + for i in 0..512 { + let entry_address = (PMD_ADDRESS + i * 8) as *mut usize; + let page_address = i * PMD_SIZE; + + if page_address < 0x1000 { + write_volatile( + entry_address, + page_address | PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2 | PD_BLOCK), + ); + } else if page_address < 0x3C00_0000 { + write_volatile( + entry_address, + page_address | PD_ACCESS | AP_RW_EL0 | (MAIR_IDX_NORMAL_NOCACHE << 2 | PD_BLOCK), + ); + } else { + write_volatile( + entry_address, + page_address | PD_ACCESS | (MAIR_IDX_DEVICE_NG_NR_NE << 2 | PD_BLOCK), + ); + } + } + + asm!("isb"); + + asm!( + "msr ttbr0_el1, {PGD_addr}", + "msr ttbr1_el1, {PGD_addr}", + + PGD_addr = in(reg) PGD_ADDRESS, + ); + + // Enable MMU + asm!( + "mrs {tmp}, sctlr_el1", + "orr {tmp}, {tmp}, 1", + "msr sctlr_el1, {tmp}", + tmp = out(reg) _, + ); +} + +pub fn test() {} + +pub fn map_pages() {} diff --git a/kernel/src/cpu/registers.rs b/kernel/src/cpu/registers.rs index 6f43eb0b7..dec0e2a52 100644 --- a/kernel/src/cpu/registers.rs +++ b/kernel/src/cpu/registers.rs @@ -28,8 +28,8 @@ pub enum Register { } impl Register { - pub fn addr(&self) -> u32 { - *self as u32 + pub fn addr(&self) -> u64 { + *self as u64 } } @@ -37,7 +37,7 @@ pub struct MMIO {} impl MMIO { pub fn read(reg: Register) -> u32 { - unsafe { read_volatile(reg.addr() as *const u32) } + unsafe { read_volatile((reg.addr() + 0xFFFF_0000_0000_0000) as *const u32) } } pub fn write(reg: Register, data: u32) { diff --git a/kernel/src/linker.ld b/kernel/src/linker.ld index ce84287bf..5e287866a 100644 --- a/kernel/src/linker.ld +++ b/kernel/src/linker.ld @@ -1,21 +1,17 @@ -/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */ -__rpi_phys_binary_load_addr = 0x80000; +__rpi_phys_binary_load_addr = 0xffff000000080000; ENTRY(__rpi_phys_binary_load_addr) SECTIONS { - . = __rpi_phys_binary_load_addr; + . = __rpi_phys_binary_load_addr; - /*********************************************************************************************** - * Code - ***********************************************************************************************/ .text : ALIGN(8) { KEEP(*(.text._start)) *(.text*) /* *(.text.exception_vector_table) */ } - + .rodata : ALIGN(8) { *(.rodata*) } .data : ALIGN(8) { *(.data*) } diff --git a/kernel/src/os/allocator/buddy_system.rs b/kernel/src/os/allocator/buddy_system.rs index cea522b1c..777dfd752 100644 --- a/kernel/src/os/allocator/buddy_system.rs +++ b/kernel/src/os/allocator/buddy_system.rs @@ -1,13 +1,11 @@ use super::super::stdio::{print_hex_now, println_now}; use super::SimpleAllocator; use crate::println; -use alloc::boxed::Box; use alloc::collections::{BTreeMap, BTreeSet}; use alloc::vec::Vec; use core::{ alloc::{GlobalAlloc, Layout}, cmp, - ops::Deref, ptr::null_mut, }; @@ -15,7 +13,7 @@ static mut PRINT_DEBUG: bool = false; const FRAME_MAX_ORDER: u32 = 25; const MIN_FRAME_SIZE: usize = 32; const MAX_FRAME_SIZE: usize = MIN_FRAME_SIZE * 2usize.pow(FRAME_MAX_ORDER - 1); -const START_ADDRESS: usize = 0x0000_0000; +const START_ADDRESS: usize = 0xFFFF_0000_0000_0000; static mut FRAMES: Option, &SimpleAllocator>> = None; @@ -197,6 +195,7 @@ pub unsafe fn reserve(ptr: *mut u8, size: usize) { Some(frame) => { if PRINT_DEBUG { print_hex_now(frame.clone() as u32); + print_hex_now(((frame.clone() as u64) >> 32) as u32); } buddy_set.remove(&frame.clone()); } diff --git a/kernel/src/os/exception_handler.rs b/kernel/src/os/exception_handler.rs index 79c0cd3aa..54e9987c4 100644 --- a/kernel/src/os/exception_handler.rs +++ b/kernel/src/os/exception_handler.rs @@ -6,12 +6,16 @@ use core::{ ptr::read_volatile, }; -use super::stdio::println_now; mod system_call; pub mod trap_frame; global_asm!(include_str!("exception_handler/exception_handler.s")); +#[no_mangle] +unsafe extern "C" fn exception_handler_rust(trap_frame_ptr: *mut u64) { + panic!("Unknown exception"); +} + #[no_mangle] unsafe extern "C" fn irq_handler_rust(trap_frame_ptr: *mut u64) { thread::TRAP_FRAME_PTR = Some(trap_frame_ptr); @@ -25,7 +29,7 @@ unsafe extern "C" fn irq_handler_rust(trap_frame_ptr: *mut u64) { if read_volatile(0x3F21_5000 as *const u32) & 0x1 == 0x1 { uart::irq_handler(); } - + thread::TRAP_FRAME_PTR = None; } diff --git a/kernel/src/os/exception_handler/exception_handler.s b/kernel/src/os/exception_handler/exception_handler.s index bfa7e9521..f79f81be9 100644 --- a/kernel/src/os/exception_handler/exception_handler.s +++ b/kernel/src/os/exception_handler/exception_handler.s @@ -87,9 +87,15 @@ exception_vector_table: add sp, sp, 36 * 8 .endm -# Dummy handlers +// Dummy handlers .global exception_handler -exception_handler: + exception_handler: + save_all + bl disable_irq + mov x0, sp + bl exception_handler_rust + bl enable_irq + load_all eret .global irq_handler diff --git a/kernel/src/os/thread.rs b/kernel/src/os/thread.rs index 42717f2b7..bbe7deecc 100644 --- a/kernel/src/os/thread.rs +++ b/kernel/src/os/thread.rs @@ -141,8 +141,8 @@ pub fn create_thread( stack, stack_size, state: ThreadState::Waiting(ThreadContext { - pc: program as usize, - sp: stack as usize + stack_size, + pc: (program as u64 & 0xFFFFFFFF) as usize, + sp: (stack as u64 & 0xFFFFFFFF) as usize + stack_size, ..Default::default() }), }); @@ -151,6 +151,7 @@ pub fn create_thread( id } +#[no_mangle] pub fn run_thread(id: Option) { unsafe { let threads = THREADS.as_mut().unwrap(); @@ -162,9 +163,9 @@ pub fn run_thread(id: Option) { .expect("Thread not found"), None => threads .iter_mut() - .find(|thread| match &thread.state { - ThreadState::Waiting(_) => true, - _ => false, + .find(|thread| { + let state = &thread.state; + matches!(ThreadState::Waiting, state) }) .expect("No running thread"), }; @@ -226,11 +227,8 @@ pub fn save_context(trap_frame_ptr: *mut u64) -> bool { let current_thread = threads .iter_mut() .find(|thread| { - if let ThreadState::Running(_) = &thread.state { - true - } else { - false - } + let state = &thread.state; + matches!(ThreadState::Running, state) }) .expect("SAVE_CONTEXT: No running thread"); From af18e375b8e0eb0d24960b7d16eea3c760657d70 Mon Sep 17 00:00:00 2001 From: zolark173 Date: Mon, 10 Jun 2024 02:11:33 +0800 Subject: [PATCH 3/6] Update buddy system alignment checking --- kernel/src/os/allocator/buddy_system.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/kernel/src/os/allocator/buddy_system.rs b/kernel/src/os/allocator/buddy_system.rs index 777dfd752..ed5f8953f 100644 --- a/kernel/src/os/allocator/buddy_system.rs +++ b/kernel/src/os/allocator/buddy_system.rs @@ -117,7 +117,7 @@ unsafe fn dealloc_iter(ptr: *mut u8, size: usize) -> bool { let buddy_ptr = match current_ptr as usize % (current_size * 2) { 0 => current_ptr.add(current_size), - rem => current_ptr.sub(current_size), + _ => current_ptr.sub(current_size), }; let buddy_set = FRAMES.as_mut().unwrap().get_mut(¤t_size).unwrap(); @@ -219,11 +219,9 @@ unsafe impl GlobalAlloc for BuddyAllocator { } assert_ne!(FRAMES, None, "BuddyAllocator is not initialized"); - assert!(layout.align() <= MIN_FRAME_SIZE, "Alignment too large"); + assert!(layout.align() <= MIN_FRAME_SIZE || layout.size() >= layout.align(), "Alignment too large"); - let allocate_status = alloc_recursive(layout.size()); - - match allocate_status { + match alloc_recursive(layout.size()) { Some(ptr) => { if PRINT_DEBUG { println_now("Memory allocated"); From e8494ad1454cff36e77d6312ae158a1132b52a19 Mon Sep 17 00:00:00 2001 From: zolark173 Date: Mon, 10 Jun 2024 02:12:44 +0800 Subject: [PATCH 4/6] feat: Program will be loaded in unit of 4KB --- kernel/src/os/shell/commands.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/src/os/shell/commands.rs b/kernel/src/os/shell/commands.rs index 3e8ef6df1..160f7608c 100644 --- a/kernel/src/os/shell/commands.rs +++ b/kernel/src/os/shell/commands.rs @@ -1,4 +1,4 @@ -use crate::os::stdio::{get_line, println_now}; +use crate::os::stdio::{get_line, print_hex_now, println_now}; use crate::os::{allocator, thread, timer}; use crate::println; use alloc::boxed::Box; @@ -96,9 +96,10 @@ pub fn exec(args: Vec) { } }; let stack_size = 4096; + let program_size = (filesize + (0x1000 - 1)) & !(0x1000 - 1); let program_ptr = unsafe { - alloc::alloc::alloc(Layout::from_size_align(filesize, THREAD_ALIGNMENT).unwrap()) + alloc::alloc::alloc(Layout::from_size_align(program_size, THREAD_ALIGNMENT).unwrap()) }; let program_stack_ptr = unsafe { alloc::alloc::alloc(Layout::from_size_align(stack_size, THREAD_ALIGNMENT).unwrap()) @@ -118,7 +119,7 @@ pub fn exec(args: Vec) { } } - let pid = thread::create_thread(program_ptr, filesize, program_stack_ptr, stack_size); + let pid = thread::create_thread(program_ptr, program_size, program_stack_ptr, stack_size); println!("PID: {}", pid); println!("PC: {:X?}", program_ptr); } From 4cbfc1eb856bf4f9c93cf72093373f1e40401df6 Mon Sep 17 00:00:00 2001 From: zolark173 Date: Mon, 10 Jun 2024 02:13:12 +0800 Subject: [PATCH 5/6] feat: Add virtual memory support --- kernel/src/cpu.rs | 2 +- kernel/src/cpu/boot.rs | 4 +- kernel/src/cpu/mailbox.rs | 18 +- kernel/src/cpu/mmu.rs | 248 ++++++++++++++++-- kernel/src/cpu/registers.rs | 6 +- kernel/src/main.rs | 1 + kernel/src/os/allocator.rs | 2 +- kernel/src/os/critical_section.rs | 2 +- kernel/src/os/exception_handler.rs | 19 +- .../src/os/exception_handler/system_call.rs | 24 +- kernel/src/os/file_system/cpio.rs | 2 + kernel/src/os/shell.rs | 2 +- kernel/src/os/thread.rs | 184 +++++++------ 13 files changed, 387 insertions(+), 127 deletions(-) diff --git a/kernel/src/cpu.rs b/kernel/src/cpu.rs index 843b01a3c..77021f74c 100644 --- a/kernel/src/cpu.rs +++ b/kernel/src/cpu.rs @@ -4,4 +4,4 @@ pub mod uart; pub mod mailbox; pub mod reboot; mod device_tree; -mod mmu; +pub mod mmu; diff --git a/kernel/src/cpu/boot.rs b/kernel/src/cpu/boot.rs index b86c7a651..a9776cb38 100644 --- a/kernel/src/cpu/boot.rs +++ b/kernel/src/cpu/boot.rs @@ -21,7 +21,7 @@ pub unsafe fn _start_rust() { allocator::reserve(0xFFFF_0000_0800_0000 as *mut u8, 0x0010_0000); // Initramfs allocator::reserve(DeviceTree::get_address(), 0x0100_0000); // Device Tree allocator::reserve(0xFFFF_0000_0880_0000 as *mut u8, 0x0780_0000); // Simple Allocator - + // Enable interrupts asm!("msr DAIFClr, 0xf"); @@ -37,7 +37,7 @@ pub unsafe fn _start_rust() { } val = val.swap_bytes(); println!("Initrd start address: {:#X}", val); - val + val as u64 + 0xFFFF_0000_0000_0000 } None => { println!("No initrd"); diff --git a/kernel/src/cpu/mailbox.rs b/kernel/src/cpu/mailbox.rs index 527b56697..bb52da4b4 100644 --- a/kernel/src/cpu/mailbox.rs +++ b/kernel/src/cpu/mailbox.rs @@ -3,11 +3,12 @@ use core::{ ptr::{read_volatile, write_volatile}, usize, }; +use alloc::format; -const MAILBOX_BASE: u32 = 0x3F00_B880; -const MAILBOX_READ: u32 = MAILBOX_BASE + 0x00; -const MAILBOX_STATUS: u32 = MAILBOX_BASE + 0x18; -const MAILBOX_WRITE: u32 = MAILBOX_BASE + 0x20; +const MAILBOX_BASE: usize = 0xFFFF_0000_3F00_B880; +const MAILBOX_READ: usize = MAILBOX_BASE + 0x00; +const MAILBOX_STATUS: usize = MAILBOX_BASE + 0x18; +const MAILBOX_WRITE: usize = MAILBOX_BASE + 0x20; const MAILBOX_EMPTY: u32 = 0x4000_0000; const MAILBOX_FULL: u32 = 0x8000_0000; @@ -27,9 +28,12 @@ pub enum MailboxTag { #[inline(never)] pub fn mailbox_call(channel: u8, mailbox: *mut u32) { - let mut mailbox_addr = mailbox as u32; + let mut mailbox_addr = mailbox.mask(0xFFFF_FFFF) as u32; mailbox_addr = mailbox_addr & !0xF | (channel as u32 & 0xF); + // println_now(format!("MBOX_ADDR {:x}", mailbox as usize).as_str()); + // println_now(format!("MBOX_ADDR {:x}", mailbox_addr).as_str()); + unsafe { while (read_volatile(MAILBOX_STATUS as *const u32) & MAILBOX_FULL) != 0 {} write_volatile(MAILBOX_WRITE as *mut u32, mailbox_addr); @@ -61,6 +65,8 @@ pub fn get(tag: MailboxTag) -> (u32, u32) { unsafe { let mailbox_ptr = mailbox.as_mut_ptr().add(start_idx); + // println_now(format!("MBOX_ADDR {:x}", mailbox_ptr as usize).as_str()); + match tag { MailboxTag::GetBoardRevision => { write_volatile(mailbox_ptr.add(0), 7 * 4); // buffer size in bytes @@ -77,7 +83,7 @@ pub fn get(tag: MailboxTag) -> (u32, u32) { write_volatile(mailbox_ptr.add(5), 0); // value buffer write_volatile(mailbox_ptr.add(6), END_TAG); - mailbox_call(8, mailbox.as_mut_ptr().add(start_idx) as *mut u32); + mailbox_call(8, mailbox_ptr); } match tag { diff --git a/kernel/src/cpu/mmu.rs b/kernel/src/cpu/mmu.rs index 993c38562..a97650776 100644 --- a/kernel/src/cpu/mmu.rs +++ b/kernel/src/cpu/mmu.rs @@ -1,6 +1,9 @@ +use alloc::vec::Vec; +use core::alloc::Layout; use core::arch::asm; -use core::ptr::{read_volatile, write_volatile}; +use core::ptr::{self, null_mut, read_volatile, write_volatile}; +use crate::os::stdio::{print_hex_now, println_now}; use crate::println; const TCR_CONFIG_REGION_48BIT: usize = ((64 - 48) << 0) | ((64 - 48) << 16); @@ -17,7 +20,9 @@ const MAIR_CONFIG_DEFAULT: usize = (MAIR_DEVICE_NG_NR_NE << (MAIR_IDX_DEVICE_NG_ const PD_TABLE: usize = 0b11; const PD_BLOCK: usize = 0b01; const PD_ACCESS: usize = 1 << 10; + const AP_RW_EL0: usize = 0b01 << 6; +const AP_RO_EL0: usize = 0b11 << 6; const BOOT_PGD_ATTR: usize = PD_TABLE; const BOOT_PUD_ATTR_DEVICE: usize = @@ -29,23 +34,6 @@ const PGD_ADDRESS: usize = 0x2000; const PUD_ADDRESS: usize = 0x3000; const PMD_ADDRESS: usize = 0x4000; -unsafe fn add_entry() {} - -/* -ESR_EL1 -100100 1 0 ~ 0 1 001110 -^ ^ ^ ^ -| | | | -| | | Permission fault, level2 -| | | -| | Abort caused by an instruction writing to a memory location. -| | -| 32-bit instruction trap -| -EC: Data Abort exception from a lower Exception level. -Used for MMU faults generated by data accesses, alignment faults other than those caused by Stack Pointer misalignment, and synchronous External aborts, including synchronous parity or ECC errors. Not used for debug-related exceptions. -*/ - #[no_mangle] unsafe extern "C" fn setup_mmu() { // Initialize TCR @@ -64,7 +52,7 @@ unsafe extern "C" fn setup_mmu() { write_volatile(PGD_ADDRESS as *mut usize, PUD_ADDRESS | BOOT_PGD_ATTR); write_volatile( PUD_ADDRESS as *mut usize, - PMD_ADDRESS | PD_ACCESS | AP_RW_EL0 | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_TABLE, + PMD_ADDRESS | PD_ACCESS | AP_RW_EL0 | MAIR_IDX_NORMAL_NOCACHE << 2 | PD_TABLE, ); write_volatile( (PUD_ADDRESS + 8) as *mut usize, @@ -80,12 +68,12 @@ unsafe extern "C" fn setup_mmu() { if page_address < 0x1000 { write_volatile( entry_address, - page_address | PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2 | PD_BLOCK), + page_address | PD_ACCESS | MAIR_IDX_NORMAL_NOCACHE << 2 | PD_BLOCK, ); } else if page_address < 0x3C00_0000 { write_volatile( entry_address, - page_address | PD_ACCESS | AP_RW_EL0 | (MAIR_IDX_NORMAL_NOCACHE << 2 | PD_BLOCK), + page_address | PD_ACCESS | AP_RW_EL0 | MAIR_IDX_NORMAL_NOCACHE << 2 | PD_BLOCK, ); } else { write_volatile( @@ -95,8 +83,6 @@ unsafe extern "C" fn setup_mmu() { } } - asm!("isb"); - asm!( "msr ttbr0_el1, {PGD_addr}", "msr ttbr1_el1, {PGD_addr}", @@ -113,6 +99,218 @@ unsafe extern "C" fn setup_mmu() { ); } -pub fn test() {} +pub fn vm_setup( + program_ptr: *mut u8, + program_size: usize, + stack_ptr: *mut u8, + stack_size: usize, +) -> *mut u8 { + let pgd_page_ptr = unsafe { + alloc::alloc::alloc(Layout::from_size_align(4096, 4096).expect("Cannot allocate")) + }; + + unsafe { + core::ptr::write_bytes(pgd_page_ptr, 0, 4096); + } + + // println!("=====PROGRAM====="); + // program + vm_setup_recursive( + 0, + pgd_page_ptr as *mut usize, + 0, + 0, + program_ptr, + program_size, + MAIR_NORMAL_NOCACHE, + ); + + // println!("=====STACK====="); + // stack + vm_setup_recursive( + 0, + pgd_page_ptr as *mut usize, + 0, + 0x1_0000_0000_0000 - stack_size, + stack_ptr, + stack_size, + MAIR_NORMAL_NOCACHE, + ); + + // GPU + vm_setup_recursive( + 0, + pgd_page_ptr as *mut usize, + 0, + 0x3C00_0000, + 0x3C00_0000 as *mut u8, + 0x400_0000, + MAIR_DEVICE_NG_NR_NE, + ); + + pgd_page_ptr.mask(0xFFFF_FFFF) +} + +fn vm_setup_recursive( + level: u8, + page_table_ptr: *mut usize, + page_table_base: usize, + vm_addr: usize, + pm_addr: *mut u8, + size: usize, + MAIR: usize, +) { + if level > 3 { + return; + } + + let memory_size_per_entry: usize = match level { + 0 => 1024 * 1024 * 1024 * 512, + 1 => 1024 * 1024 * 1024, + 2 => 1024 * 1024 * 2, + 3 => 1024 * 4, + _ => panic!("Cannot find level"), + }; + + // if level < 4 { + // println!("\nLevel: {}", level); + // println!("Page table addr: {:x}", page_table_ptr as usize); + // println!("Page table base: {:x}", page_table_base); + // println!("vm_addr: {:x}", vm_addr); + // println!("entry_size: {} byte", memory_size_per_entry); + // println!("size: {} byte", size); + // } + + assert!( + memory_size_per_entry * 512 >= size, + "Cannot fit in virtual memory table" + ); + + for i in 0..512 { + let entry_ptr = unsafe { page_table_ptr.add(i) }; + let entry_vm_addr = page_table_base + i * memory_size_per_entry; + + if vm_addr + size <= entry_vm_addr || entry_vm_addr + memory_size_per_entry <= vm_addr { + // unsafe { + // write_volatile(entry_ptr, 0); + // } + continue; + } + + // println!("entry_ptr: {:x}", entry_ptr as usize); + // println!("entry_vm_addr: {:x}", entry_vm_addr); -pub fn map_pages() {} + let address; + let entry; + let original_entry = unsafe { read_volatile(entry_ptr) }; + + if level < 3 { + if original_entry & PD_ACCESS > 0 { + address = + ((original_entry & 0xFFFF_FFFF_F000usize) + 0xFFFF_0000_0000_0000) as *mut u8; + entry = None; + } else { + address = unsafe { + alloc::alloc::alloc( + Layout::from_size_align(4096, 4096).expect("Cannot allocate"), + ) + }; + entry = Some( + address.mask(0xFFFF_FFFF_FFFF) as usize + | PD_ACCESS + | AP_RW_EL0 + | MAIR << 2 + | PD_TABLE, + ); + } + } else { + assert!(entry_vm_addr >= vm_addr); + let offset = entry_vm_addr - vm_addr; + + address = unsafe { pm_addr.add(offset) }; + entry = + Some(address.mask(0xFFFF_FFFF_FFFF) as usize | PD_ACCESS | AP_RW_EL0 | MAIR << 2 | 0b11); + } + + // println!("entry: {:016x}", entry); + // let test = ((entry >> 12) & 0xFFFF_FFFF) << 12; + // println!("test: {:x}", test); + // println!("addr: {:x}", address as usize); + + assert!(address.align_offset(4096) == 0, "Broken"); + // println!(""); + + unsafe { + if let Some(entry_data) = entry { + write_volatile(entry_ptr, entry_data); + } + + let vm = entry_vm_addr.max(vm_addr); + let pm = pm_addr.add(vm - vm_addr); + + vm_setup_recursive( + level + 1, + address as *mut usize, + entry_vm_addr, + vm, + pm, + memory_size_per_entry.min(size), + MAIR, + ); + } + } +} + +pub fn vm_to_pm(vm_addr: usize) -> usize { + let pgd_addr: usize; + unsafe { + if vm_addr < 0xFFFF_0000_0000_0000 { + asm!( + "mrs {PGD_addr}, ttbr0_el1", + PGD_addr = out(reg) pgd_addr, + ); + } else { + asm!( + "mrs {PGD_addr}, ttbr1_el1", + PGD_addr = out(reg) pgd_addr, + ); + } + } + vm_to_pm_addr_recursive( + 0, + (pgd_addr + 0xFFFF_0000_0000_0000) as *mut u64, + 0, + vm_addr, + ) +} + +fn vm_to_pm_addr_recursive( + level: u8, + page_table: *mut u64, + page_table_base: usize, + vm_addr: usize, +) -> usize { + let memory_size_per_entry: usize = match level { + 0 => 1024 * 1024 * 1024 * 512, + 1 => 1024 * 1024 * 1024, + 2 => 1024 * 1024 * 2, + 3 => 1024 * 4, + _ => panic!("Cannot find level"), + }; + + let target_entry_idx = (vm_addr - page_table_base) / memory_size_per_entry; + let offset = vm_addr - page_table_base - target_entry_idx * memory_size_per_entry; + let entry = unsafe { read_volatile(page_table.add(target_entry_idx)) }; + let target_address = (entry & 0xFFFF_FFFF_F000u64) as usize; + + if level < 3 { + vm_to_pm_addr_recursive( + level + 1, + (target_address + 0xFFFF_0000_0000_0000) as *mut u64, + page_table_base + memory_size_per_entry * target_entry_idx, + vm_addr, + ) + } else { + target_address + offset + 0xFFFF_0000_0000_0000 + } +} diff --git a/kernel/src/cpu/registers.rs b/kernel/src/cpu/registers.rs index dec0e2a52..0dee5ee26 100644 --- a/kernel/src/cpu/registers.rs +++ b/kernel/src/cpu/registers.rs @@ -28,8 +28,8 @@ pub enum Register { } impl Register { - pub fn addr(&self) -> u64 { - *self as u64 + pub fn addr(&self) -> usize { + *self as usize } } @@ -42,7 +42,7 @@ impl MMIO { pub fn write(reg: Register, data: u32) { unsafe { - write_volatile(reg.addr() as *mut u32, data); + write_volatile((reg.addr() + 0xFFFF_0000_0000_0000) as *mut u32, data); } } } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index b7f9e50f1..1ed4bbc4a 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -2,6 +2,7 @@ #![no_std] #![feature(allocator_api)] #![feature(btreemap_alloc)] +#![feature(ptr_mask)] #![allow(unused_variables)] #![allow(non_camel_case_types)] diff --git a/kernel/src/os/allocator.rs b/kernel/src/os/allocator.rs index 783b0629d..474c0d961 100644 --- a/kernel/src/os/allocator.rs +++ b/kernel/src/os/allocator.rs @@ -45,7 +45,7 @@ unsafe impl GlobalAlloc for SimpleAllocator { panic!("Out of memory"); } - allocated_start + allocated_start.add(0xFFFF_0000_0000_0000) } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {} diff --git a/kernel/src/os/critical_section.rs b/kernel/src/os/critical_section.rs index 5a928d949..e72526853 100644 --- a/kernel/src/os/critical_section.rs +++ b/kernel/src/os/critical_section.rs @@ -1,7 +1,7 @@ use core::arch::asm; use core::ptr::{read_volatile, write_volatile}; -const CS_COUNTER: *mut u32 = 0x7_5000 as *mut u32; +const CS_COUNTER: *mut u32 = 0xFFFF_0000_0007_5000 as *mut u32; #[no_mangle] #[inline(never)] diff --git a/kernel/src/os/exception_handler.rs b/kernel/src/os/exception_handler.rs index 54e9987c4..5c67a72c8 100644 --- a/kernel/src/os/exception_handler.rs +++ b/kernel/src/os/exception_handler.rs @@ -1,4 +1,7 @@ +use alloc::format; + use crate::cpu::uart; +use crate::os::stdio::{print_hex_now, println_now}; use crate::os::{thread, timer}; use core::{ @@ -13,6 +16,7 @@ global_asm!(include_str!("exception_handler/exception_handler.s")); #[no_mangle] unsafe extern "C" fn exception_handler_rust(trap_frame_ptr: *mut u64) { + println_now("Unknown exception"); panic!("Unknown exception"); } @@ -20,16 +24,16 @@ unsafe extern "C" fn exception_handler_rust(trap_frame_ptr: *mut u64) { unsafe extern "C" fn irq_handler_rust(trap_frame_ptr: *mut u64) { thread::TRAP_FRAME_PTR = Some(trap_frame_ptr); - let interrupt_source = read_volatile(0x40000060 as *const u32); + let interrupt_source = read_volatile(0xFFFF_0000_4000_0060 as *const u32); if interrupt_source & 0x2 > 0 { timer::irq_handler(); } - if read_volatile(0x3F21_5000 as *const u32) & 0x1 == 0x1 { + if read_volatile(0xFFFF_0000_3F21_5000 as *const u32) & 0x1 == 0x1 { uart::irq_handler(); } - + thread::TRAP_FRAME_PTR = None; } @@ -62,10 +66,11 @@ unsafe extern "C" fn svc_handler_rust(trap_frame_ptr: *mut u64) { } // println!("System call number: {}", system_call_num); } else { - println!("Unknown exception: {:08x}", esr_el1); - println!("ELR_EL1: {:08x}", elr_el1); - println!("SP_EL0: {:08x}", sp_el0); - loop {} + println_now("Unknown exception"); + println_now(format!("ESR_EL1: {:08x}", esr_el1).as_str()); + println_now(format!("ELR_EL1: {:08x}", elr_el1).as_str()); + println_now(format!("SP_EL0: {:08x}", sp_el0).as_str()); + panic!(); } thread::TRAP_FRAME_PTR = None; diff --git a/kernel/src/os/exception_handler/system_call.rs b/kernel/src/os/exception_handler/system_call.rs index 680ab705c..8e1f9fe0d 100644 --- a/kernel/src/os/exception_handler/system_call.rs +++ b/kernel/src/os/exception_handler/system_call.rs @@ -1,14 +1,19 @@ use super::super::thread; use super::trap_frame; -use crate::cpu::uart; +use crate::{cpu::{mmu::vm_to_pm, uart}, os::stdio::println_now}; use alloc::{string::String, vec::Vec}; use core::ptr::{read_volatile, write_volatile}; +use alloc::format; +#[no_mangle] +#[inline(never)] pub unsafe fn get_pid(trap_frame_ptr: *mut u64, current_pc: u64) { let pid = thread::get_id_by_pc(current_pc as usize).expect("Failed to get PID"); trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, pid as u64); } +#[no_mangle] +#[inline(never)] pub unsafe fn read_from_uart(trap_frame_ptr: *mut u64) { let buf = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as *mut u8; let size = trap_frame::get(trap_frame_ptr, trap_frame::Register::X1) as usize; @@ -34,6 +39,8 @@ pub unsafe fn read_from_uart(trap_frame_ptr: *mut u64) { trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, idx as u64); } +#[no_mangle] +#[inline(never)] pub unsafe fn write_to_uart(trap_frame_ptr: *mut u64) { let buf = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as *const u8; let size = trap_frame::get(trap_frame_ptr, trap_frame::Register::X1) as usize; @@ -45,6 +52,8 @@ pub unsafe fn write_to_uart(trap_frame_ptr: *mut u64) { trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, size as u64); } +#[no_mangle] +#[inline(never)] pub unsafe fn exec(trap_frame_ptr: *mut u64) { let mut program_name_ptr = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as *mut u8; let program_args_ptr = trap_frame::get(trap_frame_ptr, trap_frame::Register::X1) as *mut u8; @@ -63,6 +72,8 @@ pub unsafe fn exec(trap_frame_ptr: *mut u64) { thread::restore_context(trap_frame_ptr); } +#[no_mangle] +#[inline(never)] pub unsafe fn fork(trap_frame_ptr: *mut u64) { thread::save_context(trap_frame_ptr); match thread::fork() { @@ -71,6 +82,8 @@ pub unsafe fn fork(trap_frame_ptr: *mut u64) { } } +#[no_mangle] +#[inline(never)] pub unsafe fn exit(trap_frame_ptr: *mut u64) { let pc = trap_frame::get(trap_frame_ptr, trap_frame::Register::PC) as usize; let pid = thread::get_id_by_pc(pc).expect("Failed to get PID"); @@ -78,16 +91,23 @@ pub unsafe fn exit(trap_frame_ptr: *mut u64) { thread::switch_to_thread(None, trap_frame_ptr); } +#[no_mangle] +#[inline(never)] pub unsafe fn mailbox_call(trap_frame_ptr: *mut u64) { // mail box let channel = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as u8; let mbox_ptr = trap_frame::get(trap_frame_ptr, trap_frame::Register::X1) as *mut u32; - crate::cpu::mailbox::mailbox_call(channel, mbox_ptr); + let mbox_pm = vm_to_pm(mbox_ptr as usize); + println_now(format!("PM: {:X}", mbox_pm).as_str()); + + crate::cpu::mailbox::mailbox_call(channel, mbox_pm as *mut u32); trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, 1); } +#[no_mangle] +#[inline(never)] pub unsafe fn kill(trap_frame_ptr: *mut u64) { let pc = trap_frame::get(trap_frame_ptr, trap_frame::Register::PC) as usize; let my_pid = thread::get_id_by_pc(pc).expect("Failed to get PID"); diff --git a/kernel/src/os/file_system/cpio.rs b/kernel/src/os/file_system/cpio.rs index 72d244953..8720cc607 100644 --- a/kernel/src/os/file_system/cpio.rs +++ b/kernel/src/os/file_system/cpio.rs @@ -3,6 +3,8 @@ use crate::println; use crate::os::stdio::*; use alloc::vec::Vec; +use alloc::format; + #[allow(dead_code)] pub enum CpioHeaderField { Magic, diff --git a/kernel/src/os/shell.rs b/kernel/src/os/shell.rs index bb63293c6..905cd2fc0 100644 --- a/kernel/src/os/shell.rs +++ b/kernel/src/os/shell.rs @@ -142,7 +142,7 @@ fn get_input(commands: &Vec) -> String { } } -pub fn start(initrd_start: u32) { +pub fn start(initrd_start: u64) { unsafe { INITRAMFS = Some(cpio::CpioArchive::load(initrd_start as *const u8)); } diff --git a/kernel/src/os/thread.rs b/kernel/src/os/thread.rs index bbe7deecc..a5efd2feb 100644 --- a/kernel/src/os/thread.rs +++ b/kernel/src/os/thread.rs @@ -1,15 +1,16 @@ -use crate::os::stdio::{print_hex_now, println_now}; - use super::{exception_handler::trap_frame, shell::INITRAMFS}; +use crate::cpu::mmu::{self, vm_setup, vm_to_pm}; +use crate::os::stdio::{print_hex_now, println_now}; use alloc::{alloc::dealloc, string::String, vec::Vec}; +use core::ptr::{read_volatile, write_volatile}; use core::{alloc::Layout, arch::asm}; static mut THREADS: Option> = None; pub static mut TRAP_FRAME_PTR: Option<*mut u64> = None; -pub const THREAD_ALIGNMENT: usize = 32; +pub const THREAD_ALIGNMENT: usize = 4096; -#[derive(Clone)] +#[derive(Clone, Default)] struct ThreadContext { x0: usize, x1: usize, @@ -48,48 +49,6 @@ struct ThreadContext { spsr: usize, } -impl Default for ThreadContext { - fn default() -> Self { - ThreadContext { - x0: 0, - x1: 0, - x2: 0, - x3: 0, - x4: 0, - x5: 0, - x6: 0, - x7: 0, - x8: 0, - x9: 0, - x10: 0, - x11: 0, - x12: 0, - x13: 0, - x14: 0, - x15: 0, - x16: 0, - x17: 0, - x18: 0, - x19: 0, - x20: 0, - x21: 0, - x22: 0, - x23: 0, - x24: 0, - x25: 0, - x26: 0, - x27: 0, - x28: 0, - x29: 0, - x30: 0, - x31: 0, - pc: 0, - sp: 0, - spsr: 0, - } - } -} - #[derive(Clone)] enum ThreadState { Running(ThreadContext), @@ -105,6 +64,7 @@ struct Thread { stack: *mut u8, stack_size: usize, state: ThreadState, + page_table: *mut u8, } impl Default for Thread { @@ -116,6 +76,7 @@ impl Default for Thread { stack: core::ptr::null_mut(), stack_size: 0, state: ThreadState::Dead, + page_table: core::ptr::null_mut(), } } } @@ -134,6 +95,9 @@ pub fn create_thread( ) -> usize { let threads = unsafe { THREADS.as_mut().unwrap() }; let id = threads.len(); + + let page_table = mmu::vm_setup(program, program_size, stack, stack_size); + threads.push(Thread { id, program, @@ -141,11 +105,13 @@ pub fn create_thread( stack, stack_size, state: ThreadState::Waiting(ThreadContext { - pc: (program as u64 & 0xFFFFFFFF) as usize, - sp: (stack as u64 & 0xFFFFFFFF) as usize + stack_size, + pc: 0, + sp: 0xFFFF_FFFF_FFF0, ..Default::default() }), + page_table, }); + println!("Stack SP: {:X?}", stack as usize + stack_size); println!("Thread created: {}", id); id @@ -179,6 +145,11 @@ pub fn run_thread(id: Option) { }; if let ThreadState::Running(context) = &target_thread.state { + asm!( + "msr ttbr0_el1, {PGD_addr}", + PGD_addr = in(reg) target_thread.page_table + ); + asm!( "mrs {tmp}, cntkctl_el1", "orr {tmp}, {tmp}, 1", @@ -212,8 +183,9 @@ pub fn get_id_by_pc(pc: usize) -> Option { .iter() .find(|thread| { if let ThreadState::Running(context) = &thread.state { - (thread.program as usize) <= pc - && pc < (thread.program as usize + thread.program_size) + true + // (thread.program as usize) <= pc + // && pc < (thread.program as usize + thread.program_size) } else { false } @@ -228,7 +200,7 @@ pub fn save_context(trap_frame_ptr: *mut u64) -> bool { .iter_mut() .find(|thread| { let state = &thread.state; - matches!(ThreadState::Running, state) + matches!(state, ThreadState::Running(_)) }) .expect("SAVE_CONTEXT: No running thread"); @@ -272,7 +244,7 @@ pub fn save_context(trap_frame_ptr: *mut u64) -> bool { ThreadState::Running(context) } else { - ThreadState::Dead + panic!(); }; true @@ -425,6 +397,7 @@ pub fn restore_context(trap_frame_ptr: *mut u64) { pub fn context_switching() { // println!("Context switching"); + let threads = unsafe { THREADS.as_mut().unwrap() }; let trap_frame_ptr = unsafe { TRAP_FRAME_PTR.unwrap() }; @@ -433,6 +406,18 @@ pub fn context_switching() { return; } + // for i in threads.iter() { + // println!("PID: {}", i.id); + // println!( + // "state: {}", + // match i.state { + // ThreadState::Running(_) => "Running", + // ThreadState::Waiting(_) => "Waiting", + // ThreadState::Dead => "Dead", + // } + // ); + // } + let mut current_thread_iter = threads.iter_mut(); let mut current_thread; let mut next_thread; @@ -451,15 +436,15 @@ pub fn context_switching() { } } - next_thread = current_thread_iter.find(|thread| match &thread.state { - ThreadState::Waiting(_) => true, - _ => false, + next_thread = current_thread_iter.find(|thread| { + let state = &thread.state; + matches!(state, ThreadState::Waiting(_)) }); if next_thread.is_none() { - next_thread = threads.iter_mut().find(|thread| match &thread.state { - ThreadState::Waiting(_) => true, - _ => false, + next_thread = threads.iter_mut().find(|thread| { + let state = &thread.state; + matches!(state, ThreadState::Waiting(_)) }); assert!(next_thread.is_some(), "No thread to switch"); } @@ -494,6 +479,20 @@ pub fn context_switching() { let next_thread_id = next_thread.id; + unsafe { + asm!( + "dsb ish", + "msr ttbr0_el1, {PGD_addr}", + "tlbi vmalle1is", + "dsb ish", + "isb", + PGD_addr = in(reg) next_thread.page_table + ); + } + + // println!("PID: {}", next_thread_id); + // println!("Page table: {:x}", next_thread.page_table as usize); + restore_context(trap_frame_ptr); // println!("Context switched: {}", next_thread_id); @@ -510,9 +509,9 @@ pub fn context_switching() { pub fn fork() -> Option { let threads = unsafe { THREADS.as_mut().unwrap() }; - let current_thread = threads.iter().find(|thread| match &thread.state { - ThreadState::Running(_) => true, - _ => false, + let current_thread = threads.iter().find(|thread| { + let state = &thread.state; + matches!(state, ThreadState::Running(_)) }); if current_thread.is_some() { @@ -538,6 +537,14 @@ pub fn fork() -> Option { .expect("Layout error"), ) }; + + let page_table = vm_setup( + program_ptr, + current_thread.program_size, + stack_ptr, + current_thread.stack_size, + ); + unsafe { core::ptr::copy_nonoverlapping( current_thread.program, @@ -551,9 +558,6 @@ pub fn fork() -> Option { ); } - let pc = current_thread_context.pc - current_thread.program as usize + program_ptr as usize; - let sp = current_thread_context.sp - current_thread.stack as usize + stack_ptr as usize; - println!("Old pc: {:X}", current_thread_context.pc); threads.push(Thread { id: new_pid, @@ -562,16 +566,15 @@ pub fn fork() -> Option { stack: stack_ptr, stack_size: current_thread.stack_size, state: ThreadState::Waiting(ThreadContext { - pc, - sp, x0: 0, ..*current_thread_context }), + page_table, }); println!("New program start: {:X}", program_ptr as usize); - println!("new pc: {:X}", pc); + // println!("new pc: {:X}", pc); println!("New stack start: {:X}", stack_ptr as usize); - println!("new sp: {:X}", sp); + // println!("new sp: {:X}", sp); Some(new_pid) } else { @@ -582,9 +585,9 @@ pub fn fork() -> Option { pub fn exec(program_name: String, program_args: Vec) { let threads = unsafe { THREADS.as_mut().unwrap() }; - let current_thread = threads.iter_mut().find(|thread| match &thread.state { - ThreadState::Running(_) => true, - _ => false, + let current_thread = threads.iter_mut().find(|thread| { + let state = &thread.state; + matches!(state, ThreadState::Running(_)) }); if current_thread.is_none() { @@ -625,6 +628,7 @@ pub fn exec(program_name: String, program_args: Vec) { Layout::from_size_align(4096, THREAD_ALIGNMENT).expect("Layout error"), ); + // Clear memory core::ptr::write_bytes(current_thread.program, 0, current_thread.program_size); INITRAMFS @@ -634,11 +638,27 @@ pub fn exec(program_name: String, program_args: Vec) { current_thread.program_size = filesize; current_thread.stack_size = stack_size; + + current_thread.page_table = vm_setup( + current_thread.program, + current_thread.program_size, + current_thread.stack, + current_thread.stack_size, + ); + + asm!( + "dsb ish", + "msr ttbr0_el1, {PGD_addr}", + "tlbi vmalle1is", + "dsb ish", + "isb", + PGD_addr = in(reg) current_thread.page_table + ); } current_thread.state = ThreadState::Running(ThreadContext { - pc: current_thread.program as usize, - sp: current_thread.stack as usize + stack_size, + pc: 0, + sp: 0xFFFF_FFFF_FFF0, ..ThreadContext::default() }); } @@ -664,10 +684,7 @@ pub fn switch_to_thread(id: Option, trap_frame_ptr: *mut u64) { .expect("Thread not found"), None => threads .iter_mut() - .find(|thread| match &thread.state { - ThreadState::Waiting(_) => true, - _ => false, - }) + .find(|thread| matches!(&thread.state, ThreadState::Waiting(_))) .expect("No running thread"), }; @@ -678,6 +695,17 @@ pub fn switch_to_thread(id: Option, trap_frame_ptr: *mut u64) { }; assert!(matches!(target_thread.state, ThreadState::Running(_))); - + + unsafe { + asm!( + "dsb ish", + "msr ttbr0_el1, {PGD_addr}", + "tlbi vmalle1is", + "dsb ish", + "isb", + PGD_addr = in(reg) target_thread.page_table + ); + } + restore_context(trap_frame_ptr); } From b5b8e5c65c191652fbcd96e966fdd1596b8bb16e Mon Sep 17 00:00:00 2001 From: zolark173 Date: Thu, 27 Jun 2024 19:43:34 +0800 Subject: [PATCH 6/6] FS support --- kernel/Cargo.toml | 2 +- kernel/src/cpu/boot.rs | 12 +- kernel/src/main.rs | 2 - kernel/src/os/exception_handler.rs | 13 ++ .../src/os/exception_handler/system_call.rs | 160 ++++++++++++++- kernel/src/os/file_system.rs | 5 +- kernel/src/os/file_system/cpio.rs | 19 +- kernel/src/os/file_system/initramfs.rs | 60 ++++++ kernel/src/os/file_system/tmpfs.rs | 67 +++++++ kernel/src/os/file_system/vfs.rs | 184 ++++++++++++++++++ kernel/src/os/panic_wait.rs | 2 + kernel/src/os/shell.rs | 48 ++++- kernel/src/os/shell/commands.rs | 170 +++++++++++++++- kernel/src/os/thread.rs | 148 ++++++++++---- 14 files changed, 827 insertions(+), 65 deletions(-) create mode 100644 kernel/src/os/file_system/initramfs.rs create mode 100644 kernel/src/os/file_system/tmpfs.rs create mode 100644 kernel/src/os/file_system/vfs.rs diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index d077897a9..d95450142 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [profile.release] -strip = "symbols" # This strips both symbol table (symtab) and string table (strtab) along with debugging information. +# strip = true # This strips both symbol table (symtab) and string table (strtab) along with debugging information. [dependencies] diff --git a/kernel/src/cpu/boot.rs b/kernel/src/cpu/boot.rs index a9776cb38..e0a77dcd4 100644 --- a/kernel/src/cpu/boot.rs +++ b/kernel/src/cpu/boot.rs @@ -3,6 +3,7 @@ use crate::os::stdio::{print_hex_now, println_now}; use crate::os::{allocator, shell, thread, timer}; use crate::println; use core::arch::{asm, global_asm}; +use crate::os::file_system::{vfs, tmpfs, initramfs}; global_asm!(include_str!("boot.s")); @@ -25,9 +26,14 @@ pub unsafe fn _start_rust() { // Enable interrupts asm!("msr DAIFClr, 0xf"); + vfs::register_fs(tmpfs::init()); + vfs::mount("tmpfs", "/"); + vfs::register_fs(initramfs::init()); + vfs::mount("initramfs", "/initramfs/"); + let dt = DeviceTree::init(); - println_now("Device tree initialized"); + // println_now("Device tree initialized"); let initrd_start = match dt.get("linux,initrd-start") { Some(v) => { @@ -46,7 +52,7 @@ pub unsafe fn _start_rust() { }; // let initrd_start = 0x8000000; - println_now("before print information"); + // println_now("before print information"); print_information(); @@ -62,5 +68,5 @@ fn print_information() { let memory = mailbox::get(mailbox::MailboxTag::GetArmMemory); println!("Memory base: {:#010X}", memory.0); println!("Memory size: {:#010X}", memory.1); - println!("Boot time: {} ms", timer::get_time_ms()); + // println!("Boot time: {} ms", timer::get_time_ms()); } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 1ed4bbc4a..ab97065ef 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -3,8 +3,6 @@ #![feature(allocator_api)] #![feature(btreemap_alloc)] #![feature(ptr_mask)] -#![allow(unused_variables)] -#![allow(non_camel_case_types)] mod cpu; mod os; diff --git a/kernel/src/os/exception_handler.rs b/kernel/src/os/exception_handler.rs index 5c67a72c8..bb42271b7 100644 --- a/kernel/src/os/exception_handler.rs +++ b/kernel/src/os/exception_handler.rs @@ -42,11 +42,16 @@ unsafe extern "C" fn svc_handler_rust(trap_frame_ptr: *mut u64) { let esr_el1: u64; let elr_el1: u64; let sp_el0: u64; + let sp_el1: u64; + asm!("mrs {esr_el1}, esr_el1", esr_el1 = out(reg) esr_el1); asm!("mrs {elr_el1}, elr_el1", elr_el1 = out(reg) elr_el1); asm!("mrs {sp_el0}, sp_el0", sp_el0 = out(reg) sp_el0); + asm!("mrs {sp_el1}, sp_el1", sp_el1 = out(reg) sp_el1); thread::TRAP_FRAME_PTR = Some(trap_frame_ptr); + assert_eq!(elr_el1, trap_frame::get(trap_frame_ptr, trap_frame::Register::PC), "ELR_EL1 and PC mismatch"); + // println!("ESR_EL1: {:08x}", esr_el1); // println!("ELR_EL1: {:08x}", elr_el1); // println!("SP_EL0: {:08x}", sp_el0); @@ -62,6 +67,13 @@ unsafe extern "C" fn svc_handler_rust(trap_frame_ptr: *mut u64) { 5 => system_call::exit(trap_frame_ptr), 6 => system_call::mailbox_call(trap_frame_ptr), 7 => system_call::kill(trap_frame_ptr), + 11 => system_call::open(trap_frame_ptr), + 12 => system_call::close(trap_frame_ptr), + 13 => system_call::write(trap_frame_ptr), + 14 => system_call::read(trap_frame_ptr), + 15 => system_call::mkdir(trap_frame_ptr), + 16 => system_call::mount(trap_frame_ptr), + 17 => system_call::chdir(trap_frame_ptr), _ => panic!("Unknown system call number: {}", system_call_num), } // println!("System call number: {}", system_call_num); @@ -70,6 +82,7 @@ unsafe extern "C" fn svc_handler_rust(trap_frame_ptr: *mut u64) { println_now(format!("ESR_EL1: {:08x}", esr_el1).as_str()); println_now(format!("ELR_EL1: {:08x}", elr_el1).as_str()); println_now(format!("SP_EL0: {:08x}", sp_el0).as_str()); + println_now(format!("SP_EL1: {:08x}", sp_el1).as_str()); panic!(); } diff --git a/kernel/src/os/exception_handler/system_call.rs b/kernel/src/os/exception_handler/system_call.rs index 8e1f9fe0d..9786ee03f 100644 --- a/kernel/src/os/exception_handler/system_call.rs +++ b/kernel/src/os/exception_handler/system_call.rs @@ -1,14 +1,19 @@ -use super::super::thread; +use super::super::{file_system::vfs, thread}; use super::trap_frame; -use crate::{cpu::{mmu::vm_to_pm, uart}, os::stdio::println_now}; +use crate::os::file_system::vfs::path_process; +use crate::{ + cpu::{mmu::vm_to_pm, uart}, + os::stdio::println_now, +}; +use alloc::vec; +use alloc::{format, slice}; use alloc::{string::String, vec::Vec}; use core::ptr::{read_volatile, write_volatile}; -use alloc::format; #[no_mangle] #[inline(never)] pub unsafe fn get_pid(trap_frame_ptr: *mut u64, current_pc: u64) { - let pid = thread::get_id_by_pc(current_pc as usize).expect("Failed to get PID"); + let pid = thread::get_running_thread_id().expect("Failed to get PID"); trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, pid as u64); } @@ -86,7 +91,7 @@ pub unsafe fn fork(trap_frame_ptr: *mut u64) { #[inline(never)] pub unsafe fn exit(trap_frame_ptr: *mut u64) { let pc = trap_frame::get(trap_frame_ptr, trap_frame::Register::PC) as usize; - let pid = thread::get_id_by_pc(pc).expect("Failed to get PID"); + let pid = thread::get_running_thread_id().expect("Failed to get PID"); thread::kill(pid); thread::switch_to_thread(None, trap_frame_ptr); } @@ -100,7 +105,7 @@ pub unsafe fn mailbox_call(trap_frame_ptr: *mut u64) { let mbox_pm = vm_to_pm(mbox_ptr as usize); println_now(format!("PM: {:X}", mbox_pm).as_str()); - + crate::cpu::mailbox::mailbox_call(channel, mbox_pm as *mut u32); trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, 1); @@ -109,12 +114,149 @@ pub unsafe fn mailbox_call(trap_frame_ptr: *mut u64) { #[no_mangle] #[inline(never)] pub unsafe fn kill(trap_frame_ptr: *mut u64) { - let pc = trap_frame::get(trap_frame_ptr, trap_frame::Register::PC) as usize; - let my_pid = thread::get_id_by_pc(pc).expect("Failed to get PID"); let pid = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as usize; + + let my_pid = thread::get_running_thread_id().expect("Failed to get PID"); + if my_pid != pid { thread::kill(pid); } else { - println!("Cannot kill itself"); + println!("Cannot kill yourself"); + } +} + +#[no_mangle] +#[inline(never)] +pub unsafe fn open(trap_frame_ptr: *mut u64) { + let path_ptr = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as *mut u8; + let flags = trap_frame::get(trap_frame_ptr, trap_frame::Register::X1) as u32; + + let path = char_ptr_to_string(path_ptr); + let path = running_thread_full_path(path); + + // Create file + if flags == 0x40 { + vfs::create(path.as_str()); + } + + let fd = vfs::open(path.as_str()).expect("Failed to open file"); + let fd = running_thread_new_fd(fd); + + trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, fd as u64); +} + +#[no_mangle] +#[inline(never)] +pub unsafe fn close(trap_frame_ptr: *mut u64) { + let fd = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as usize; + + let fd = running_thread_fd_lookup(fd); + vfs::close(fd); + + trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, 0); +} + +#[no_mangle] +#[inline(never)] +pub unsafe fn write(trap_frame_ptr: *mut u64) { + let fd = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as usize; + let buf = trap_frame::get(trap_frame_ptr, trap_frame::Register::X1) as *const u8; + let len = trap_frame::get(trap_frame_ptr, trap_frame::Register::X2) as usize; + + let fd = running_thread_fd_lookup(fd); + + let written_len = vfs::write(fd, slice::from_raw_parts(buf, len), len); + assert!(written_len <= len); + + trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, written_len as u64); +} + +#[no_mangle] +#[inline(never)] +pub unsafe fn read(trap_frame_ptr: *mut u64) { + let fd = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as usize; + let buf = trap_frame::get(trap_frame_ptr, trap_frame::Register::X1) as *mut u8; + let len = trap_frame::get(trap_frame_ptr, trap_frame::Register::X2) as usize; + + let fd = running_thread_fd_lookup(fd); + let buf_arr = slice::from_raw_parts_mut(buf, len); + + let read_len = vfs::read(fd, buf_arr, len); + assert!(read_len <= len); + + trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, read_len as u64); +} + +#[no_mangle] +#[inline(never)] +pub unsafe fn mkdir(trap_frame_ptr: *mut u64) { + let path_ptr = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as *mut u8; + let _mode = trap_frame::get(trap_frame_ptr, trap_frame::Register::X1) as u32; // unused + + let path = char_ptr_to_string(path_ptr); + + vfs::create(path.as_str()); + + trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, 0); +} + +#[no_mangle] +#[inline(never)] +pub unsafe fn mount(trap_frame_ptr: *mut u64) { + // unimplemented!("MOUNT system call is not implemented"); + let _src = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as *mut u8; + let target_ptr = trap_frame::get(trap_frame_ptr, trap_frame::Register::X1) as *mut u8; + let fs_ptr = trap_frame::get(trap_frame_ptr, trap_frame::Register::X2) as *mut u8; + let _flags = trap_frame::get(trap_frame_ptr, trap_frame::Register::X3) as u32; + let _data = trap_frame::get(trap_frame_ptr, trap_frame::Register::X4) as *mut u8; + + let target = char_ptr_to_string(target_ptr); + let fs = char_ptr_to_string(fs_ptr); + + vfs::mount(fs.as_str(), target.as_str()); + + trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, 0); +} + +#[no_mangle] +#[inline(never)] +pub unsafe fn chdir(trap_frame_ptr: *mut u64) { + let path_ptr = trap_frame::get(trap_frame_ptr, trap_frame::Register::X0) as *mut u8; + + let path = char_ptr_to_string(path_ptr); + let path = path_process(path.as_str()); + + let pid = thread::get_running_thread_id().expect("Failed to get running thread PID"); + thread::set_working_dir(pid, path); + + trap_frame::set(trap_frame_ptr, trap_frame::Register::X0, 0); +} + +fn char_ptr_to_string(arr: *mut u8) -> String { + let mut len = 0; + while unsafe { *arr.add(len) } != 0 { + len += 1; } + let slice = unsafe { core::slice::from_raw_parts(arr, len) }; + String::from_utf8(slice.to_vec()).expect("Failed to convert char ptr to string") +} + +fn running_thread_fd_lookup(fd: usize) -> usize { + let pid = thread::get_running_thread_id().expect("Failed to get running thread PID"); + thread::get_fd(pid, fd).expect("Failed to get file descriptor") +} + +fn running_thread_full_path(path: String) -> String { + let pid = thread::get_running_thread_id().expect("Failed to get running thread PID"); + let working_dir = thread::get_working_dir(pid).expect("Failed to get working directory"); + + let full_path = format!("{}/{}", working_dir, path); + let full_path = path_process(full_path.as_str()); + + full_path } + +fn running_thread_new_fd(fd: usize) -> usize { + let pid = thread::get_running_thread_id().expect("Failed to get running thread PID"); + thread::add_fd(pid, fd) +} \ No newline at end of file diff --git a/kernel/src/os/file_system.rs b/kernel/src/os/file_system.rs index 234dfef2b..0c15a211a 100644 --- a/kernel/src/os/file_system.rs +++ b/kernel/src/os/file_system.rs @@ -1 +1,4 @@ -pub mod cpio; \ No newline at end of file +pub mod cpio; +pub mod vfs; +pub mod tmpfs; +pub mod initramfs; \ No newline at end of file diff --git a/kernel/src/os/file_system/cpio.rs b/kernel/src/os/file_system/cpio.rs index 8720cc607..1921242d8 100644 --- a/kernel/src/os/file_system/cpio.rs +++ b/kernel/src/os/file_system/cpio.rs @@ -38,7 +38,7 @@ impl CpioArchive { let mut files = Vec::new(); let mut current_ptr = self.header_ptr; loop { - files.push(self.get_file_name(current_ptr)); + files.push(self.get_file_name(current_ptr).trim_end_matches('\0')); match self.get_next_file_ptr(current_ptr) { Some(ptr) => current_ptr = ptr, @@ -75,7 +75,7 @@ impl CpioArchive { None => break, } } - println("File not found"); + println("CPIO: File not found"); } pub fn get_filesize_by_name(&self, filename: &str) -> Option { @@ -85,18 +85,21 @@ impl CpioArchive { } } - pub fn load_file_to_memory(&self, filename: &str, addr: *mut u8) -> bool { + pub fn load_file_to_memory(&self, filename: &str, addr: *mut u8, offset: usize, len: usize) -> usize { println!("Loading file to memory: {:X?}", addr as u64); match self.get_file_content_by_name(filename) { Some(content) => { + if content.len() < offset + len { + return 0; + } + + let len = core::cmp::min(len, content.len() - offset); unsafe { - for i in 0..content.len() { - core::ptr::write(addr.add(i), content[i]); - } + addr.copy_from(content.as_ptr().add(offset), len); } - true + len } - None => false, + None => 0, } } diff --git a/kernel/src/os/file_system/initramfs.rs b/kernel/src/os/file_system/initramfs.rs new file mode 100644 index 000000000..70146a3e3 --- /dev/null +++ b/kernel/src/os/file_system/initramfs.rs @@ -0,0 +1,60 @@ +use crate::println; + +use super::cpio; +use super::vfs::{FileHandle, FileSystem}; +use alloc::boxed::Box; +use alloc::format; +use alloc::string::String; + +use super::super::shell::INITRAMFS; + +struct InitramFS; + +pub fn init() -> Box { + Box::new(InitramFS) +} + +impl FileSystem for InitramFS { + fn get_fs_name(&self) -> String { + String::from("initramfs") + } + + fn create(&mut self, _path: &str) { + println!("Cannot create file in initramfs"); + } + + fn open(&mut self, path: &str) -> bool { + let initramfs = unsafe { INITRAMFS.as_ref().unwrap() }; + let path = path.trim_start_matches('/'); + + println!("initramfs open: {}", path); + + initramfs.get_file_list().iter().any(|file| *file == path) + } + + fn close(&mut self) { + // do nothing + } + + fn lookup(&self, path: &str) -> bool { + let initramfs = unsafe { INITRAMFS.as_ref().unwrap() }; + let path = path.trim_start_matches('/'); + + initramfs + .get_file_list() + .iter() + .any(|file| file.trim_end_matches("\0") == path) + } + + fn read(&self, path: &str, offset: usize, buf: &mut [u8], len: usize) -> usize { + let initramfs = unsafe { INITRAMFS.as_ref().unwrap() }; + let path = path.trim_start_matches('/'); + + initramfs.load_file_to_memory(path, buf.as_mut_ptr(), offset, len) + } + + fn write(&mut self, path: &str, offset: usize, buf: &[u8], len: usize) -> usize { + println!("Cannot write to initramfs"); + 0 + } +} diff --git a/kernel/src/os/file_system/tmpfs.rs b/kernel/src/os/file_system/tmpfs.rs new file mode 100644 index 000000000..3dcd9bfa4 --- /dev/null +++ b/kernel/src/os/file_system/tmpfs.rs @@ -0,0 +1,67 @@ +use super::vfs::{FileHandle, FileSystem}; +use crate::alloc::string::ToString; +use alloc::boxed::Box; +use alloc::format; +use alloc::string::String; +use alloc::vec::Vec; + +struct TmpFS { + files: Vec<(String, Vec)>, +} + +pub fn init() -> Box { + let mut ret = Box::new(TmpFS { files: Vec::new() }); + ret.create("/"); + ret.create("/dev/"); + ret.create("/dev/null"); + ret.create("/test.txt"); + ret.write("/test.txt", 0, b"Hello, world!", 13); + ret +} + +impl FileSystem for TmpFS { + fn get_fs_name(&self) -> String { + String::from("tmpfs") + } + + fn create(&mut self, path: &str) { + self.files.push((path.to_string(), Vec::new())); + } + + fn open(&mut self, path: &str) -> bool { + self.files.iter().any(|(name, _)| name == path) + } + + fn close(&mut self) { + // do nothing + } + + fn lookup(&self, path: &str) -> bool { + self.files.iter().any(|(n, _)| *n == path) + } + + fn read(&self, path: &str, offset: usize, buf: &mut [u8], len: usize) -> usize { + if let Some((_, data)) = self.files.iter().find(|(name, _)| name == path) { + let data = &data[offset..]; + let len = core::cmp::min(len, data.len()); + buf[..len].copy_from_slice(&data[..len]); + len + } else { + 0 + } + } + + fn write(&mut self, path: &str, offset: usize, buf: &[u8], len: usize) -> usize { + if let Some((_, data)) = self.files.iter_mut().find(|(name, _)| name == path) { + if offset >= data.len() { + data.resize(offset + len, 0); + } + for i in 0..len { + data[offset + i] = buf[i]; + } + len + } else { + 0 + } + } +} diff --git a/kernel/src/os/file_system/vfs.rs b/kernel/src/os/file_system/vfs.rs new file mode 100644 index 000000000..111a362f4 --- /dev/null +++ b/kernel/src/os/file_system/vfs.rs @@ -0,0 +1,184 @@ +use crate::alloc::string::ToString; +use crate::println; +use alloc::boxed::Box; +use alloc::format; +use alloc::string::String; +use alloc::vec::Vec; + +static mut FS: Vec<(String, Box)> = Vec::new(); // (name, fs) +static mut MOUNT_POINTS: Vec<(String, usize)> = Vec::new(); // (mount_point, fs_idx) +static mut FILE_HANDLES: Vec = Vec::new(); + +pub struct FileHandle { + pub path: String, + pub offset: usize, + pub fs: usize, +} + +pub trait FileSystem { + fn get_fs_name(&self) -> String; + + fn lookup(&self, path: &str) -> bool; + fn create(&mut self, path: &str); + fn open(&mut self, path: &str) -> bool; + fn close(&mut self); + + fn read(&self, path: &str, offset: usize, buf: &mut [u8], len: usize) -> usize; + fn write(&mut self, path: &str, offset: usize, buf: &[u8], len: usize) -> usize; +} + +pub fn register_fs(fs: Box) { + unsafe { + // println!("Registered file system #{}: {}", FS.len(), &fs.get_fs_name()); + FS.push((fs.get_fs_name(), fs)); + } +} + +pub fn mount(fs_name: &str, path: &str) { + unsafe { + let fs_idx = FS + .iter() + .position(|(name, _)| *name == fs_name) + .expect(format!("File system not found: {}", fs_name).as_str()); + // println!("Mounting {} to {}", fs_name, path); + MOUNT_POINTS.push((path.to_string(), fs_idx)); + } +} + +fn get_fs(path: &str) -> Option<(usize, String)> { + unsafe { + let mut most_matched: Option<(usize, String)> = None; // (fs_idx, fs_path) + + for (mount_point, fs_idx) in MOUNT_POINTS.iter() { + if path.starts_with(mount_point.as_str()) { + let fs_path = path.replace(mount_point, "/"); + if most_matched.is_none() || fs_path.len() < most_matched.as_ref().unwrap().1.len() { + // println!("matching fs: {}", mount_point); + most_matched = Some((*fs_idx, fs_path)); + } + } + } + + most_matched + } +} + +pub fn path_process(path: &str) -> String { + let mut path = path.to_string(); + + let is_dir = path.ends_with("/"); + + // Only support absolute path + if !path.starts_with("/") { + panic!("Only support absolute path"); + } + + // Remove duplicate slashes + while path.contains("//") { + path = path.replace("//", "/"); + } + + // Convert ".." and "." to absolute path + let path_vec: Vec<&str> = path.split("/").collect(); + let mut new_path_vec: Vec<&str> = Vec::new(); + for i in 0..path_vec.len() { + if path_vec[i] == ".." { + new_path_vec.pop(); + } else if path_vec[i] != "." && path_vec[i] != "" { + new_path_vec.push(path_vec[i]); + } + } + + let new_path = new_path_vec.join("/"); + if new_path == "" { + "/".to_string() + } else { + if is_dir { + format!("/{}/", new_path) + } else { + format!("/{}", new_path) + } + } +} + +pub fn lookup(path: &str) -> bool { + unsafe { + let fs = get_fs(&path_process(&path)); + if let Some((fs_idx, fs_path)) = fs { + if fs_path == "/" { + return true; + } + FS[fs_idx].1.lookup(&fs_path) + } else { + false + } + } +} + +pub fn create(path: &str) { + unsafe { + let fs = get_fs(&path_process(path)); + if let Some((fs_idx, fs_path)) = fs { + FS[fs_idx].1.create(&fs_path); + } + } +} + +pub fn open(path: &str) -> Option { + unsafe { + let fs = get_fs(&path_process(path)); + if let Some((fs_idx, fs_path)) = fs { + if FS[fs_idx].1.open(&fs_path) { + FILE_HANDLES.push(FileHandle { + path: fs_path, + offset: 0, + fs: fs_idx, + }); + Some(FILE_HANDLES.len() - 1) + } else { + println!("VFS open: File not found"); + None + } + } else { + None + } + } +} + +pub fn close(fd: usize) { + unsafe { + let file = FILE_HANDLES.get(fd); + if let Some(file) = file { + FS[file.fs].1.close(); + } + } +} + +pub fn read(fd: usize, buf: &mut [u8], len: usize) -> usize { + unsafe { + let file = FILE_HANDLES.get_mut(fd); + if let Some(file) = file { + println!("fs_idx: {}", file.fs); + let fs = &FS[file.fs].1; + let count = fs.read(&file.path, file.offset, buf, len); + file.offset += count; + count + } else { + 0 + } + } +} + +pub fn write(fd: usize, buf: &[u8], len: usize) -> usize { + unsafe { + let file = FILE_HANDLES.get_mut(fd); + if let Some(file) = file { + let fs = &mut FS[file.fs].1; + let written_len = fs.write(&file.path, file.offset, buf, len); + file.offset += written_len; + written_len + } else { + 0 + } + } +} diff --git a/kernel/src/os/panic_wait.rs b/kernel/src/os/panic_wait.rs index de52e7331..fdf6e37aa 100644 --- a/kernel/src/os/panic_wait.rs +++ b/kernel/src/os/panic_wait.rs @@ -1,5 +1,6 @@ use core::panic::PanicInfo; use alloc::string::ToString; +use crate::cpu::reboot; use crate::os::stdio::*; @@ -7,5 +8,6 @@ use crate::os::stdio::*; fn panic(info: &PanicInfo) -> ! { println_now("PANIC"); println_now(info.to_string().as_str()); + reboot::reset(1000); loop {} } diff --git a/kernel/src/os/shell.rs b/kernel/src/os/shell.rs index 905cd2fc0..43a1d8090 100644 --- a/kernel/src/os/shell.rs +++ b/kernel/src/os/shell.rs @@ -13,6 +13,8 @@ fn print_time(time: u64) { } pub static mut INITRAMFS: Option = None; +pub static mut PATH: String = String::new(); +pub static mut OPENED_FILE: Option<(String, usize)> = None; fn push_all_commands(commands: &mut Vec) { commands.push(commands::command::new( @@ -60,6 +62,45 @@ fn push_all_commands(commands: &mut Vec) { "Print current exception level", commands::current_el, )); + commands.push(commands::command::new( + "cd", + "change directory", + commands::change_directory, + )); + commands.push(commands::command::new( + "mkdir", + "make directory", + commands::make_directory, + )); + commands.push(commands::command::new( + "touch", + "create file", + commands::touch, + )); + commands.push(commands::command::new( + "open", + "open a file", + commands::open, + )); + commands.push(commands::command::new( + "close", + "close opened file", + commands::close, + )); + commands.push(commands::command::new( + "read", + "read from a file", + commands::read, + )); +} + +fn print_prompt(input_buffer: &String) { + unsafe { + if OPENED_FILE.is_some() { + print!("[{}] ", OPENED_FILE.clone().unwrap().0); + } + print!("{} > {}", PATH.clone(), input_buffer); + } } fn get_input(commands: &Vec) -> String { @@ -123,8 +164,7 @@ fn get_input(commands: &Vec) -> String { width = padding ); } - print!("> "); - print!("{}", input_buffer); + print_prompt(&input_buffer); } } 127 => { @@ -145,6 +185,8 @@ fn get_input(commands: &Vec) -> String { pub fn start(initrd_start: u64) { unsafe { INITRAMFS = Some(cpio::CpioArchive::load(initrd_start as *const u8)); + PATH = String::from("/"); + OPENED_FILE = None; } let mut commands = Vec::new(); @@ -152,7 +194,7 @@ pub fn start(initrd_start: u64) { commands.sort_by(|a, b| a.get_name().cmp(b.get_name())); 'shell: loop { - print!("> "); + print_prompt(&String::new()); let input = get_input(&commands); let mut input = input.split_whitespace(); diff --git a/kernel/src/os/shell/commands.rs b/kernel/src/os/shell/commands.rs index 160f7608c..667aa1a73 100644 --- a/kernel/src/os/shell/commands.rs +++ b/kernel/src/os/shell/commands.rs @@ -1,8 +1,12 @@ +use super::super::file_system::vfs::path_process; +use crate::os::file_system::vfs; use crate::os::stdio::{get_line, print_hex_now, println_now}; use crate::os::{allocator, thread, timer}; use crate::println; use alloc::boxed::Box; +use alloc::format; use alloc::string::String; +use alloc::vec; use alloc::vec::Vec; use core::alloc::Layout; use core::arch::asm; @@ -10,7 +14,7 @@ use core::fmt::Display; use super::super::thread::THREAD_ALIGNMENT; -use super::INITRAMFS; +use super::{INITRAMFS, OPENED_FILE, PATH}; const CONTEXT_SWITCHING_DELAY: u64 = 1000 / 32; @@ -95,6 +99,7 @@ pub fn exec(args: Vec) { return; } }; + let stack_size = 4096; let program_size = (filesize + (0x1000 - 1)) & !(0x1000 - 1); @@ -111,12 +116,12 @@ pub fn exec(args: Vec) { } } - match initramfs.load_file_to_memory(filename.as_str(), program_ptr) { - true => println!("File loaded to memory"), - false => { + match initramfs.load_file_to_memory(filename.as_str(), program_ptr, 0, filesize) { + 0 => { println!("File not found"); return; } + _ => println!("File loaded to memory"), } let pid = thread::create_thread(program_ptr, program_size, program_stack_ptr, stack_size); @@ -214,3 +219,160 @@ pub fn current_el(args: Vec) { } println!("CurrentEL: {}", (current_el >> 2) & 0b11); } + +pub fn change_directory(args: Vec) { + let folder = match args.get(1) { + Some(path) => path, + None => { + println!("Usage: cd "); + return; + } + }; + + if !folder.ends_with("/") { + println!("Not a directory"); + return; + } + + let full_path = format!("{}{}", unsafe { PATH.clone() }, folder); + let full_path = path_process(full_path.as_str()); + + // Split full_path into two parts: the last part split by '/' and the rest + let mut split_path = full_path.split('/').collect::>(); + + let folder = split_path.pop().unwrap(); + let path = format!("/{}/", split_path.join("/")); + + unsafe { + if vfs::lookup(&full_path) { + PATH = full_path; + } else { + println!("Directory not found"); + } + } +} + +pub fn make_directory(args: Vec) { + let folder = match args.get(1) { + Some(path) => path, + None => { + println!("Usage: mkdir "); + return; + } + }; + + if !folder.ends_with("/") { + println!("Not a directory"); + return; + } + + unsafe { + let full_path = format!("{}{}", PATH, folder); + + if vfs::lookup(&full_path) { + println!("Directory already exists"); + } else { + vfs::create(full_path.as_str()); + } + } +} + +pub fn touch(args: Vec) { + let file = match args.get(1) { + Some(path) => path, + None => { + println!("Usage: touch "); + return; + } + }; + + if file.ends_with("/") { + println!("Not a file"); + return; + } + + unsafe { + let full_path = format!("{}{}", PATH, file); + + if vfs::lookup(&full_path) { + println!("File already exists"); + } else { + vfs::create(full_path.as_str()); + } + } +} + +pub fn open(args: Vec) { + let file = match args.get(1) { + Some(path) => path, + None => { + println!("Usage: open "); + return; + } + }; + + if file.ends_with("/") { + println!("Not a file"); + return; + } + + unsafe { + let full_path = format!("{}{}", PATH, file); + + if vfs::lookup(&full_path) { + let fd = vfs::open(full_path.as_str()); + OPENED_FILE = Some((full_path, fd.expect("File not found"))); + } else { + println!("Open cmd: File not found"); + } + } +} + +pub fn close(args: Vec) { + unsafe { + OPENED_FILE = None; + } +} + +// read +pub fn read(args: Vec) { + let length = match args.get(1) { + Some(length) => length, + None => { + println!("Usage: read "); + return; + } + }; + + let length = match length.parse::() { + Ok(length) => length, + Err(_) => { + println!("Invalid length: {}", length); + return; + } + }; + + unsafe { + let file = match OPENED_FILE.clone() { + Some(file) => file, + None => { + println!("No file opened"); + return; + } + }; + + let mut buf = Vec::new(); + buf.resize(length, 0); + + let num = vfs::read(file.1, &mut buf, length); + + println!("Read {} bytes", num); + if num == 0 { + return; + } + for i in 0..num { + print!("{}", buf[i] as char); + } + println!(""); + } +} diff --git a/kernel/src/os/thread.rs b/kernel/src/os/thread.rs index a5efd2feb..b7b6c75fe 100644 --- a/kernel/src/os/thread.rs +++ b/kernel/src/os/thread.rs @@ -1,8 +1,8 @@ use super::{exception_handler::trap_frame, shell::INITRAMFS}; use crate::cpu::mmu::{self, vm_setup, vm_to_pm}; use crate::os::stdio::{print_hex_now, println_now}; -use alloc::{alloc::dealloc, string::String, vec::Vec}; -use core::ptr::{read_volatile, write_volatile}; + +use alloc::{alloc::dealloc, collections::btree_map::BTreeMap, string::String, vec::Vec}; use core::{alloc::Layout, arch::asm}; static mut THREADS: Option> = None; @@ -64,9 +64,23 @@ struct Thread { stack: *mut u8, stack_size: usize, state: ThreadState, + + fds: BTreeMap, // fd, file handle index + working_dir: String, + page_table: *mut u8, } +impl Thread { + pub fn get_working_dir(&self) -> &String { + &self.working_dir + } + + pub fn set_working_dir(&mut self, working_dir: String) { + self.working_dir = working_dir; + } +} + impl Default for Thread { fn default() -> Self { Thread { @@ -76,11 +90,21 @@ impl Default for Thread { stack: core::ptr::null_mut(), stack_size: 0, state: ThreadState::Dead, + fds: BTreeMap::new(), + working_dir: String::new(), page_table: core::ptr::null_mut(), } } } +pub fn init_fds() -> BTreeMap { + let mut fds = BTreeMap::new(); + fds.insert(0, 0); + fds.insert(1, 1); + fds.insert(2, 2); + fds +} + pub fn init() { unsafe { THREADS = Some(Vec::new()); @@ -98,6 +122,9 @@ pub fn create_thread( let page_table = mmu::vm_setup(program, program_size, stack, stack_size); + let fds = init_fds(); + let working_dir = String::from("/"); + threads.push(Thread { id, program, @@ -109,6 +136,8 @@ pub fn create_thread( sp: 0xFFFF_FFFF_FFF0, ..Default::default() }), + fds, + working_dir, page_table, }); @@ -117,7 +146,6 @@ pub fn create_thread( id } -#[no_mangle] pub fn run_thread(id: Option) { unsafe { let threads = THREADS.as_mut().unwrap(); @@ -176,7 +204,7 @@ pub fn run_thread(id: Option) { } } -pub fn get_id_by_pc(pc: usize) -> Option { +pub fn get_running_thread_id() -> Option { let threads = unsafe { THREADS.as_ref().unwrap() }; threads @@ -184,8 +212,6 @@ pub fn get_id_by_pc(pc: usize) -> Option { .find(|thread| { if let ThreadState::Running(context) = &thread.state { true - // (thread.program as usize) <= pc - // && pc < (thread.program as usize + thread.program_size) } else { false } @@ -558,6 +584,8 @@ pub fn fork() -> Option { ); } + let new_fds = init_fds(); + println!("Old pc: {:X}", current_thread_context.pc); threads.push(Thread { id: new_pid, @@ -569,6 +597,8 @@ pub fn fork() -> Option { x0: 0, ..*current_thread_context }), + fds: new_fds, + working_dir: current_thread.working_dir.clone(), page_table, }); println!("New program start: {:X}", program_ptr as usize); @@ -590,11 +620,7 @@ pub fn exec(program_name: String, program_args: Vec) { matches!(state, ThreadState::Running(_)) }); - if current_thread.is_none() { - panic!("No running thread to exec"); - } - - let current_thread = current_thread.unwrap(); + let current_thread = current_thread.expect("No running thread to exec"); let stack_size = 4096; unsafe { @@ -621,31 +647,46 @@ pub fn exec(program_name: String, program_args: Vec) { .expect("Layout error"), ); - current_thread.program = alloc::alloc::alloc( + // Construct new program + + let program = alloc::alloc::alloc( Layout::from_size_align(filesize, THREAD_ALIGNMENT).expect("Layout error"), ); - current_thread.stack = alloc::alloc::alloc( - Layout::from_size_align(4096, THREAD_ALIGNMENT).expect("Layout error"), - ); + let program_size = (filesize + (0x1000 - 1)) & !(0x1000 - 1); - // Clear memory core::ptr::write_bytes(current_thread.program, 0, current_thread.program_size); - INITRAMFS .as_ref() .unwrap() - .load_file_to_memory(program_name.as_str(), current_thread.program); - - current_thread.program_size = filesize; - current_thread.stack_size = stack_size; + .load_file_to_memory(program_name.as_str(), current_thread.program, 0, filesize); - current_thread.page_table = vm_setup( - current_thread.program, - current_thread.program_size, - current_thread.stack, - current_thread.stack_size, + let stack_size = 4096; + let stack = alloc::alloc::alloc( + Layout::from_size_align(stack_size, THREAD_ALIGNMENT).expect("Layout error"), ); + let fds = init_fds(); + let working_dir = String::from("/"); + let page_table = vm_setup(program, program_size, stack, stack_size); + let state = ThreadState::Running(ThreadContext { + pc: 0, + sp: 0xFFFF_FFFF_FFF0, + ..ThreadContext::default() + }); + + *current_thread = Thread { + program, + program_size, + stack, + stack_size, + state, + fds, + working_dir, + page_table, + ..current_thread.clone() + }; + + // Clear TLB and switch to new page table asm!( "dsb ish", "msr ttbr0_el1, {PGD_addr}", @@ -655,12 +696,6 @@ pub fn exec(program_name: String, program_args: Vec) { PGD_addr = in(reg) current_thread.page_table ); } - - current_thread.state = ThreadState::Running(ThreadContext { - pc: 0, - sp: 0xFFFF_FFFF_FFF0, - ..ThreadContext::default() - }); } pub fn kill(id: usize) { @@ -695,7 +730,7 @@ pub fn switch_to_thread(id: Option, trap_frame_ptr: *mut u64) { }; assert!(matches!(target_thread.state, ThreadState::Running(_))); - + unsafe { asm!( "dsb ish", @@ -706,6 +741,51 @@ pub fn switch_to_thread(id: Option, trap_frame_ptr: *mut u64) { PGD_addr = in(reg) target_thread.page_table ); } - + restore_context(trap_frame_ptr); } + +pub fn get_working_dir(id: usize) -> Option { + let threads = unsafe { THREADS.as_ref().unwrap() }; + + threads + .iter() + .find(|thread| thread.id == id) + .map(|thread| thread.get_working_dir().clone()) +} + +pub fn set_working_dir(id: usize, working_dir: String) { + let threads = unsafe { THREADS.as_mut().unwrap() }; + + let target_thread = threads + .iter_mut() + .find(|thread| thread.id == id) + .expect("Thread not found"); + + target_thread.set_working_dir(working_dir); +} + +pub fn get_fd(pid: usize, fd: usize) -> Option { + let threads = unsafe { THREADS.as_ref().unwrap() }; + + let fds = threads + .iter() + .find(|thread| thread.id == pid) + .map(|thread| &thread.fds).unwrap(); + + fds.get(&fd).copied() +} + +pub fn add_fd(pid: usize, file_handle: usize) -> usize { + let threads = unsafe { THREADS.as_mut().unwrap() }; + + let target_thread = threads + .iter_mut() + .find(|thread| thread.id == pid) + .expect("Thread not found"); + + let new_fd = target_thread.fds.len(); + target_thread.fds.insert(new_fd, file_handle); + + new_fd +} \ No newline at end of file