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.rs b/kernel/src/cpu.rs index 780b1ae8c..77021f74c 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; +pub mod mmu; diff --git a/kernel/src/cpu/boot.rs b/kernel/src/cpu/boot.rs index 84db5d058..e0a77dcd4 100644 --- a/kernel/src/cpu/boot.rs +++ b/kernel/src/cpu/boot.rs @@ -2,8 +2,8 @@ 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}; +use crate::os::file_system::{vfs, tmpfs, initramfs}; global_asm!(include_str!("boot.s")); @@ -13,21 +13,27 @@ 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"); + 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) => { @@ -37,7 +43,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"); @@ -46,12 +52,13 @@ pub unsafe fn _start_rust() { }; // let initrd_start = 0x8000000; - println_now("before print information"); + // println_now("before print information"); print_information(); shell::start(initrd_start); - loop {} + + panic!("Shell stoped."); } fn print_information() { @@ -61,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/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/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 new file mode 100644 index 000000000..a97650776 --- /dev/null +++ b/kernel/src/cpu/mmu.rs @@ -0,0 +1,316 @@ +use alloc::vec::Vec; +use core::alloc::Layout; +use core::arch::asm; +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); +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 AP_RO_EL0: usize = 0b11 << 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; + +#[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!( + "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 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); + + 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 6f43eb0b7..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) -> u32 { - *self as u32 + pub fn addr(&self) -> usize { + *self as usize } } @@ -37,12 +37,12 @@ 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) { 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/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/main.rs b/kernel/src/main.rs index b7f9e50f1..ab97065ef 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -2,8 +2,7 @@ #![no_std] #![feature(allocator_api)] #![feature(btreemap_alloc)] -#![allow(unused_variables)] -#![allow(non_camel_case_types)] +#![feature(ptr_mask)] mod cpu; mod os; 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/allocator/buddy_system.rs b/kernel/src/os/allocator/buddy_system.rs index cea522b1c..ed5f8953f 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; @@ -119,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(); @@ -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()); } @@ -220,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"); 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 79c0cd3aa..bb42271b7 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::{ @@ -6,23 +9,28 @@ 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) { + println_now("Unknown exception"); + 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); - 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(); } @@ -34,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); @@ -54,14 +67,23 @@ 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); } 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()); + println_now(format!("SP_EL1: {:08x}", sp_el1).as_str()); + panic!(); } 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/exception_handler/system_call.rs b/kernel/src/os/exception_handler/system_call.rs index 680ab705c..9786ee03f 100644 --- a/kernel/src/os/exception_handler/system_call.rs +++ b/kernel/src/os/exception_handler/system_call.rs @@ -1,14 +1,24 @@ -use super::super::thread; +use super::super::{file_system::vfs, thread}; use super::trap_frame; -use crate::cpu::uart; +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}; +#[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); } +#[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 +44,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 +57,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 +77,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,30 +87,176 @@ 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"); + let pid = thread::get_running_thread_id().expect("Failed to get PID"); thread::kill(pid); 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"); 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 72d244953..1921242d8 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, @@ -36,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, @@ -73,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 { @@ -83,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 738e018e7..43a1d8090 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; @@ -17,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( @@ -64,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 { @@ -71,70 +108,85 @@ 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!("{: { + 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); } } } } -pub fn start(initrd_start: u32) { +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(); @@ -142,10 +194,10 @@ pub fn start(initrd_start: u32) { 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.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 +210,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!("{: ) { return; } }; + 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()) @@ -110,15 +116,15 @@ 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, 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); } @@ -213,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 42717f2b7..b7b6c75fe 100644 --- a/kernel/src/os/thread.rs +++ b/kernel/src/os/thread.rs @@ -1,15 +1,16 @@ +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 super::{exception_handler::trap_frame, shell::INITRAMFS}; -use alloc::{alloc::dealloc, string::String, vec::Vec}; +use alloc::{alloc::dealloc, collections::btree_map::BTreeMap, string::String, vec::Vec}; 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,21 @@ 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 { @@ -116,10 +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()); @@ -134,6 +119,12 @@ 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); + + let fds = init_fds(); + let working_dir = String::from("/"); + threads.push(Thread { id, program, @@ -141,11 +132,15 @@ pub fn create_thread( stack, stack_size, state: ThreadState::Waiting(ThreadContext { - pc: program as usize, - sp: stack as usize + stack_size, + pc: 0, + sp: 0xFFFF_FFFF_FFF0, ..Default::default() }), + fds, + working_dir, + page_table, }); + println!("Stack SP: {:X?}", stack as usize + stack_size); println!("Thread created: {}", id); id @@ -162,9 +157,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"), }; @@ -178,6 +173,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", @@ -204,15 +204,14 @@ 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 .iter() .find(|thread| { if let ThreadState::Running(context) = &thread.state { - (thread.program as usize) <= pc - && pc < (thread.program as usize + thread.program_size) + true } else { false } @@ -226,11 +225,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!(state, ThreadState::Running(_)) }) .expect("SAVE_CONTEXT: No running thread"); @@ -274,7 +270,7 @@ pub fn save_context(trap_frame_ptr: *mut u64) -> bool { ThreadState::Running(context) } else { - ThreadState::Dead + panic!(); }; true @@ -427,6 +423,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() }; @@ -435,6 +432,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; @@ -453,15 +462,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"); } @@ -496,6 +505,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); @@ -512,9 +535,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() { @@ -540,6 +563,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, @@ -553,8 +584,7 @@ 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; + let new_fds = init_fds(); println!("Old pc: {:X}", current_thread_context.pc); threads.push(Thread { @@ -564,16 +594,17 @@ pub fn fork() -> Option { stack: stack_ptr, stack_size: current_thread.stack_size, state: ThreadState::Waiting(ThreadContext { - pc, - sp, 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); - 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 { @@ -584,16 +615,12 @@ 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() { - 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 { @@ -620,29 +647,55 @@ 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); 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); + .load_file_to_memory(program_name.as_str(), current_thread.program, 0, filesize); - current_thread.program_size = filesize; - current_thread.stack_size = stack_size; - } + let stack_size = 4096; + let stack = alloc::alloc::alloc( + Layout::from_size_align(stack_size, THREAD_ALIGNMENT).expect("Layout error"), + ); - current_thread.state = ThreadState::Running(ThreadContext { - pc: current_thread.program as usize, - sp: current_thread.stack as usize + stack_size, - ..ThreadContext::default() - }); + 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}", + "tlbi vmalle1is", + "dsb ish", + "isb", + PGD_addr = in(reg) current_thread.page_table + ); + } } pub fn kill(id: usize) { @@ -666,10 +719,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"), }; @@ -681,5 +731,61 @@ 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); } + +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