saving this just in case i give up
This commit is contained in:
parent
83180d098b
commit
882b6898f3
15 changed files with 779 additions and 112 deletions
|
@ -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"
|
||||
|
|
13
Makefile
13
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)
|
||||
|
|
|
@ -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
|
||||
|
|
314
assembly/ppc32/get_real.S
Normal file
314
assembly/ppc32/get_real.S
Normal file
|
@ -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
|
|
@ -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 = .;
|
||||
}
|
5
build.rs
5
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);
|
||||
}
|
172
src/bootstrap.rs
Normal file
172
src/bootstrap.rs
Normal file
|
@ -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
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
let val = unsafe {
|
||||
let mut val: u32;
|
||||
asm!("mfdec {}", out(reg) val);
|
||||
val
|
||||
};
|
||||
println!("decrementer value: {}", val);
|
||||
}
|
||||
|
|
|
@ -1 +1,73 @@
|
|||
pub mod decrementer;
|
||||
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");
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
132
src/main.rs
132
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!();
|
||||
|
|
37
src/memory.rs
Normal file
37
src/memory.rs
Normal file
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,11 +22,6 @@ impl<T: Clone> MessageQueue<T> {
|
|||
|
||||
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<T: Copy> NoAllocQueue<T> {
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ use crate::prom::PROMHNDL;
|
|||
pub fn of_singlevar_get<T>(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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue