diff --git a/GNUmakefile b/GNUmakefile index 96ba9a2..569a83e 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,16 +1,10 @@ +include config.mk + # Nuke built-in rules and variables. MAKEFLAGS += -rR .SUFFIXES: -# Convenience macro to reliably declare user overridable variables. -override USER_VARIABLE = $(if $(filter $(origin $(1)),default undefined),$(eval override $(1) := $(2))) - -# Target architecture to build for. Default to x86_64. -$(call USER_VARIABLE,KARCH,x86_64) - -# Default user QEMU flags. These are appended to the QEMU command calls. -$(call USER_VARIABLE,QEMUFLAGS,-m 2G) - +override QEMUFLAGS := -m $(MEMORY) override IMAGE_NAME := XunilOS-$(KARCH) .PHONY: all diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..68efdd7 --- /dev/null +++ b/config.mk @@ -0,0 +1,4 @@ +export KARCH ?= aarch64 +export OUTPUT ?= kernel +export MEMORY ?= 512M +export TIMER_FREQUENCY_HZ ?= 1000 diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index ae6aefb..0aa6674 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -7,6 +7,7 @@ name = "XunilOS" version = "0.1.0" dependencies = [ "aarch64-cpu", + "fdt", "font8x8", "heapless", "lazy_static", @@ -51,6 +52,12 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413d67b29ef1021b4d60f4aa1e925ca031751e213832b4b1d588fae623c05c60" +[[package]] +name = "fdt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67" + [[package]] name = "font8x8" version = "0.3.1" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index adf905c..26b6825 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -23,6 +23,7 @@ x86_64 = "0.15.4" [target.'cfg(target_arch = "aarch64")'.dependencies] aarch64-cpu = "11.2.0" +fdt = "0.1.5" [profile.dev] panic = "abort" diff --git a/kernel/GNUmakefile b/kernel/GNUmakefile index 46e0f2b..e99dba0 100644 --- a/kernel/GNUmakefile +++ b/kernel/GNUmakefile @@ -2,15 +2,7 @@ MAKEFLAGS += -rR .SUFFIXES: -# This is the name that our final executable will have. -# Change as needed. -override OUTPUT := kernel - -# Convenience macro to reliably declare user overridable variables. -override USER_VARIABLE = $(if $(filter $(origin $(1)),default undefined),$(eval override $(1) := $(2))) - -# Target architecture to build for. Default to x86_64. -$(call USER_VARIABLE,KARCH,x86_64) +include ../config.mk ifeq ($(RUST_TARGET),) override RUST_TARGET := $(KARCH)-unknown-none diff --git a/kernel/build.rs b/kernel/build.rs index b8d05be..f7c93d1 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -1,5 +1,23 @@ +use std::env; +use std::fs; +use std::path::PathBuf; + fn main() { let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + + let timer_frequency_hz = env::var("TIMER_FREQUENCY_HZ").unwrap_or_else(|_| "1000".to_string()); + + let out_dir = PathBuf::from("src"); + fs::write( + out_dir.join("config.rs"), + format!(r#"pub const TIMER_FREQUENCY_HZ: usize = {timer_frequency_hz};"#), + ) + .unwrap(); + + println!("cargo:rerun-if-env-changed=KARCH"); + println!("cargo:rerun-if-env-changed=TIMER_FREQUENCY_HZ"); + println!("cargo:rerun-if-env-changed=OUTPUT"); + // Tell cargo to pass the linker script to the linker.. println!("cargo:rustc-link-arg=-Tlinker-{arch}.ld"); // ..and to re-run if it changes. diff --git a/kernel/linker-aarch64.ld b/kernel/linker-aarch64.ld index e40ab19..d6d5013 100644 --- a/kernel/linker-aarch64.ld +++ b/kernel/linker-aarch64.ld @@ -23,8 +23,13 @@ SECTIONS . = 0xffffffff80000000; __kernel_start = .; + __text_start = .; - .text : { *(.text .text.*) } :text + .text : ALIGN(0x1000) { + *(.text.vectors) + *(.text .text.*) + } :text + . = ALIGN(CONSTANT(MAXPAGESIZE)); __text_end = .; diff --git a/kernel/rust-toolchain.toml b/kernel/rust-toolchain.toml index 56129dc..c1e44f3 100644 --- a/kernel/rust-toolchain.toml +++ b/kernel/rust-toolchain.toml @@ -1,7 +1,7 @@ [toolchain] channel = "nightly" targets = [ - # "x86_64-unknown-none", + "x86_64-unknown-none", "aarch64-unknown-none", # "riscv64gc-unknown-none-elf", # "loongarch64-unknown-none", diff --git a/kernel/src/arch/aarch64/dtb.rs b/kernel/src/arch/aarch64/dtb.rs new file mode 100644 index 0000000..c81d830 --- /dev/null +++ b/kernel/src/arch/aarch64/dtb.rs @@ -0,0 +1,33 @@ +// TODO: actually use this? + +use fdt::Fdt; + +fn get_midr() -> u64 { + let midr: u64; + unsafe { core::arch::asm!("mrs {}, MIDR_EL1", out(reg) midr, options(nomem, nostack)) }; + midr +} + +pub fn is_qemu() -> bool { + let midr = get_midr(); + let implementer = (midr >> 24) & 0xFF; + + implementer == 0x00 +} + +pub unsafe fn read_dtb<'a>() -> Fdt<'a> { + match is_qemu() { + true => { + let ptr: *mut u32 = 0x4000_0000 as *mut u32; + + let magic = u32::from_be(unsafe { ptr.read_volatile() }); + assert_eq!(magic, 0xd00dfeed); + + let size = u32::from_be(unsafe { ptr.add(1).read_volatile() }) as usize; + let bytes = unsafe { core::slice::from_raw_parts(ptr as *const u8, size) }; + + return Fdt::new(bytes).unwrap(); + } + false => panic!("Can't read DTB of non-qemu device. Unimplemented."), + } +} diff --git a/kernel/src/arch/aarch64/init.rs b/kernel/src/arch/aarch64/init.rs index c58b0cf..b78dfe4 100644 --- a/kernel/src/arch/aarch64/init.rs +++ b/kernel/src/arch/aarch64/init.rs @@ -1,21 +1,57 @@ -use crate::arch::aarch64::{ - heap::init_heap, - paging::{AArchPageTable, initialize_paging_aarch64}, +use crate::{ + arch::aarch64::{ + heap::init_heap, + interrupts::init_interrupts, + kmi::setup_kmi, + paging::{AArchPageTable, initialize_paging_aarch64}, + }, + config::TIMER_FREQUENCY_HZ, }; use limine::response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse}; -pub fn init_aarch64<'a>( +// needs to be page aligned since we map it into the page table +#[repr(align(4096))] +pub struct Stack(pub [u8; 64 * 1024]); + +pub static KERNEL_STACK: Stack = Stack([0; 64 * 1024]); + +pub fn set_timer_freq(freq: usize) { + unsafe { + core::arch::asm!("mrs {}, cntp_tval_el0", in(reg) freq); + } +} + +#[unsafe(naked)] +pub unsafe fn init_aarch64_trampoline(mapper: &mut AArchPageTable) { + // fix stack, since limine's bootloader stack is not mapped + core::arch::naked_asm!( + "msr spsel, #1", + "adrp x1, {stack}", + "add x1, x1, :lo12:{stack}", + "add sp, x1, {size}", + "b kernel_main_aarch64", + stack = sym KERNEL_STACK, + size = const 64 * 1024, + ); +} + +#[unsafe(no_mangle)] +pub extern "C" fn init_aarch64(mapper: &mut AArchPageTable) { + init_heap(mapper); + set_timer_freq(TIMER_FREQUENCY_HZ); + init_interrupts(); + unsafe { setup_kmi() }; +} + +pub fn preinit_aarch64<'a>( hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse, executable_address_response: &ExecutableAddressResponse, -) -> AArchPageTable { +) { let mut mapper = initialize_paging_aarch64( hhdm_response, memory_map_response, executable_address_response, ); - - init_heap(&mut mapper); - - return mapper; + unsafe { init_aarch64_trampoline(&mut mapper) }; } diff --git a/kernel/src/arch/aarch64/interrupts.rs b/kernel/src/arch/aarch64/interrupts.rs index 54e1ac6..828ec48 100644 --- a/kernel/src/arch/aarch64/interrupts.rs +++ b/kernel/src/arch/aarch64/interrupts.rs @@ -1 +1,293 @@ -// TODO: add interrupts +use core::{arch::global_asm, sync::atomic::Ordering}; + +use crate::{ + arch::syscall::syscall_dispatch, + driver::{ + graphics::framebuffer::with_framebuffer, + keyboard::push_scancode, + kmi::{keyboard_interrupt, mouse_interrupt}, + serial::with_serial_console, + timer::TIMER, + }, + task::context::UserContext, +}; + +use aarch64_cpu::registers::{DAIF, Writeable}; + +global_asm!( + r#" + .section .text.vectors + .global __exception_vectors + .balign 0x800 + + __exception_vectors: + .balign 0x80; ldr x16, =current_el_sp0_sync; br x16 + .balign 0x80; ldr x16, =current_el_sp0_irq; br x16 + .balign 0x80; ldr x16, =current_el_sp0_fiq; br x16 + .balign 0x80; ldr x16, =current_el_sp0_serror; br x16 + + .balign 0x80; ldr x16, =current_el_spx_sync; br x16 + .balign 0x80; ldr x16, =current_el_spx_irq; br x16 + .balign 0x80; ldr x16, =current_el_spx_fiq; br x16 + .balign 0x80; ldr x16, =current_el_spx_serror; br x16 + + .balign 0x80; ldr x16, =lower_el_aarch64_sync; br x16 + .balign 0x80; ldr x16, =lower_el_aarch64_irq; br x16 + .balign 0x80; ldr x16, =lower_el_aarch64_fiq; br x16 + .balign 0x80; ldr x16, =lower_el_aarch64_serror; br x16 + + .balign 0x80; ldr x16, =lower_el_aarch32_sync; br x16 + .balign 0x80; ldr x16, =lower_el_aarch32_irq; br x16 + .balign 0x80; ldr x16, =lower_el_aarch32_fiq; br x16 + .balign 0x80; ldr x16, =lower_el_aarch32_serror; br x16 + "# +); + +// stp allows storing in pairs, ldp loads in pairs +macro_rules! exception_handler { + ($name:ident, $rust_handler:ident) => { + #[unsafe(naked)] + #[unsafe(no_mangle)] + unsafe extern "C" fn $name() { + core::arch::naked_asm!( + "sub sp, sp, #288", + "stp x0, x1, [sp, #0]", + "stp x2, x3, [sp, #16]", + "stp x4, x5, [sp, #32]", + "stp x6, x7, [sp, #48]", + "stp x8, x9, [sp, #64]", + "stp x10, x11, [sp, #80]", + "stp x12, x13, [sp, #96]", + "stp x14, x15, [sp, #112]", + "stp x16, x17, [sp, #128]", + "stp x18, x19, [sp, #144]", + "stp x20, x21, [sp, #160]", + "stp x22, x23, [sp, #176]", + "stp x24, x25, [sp, #192]", + "stp x26, x27, [sp, #208]", + "stp x28, x29, [sp, #224]", + "mrs x0, elr_el1", + "mrs x1, spsr_el1", + "stp x30, x0, [sp, #240]", + "str x1, [sp, #256]", + "mrs x2, esr_el1", + "mrs x3, far_el1", + "stp x2, x3, [sp, #264]", + "mov x0, sp", + concat!("bl ", stringify!($rust_handler)), + "ldr x1, [sp, #256]", + "ldp x30, x0, [sp, #240]", + "msr spsr_el1, x1", + "msr elr_el1, x0", + "ldp x0, x1, [sp, #0]", + "ldp x2, x3, [sp, #16]", + "ldp x4, x5, [sp, #32]", + "ldp x6, x7, [sp, #48]", + "ldp x8, x9, [sp, #64]", + "ldp x10, x11, [sp, #80]", + "ldp x12, x13, [sp, #96]", + "ldp x14, x15, [sp, #112]", + "ldp x16, x17, [sp, #128]", + "ldp x18, x19, [sp, #144]", + "ldp x20, x21, [sp, #160]", + "ldp x22, x23, [sp, #176]", + "ldp x24, x25, [sp, #192]", + "ldp x26, x27, [sp, #208]", + "ldp x28, x29, [sp, #224]", + "add sp, sp, #288", + "eret" + ); + } + }; +} + +unsafe fn use_exception_vectors() { + unsafe { + core::arch::asm!( + "adrp x0, __exception_vectors", + "add x0, x0, :lo12:__exception_vectors", + "msr vbar_el1, x0", + "isb" + ); + } +} + +const GICD_BASE: u64 = 0xFFFF_0000_0800_0000; +const GICC_BASE: u64 = 0xFFFF_0000_0801_0000; +const ESR_EC_SHIFT: u64 = 26; +const ESR_EC_MASK: u64 = 0x3F; +const EC_SVC_AA64: u64 = 0x15; + +unsafe fn gic_init() { + let gicd_ctrl = GICD_BASE as *mut u32; + unsafe { + gicd_ctrl.write_volatile(1); + } + + let gicc_ctrl = GICC_BASE as *mut u32; + unsafe { + gicc_ctrl.write_volatile(1); + } + + let gicc_pmr = (GICC_BASE + 0x4) as *mut u32; + unsafe { + gicc_pmr.write_volatile(0xFF); // allow all priorities + } +} + +unsafe fn gic_enable_interrupt(id: u32) { + let reg = (GICD_BASE + 0x100 + (id as u64 / 32 * 4)) as *mut u32; + unsafe { reg.write_volatile(1 << (id % 32)) }; +} + +unsafe fn gic_acknowledge() -> u32 { + let gicc_air = (GICC_BASE + 0xC) as *mut u32; + unsafe { gicc_air.read_volatile() & 0x3FF } // interrupt id +} + +unsafe fn gic_eoi(id: u32) { + let gicc_eoir = (GICC_BASE + 0x10) as *mut u32; + unsafe { + gicc_eoir.write_volatile(id); + } +} + +pub fn init_interrupts() { + unsafe { use_exception_vectors() }; + unsafe { gic_init() }; + unsafe { core::arch::asm!("isb") }; +} + +pub fn enable_interrupts() { + unsafe { + gic_enable_interrupt(30); // timer IRQ + gic_enable_interrupt(17); // keyboard IRQ + gic_enable_interrupt(18); // mouse IRQ + core::arch::asm!("msr cntp_ctl_el0, {}", in(reg) 1u64); // enable timer + } + DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Unmasked + DAIF::F::Masked); +} + +#[allow(unused_variables, dead_code)] +#[unsafe(no_mangle)] + +unsafe extern "C" fn no_operation(ctx: *mut UserContext) { + let interrupt_id = unsafe { gic_acknowledge() }; + + unsafe { + gic_eoi(interrupt_id); + } +} + +#[allow(unused_variables, dead_code)] +#[unsafe(no_mangle)] +unsafe extern "C" fn irq_handler(ctx: *mut UserContext) { + let interrupt_id = unsafe { gic_acknowledge() }; + match interrupt_id { + 30 => { + TIMER.interrupt(); + + let t = TIMER.interrupt_count.load(Ordering::Relaxed); + + if t % 60 == 0 { + with_framebuffer(|fb| { + with_serial_console(|serial_console| { + serial_console.print(".", fb); + serial_console.render(fb) + }); + fb.present(); + }); + } + } + 17 => { + if let Some(scancode) = keyboard_interrupt() { + push_scancode(scancode); + } + } + 18 => { + mouse_interrupt(); + } + + _ => {} + } + + unsafe { + gic_eoi(interrupt_id); + } +} + +fn handle_aborts(ec: u64, ctx: &UserContext) { + match ec { + 0x25 => { + panic!( + "Data abort at VA={:#x} ELR={:#x} ESR={:#x}", + ctx.far_el1, ctx.elr_el1, ctx.esr_el1 + ); + } + 0x21 => { + panic!( + "Instruction abort at VA={:#x} ELR={:#x}", + ctx.far_el1, ctx.elr_el1 + ); + } + _ => { + panic!( + "Unhandled sync abort VA={:#x} ELR={:#x} ESR={:#x}", + ctx.far_el1, ctx.elr_el1, ctx.esr_el1 + ); + } + } +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn sync_handler_user(ctx: *mut UserContext) { + let mut ctx = unsafe { *ctx }; + let ec = (ctx.esr_el1 >> ESR_EC_SHIFT) & ESR_EC_MASK; + + #[allow(unused_assignments)] + match ec { + EC_SVC_AA64 => { + ctx.x0 = unsafe { + syscall_dispatch( + ctx.x8 as usize, + ctx.x0 as isize, + ctx.x1 as isize, + ctx.x2 as isize, + ctx.x3 as isize, + ctx.x4 as isize, + ctx.x5 as isize, + ) + } as u64; + } + _ => handle_aborts(ec, &ctx), + } +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn sync_handler_kernel(ctx: *mut UserContext) { + let ctx = unsafe { *ctx }; + let ec = (ctx.esr_el1 >> ESR_EC_SHIFT) & ESR_EC_MASK; + handle_aborts(ec, &ctx) +} + +// these are UB and should not happen +exception_handler!(current_el_sp0_sync, no_operation); +exception_handler!(current_el_sp0_irq, no_operation); +exception_handler!(current_el_sp0_fiq, no_operation); +exception_handler!(current_el_sp0_serror, no_operation); +exception_handler!(lower_el_aarch32_sync, no_operation); +exception_handler!(lower_el_aarch32_irq, no_operation); +exception_handler!(lower_el_aarch32_fiq, no_operation); +exception_handler!(lower_el_aarch32_serror, no_operation); + +// kernel +exception_handler!(current_el_spx_sync, sync_handler_kernel); +exception_handler!(current_el_spx_irq, irq_handler); +exception_handler!(current_el_spx_fiq, no_operation); +exception_handler!(current_el_spx_serror, no_operation); + +// usermode +exception_handler!(lower_el_aarch64_sync, sync_handler_user); +exception_handler!(lower_el_aarch64_irq, no_operation); +exception_handler!(lower_el_aarch64_fiq, no_operation); +exception_handler!(lower_el_aarch64_serror, no_operation); diff --git a/kernel/src/arch/aarch64/keyboard.rs b/kernel/src/arch/aarch64/keyboard.rs deleted file mode 100644 index 9f6d18f..0000000 --- a/kernel/src/arch/aarch64/keyboard.rs +++ /dev/null @@ -1 +0,0 @@ -// TODO: add keyboard logic diff --git a/kernel/src/arch/aarch64/kmi.rs b/kernel/src/arch/aarch64/kmi.rs new file mode 100644 index 0000000..bd2ffd5 --- /dev/null +++ b/kernel/src/arch/aarch64/kmi.rs @@ -0,0 +1,87 @@ +use crate::arch::arch::safe_lock; + +const KMI0_BASE: u64 = 0xFFFF_0000_0905_0000; +const KMI1_BASE: u64 = 0xFFFF_0000_0906_0000; +const KMI_CR: u64 = 0x00; +const KMI_STAT: u64 = 0x04; +const KMI_DATA: u64 = 0x08; + +pub unsafe fn kmi_write(base: u64, kmi_type: u64, val: u8) { + let data = (base + kmi_type) as *mut u32; + unsafe { data.write_volatile(val as u32) }; +} + +pub fn kmi_read(base: u64, kmi_type: u64) -> u8 { + let data = (base + kmi_type) as *const u32; + unsafe { data.read_volatile() as u8 } +} + +pub unsafe fn read_mouse_control() -> u8 { + kmi_read(KMI1_BASE, KMI_STAT) +} + +pub unsafe fn read_mouse_data() -> u8 { + kmi_read(KMI1_BASE, KMI_DATA) +} + +pub unsafe fn read_keyboard_control() -> u8 { + kmi_read(KMI0_BASE, KMI_STAT) +} +pub unsafe fn read_keyboard_data() -> u8 { + kmi_read(KMI0_BASE, KMI_DATA) +} + +pub unsafe fn setup_kmi() -> u8 { + safe_lock(|| unsafe { + let cr0 = (KMI0_BASE + KMI_CR) as *mut u32; + cr0.write_volatile(0x14); // enable keyboard + + kmi_write(KMI0_BASE, KMI_DATA, 0xFF); // reset keyboard + + if kmi_read(KMI0_BASE, KMI_DATA) != 0xFA { + // ACK + return 2; + } + + if kmi_read(KMI0_BASE, KMI_DATA) != 0xAA { + // self-test passed + return 3; + } + + kmi_write(KMI0_BASE, KMI_DATA, 0xF4); // enable keyboard data reporting + + if kmi_read(KMI0_BASE, KMI_DATA) != 0xFA { + // ACK + return 4; + } + + let cr1 = (KMI1_BASE + KMI_CR) as *mut u32; + cr1.write_volatile(0x14); // enable mouse + + kmi_write(KMI1_BASE, KMI_DATA, 0xFF); // reset mouse + + if kmi_read(KMI1_BASE, KMI_DATA) != 0xFA { + // ACK + return 5; + } + + if kmi_read(KMI1_BASE, KMI_DATA) != 0xAA { + // self-test passed + return 6; + } + + if kmi_read(KMI1_BASE, KMI_DATA) != 0x00 { + // mouse ID + return 7; + } + + kmi_write(KMI1_BASE, KMI_DATA, 0xF4); // enable mouse data reporting + + if kmi_read(KMI1_BASE, KMI_DATA) != 0xFA { + // ACK + return 8; + } + + return 9; + }) +} diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index cec215e..10691a4 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -1,7 +1,8 @@ +pub mod dtb; pub mod heap; pub mod init; pub mod interrupts; -pub mod mouse; +pub mod kmi; pub mod paging; pub mod syscall; pub mod usermode; diff --git a/kernel/src/arch/aarch64/mouse.rs b/kernel/src/arch/aarch64/mouse.rs deleted file mode 100644 index 0703d0a..0000000 --- a/kernel/src/arch/aarch64/mouse.rs +++ /dev/null @@ -1 +0,0 @@ -// TODO: add mouse logic diff --git a/kernel/src/arch/aarch64/paging.rs b/kernel/src/arch/aarch64/paging.rs index 6b7945b..f0dfa18 100644 --- a/kernel/src/arch/aarch64/paging.rs +++ b/kernel/src/arch/aarch64/paging.rs @@ -1,4 +1,12 @@ -use crate::arch::arch::{HHDM_OFFSET, XunilFrameAllocator, safe_lock}; +use core::sync::atomic::{AtomicBool, Ordering}; + +use crate::{ + arch::{ + aarch64::init::KERNEL_STACK, + arch::{HHDM_OFFSET, XunilFrameAllocator, safe_lock, serial_print}, + }, + util::U64Buf, +}; use limine::{ memory_map::EntryType, response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse}, @@ -48,9 +56,24 @@ pub fn device_flags() -> u64 { // no SH bits for device memory } +static HHDM_OVERFLOW_REPORTED: AtomicBool = AtomicBool::new(false); + fn phys_to_virt(phys: u64) -> *mut u64 { - let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed); - (phys + hhdm_offset) as *mut u64 + let hhdm_offset = HHDM_OFFSET.load(Ordering::Relaxed); + + match phys.checked_add(hhdm_offset) { + Some(virt) => virt as *mut u64, + None => { + if !HHDM_OVERFLOW_REPORTED.swap(true, Ordering::Relaxed) { + serial_print("HHDM overflow phys="); + serial_print(U64Buf::new(phys).as_str()); + serial_print(", hhdm_offset="); + serial_print(U64Buf::new(hhdm_offset).as_str()); + serial_print("\n"); + } + panic!("phys_to_virt overflow"); + } + } } pub fn tlb_flush() { @@ -73,6 +96,11 @@ pub fn set_page_table(root_phys: u64) { } } +pub fn setup_mair() { + let mair: u64 = (0xFF << 0) | (0x00 << 8); + unsafe { core::arch::asm!("msr mair_el1, {0}", "isb", in(reg) mair) } +} + // translation control register: handles addresses fn setup_tcr() { unsafe { @@ -85,8 +113,10 @@ fn setup_tcr() { (0b01 << 10)| // ORGN0: normal WB RAWA (0b01 << 26)| // ORGN1 (0b01 << 8) | // IRGN0 - (0b01 << 24); // IRGN1 - core::arch::asm!("msr tcr_el1, {0}", in(reg) tcr); + (0b01 << 24) | // IRGN1 + (0b101 << 32); // IPS: 48-bit PA (256GB) + + core::arch::asm!("msr tcr_el1, {0}", "isb", in(reg) tcr); } } @@ -151,9 +181,19 @@ pub fn initialize_paging_aarch64<'a>( ); } - page_table.map_page(0xFFFF_0000_0900_0000, 0x0900_0000, device_flags()); // the UART - + page_table.map_range(0xFFFF_0000_0900_0000, 0x0900_0000, 0x1000, device_flags()); // the UART + page_table.map_range(0xFFFF_0000_0800_0000, 0x0800_0000, 0x10000, device_flags()); // the GICD + page_table.map_range(0xFFFF_0000_0801_0000, 0x0801_0000, 0x10000, device_flags()); // the GICC + page_table.map_page(0xFFFF_0000_0905_0000, 0x0905_0000, device_flags()); // KMI0 (keyboard) + page_table.map_page(0xFFFF_0000_0906_0000, 0x0906_0000, device_flags()); // KMI1 (mouse) + setup_mair(); setup_tcr(); + + let stack_phys = KERNEL_STACK.0.as_ptr() as u64 - k_virt_base + k_phys_base; + let stack_virt = KERNEL_STACK.0.as_ptr() as u64; + + page_table.map_range(stack_virt, stack_phys, 64 * 1024, kernel_data_flags()); + set_page_table(page_table.root_phys); tlb_flush(); @@ -166,9 +206,9 @@ pub struct AArchPageTable { pub fn alloc_frame() -> Option { let mut frame_allocator = safe_lock(|| FRAME_ALLOCATOR_AARCH64.lock()); - let frame = frame_allocator.allocate_frame(); + let frame_opt = frame_allocator.allocate_frame(); drop(frame_allocator); - return frame; + return frame_opt; } impl AArchPageTable { @@ -179,7 +219,7 @@ impl AArchPageTable { .expect("Could not allocate frame for page table"); unsafe { - core::ptr::write_bytes(phys_to_virt(root_phys), 0, 512); + core::ptr::write_bytes(phys_to_virt(root_phys), 0, 4096); } AArchPageTable { root_phys } @@ -200,7 +240,7 @@ impl AArchPageTable { } else { let child = alloc_frame().expect("Could not allocate frame when creating page table"); unsafe { - core::ptr::write_bytes(phys_to_virt(child), 0, 512); + core::ptr::write_bytes(phys_to_virt(child), 0, 4096); entry_ptr.write_volatile(child | VALID | TABLE); } return child; @@ -216,7 +256,6 @@ impl AArchPageTable { let l1_phys = self.get_or_create_table(self.root_phys, l0); let l2_phys = self.get_or_create_table(l1_phys, l1); let l3_phys = self.get_or_create_table(l2_phys, l2); - let entry_ptr = self.table_ptr(l3_phys, l3); unsafe { diff --git a/kernel/src/arch/arch.rs b/kernel/src/arch/arch.rs index ef6b966..6e27d83 100644 --- a/kernel/src/arch/arch.rs +++ b/kernel/src/arch/arch.rs @@ -91,24 +91,13 @@ impl XunilFrameAllocator { } #[cfg(target_arch = "x86_64")] -pub fn init<'a>( - hhdm_response: &HhdmResponse, - memory_map_response: &'a MemoryMapResponse, -) -> OffsetPageTable<'static> { - return init_x86_64(hhdm_response, memory_map_response); +pub fn init<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) { + init_x86_64(hhdm_response, memory_map_response); } #[cfg(target_arch = "aarch64")] -pub fn init<'a>( - hhdm_response: &HhdmResponse, - memory_map_response: &'a MemoryMapResponse, - executable_address_response: &ExecutableAddressResponse, -) -> AArchPageTable { - return init_aarch64( - hhdm_response, - memory_map_response, - executable_address_response, - ); +pub fn init(mapper: &mut AArchPageTable) { + init_aarch64(mapper); } #[cfg(target_arch = "x86_64")] diff --git a/kernel/src/arch/x86_64/init.rs b/kernel/src/arch/x86_64/init.rs index 967ea81..8be72b2 100644 --- a/kernel/src/arch/x86_64/init.rs +++ b/kernel/src/arch/x86_64/init.rs @@ -3,11 +3,12 @@ use crate::{ gdt::load_gdt_x86_64, heap::init_heap, interrupts::{PICS, init_idt_x86_64}, - mouse::setup_mouse, + kmi::setup_kmi, paging::{FRAME_ALLOCATOR_X86_64, initialize_paging_x86_64}, syscall::init_syscalls, }, - driver::mouse::MOUSE, + config::TIMER_FREQUENCY_HZ, + driver::kmi::MOUSE, }; use x86_64::{ @@ -19,8 +20,7 @@ use x86_64::{ use limine::response::{HhdmResponse, MemoryMapResponse}; -const TIMER_PRECISION_HZ: u32 = 1000; -const PIT_DIVISOR: u16 = (1_193_182_u32 / TIMER_PRECISION_HZ) as u16; +const PIT_DIVISOR: u16 = (1_193_182_u32 / TIMER_FREQUENCY_HZ as u32) as u16; pub fn memory_management_init( hhdm_response: &HhdmResponse, @@ -47,10 +47,7 @@ pub fn set_pit_interval() { }); } -pub fn init_x86_64<'a>( - hhdm_response: &HhdmResponse, - memory_map_response: &'a MemoryMapResponse, -) -> OffsetPageTable<'static> { +pub fn init_x86_64<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) { load_gdt_x86_64(); unsafe { @@ -78,7 +75,7 @@ pub fn init_x86_64<'a>( pics.write_masks(master_mask, slave_mask); } - let mouse_status = setup_mouse(); + let kmi_status = setup_kmi(); set_pit_interval(); interrupts::enable(); @@ -89,7 +86,5 @@ pub fn init_x86_64<'a>( .ok() .expect("Failed to initalize heap"); - MOUSE.set_status(mouse_status); - - return mapper; + MOUSE.set_status(kmi_status); } diff --git a/kernel/src/arch/x86_64/interrupts.rs b/kernel/src/arch/x86_64/interrupts.rs index 1177381..1ece733 100644 --- a/kernel/src/arch/x86_64/interrupts.rs +++ b/kernel/src/arch/x86_64/interrupts.rs @@ -1,10 +1,13 @@ use core::sync::atomic::Ordering; use crate::{ - arch::x86_64::{gdt, mouse::mouse_interrupt}, + arch::x86_64::gdt, driver::{ - graphics::framebuffer::with_framebuffer, keyboard::push_scancode, mouse::MOUSE, - serial::with_serial_console, timer::TIMER, + graphics::framebuffer::with_framebuffer, + keyboard::push_scancode, + kmi::{keyboard_interrupt, mouse_interrupt}, + serial::with_serial_console, + timer::TIMER, }, println, }; @@ -12,7 +15,6 @@ use lazy_static::lazy_static; use pic8259::ChainedPics; use spin::Mutex; use x86_64::{ - instructions::port::Port, registers::control::Cr2, structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}, }; @@ -115,17 +117,7 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr } extern "x86-interrupt" fn mouse_interrupt_handler(_stack_frame: InterruptStackFrame) { - let interrupt_result = mouse_interrupt(); - - if let Some(interrupt_result) = interrupt_result { - MOUSE.interrupt( - interrupt_result.0, - interrupt_result.1, - interrupt_result.2, - interrupt_result.3, - interrupt_result.4, - ); - } + mouse_interrupt(); unsafe { PICS.lock() @@ -134,10 +126,9 @@ extern "x86-interrupt" fn mouse_interrupt_handler(_stack_frame: InterruptStackFr } pub extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { - let mut port = Port::new(0x60); - let scancode: u8 = unsafe { port.read() }; - - push_scancode(scancode); + if let Some(scancode) = keyboard_interrupt() { + push_scancode(scancode); + } unsafe { PICS.lock() diff --git a/kernel/src/arch/x86_64/mouse.rs b/kernel/src/arch/x86_64/kmi.rs similarity index 57% rename from kernel/src/arch/x86_64/mouse.rs rename to kernel/src/arch/x86_64/kmi.rs index 2199a04..5b24b72 100644 --- a/kernel/src/arch/x86_64/mouse.rs +++ b/kernel/src/arch/x86_64/kmi.rs @@ -1,14 +1,5 @@ -// Comment to self: WHY IS THIS SOO HARD - -use crate::util::get_bit; -use core::sync::atomic::{AtomicU8, Ordering}; - -use x86_64::instructions::{interrupts::without_interrupts, port::Port}; - -static CURRENTLY_RECEIVING_STATE: AtomicU8 = AtomicU8::new(0); -static FLAGS_BYTE: AtomicU8 = AtomicU8::new(0); -static X_DELTA_BYTE: AtomicU8 = AtomicU8::new(0); -static Y_DELTA_BYTE: AtomicU8 = AtomicU8::new(0); +use crate::arch::arch::safe_lock; +use x86_64::instructions::port::Port; fn wait_input_buffer_clear(command_port: &mut Port) { unsafe { @@ -83,8 +74,8 @@ fn clear_and_expect_output( } } -pub fn setup_mouse() -> u8 { - without_interrupts(|| { +pub fn setup_kmi() -> u8 { + safe_lock(|| { let mut command_port: Port = Port::new(0x64); let mut data_port: Port = Port::new(0x60); @@ -143,88 +134,29 @@ pub fn setup_mouse() -> u8 { }) } -fn reset_state() { - CURRENTLY_RECEIVING_STATE.store(0, Ordering::Relaxed); - FLAGS_BYTE.store(0, Ordering::Relaxed); - X_DELTA_BYTE.store(0, Ordering::Relaxed); - Y_DELTA_BYTE.store(0, Ordering::Relaxed); -} - -pub fn mouse_interrupt() -> Option<(u8, u8, u8, i16, i16)> { +pub unsafe fn read_mouse_control() -> u8 { let mut command_port: Port = Port::new(0x64); - let mut data_port: Port = Port::new(0x60); - unsafe { - if (command_port.read() & 0x20) == 0 { - // if this interrupt is not for the mouse, return - return None; - } - - let byte = data_port.read(); - - let state_idx = CURRENTLY_RECEIVING_STATE.fetch_add(1, Ordering::Relaxed); - - if state_idx == 0 { - if (byte & 0x08) == 0 { - // if sync bit unset, return - reset_state(); - return None; - } - - if (byte & 0b0100_0000) != 0 { - // if x overflow set, return - reset_state(); - return None; - } - - if (byte & 0b1000_0000) != 0 { - // if y overflow set, return - reset_state(); - return None; - } - - FLAGS_BYTE.store(byte, Ordering::Relaxed); - None - } else if state_idx == 1 { - X_DELTA_BYTE.store(byte, Ordering::Relaxed); - None - } else if state_idx == 2 { - Y_DELTA_BYTE.store(byte, Ordering::Relaxed); - let flags = FLAGS_BYTE.load(Ordering::Relaxed); - let left_button_pressed = get_bit(flags, 0); - let right_button_pressed = get_bit(flags, 1); - let middle_button_pressed = get_bit(flags, 2); - let x_delta_sign = get_bit(flags, 4); - let y_delta_sign = get_bit(flags, 5); - - let x_delta: i16 = { - let x_delta = X_DELTA_BYTE.load(Ordering::Relaxed); - if x_delta_sign == 1 { - (x_delta as i16) - 256 - } else { - x_delta as i16 - } - }; - - let y_delta: i16 = -{ - let y_delta = Y_DELTA_BYTE.load(Ordering::Relaxed); - if y_delta_sign == 1 { - (y_delta as i16) - 256 - } else { - y_delta as i16 - } - }; - - reset_state(); - - Some(( - left_button_pressed, - right_button_pressed, - middle_button_pressed, - x_delta, - y_delta, - )) - } else { - None - } - } + unsafe { command_port.read() } +} + +pub unsafe fn read_mouse_data() -> u8 { + let mut data: Port = Port::new(0x60); + unsafe { data.read() } +} + +pub unsafe fn write_mouse_control(byte: u8) { + let mut command_port: Port = Port::new(0x64); + unsafe { command_port.write(byte) } +} + +pub unsafe fn write_mouse_data(byte: u8) { + let mut command_port: Port = Port::new(0x60); + unsafe { command_port.write(byte) } +} + +pub unsafe fn read_keyboard_data() -> u8 { + unsafe { read_mouse_data() } +} +pub unsafe fn read_keyboard_control() -> u8 { + unsafe { read_mouse_control() } } diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 3848629..5325958 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -2,7 +2,7 @@ pub mod gdt; pub mod heap; pub mod init; pub mod interrupts; -pub mod mouse; +pub mod kmi; pub mod paging; pub mod syscall; pub mod usermode; diff --git a/kernel/src/config.rs b/kernel/src/config.rs new file mode 100644 index 0000000..3511ca7 --- /dev/null +++ b/kernel/src/config.rs @@ -0,0 +1 @@ +pub const TIMER_FREQUENCY_HZ: usize = 1000; \ No newline at end of file diff --git a/kernel/src/driver/kmi.rs b/kernel/src/driver/kmi.rs new file mode 100644 index 0000000..c50c9c4 --- /dev/null +++ b/kernel/src/driver/kmi.rs @@ -0,0 +1,190 @@ +use crate::util::get_bit; +use core::sync::atomic::{AtomicI16, AtomicU8, Ordering}; + +#[cfg(target_arch = "aarch64")] +use crate::arch::aarch64::kmi::{ + read_keyboard_control, read_keyboard_data, read_mouse_control, read_mouse_data, +}; +#[cfg(target_arch = "x86_64")] +use crate::arch::x86_64::kmi::{ + read_keyboard_control, read_keyboard_data, read_mouse_control, read_mouse_data, +}; + +static CURRENTLY_RECEIVING_STATE: AtomicU8 = AtomicU8::new(0); +static FLAGS_BYTE: AtomicU8 = AtomicU8::new(0); +static X_DELTA_BYTE: AtomicU8 = AtomicU8::new(0); +static Y_DELTA_BYTE: AtomicU8 = AtomicU8::new(0); + +pub struct Mouse { + left_button_pressed: AtomicU8, + right_button_pressed: AtomicU8, + middle_button_pressed: AtomicU8, + x_delta: AtomicI16, + y_delta: AtomicI16, + status: AtomicU8, +} + +impl Mouse { + const fn new() -> Mouse { + Mouse { + left_button_pressed: AtomicU8::new(0), + right_button_pressed: AtomicU8::new(0), + middle_button_pressed: AtomicU8::new(0), + x_delta: AtomicI16::new(0), + y_delta: AtomicI16::new(0), + status: AtomicU8::new(0), + } + } + + pub fn interrupt( + &self, + left_button_pressed: u8, + right_button_pressed: u8, + middle_button_pressed: u8, + x_delta: i16, + y_delta: i16, + ) { + self.left_button_pressed + .store(left_button_pressed, Ordering::Relaxed); + self.right_button_pressed + .store(right_button_pressed, Ordering::Relaxed); + self.middle_button_pressed + .store(middle_button_pressed, Ordering::Relaxed); + self.x_delta.fetch_add(x_delta, Ordering::Relaxed); + self.y_delta.fetch_add(y_delta, Ordering::Relaxed); + } + + pub fn button_state(&self) -> (u8, u8, u8) { + ( + self.left_button_pressed.load(Ordering::Relaxed), + self.right_button_pressed.load(Ordering::Relaxed), + self.middle_button_pressed.load(Ordering::Relaxed), + ) + } + pub fn take_motion(&self) -> (i16, i16) { + ( + self.x_delta.swap(0, Ordering::Relaxed), + self.y_delta.swap(0, Ordering::Relaxed), + ) + } + pub fn set_status(&self, status: u8) { + self.status.store(status, Ordering::Relaxed); + } + pub fn get_status(&self) -> u8 { + self.status.load(Ordering::Relaxed) + } +} + +fn reset_state() { + CURRENTLY_RECEIVING_STATE.store(0, Ordering::Relaxed); + FLAGS_BYTE.store(0, Ordering::Relaxed); + X_DELTA_BYTE.store(0, Ordering::Relaxed); + Y_DELTA_BYTE.store(0, Ordering::Relaxed); +} + +pub fn process_mouse_interrupt() -> Option<(u8, u8, u8, i16, i16)> { + #[cfg(target_arch = "x86_64")] + if (unsafe { read_mouse_control() } & 0x20) == 0 { + return None; + } + #[cfg(target_arch = "aarch64")] + if (unsafe { read_mouse_control() } & 0x10) == 0 { + return None; + } + + let byte = unsafe { read_mouse_data() }; + + let state_idx = CURRENTLY_RECEIVING_STATE.fetch_add(1, Ordering::Relaxed); + + if state_idx == 0 { + if (byte & 0x08) == 0 { + // if sync bit unset, return + reset_state(); + return None; + } + + if (byte & 0b0100_0000) != 0 { + // if x overflow set, return + reset_state(); + return None; + } + + if (byte & 0b1000_0000) != 0 { + // if y overflow set, return + reset_state(); + return None; + } + + FLAGS_BYTE.store(byte, Ordering::Relaxed); + None + } else if state_idx == 1 { + X_DELTA_BYTE.store(byte, Ordering::Relaxed); + None + } else if state_idx == 2 { + Y_DELTA_BYTE.store(byte, Ordering::Relaxed); + let flags = FLAGS_BYTE.load(Ordering::Relaxed); + let left_button_pressed = get_bit(flags, 0); + let right_button_pressed = get_bit(flags, 1); + let middle_button_pressed = get_bit(flags, 2); + let x_delta_sign = get_bit(flags, 4); + let y_delta_sign = get_bit(flags, 5); + + let x_delta: i16 = { + let x_delta = X_DELTA_BYTE.load(Ordering::Relaxed); + if x_delta_sign == 1 { + (x_delta as i16) - 256 + } else { + x_delta as i16 + } + }; + + let y_delta: i16 = -{ + let y_delta = Y_DELTA_BYTE.load(Ordering::Relaxed); + if y_delta_sign == 1 { + (y_delta as i16) - 256 + } else { + y_delta as i16 + } + }; + + reset_state(); + + Some(( + left_button_pressed, + right_button_pressed, + middle_button_pressed, + x_delta, + y_delta, + )) + } else { + None + } +} + +pub fn mouse_interrupt() { + if let Some(interrupt_result) = process_mouse_interrupt() { + MOUSE.interrupt( + interrupt_result.0, + interrupt_result.1, + interrupt_result.2, + interrupt_result.3, + interrupt_result.4, + ); + } +} + +pub fn keyboard_interrupt() -> Option { + #[cfg(target_arch = "x86_64")] + if (unsafe { read_keyboard_control() } & 0x01) == 0 { + return None; // OBF clear, no data + } + #[cfg(target_arch = "aarch64")] + if (unsafe { read_keyboard_control() } & 0x10) == 0 { + return None; // RXFULL clear, no data + } + + let scancode = unsafe { read_keyboard_data() }; + Some(scancode) +} + +pub static MOUSE: Mouse = Mouse::new(); diff --git a/kernel/src/driver/mod.rs b/kernel/src/driver/mod.rs index 65c28d7..a3ebc3a 100644 --- a/kernel/src/driver/mod.rs +++ b/kernel/src/driver/mod.rs @@ -2,6 +2,6 @@ pub mod elf; pub mod fs; pub mod graphics; pub mod keyboard; -pub mod mouse; +pub mod kmi; pub mod serial; pub mod timer; diff --git a/kernel/src/driver/mouse.rs b/kernel/src/driver/mouse.rs deleted file mode 100644 index 5438278..0000000 --- a/kernel/src/driver/mouse.rs +++ /dev/null @@ -1,63 +0,0 @@ -use core::sync::atomic::{AtomicI16, AtomicU8, Ordering}; - -pub struct Mouse { - left_button_pressed: AtomicU8, - right_button_pressed: AtomicU8, - middle_button_pressed: AtomicU8, - x_delta: AtomicI16, - y_delta: AtomicI16, - status: AtomicU8, -} - -impl Mouse { - const fn new() -> Mouse { - Mouse { - left_button_pressed: AtomicU8::new(0), - right_button_pressed: AtomicU8::new(0), - middle_button_pressed: AtomicU8::new(0), - x_delta: AtomicI16::new(0), - y_delta: AtomicI16::new(0), - status: AtomicU8::new(0), - } - } - - pub fn interrupt( - &self, - left_button_pressed: u8, - right_button_pressed: u8, - middle_button_pressed: u8, - x_delta: i16, - y_delta: i16, - ) { - self.left_button_pressed - .store(left_button_pressed, Ordering::Relaxed); - self.right_button_pressed - .store(right_button_pressed, Ordering::Relaxed); - self.middle_button_pressed - .store(middle_button_pressed, Ordering::Relaxed); - self.x_delta.fetch_add(x_delta, Ordering::Relaxed); - self.y_delta.fetch_add(y_delta, Ordering::Relaxed); - } - - pub fn button_state(&self) -> (u8, u8, u8) { - ( - self.left_button_pressed.load(Ordering::Relaxed), - self.right_button_pressed.load(Ordering::Relaxed), - self.middle_button_pressed.load(Ordering::Relaxed), - ) - } - pub fn take_motion(&self) -> (i16, i16) { - ( - self.x_delta.swap(0, Ordering::Relaxed), - self.y_delta.swap(0, Ordering::Relaxed), - ) - } - pub fn set_status(&self, status: u8) { - self.status.store(status, Ordering::Relaxed); - } - pub fn get_status(&self) -> u8 { - self.status.load(Ordering::Relaxed) - } -} - -pub static MOUSE: Mouse = Mouse::new(); diff --git a/kernel/src/driver/serial.rs b/kernel/src/driver/serial.rs index 8584f80..485965b 100644 --- a/kernel/src/driver/serial.rs +++ b/kernel/src/driver/serial.rs @@ -1,3 +1,4 @@ +use crate::alloc::string::ToString; use crate::driver::graphics::font_render::render_text; use crate::driver::graphics::framebuffer::Framebuffer; use crate::{arch::arch::safe_lock, driver::graphics::base::rgb}; @@ -20,7 +21,7 @@ impl Write for ConsoleWriter<'_> { pub struct SerialConsole { text: String, - font_size: usize, + pub font_size: usize, dirty: bool, } @@ -35,10 +36,45 @@ impl SerialConsole { pub fn print(&mut self, text: &str, fb: &mut Framebuffer) { let max_height = fb.height / (12 * self.font_size); - if self.text.split('\n').count() > max_height { - self.clear(); + let max_width = fb.width / (8 * self.font_size); + + for ch in text.chars() { + if ch == '\n' { + self.text.push('\n'); + continue; + } + + let line_len = self + .text + .rsplit('\n') + .next() + .map(|l| l.chars().count()) + .unwrap_or(0); + + if line_len >= max_width { + self.text.push('\n'); + } + + self.text.push(ch); } - self.text.push_str(text); + + let lines = self.text.lines().count(); + + if lines > max_height { + let remove = lines - max_height; + let mut split = 0; + + for (i, c) in self.text.char_indices() { + if c == '\n' { + split += 1; + if split == remove { + self.text = self.text[i + 1..].to_string(); + break; + } + } + } + } + self.dirty = true; } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 6cba699..37216fc 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -5,17 +5,24 @@ extern crate alloc; use core::fmt::Write; +#[cfg(target_arch = "aarch64")] +use aarch64_cpu::registers::{DAIF, Writeable}; use limine::BaseRevision; use limine::request::{ DateAtBootRequest, ExecutableAddressRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest, RequestsEndMarker, RequestsStartMarker, }; pub mod arch; +pub mod config; pub mod driver; pub mod mm; pub mod task; pub mod util; +#[cfg(target_arch = "aarch64")] +use crate::arch::aarch64::interrupts::enable_interrupts; +#[cfg(target_arch = "aarch64")] +use crate::arch::aarch64::paging::AArchPageTable; use crate::arch::arch::{HHDM_OFFSET, infinite_idle, init, kernel_crash, serial_print}; #[cfg(target_arch = "x86_64")] use crate::driver::elf::loader::run_elf; @@ -104,42 +111,56 @@ pub fn _print(args: core::fmt::Arguments) { #[unsafe(no_mangle)] unsafe extern "C" fn kmain() -> ! { - // All limine requests must also be referenced in a called function, otherwise they may be - // removed by the linker. - assert!(BASE_REVISION.is_supported()); + // mask everything early to prevent stack corruption and other undefined behavior + #[cfg(target_arch = "aarch64")] + { + DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Masked + DAIF::F::Masked); + } if let Some(hhdm_response) = HHDM_REQUEST.get_response() { HHDM_OFFSET.store( hhdm_response.offset(), core::sync::atomic::Ordering::Relaxed, ); + #[allow(unused_variables)] if let Some(memory_map_response) = MEMORY_MAP_REQUEST.get_response() { - #[cfg(target_arch = "x86_64")] - init(hhdm_response, memory_map_response); - #[cfg(target_arch = "aarch64")] if let Some(executable_address_response) = EXECUTABLE_ADDRESS_REQUEST.get_response() { - init( + use crate::arch::aarch64::init::preinit_aarch64; + preinit_aarch64( hhdm_response, memory_map_response, executable_address_response, ); + + loop {} } else { kernel_crash() } + + #[cfg(target_arch = "x86_64")] + unsafe { + kernel_main_x86_64() + } } else { kernel_crash(); // Could not get required info from Limine's memory map. } } else { kernel_crash(); // Could not get required info from Limine's higher-half direct mapping. } +} + +#[cfg(target_arch = "aarch64")] +#[unsafe(no_mangle)] +pub unsafe extern "C" fn kernel_main_aarch64(mapper: &mut AArchPageTable) -> ! { + // All limine requests must also be referenced in a called function, otherwise they may be + // removed by the linker. + assert!(BASE_REVISION.is_supported()); + init(mapper); if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { if let Some(limine_framebuffer) = framebuffer_response.framebuffers().next() { init_framebuffer(&limine_framebuffer); - #[cfg(target_arch = "x86_64")] - with_framebuffer(|fb| fb.setup_x86_64()); - #[cfg(target_arch = "aarch64")] with_framebuffer(|fb| fb.setup_aarch64()); } else { serial_print("no framebuffers found"); @@ -156,17 +177,52 @@ unsafe extern "C" fn kmain() -> ! { println!("Could not get date at boot. Will default to 0.") } - #[cfg(target_arch = "aarch64")] - { - println!("Hello from Aarch64!"); - with_framebuffer(|fb| { - with_serial_console(|sc| sc.render(fb)); - rectangle_filled(fb, 100, 100, 20, 20, rgb(255, 255, 255)); - fb.present(); - }); + println!("Hello from Aarch64!"); + with_framebuffer(|fb| { + with_serial_console(|sc| sc.render(fb)); + rectangle_filled(fb, 100, 100, 20, 20, rgb(255, 255, 255)); + }); + + enable_interrupts(); + + loop {} +} + +#[cfg(target_arch = "x86_64")] +pub unsafe fn kernel_main_x86_64() -> ! { + // All limine requests must also be referenced in a called function, otherwise they may be + // removed by the linker. + assert!(BASE_REVISION.is_supported()); + + if let Some(hhdm_response) = HHDM_REQUEST.get_response() { + if let Some(memory_map_response) = MEMORY_MAP_REQUEST.get_response() { + init(hhdm_response, memory_map_response); + } else { + kernel_crash(); // Could not get required info from Limine's memory map. + } + } else { + kernel_crash(); // Could not get required info from Limine's higher-half direct mapping. + } + + if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { + if let Some(limine_framebuffer) = framebuffer_response.framebuffers().next() { + init_framebuffer(&limine_framebuffer); + with_framebuffer(|fb| fb.setup_x86_64()); + } else { + serial_print("no framebuffers found"); + } + } + + init_serial_console(); + + init_keyboard(); + + if let Some(date_at_boot_response) = DATE_AT_BOOT_REQUEST.get_response() { + TIMER.set_date_at_boot(date_at_boot_response.timestamp().as_secs()); + } else { + println!("Could not get date at boot. Will default to 0.") } - #[cfg(target_arch = "x86_64")] run_elf(INIT_ELF_BYTES, false); loop {} @@ -200,7 +256,7 @@ fn rust_panic(_info: &core::panic::PanicInfo) -> ! { let mut buf = [0u8; 512]; let msg = { let mut w = BufWriter::new(&mut buf); - let _ = core::fmt::write(&mut w, core::format_args!("{}", _info.message())); + let _ = core::fmt::write(&mut w, core::format_args!("{}", _info)); let len = w.pos; core::str::from_utf8(&buf[..len]).unwrap_or("(utf8 error)") }; diff --git a/kernel/src/task/context.rs b/kernel/src/task/context.rs index 9584ca3..61af5fa 100644 --- a/kernel/src/task/context.rs +++ b/kernel/src/task/context.rs @@ -26,7 +26,44 @@ pub struct UserContext { #[cfg(target_arch = "aarch64")] #[repr(C)] #[derive(Clone, Copy)] -pub struct UserContext {} +pub struct UserContext { + pub x0: u64, + pub x1: u64, + pub x2: u64, + pub x3: u64, + pub x4: u64, + pub x5: u64, + pub x6: u64, + pub x7: u64, + pub x8: u64, + pub x9: u64, + pub x10: u64, + pub x11: u64, + pub x12: u64, + pub x13: u64, + pub x14: u64, + pub x15: u64, + pub x16: u64, + pub x17: u64, + pub x18: u64, + pub x19: u64, + pub x20: u64, + pub x21: u64, + pub x22: u64, + pub x23: u64, + pub x24: u64, + pub x25: u64, + pub x26: u64, + pub x27: u64, + pub x28: u64, + pub x29: u64, + pub x30: u64, + pub elr_el1: u64, + pub spsr_el1: u64, + pub esr_el1: u64, // exception type + pub far_el1: u64, // fault type + _pad: u64, +} #[unsafe(no_mangle)] pub extern "C" fn ctx_save(regs: *const UserContext) { diff --git a/kernel/src/util.rs b/kernel/src/util.rs index d55cbb6..8821035 100644 --- a/kernel/src/util.rs +++ b/kernel/src/util.rs @@ -1,6 +1,36 @@ use crate::{driver::timer::TIMER, println}; use spin::{Mutex, MutexGuard}; +pub struct U64Buf { + buf: [u8; 20], + start: usize, +} + +impl U64Buf { + pub fn new(n: u64) -> Self { + let mut buf = [0u8; 20]; + let mut pos = 20; + let mut val = n; + + if val == 0 { + buf[19] = b'0'; + return Self { buf, start: 19 }; + } + + while val > 0 { + pos -= 1; + buf[pos] = b'0' + (val % 10) as u8; + val /= 10; + } + + Self { buf, start: pos } + } + + pub fn as_str(&self) -> &str { + unsafe { core::str::from_utf8_unchecked(&self.buf[self.start..]) } + } +} + pub struct Locked { inner: Mutex, } diff --git a/user/libxunil b/user/libxunil index 695da84..e134040 160000 --- a/user/libxunil +++ b/user/libxunil @@ -1 +1 @@ -Subproject commit 695da849016f98f7a28b69c800bb33c0e49fc202 +Subproject commit e134040a9f7a644b7d3405e7a8b2742f2749ff6f