diff --git a/Cargo.toml b/Cargo.toml index 5144392..78fc94d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,12 +6,11 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ieee1275 = { git = "https://github.com/floppydiskette/ieee1275-rs", features = ["no_panic_handler"] } +ieee1275 = { git = "https://github.com/floppydiskette/ieee1275-rs", features = ["no_panic_handler", "no_global_allocator"] } builddate = { path = "../builddate" } [profile.dev] panic = "abort" -strip = true [profile.release] panic = "abort" diff --git a/Makefile b/Makefile index 0aceb07..a5977eb 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,22 @@ arch ?= ppc32 target ?= powerpc-unknown-linux-gnu -kernel ?= target/$(target)/release/vap +build_type ?= release +kernel ?= target/$(target)/$(build_type)/vap linker_script := assembly/$(arch)/linker.ld KERNEL_FLAGS ?= -Zbuild-std=core,alloc -final = build/$(target)/release/vap +final = build/$(target)/$(build_type)/vap ifeq "$(arch)" "ppc32" target := powerpc-unknown-linux-gnu -kernel := target/$(target)/release/vap +kernel := target/$(target)/$(build_type)/vap linker_script := assembly/$(arch)/linker.ld KERNEL_FLAGS := endif +ifeq "$(build_type)" "release" +KERNEL_FLAGS += --release +endif + .PHONY: all clean quick_invalidate all: $(final) @@ -31,4 +36,4 @@ $(final): $(kernel) @cp $(kernel) $(final) $(kernel): - @RUST_TARGET_PATH="$(shell pwd)" VAP_ARCH="$(arch)" cross +nightly build --release --target $(target) $(KERNEL_FLAGS) + @RUST_TARGET_PATH="$(shell pwd)" VAP_ARCH="$(arch)" cross +nightly build --target $(target) $(KERNEL_FLAGS) diff --git a/assembly/ppc32/exception.S b/assembly/ppc32/exception.S index 20ee0cd..d545648 100644 --- a/assembly/ppc32/exception.S +++ b/assembly/ppc32/exception.S @@ -199,6 +199,7 @@ // _decrementer_exception_wrapper // called when the decrementer exception occurs (i.e. when it reaches 0) .org ABSOLUTE(0x900) +.global _decrementer_exception_wrapper _decrementer_exception_wrapper: rfi CTX_SAVE diff --git a/assembly/ppc32/get_real.S b/assembly/ppc32/get_real.S new file mode 100644 index 0000000..4a0ebe8 --- /dev/null +++ b/assembly/ppc32/get_real.S @@ -0,0 +1,314 @@ +.section .text + +// oh how much more powerpc assembly must i write. woe is me + + +// BAT stuff is completely ripped from helenos +.macro BAT_COMPUTE base size mask lower upper + // less than 128 KB -> no BAT + + lis \upper, 0x0002 + cmpw \size, \upper + blt no_bat + + // mask = total >> 18 + + li \upper, 18 + srw \mask, \size, \upper + + // create Block Length mask by replicating + // the leading logical one 14 times + + li \upper, 14 + mtctr \mask + li \upper, 1 + + 0: + // mask = (mask >> 1) | mask + + srw \lower, \mask, \upper + or \mask, \mask, \lower + + bdnz 0b + + // mask = mask & 0x07ff + // (BAT can map up to 256 MB) + + andi. \mask, \mask, 0x07ff + + // mask = (mask << 2) | 0x0002 + // (priviledged access only) + + li \upper, 2 + slw \mask, \mask, \upper + ori \mask, \mask, 0x0002 + + lis \upper, (0x8000 + \base) + or \upper, \upper, \mask + + lis \lower, \base + ori \lower, \lower, 0x0002 +.endm + +.global get_real +get_real: + // r3 = address of the function to call once we're in real mode (physical address) + // r4 = kernel base address (physical address) + // r5 = kernel size + // r6 = final address (physical address) + // r7 translate table (physical address) + // r8 = memory size (physical address) + // r9 = pages to translate + + // get msr value + mfmsr 31 + // disable interrupts + rlwinm 31,31,0,17,15 + // set msr + mtmsr 31 + + // move r3 into srr0 (so we can jump to it with the rfi instruction) + mtsrr0 3 + + // set srr1 to the pending msr value we want for real mode + mfmsr 31 + lis 30, ~0@h + // "interrupts, instruction relocation, and data relocation" + ori 30, 30, ~((1<<15) | (1<<5) | (1<<4))@l + and 31, 31, 30 + mtsrr1 31 + + // WE'RE GETTING REAL + sync + isync + rfi + +#define PAGE_WIDTH 12 +#define PAGE_SIZE (1 << PAGE_WIDTH) + +.global get_fake +get_fake: + + // we want parameters in the format of + // memory_size, translate_table, pages_to_translate, kernel_fake_address, kernel_real_address + // so lets move them into the right registers + mr 31, 4 + mr 3, 8 + mr 4, 7 + mr 5, 9 + mr 6, 6 + mr 7, 31 + // r3 = memory size, r4 = translate table, r5 = pages to translate, r6 = where we jump after finishing + + li 31, PAGE_SIZE >> 2 // number of words to copy per page + mr 30, 7 // 30 = beginning of kernel (physical address), we want to copy it to the beginning of the kernel (virtual address) + + page_copy: + cmpwi 5, 0 // are pages = 0? + beq page_copy_done + + mtctr 31 // load counter with number of words to copy + lwz 29, 0(4) // 29 = address of this page as a physical address + + page_copy_loop: + lwz 28, 0(29) // load word from physical address + stw 28, 0(30) // store word to virtual address + + dcbst 0, 30 // sync + sync + icbi 0, 30 + sync + isync + + addi 29, 29, 4 // add 4 to physical address + addi 30, 30, 4 // add 4 to virtual address + + bdnz page_copy_loop + // move to next translate table entry + addi 4, 4, 4 // most confusing assembly language award goes to... + subi 5, 5, 1 + b page_copy + page_copy_done: + + // infinite loop for debugging + debug_loop: + b debug_loop + + // fill segment registers + li 31, 0 + li 29, 8 + mtctr 29 + li 30, 0 + + seg_fill_unpriv: + mtsrin 30, 31 + addi 30, 30, 1 + addis 31, 31, 0x1000 + bdnz seg_fill_unpriv + li 29, 8 + mtctr 29 + lis 30, 0x4000 + ori 30, 30, 8 + + seg_fill_priv: + mtsrin 30, 31 + addi 30, 30, 1 + addis 31, 31, 0x1000 + bdnz seg_fill_priv + + // invalidate bat registers + li 31, 0 + mtspr 528, 31 + mtspr 529, 31 + mtspr 530, 31 + mtspr 531, 31 + mtspr 532, 31 + mtspr 533, 31 + mtspr 534, 31 + mtspr 535, 31 + + mtspr 536, 31 + mtspr 537, 31 + mtspr 538, 31 + mtspr 539, 31 + mtspr 540, 31 + mtspr 541, 31 + mtspr 542, 31 + mtspr 543, 31 + + // set up page hash table + lis 31, 65536@h + ori 31, 31, 65536@l + subi 29, 31, 1 + sub 30, 3, 31 + andc 31, 31, 29 + + mtsdr1 30 + + li 29, 2 + srw 31, 31, 29 + li 29, 0 + + pht_clear: + stw 29, 0(30) + dcbst 0, 30 + sync + isync + addi 30, 30, 4 + subi 31, 31, 4 + cmpwi 31, 0 + beq pht_clear_done + bdnz pht_clear + pht_clear_done: + + mr 31, 3 + + lis 30, 268435456@h + ori 30, 30, 268435456@l // 256MiB + + // bat 0 + + cmpw 31, 30 + blt bat0_31 + mr 29, 30 + b bat0_30 + bat0_31: + mr 29, 31 + bat0_30: + + BAT_COMPUTE 0x0000 29 28 27 26 + mtspr 528, 26 + mtspr 529, 27 + mtspr 536, 26 + mtspr 537, 27 + + // BAT1 + + sub 31, 31, 29 + + cmpw 31, 30 + blt bat1_r31 + + mr 29, 30 + b bat1_r30 + + bat1_r31: + + mr 29, 31 + + bat1_r30: + + BAT_COMPUTE 0x1000 29 28 27 26 + mtspr 530, 26 + mtspr 531, 27 + + mtspr 538, 26 + mtspr 539, 27 + + // BAT2 + + sub 31, 31, 29 + + cmpw 31, 30 + blt bat2_r31 + + mr 29, 30 + b bat2_r30 + + bat2_r31: + + mr 29, 31 + + bat2_r30: + + BAT_COMPUTE 0x2000 29 28 27 26 + mtspr 532, 26 + mtspr 533, 27 + + mtspr 540, 26 + mtspr 541, 27 + + // BAT3 + + sub 31, 31, 29 + + cmpw 31, 30 + blt bat3_r31 + + mr 29, 30 + b bat3_r30 + + bat3_r31: + + mr 29, 31 + + bat3_r30: + + BAT_COMPUTE 0x3000 29 28 27 26 + mtspr 534, 26 + mtspr 535, 27 + + mtspr 542, 26 + mtspr 543, 27 + + no_bat: + + // flush tlb + li 31, 0 + sync + eieio + tlbsync + sync + + // jump to the final function! + mtsrr0 6 + + li 1, 0 // stack pointer + + mfmsr 31 + ori 31, 31, ((1<<5) | (1<<4))@l + mtsrr1 31 + + sync + isync + rfi \ No newline at end of file diff --git a/assembly/ppc32/linker.ld b/assembly/ppc32/linker.ld index 674966a..45dedfc 100644 --- a/assembly/ppc32/linker.ld +++ b/assembly/ppc32/linker.ld @@ -1,17 +1,30 @@ OUTPUT_FORMAT("elf32-powerpc") OUTPUT_ARCH("powerpc:common") -ENTRY(ppc_entry) +ENTRY(_start) SECTIONS { - /*.vector_table (SIZEOF_HEADERS): AT (SIZEOF_HEADERS) { - . = ALIGN(0x100); - *(V_TEXT_GENESIS); - }*/ - . = 0x10000000; + .text : { + *(.text .text.*) + } - .program_code 0x10008000 : { - *(*); - } + .rodata : { + *(.rodata .rodata.*) + } + + .data : { + *(.data .data.*) + } + + .bss : { + *(COMMON) + *(.bss .bss.*) + } + + .other : { + *(*) + } + + VAP_KERN_END = .; } \ No newline at end of file diff --git a/build.rs b/build.rs index 8b3e7a9..a39b288 100644 --- a/build.rs +++ b/build.rs @@ -5,6 +5,7 @@ fn main() { let mut cc_build = cc::Build::new(); let cc_build = cc_build + .file(format!("assembly/{}/get_real.S", arch)) .file(format!("assembly/{}/pls_stabilise_inline_ppc_asm.S", arch)) .file(format!("assembly/{}/exception.S", arch)); @@ -22,8 +23,8 @@ fn main() { cc_build.compile("vap_asm"); // link to the assembly file - //println!("cargo:rustc-link-lib=static=vap_asm"); + println!("cargo:rustc-link-lib=static=vap_asm"); // specify the linker.ld script - //println!("cargo:rustc-link-arg=-Tassembly/{}/linker.ld", arch); + println!("cargo:rustc-link-arg=-Tassembly/{}/linker.ld", arch); } \ No newline at end of file diff --git a/src/bootstrap.rs b/src/bootstrap.rs new file mode 100644 index 0000000..9dfa57c --- /dev/null +++ b/src/bootstrap.rs @@ -0,0 +1,172 @@ +use core::alloc::Layout; +use core::arch::asm; +use ieee1275::IHandle; +use ieee1275::services::{Args, CallMethodArgs}; +use crate::{debug, kernel_main, ofhelpers}; +use crate::prom::PROMHNDL; + +/// when our program first starts up, we will be in the openfirmware virtual address space. +/// the purpose of this module (in combination with `get_real.S`) is to switch to our own +/// virtual address space, which will give the kernel access to the physical memory. +/// +/// it is incredibly important that we do not allocate any memory before we switch to our +/// own virtual address space. this is because rust will think that an allocator +/// exists, when in reality it does not. this will cause a panic when we try to allocate +/// memory. and because our panic function requires memory allocation, we will lock up the +/// system. + +extern "C" { + //fn get_real(call_once_real: usize, kernel_base_addr: usize, kernel_size: usize, kernel_fake_address: usize, translate_table: usize, memory_size: usize, pages: usize); + //fn get_fake(memory_size: usize, translate_table: usize, pages: usize, kernel_fake_address: usize); + + // the following aren't functions, but rather pointers to the locations + // unfortunately, rust doesn't let me define extern variables, so i have to + // define these as functions + fn VAP_KERN_END(); +} + +pub fn bootstrap() { + let base_addr = get_kernel_base_addr(); + debug!("kernel base address: {:#x}", base_addr); + let size = get_kernel_size(); + debug!("kernel size: {:#x}", size); + let true_real_function = translate_to_phys(get_fake as usize); + debug!("real function (translated): {:#x}", true_real_function); + let true_base_addr = translate_to_phys(base_addr); + debug!("kernel base address (translated): {:#x}", true_base_addr); + let (translate_table, pages) = create_translate_table(base_addr); + debug!("translate table created with {} pages", pages); + let kernel_main_fake = final_function_translated(); + let real_translate_table = translate_to_phys(translate_table); + let memory_size = get_mem_size(); + + debug!("final function: {:#x}", kernel_main_fake); + debug!("memory size: {}MiB", memory_size / 1024 / 1024); + + // add base_addr to get_real + //let get_real = get_real as usize + base_addr; + //let get_real = get_real as *const fn(usize, usize, usize, usize, usize, usize, usize); + + debug!("get_real: {:#x}", get_real as usize); + + unsafe { + (get_real)(true_real_function, true_base_addr, size, kernel_main_fake, real_translate_table, memory_size, pages); + } + + debug!("oops! we should never get here!"); +} + +#[no_mangle] +pub extern "C" fn final_function() -> ! { + + // now, we can jump to the kernel entry point + kernel_main(); + + // we should never get here + loop {} +} + +fn translate_to_phys(addr: usize) -> usize { + let prom = unsafe { &mut PROMHNDL }; + let chosen = prom.get().find_device("/chosen\0").unwrap(); + let mut mmu: *const IHandle = core::ptr::null_mut(); + prom.get().get_property(chosen, "mmu\0", &mut mmu as *mut *const IHandle, core::mem::size_of::<*const IHandle>()).unwrap(); + #[repr(C)] + struct TranslateArgs { + args: Args, + slots: [u32; 16], + } + let mut args = TranslateArgs { + args: Args { + service: "call-method\0".as_ptr(), + nargs: 4, + nret: 5, + }, + slots: [0; 16], + }; + args.slots[0] = "translate\0".as_ptr() as u32; // takes 4 args, returns 5 + args.slots[1] = mmu as u32; + args.slots[2] = 1; + args.slots[3] = addr as u32; + match (prom.get().entry_fn)(&mut args.args as *mut Args) { + 0 => (), + e => panic!("failed to translate virtual address {:x}: {}", addr, e), + } + + if args.slots[4 + 0] != 0 { + panic!("failed to translate virtual address {:x}: {}", addr, args.slots[1]); + } + + //debug!("translated {:x} to {:?}", addr, args.slots); + + args.slots[4 + 2] as usize +} + +fn get_kernel_base_addr() -> usize { + //let mut load_base = 0u32; + //let res = ofhelpers::of_singlevar_get("load-base\0", &mut load_base).unwrap(); + //res[2] as usize + unsafe { VAP_KERN_START as usize } +} + +fn get_kernel_size() -> usize { + //let kern_base = get_kernel_base_addr(); + let kern_end = unsafe { VAP_KERN_END as usize }; + //kern_end - kern_base + kern_end +} + +pub fn ofw_alloc(layout: Layout) -> *mut u8 { + let prom = unsafe { &mut PROMHNDL }; + match prom.get().claim(layout.size(), layout.align()) { + Ok(addr) => addr, + Err(e) => panic!("failed to allocate memory: {}", e), + } +} + +pub fn ofw_free(ptr: *mut u8, layout: Layout) { + let prom = unsafe { &mut PROMHNDL }; + prom.get().release(ptr, layout.size()); +} + +fn align_up(addr: usize, align: usize) -> usize { + (addr + align - 1) & !(align - 1) +} + +// translate table addr, pages +// format: +// let i be the page number of some page of the kernel's virtual address space +// table[i] = phys addr of page i +fn create_translate_table(kern_base: usize) -> (usize, usize) { + const PAGE_WIDTH: usize = 12; + const PAGE_SIZE: usize = 1 << PAGE_WIDTH; + let pages = (align_up(get_kernel_size(), PAGE_SIZE)) >> PAGE_WIDTH; + debug!("creating translate table with {} pages", pages); + + let mut table = ofw_alloc(Layout::from_size_align(pages * 4, 4).unwrap()) as *mut u32; + for i in 0..pages { + let addr = kern_base + (i << PAGE_WIDTH); + let phys = translate_to_phys(addr); + unsafe { + *table = phys as u32; + table = table.add(1); + } + //debug!("page {} (virt: {:#x}, phys: {:#x})", i, addr, phys); + } + + (table as usize, pages) +} + +fn final_function_translated() -> usize { + let kernel_entry = final_function as usize; + //let kernel_entry = translate_to_phys(kernel_entry); + kernel_entry +} + +fn get_mem_size() -> usize { + let prom = unsafe { &mut PROMHNDL }; + let memory = prom.get().find_device("/memory\0").unwrap(); // todo: check if this is standard + let mut reg = [0u32; 2]; + prom.get().get_property(memory, "reg\0", &mut reg as *mut [u32; 2] as *mut u32, core::mem::size_of::<[u32; 2]>()).unwrap(); + reg[1] as usize +} \ No newline at end of file diff --git a/src/exceptions/decrementer.rs b/src/exceptions/decrementer.rs index a252a86..365df82 100644 --- a/src/exceptions/decrementer.rs +++ b/src/exceptions/decrementer.rs @@ -2,27 +2,41 @@ use core::arch::asm; use core::sync::atomic::{AtomicU32}; use crate::{kernel_callback, println}; -//pub static DECREMENTER_VAL: AtomicU32 = AtomicU32::new(100000000); +pub static DECREMENTER_VAL: AtomicU32 = AtomicU32::new(100000); -//extern { - //fn reset_decrementer(val: u32); -//} +extern { + fn _decrementer_exception_wrapper(); +} -//#[no_mangle] -//pub extern "C" fn _decrementer_exception_fn() { -// //println!("decrementer exception"); -// unsafe { -// //reset_decrementer(DECREMENTER_VAL.load(core::sync::atomic::Ordering::Relaxed)); -// } -//} +#[no_mangle] +pub extern "C" fn _decrementer_exception_fn() { + println!("decrementer exception"); + unsafe { + asm!("mtdec {}", in(reg) DECREMENTER_VAL.load(core::sync::atomic::Ordering::Relaxed)); + } +} pub fn init_decrementer() { + let ptr = _decrementer_exception_wrapper as *const u32; unsafe { - //reset_decrementer(DECREMENTER_VAL.load(core::sync::atomic::Ordering::Relaxed)); + //asm!("mtspr 22, {}", in(reg) ptr); + asm!("mtdec {}", in(reg) DECREMENTER_VAL.load(core::sync::atomic::Ordering::Relaxed)); + // asm!("mtspr 9, {}", in(reg) 0x8000_0000u32); } - println!("decrementer initialized"); + let val = unsafe { + let mut val: u32; + asm!("mfdec {}", out(reg) val); + val + }; + println!("decrementer value: {}", val); + println!("decrementer initialised"); } pub fn what_is_decrementer() { - println!("decrementer value: fuckyou"); -} \ No newline at end of file + let val = unsafe { + let mut val: u32; + asm!("mfdec {}", out(reg) val); + val + }; + println!("decrementer value: {}", val); +} diff --git a/src/exceptions/mod.rs b/src/exceptions/mod.rs index f955dab..36dc1fa 100644 --- a/src/exceptions/mod.rs +++ b/src/exceptions/mod.rs @@ -1 +1,73 @@ -pub mod decrementer; \ No newline at end of file +use core::arch::asm; +use ieee1275::services::Args; +use crate::prom::PROMHNDL; + +extern { + fn _decrementer_exception_wrapper(); +} + +pub mod decrementer; + +pub fn init_exceptions() { + // okay so this is a very hacky way to do this, but i like the idea of having all kernel + // functionality within one binary. + // so the decrementer exception is at the physical address 0x900, but we only have access + // to virtual addresses. so we need to map the physical address to a virtual address. + // then, we copy the exception handler to the virtual address. + // this way, we can use interrupts from openfirmware! + let prom = unsafe { &mut PROMHNDL }; + let prom = prom.get(); + + // use the "map" service to map the physical address to a virtual address + // here, we will map the physical address 0x900 to the virtual address 0x900 + #[repr(C)] + struct MapArgs { + args: Args, + phys_lo: u32, + phys_hi: u32, + virt: u32, + size: u32, + mode: u32, + } + let mut map_args = MapArgs { + args: Args { + service: "map\0".as_ptr(), + nargs: 3, + nret: 2, + }, + phys_lo: 0x900, + phys_hi: 0, + virt: 0xF0000000, + size: 0x1000, + mode: 0, + }; + match (prom.entry_fn)(&mut map_args.args as *mut Args) { + 0 => (), + e => panic!("failed to map physical address 0x900 to virtual address 0xF0000000: {}", e), + } + + // now, we need to copy the decrementer exception handler to the virtual address 0x900 + // we can probably just get away with memcpying the bytes from _decrementer_exception_wrapper + // + 1000 + let mut ptr = _decrementer_exception_wrapper as usize; + let mut dest = 0x900 as *mut u8; + unsafe { + let bytes = ptr.to_be_bytes(); + for i in 0..4 { + *dest.add(i) = bytes[i]; + } + } + + // now, we can initialize the decrementer exception + decrementer::init_decrementer(); + enable_the_interrupts_we_use(); +} + +pub fn enable_the_interrupts_we_use() { + unsafe { + // we only use the decrementer exception, so we only need to enable that + asm!("mtmsr {}", in(reg) 0x8000_0000u32); + // enable exceptions + asm!("wrteei 1"); + } +} \ No newline at end of file diff --git a/src/macros.rs b/src/macros.rs index 937db77..d306346 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -20,24 +20,32 @@ macro_rules! debug { pub static USE_RAW: AtomicBool = AtomicBool::new(true); +use core::fmt::Write; +struct OFPrinter; +impl Write for OFPrinter { + fn write_str(&mut self, s: &str) -> fmt::Result { + let _ = unsafe { &mut PROMHNDL }.get().write_stdout(s); + Ok(()) + } +} +struct TerminalPrinter; +impl Write for TerminalPrinter { + fn write_str(&mut self, s: &str) -> fmt::Result { + terminal::queue_str(s); + Ok(()) + } +} + #[doc(hidden)] pub fn _print(args: fmt::Arguments) { #[cfg(target_arch = "powerpc")] { - use core::fmt::Write; - struct OFPrinter; - impl Write for OFPrinter { - fn write_str(&mut self, s: &str) -> fmt::Result { - let _ = unsafe { &mut PROMHNDL }.get().write_stdout(s); - Ok(()) - } - } match USE_RAW.load(core::sync::atomic::Ordering::Relaxed) { true => { OFPrinter.write_fmt(args).unwrap(); }, false => { - terminal::queue_str(&format!("{}", args)); + TerminalPrinter.write_fmt(args).unwrap(); } } } @@ -47,14 +55,6 @@ pub fn _print(args: fmt::Arguments) { pub fn _debug(args: fmt::Arguments) { #[cfg(target_arch = "powerpc")] { - use core::fmt::Write; - struct OFPrinter; - impl Write for OFPrinter { - fn write_str(&mut self, s: &str) -> fmt::Result { - let _ = unsafe { &mut PROMHNDL }.get().write_stdout(s); - Ok(()) - } - } match USE_RAW.load(core::sync::atomic::Ordering::Relaxed) { true => { OFPrinter.write_str("[debug] ").unwrap(); @@ -62,7 +62,9 @@ pub fn _debug(args: fmt::Arguments) { OFPrinter.write_str("\r\n").unwrap(); }, false => { - terminal::queue_str(&format!("[debug] {}\r\n", args)); + TerminalPrinter.write_str("[debug] ").unwrap(); + TerminalPrinter.write_fmt(args).unwrap(); + TerminalPrinter.write_str("\r\n").unwrap(); } } } diff --git a/src/main.rs b/src/main.rs index 990b898..5cf832a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![feature(panic_info_message)] #![feature(alloc_error_handler)] #![feature(lang_items)] +#![feature(asm_experimental_arch)] #![no_std] #![no_main] @@ -19,6 +20,8 @@ mod windows; mod window_optimised_linked_list; mod exceptions; mod message_queue; +mod bootstrap; +mod memory; extern crate alloc; @@ -32,46 +35,69 @@ fn panic_wrapper(info: &PanicInfo) -> ! { panic(info) } +pub static PANIC_LEVEL: AtomicU8 = AtomicU8::new(0); + fn panic(info: &PanicInfo) -> ! { - macros::USE_RAW.store(true, core::sync::atomic::Ordering::Relaxed); - //println!("---KERNEL FUCKY WUKKY UWU (panic)---"); - //if let Some(s) = info.payload().downcast_ref::<&str>() { - // println!("panic payload: {s:?}") - //} else { - // println!("no panic payload") - //}; - //if let Some(msg) = info.message() { - // println!("panic msg: {}", msg) - //} else { - // println!("no message"); - //} - //if let Some(location) = info.location() { - // println!("location: file {} line {}", location.file(), location.line()); - //} else { - // println!("no location"); - //}; - let fb_size = OFFramebuffer::fb_size(); - OFFramebuffer::rectangle(COMMUNISM_RED, 0, 0, fb_size.0, fb_size.1); - let mut y = 0; - OFFramebuffer::put_string(0,y, "---KERNEL FUCKY WUKKY UWU (panic)---", VAPOREON_BLACK); - y += 16; - if let Some(s) = info.payload().downcast_ref::<&str>() { - OFFramebuffer::put_string(0,y, &format!("panic payload: {s:?}"), VAPOREON_BLACK); - } else { - OFFramebuffer::put_string(0,y, "no panic payload", VAPOREON_BLACK); - }; - y += 16; - if let Some(msg) = info.message() { - OFFramebuffer::put_string(0,y, &format!("panic msg: {}", msg), VAPOREON_BLACK); - } else { - OFFramebuffer::put_string(0,y, "no message", VAPOREON_BLACK); - }; - y += 16; - if let Some(location) = info.location() { - OFFramebuffer::put_string(0,y, &format!("location: file {} line {}", location.file(), location.line()), VAPOREON_BLACK); - } else { - OFFramebuffer::put_string(0,y, "no location", VAPOREON_BLACK); - }; + match PANIC_LEVEL.load(Ordering::Relaxed) { + 0 => { + use core::fmt::{Write, Result}; + struct OFPrinter; + impl Write for OFPrinter { + fn write_str(&mut self, s: &str) -> Result { + let _ = unsafe { &mut PROMHNDL }.get().write_stdout(s); + Ok(()) + } + } + let _ = unsafe { &mut PROMHNDL }.get().write_stdout("panic: "); + if let Some(msg) = info.message() { + OFPrinter.write_fmt(format_args!("{}", msg)).unwrap(); + } + if let Some(location) = info.location() { + OFPrinter.write_fmt(format_args!("locationg: file {} line {}", location.file(), location.line())).unwrap(); + } + } + + _ => { + //println!("---KERNEL FUCKY WUKKY UWU (panic)---"); + //if let Some(s) = info.payload().downcast_ref::<&str>() { + // println!("panic payload: {s:?}") + //} else { + // println!("no panic payload") + //}; + //if let Some(msg) = info.message() { + // println!("panic msg: {}", msg) + //} else { + // println!("no message"); + //} + //if let Some(location) = info.location() { + // println!("location: file {} line {}", location.file(), location.line()); + //} else { + // println!("no location"); + //}; + let fb_size = OFFramebuffer::fb_size(); + OFFramebuffer::rectangle(COMMUNISM_RED, 0, 0, fb_size.0, fb_size.1); + let mut y = 0; + OFFramebuffer::put_string(0, y, "---KERNEL FUCKY WUKKY UWU (panic)---", VAPOREON_BLACK); + y += 16; + if let Some(s) = info.payload().downcast_ref::<&str>() { + OFFramebuffer::put_string(0, y, &format!("panic payload: {s:?}"), VAPOREON_BLACK); + } else { + OFFramebuffer::put_string(0, y, "no panic payload", VAPOREON_BLACK); + }; + y += 16; + if let Some(msg) = info.message() { + OFFramebuffer::put_string(0, y, &format!("panic msg: {}", msg), VAPOREON_BLACK); + } else { + OFFramebuffer::put_string(0, y, "no message", VAPOREON_BLACK); + }; + y += 16; + if let Some(location) = info.location() { + OFFramebuffer::put_string(0, y, &format!("location: file {} line {}", location.file(), location.line()), VAPOREON_BLACK); + } else { + OFFramebuffer::put_string(0, y, "no location", VAPOREON_BLACK); + }; + } + } loop {} } @@ -79,7 +105,7 @@ use alloc::format; use alloc::vec::Vec; use core::num::Wrapping; use core::panic::PanicInfo; -use core::sync::atomic::AtomicBool; +use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use ieee1275::prom_init; use ieee1275::services::Args; use crate::colourdefs::{COMMUNISM_RED, VAPOREON_BLACK, VAPOREON_BLUE, VAPOREON_CUM, VAPOREON_DARK}; @@ -91,17 +117,13 @@ use crate::windows::{NeedRedrawResult, WINDOW_MANAGER}; #[no_mangle] #[link_section = ".text"] -pub extern "C" fn ppc_entry(_r3: u32, _r4: u32, entry: extern "C" fn(*mut Args) -> usize) -> isize { +pub extern "C" fn _start(_r3: u32, _r4: u32, entry: extern "C" fn(*mut Args) -> usize) -> isize { { let mut prom = unsafe { &mut PROMHNDL }; prom.set_prom(prom_init(entry)); } - { - keyboard::set(); - } - - kernel_main(); + bootstrap::bootstrap(); { (unsafe { &mut PROMHNDL }).get().exit() } @@ -136,7 +158,10 @@ pub fn kernel_callback() { redraw_all(); } - let wm_redraw_status = unsafe { let wm = &mut WINDOW_MANAGER; wm.need_redraw() }; + let wm_redraw_status = unsafe { + let wm = &mut WINDOW_MANAGER; + wm.need_redraw() + }; match wm_redraw_status { NeedRedrawResult::DontNeedRedraw => {} @@ -158,13 +183,19 @@ pub fn kernel_callback() { } else { panic!("read error: {:?}", try_read); } + + let terminal_buffer_empty = unsafe { terminal::TERMINAL_QUEUE.is_empty() }; + if !terminal_buffer_empty { + unsafe { terminal::dequeue(); } + } } #[no_mangle] pub extern "C" fn kernel_main() -> ! { use builddate::build_date; - debug!("entry point"); + let _ = unsafe { &mut PROMHNDL }.get().write_stdout("we made it!"); + loop {} print!("\n"); // no carriage return cause i like the look of centered vap print!("\n"); @@ -196,8 +227,9 @@ pub extern "C" fn kernel_main() -> ! { debug!("constructing terminal window"); terminal::construct_terminal_window(); - debug!("initialising decrementer exception"); - exceptions::decrementer::init_decrementer(); + debug!("initialising exceptions"); + exceptions::init_exceptions(); + debug!("exceptions initialised"); println!("ready!"); println!(); diff --git a/src/memory.rs b/src/memory.rs new file mode 100644 index 0000000..2150da0 --- /dev/null +++ b/src/memory.rs @@ -0,0 +1,37 @@ +use core::alloc::{GlobalAlloc, Layout}; +use core::sync::atomic::{AtomicU8, Ordering}; +use crate::debug; + +struct Allocator {} + +#[global_allocator] +static ALLOCATOR: Allocator = Allocator {}; + +pub static ALLOCATOR_STAGE: AtomicU8 = AtomicU8::new(0); + +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + match ALLOCATOR_STAGE.load(Ordering::Relaxed) { + 0 => { + panic!("allocating {:?} bytes", layout.size()); + crate::bootstrap::ofw_alloc(layout) + } + + _ => { + panic!("allocation occurred after allocator stage 0") + } + } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + match ALLOCATOR_STAGE.load(Ordering::Relaxed) { + 0 => { + crate::bootstrap::ofw_free(ptr, layout) + } + + _ => { + panic!("deallocation occurred after allocator stage 0") + } + } + } +} \ No newline at end of file diff --git a/src/message_queue/mod.rs b/src/message_queue/mod.rs index a17dd5b..a51f75a 100644 --- a/src/message_queue/mod.rs +++ b/src/message_queue/mod.rs @@ -22,11 +22,6 @@ impl MessageQueue { pub fn push(&mut self, item: T) { let head = self.head.load(core::sync::atomic::Ordering::Relaxed); - let tail = self.tail.load(core::sync::atomic::Ordering::Relaxed); - if head == tail { - // queue is full - panic!("queue is full"); - } self.queue[head] = Some(item); self.head.store((head + 1) % self.queue.len(), core::sync::atomic::Ordering::Relaxed); } @@ -94,11 +89,6 @@ impl NoAllocQueue { pub fn push(&mut self, item: T) { let head = self.head.load(core::sync::atomic::Ordering::Relaxed); - let tail = self.tail.load(core::sync::atomic::Ordering::Relaxed); - if head == tail { - // queue is full - panic!("queue is full"); - } self.queue[head] = Some(item); self.head.store((head + 1) % self.queue.len(), core::sync::atomic::Ordering::Relaxed); } diff --git a/src/ofhelpers.rs b/src/ofhelpers.rs index b5c9bdc..e1bf087 100644 --- a/src/ofhelpers.rs +++ b/src/ofhelpers.rs @@ -7,7 +7,6 @@ use crate::prom::PROMHNDL; pub fn of_singlevar_get(name: &str, buffer: *mut T) -> Result<[u32; 16], String> { let mut prom = unsafe { &mut PROMHNDL }; let prom = prom.get(); - let name = format!("{}{}", name, '\0'); #[repr(C)] struct SingleVarArgs { diff --git a/src/terminal.rs b/src/terminal.rs index fee9cb0..91e571e 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -275,7 +275,23 @@ pub fn queue_str(string: &str) { let queue = unsafe { &mut TERMINAL_QUEUE }; let mut buf = [0; 80]; for (i, c) in string.as_bytes().iter().enumerate() { + if i >= 80 { + break; + } buf[i] = *c; } queue.push((buf, string.len())); +} + +pub unsafe fn dequeue() { + let queue = &mut TERMINAL_QUEUE; + if let Some((buf, len)) = queue.pop() { + let str = core::str::from_utf8(&buf[..*len]).unwrap(); + write_string(str); + } + + unsafe { + shift_lines_up(); + request_terminal_redraw(); + } } \ No newline at end of file