From 43d045788f8438b15806ae0267b26e57687bc216 Mon Sep 17 00:00:00 2001 From: Jeremy Soller <jackpot51@gmail.com> Date: Mon, 7 Feb 2022 15:26:30 -0700 Subject: [PATCH] Support calling kernel --- asm/x86-unknown-none/gdt.asm | 2 +- asm/x86-unknown-none/long_mode.asm | 12 +++--- asm/x86-unknown-none/memory_map.asm | 33 +++++++++++++++ asm/x86-unknown-none/stage2.asm | 49 +++++++++++++++++++++++ src/disk.rs | 2 +- src/lib.rs | 62 +++++++++++++++++++++++++++-- src/paging.rs | 6 +-- 7 files changed, 151 insertions(+), 15 deletions(-) create mode 100644 asm/x86-unknown-none/memory_map.asm diff --git a/asm/x86-unknown-none/gdt.asm b/asm/x86-unknown-none/gdt.asm index 773139a..925954a 100644 --- a/asm/x86-unknown-none/gdt.asm +++ b/asm/x86-unknown-none/gdt.asm @@ -58,7 +58,7 @@ gdt_flag: gdtr: dw gdt.end + 1 ; size - dd gdt ; offset + dq gdt ; offset gdt: .null equ $ - gdt diff --git a/asm/x86-unknown-none/long_mode.asm b/asm/x86-unknown-none/long_mode.asm index de5f802..3a01d21 100644 --- a/asm/x86-unknown-none/long_mode.asm +++ b/asm/x86-unknown-none/long_mode.asm @@ -9,16 +9,12 @@ long_mode: ; disable interrupts cli - ;disable paging + ; disable paging mov eax, cr0 and eax, 0x7FFFFFFF mov cr0, eax - ;cr3 holds pointer to PML4 - mov eax, [.page_table] - mov cr3, eax - - ;enable OSXSAVE, FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension + ; enable OSXSAVE, FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension mov eax, cr4 or eax, 1 << 18 | 1 << 9 | 1 << 7 | 1 << 5 | 1 << 4 mov cr4, eax @@ -32,6 +28,10 @@ long_mode: or eax, 1 << 11 | 1 << 8 ; Set the Long-Mode-Enable and NXE bit. wrmsr + ; set page table + mov eax, [.page_table] + mov cr3, eax + ; enabling paging and protection simultaneously mov eax, cr0 or eax, 1 << 31 | 1 << 16 | 1 ;Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode diff --git a/asm/x86-unknown-none/memory_map.asm b/asm/x86-unknown-none/memory_map.asm new file mode 100644 index 0000000..460ea27 --- /dev/null +++ b/asm/x86-unknown-none/memory_map.asm @@ -0,0 +1,33 @@ +SECTION .text +USE16 + +;Generate a memory map at 0x500 to 0x5000 (available memory not used for kernel or bootloader) +memory_map: +.start equ 0x0500 +.end equ 0x5000 +.length equ .end - .start + + xor eax, eax + mov di, .start + mov ecx, .length / 4 ; moving 4 Bytes at once + cld + rep stosd + + mov di, .start + mov edx, 0x534D4150 + xor ebx, ebx +.lp: + mov eax, 0xE820 + mov ecx, 24 + + int 0x15 + jc .done ; Error or finished + + cmp ebx, 0 + je .done ; Finished + + add di, 24 + cmp di, .end + jb .lp ; Still have buffer space +.done: + ret diff --git a/asm/x86-unknown-none/stage2.asm b/asm/x86-unknown-none/stage2.asm index 7455820..69cfc4d 100644 --- a/asm/x86-unknown-none/stage2.asm +++ b/asm/x86-unknown-none/stage2.asm @@ -10,12 +10,17 @@ stage2.entry: or al, 2 out 0x92, al + ; load memory map + ;TODO: rewrite this in Rust + call memory_map + mov dword [protected_mode.func], stage3.entry jmp protected_mode.entry %include "cpuid.asm" %include "gdt.asm" %include "long_mode.asm" +%include "memory_map.asm" %include "protected_mode.asm" %include "thunk.asm" @@ -37,9 +42,53 @@ stage3.entry: xor eax, eax mov al, [disk] push eax + mov eax, kernel.entry + push eax mov eax, [stage3 + 0x18] call eax .halt: cli hlt jmp .halt + +kernel: +.stack: dq 0 +.func: dq 0 +.args: dq 0 + +.entry: + ; page_table: usize + mov eax, [esp + 4] + mov [long_mode.page_table], eax + + ; stack: u64 + mov eax, [esp + 8] + mov [.stack], eax + mov eax, [esp + 12] + mov [.stack + 4], eax + + ; func: u64 + mov eax, [esp + 16] + mov [.func], eax + mov eax, [esp + 20] + mov [.func + 4], eax + + ; args: *const KernelArgs + mov eax, [esp + 24] + mov [.args], eax + + mov eax, .inner + mov [long_mode.func], eax + jmp long_mode.entry + +USE64 + +.inner: + mov rsp, [.stack] + mov rax, [.func] + mov rdi, [.args] + call rax +.halt: + cli + hlt + jmp .halt diff --git a/src/disk.rs b/src/disk.rs index e6dcac8..bb8a320 100644 --- a/src/disk.rs +++ b/src/disk.rs @@ -44,7 +44,7 @@ impl Disk for DiskBios { fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> { for (i, chunk) in buffer.chunks_mut(BLOCK_SIZE as usize).enumerate() { unsafe { - let mut dap = DiskAddressPacket::from_block(block); + let mut dap = DiskAddressPacket::from_block(block + i as u64); ptr::write(DISK_ADDRESS_PACKET_ADDR as *mut DiskAddressPacket, dap); let mut data = ThunkData::new(); diff --git a/src/lib.rs b/src/lib.rs index dcb365d..e5571e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,6 +46,8 @@ const DISK_BIOS_ADDR: usize = 0x1000; // 4096 bytes, ends at 0x1FFF const THUNK_STACK_ADDR: usize = 0x7C00; // Grows downwards const VGA_ADDR: usize = 0xB8000; +const PHYS_OFFSET: u64 = 0xFFFF800000000000; + #[global_allocator] static ALLOCATOR: LockedHeap = LockedHeap::empty(); @@ -53,10 +55,35 @@ static VGA: Mutex<Vga> = Mutex::new( unsafe { Vga::new(VGA_ADDR, 80, 25) } ); -static mut KERNEL_PHYS: u64 = 0; +#[repr(packed)] +pub struct KernelArgs { + kernel_base: u64, + kernel_size: u64, + stack_base: u64, + stack_size: u64, + env_base: u64, + env_size: u64, + + /// The base 64-bit pointer to an array of saved RSDPs. It's up to the kernel (and possibly + /// userspace), to decide which RSDP to use. The buffer will be a linked list containing a + /// 32-bit relative (to this field) next, and the actual struct afterwards. + /// + /// This field can be NULL, and if so, the system has not booted with UEFI or in some other way + /// retrieved the RSDPs. The kernel or a userspace driver will thus try searching the BIOS + /// memory instead. On UEFI systems, searching is not guaranteed to actually work though. + acpi_rsdps_base: u64, + /// The size of the RSDPs region. + acpi_rsdps_size: u64, +} #[no_mangle] pub unsafe extern "C" fn kstart( + kernel_entry: extern "C" fn( + page_table: usize, + stack: u64, + func: u64, + args: *const KernelArgs, + ) -> !, boot_disk: usize, thunk10: extern "C" fn(), thunk13: extern "C" fn(), @@ -98,6 +125,15 @@ pub unsafe extern "C" fn kstart( println!("HEAP: {:X}:{:X}", heap_start, heap_size); ALLOCATOR.lock().init(heap_start, heap_size); + + let stack_size = 0x20000; + let stack_base = ALLOCATOR.alloc_zeroed( + Layout::from_size_align(stack_size, 4096).unwrap() + ); + if stack_base.is_null() { + panic!("Failed to allocate memory for stack"); + } + // Locate kernel on RedoxFS let kernel = { //TODO: ensure boot_disk is 8-bit @@ -142,9 +178,27 @@ pub unsafe extern "C" fn kstart( kernel }; - println!("Kernel Phys: 0x{:X}", kernel.as_ptr() as u64); - let page_phys = paging::paging_create(kernel.as_ptr() as u64); - panic!("kernel entry not implemented"); + println!("Kernel Phys: 0x{:X}", kernel.as_ptr() as usize); + let page_phys = paging::paging_create(kernel.as_ptr() as usize) + .expect("Failed to set up paging"); + + let args = KernelArgs { + kernel_base: kernel.as_ptr() as u64, + kernel_size: kernel.len() as u64, + stack_base: stack_base as u64, + stack_size: stack_size as u64, + env_base: 0, + env_size: 0, + acpi_rsdps_base: 0, + acpi_rsdps_size: 0, + }; + + kernel_entry( + page_phys, + args.stack_base + args.stack_size + PHYS_OFFSET, + *(kernel.as_ptr().add(0x18) as *const u64), + &args, + ); let mut modes = Vec::new(); { diff --git a/src/paging.rs b/src/paging.rs index 2f1e9d7..407433e 100644 --- a/src/paging.rs +++ b/src/paging.rs @@ -15,7 +15,7 @@ unsafe fn paging_allocate() -> Option<&'static mut [u64]> { } } -pub unsafe fn paging_create(kernel_phys: u64) -> Option<u64> { +pub unsafe fn paging_create(kernel_phys: usize) -> Option<usize> { // Create PML4 let pml4 = paging_allocate()?; @@ -67,12 +67,12 @@ pub unsafe fn paging_create(kernel_phys: u64) -> Option<u64> { pdp_i as u64 * 0x4000_0000 + pd_i as u64 * 0x20_0000 + pt_i as u64 * 0x1000 + - kernel_phys; + kernel_phys as u64; pt[pt_i] = addr | 1 << 1 | 1; } } } } - Some(pml4.as_ptr() as u64) + Some(pml4.as_ptr() as usize) } -- GitLab