diff --git a/.cargo/config b/.cargo/config index 4f37b14..3140991 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,6 +1,10 @@ -[target.ppc32-custom.json] +[target.powerpc-unknown-linux-gnu] linker = "powerpc-unknown-linux-gnu-gcc" ar = "powerpc-unknown-linux-gnu-ar" -#rustflags = [ "-C", "link-args=-nostdlib -ffreestanding -fPIC -Ttext 100000 -mbig-endian", "-C", "target-feature=+crt-static"] -# for some reason it wants a string -rustflags = "-C link-args='-nostdlib -ffreestanding -fPIC -Ttext 100000 -mbig-endian' -C target-feature=+crt-static" \ No newline at end of file +rustflags = [ + "-C", "link-args=-nostdlib -ffreestanding -fPIC -Ttext 100000 -mbig-endian", + "-C", "target-feature=+crt-static", +] + +[build] +target = "powerpc-unknown-linux-gnu" \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index eed6828..36dee96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,16 +5,16 @@ edition = "2021" [dependencies] spin = "0.9.1" -rlibc = "1.0" pc-keyboard = "0.6.1" cstr_core = { version = "0.2.6", features = ["alloc"] } libfar = { git = "https://github.com/realmicrosoft/libfar_nostd" } linked_list_allocator = { version = "0.9.0", optional = true } +rlibc = { version = "1.0" } [dependencies.lazy_static] version = "1.4.0" features = ["spin_no_std"] -# x86_64 specific dependencies +# apic specific dependencies [target.'cfg(target_arch = "x86_64")'.dependencies] x86_64 = "0.14.10" x2apic = "0.4.1" @@ -23,10 +23,18 @@ limine = { version = "0.1.9", optional = true } # powerpc (32) specific dependencies [target.'cfg(target_arch = "powerpc")'.dependencies] -openfirmware-sys = { git = "https://github.com/realmicrosoft/openfirmware-sys.git" } +ieee1275 = { git = "https://github.com/rust-osdev/ieee1275-rs", features = ["no_panic_handler"] } [features] -default = ["f_limine", "f_ll_alloc", "f_debug_verbose"] +default = ["f_ll_alloc", "f_debug_verbose"] f_debug_verbose = [] f_limine = ["dep:limine", "dep:acpi"] -f_ll_alloc = ["dep:linked_list_allocator"] \ No newline at end of file +f_ll_alloc = ["dep:linked_list_allocator"] + +[profile.dev] +panic = "abort" +strip = true + +[profile.release] +panic = "abort" +strip = true \ No newline at end of file diff --git a/Makefile b/Makefile index c2d5fce..5168673 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ arch ?= x86_64 -kernel := target/$(arch)-custom/debug/wukkOS iso := build/arch/$(arch)/wukkOS.iso target ?= $(arch)-custom +kernel := target/$(target)/release/wukkOS final := build/arch/$(arch)/wukkOS.bin initwukko := byob/initwukko.far initwukko_from := initwukko efi_bios := build/arch/$(arch)/OVMF-pure-efi.fd -kernel_flags := +KERNEL_FLAGS := -Zbuild-std=core,alloc RUST_FLAGS := gcc ?= gcc ld ?= ld @@ -20,9 +20,12 @@ assembly_object_files := $(patsubst arch/$(arch)/%.asm, \ ifeq "$(arch)" "x86_64" -kernel_flags += --features "f_limine" +KERNEL_FLAGS += --features "f_limine" --features "rlibc" endif ifeq "$(arch)" "ppc32" +target := powerpc-unknown-linux-gnu +kernel := target/$(target)/release/wukkOS +KERNEL_FLAGS := endif .PHONY: all clean run iso quick_invalidate build_no_iso @@ -32,7 +35,7 @@ all: $(final) $(iso) build_no_iso: $(final) clean: - @xargo clean + @cargo clean @rm -rf build run: $(final) $(iso) @@ -68,7 +71,7 @@ $(final): $(kernel) $(linker_script) $(initwukko) # --gc-sections $(kernel): - @RUSTFLAGS="$(RUST_FLAGS)" RUST_TARGET_PATH="$(shell pwd)" cargo +nightly build --target $(target) -Zbuild-std=core,alloc $(kernel_flags) + @RUST_TARGET_PATH="$(shell pwd)" cargo +nightly build --release --target $(target) $(KERNEL_FLAGS) $(initwukko): @mkdir -p $(shell dirname $@) diff --git a/ppc32-custom.json b/ppc32-custom.json index 346c8e1..1b8c57b 100644 --- a/ppc32-custom.json +++ b/ppc32-custom.json @@ -9,8 +9,7 @@ "panic-strategy": "abort", "pre-link-args": { "ld.lld": [ - "--gc-sections", - "--script=arch/ppc32/linker.ld" + "--gc-sections" ] } } \ No newline at end of file diff --git a/simple_boot/src/main.rs b/simple_boot/src/main.rs index 92814ba..cd7d5d0 100644 --- a/simple_boot/src/main.rs +++ b/simple_boot/src/main.rs @@ -28,7 +28,7 @@ fn main() { return; } - let mut run_cmd = Command::new("qemu-system-x86_64"); + let mut run_cmd = Command::new("qemu-system-apic"); run_cmd .arg("-drive") .arg(format!("format=raw,file={}", bios.display())); diff --git a/src/boot/mod.rs b/src/boot/mod.rs index 96301a5..eda38e7 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -1,108 +1,2 @@ -use alloc::boxed::Box; -use alloc::sync::Arc; -use alloc::vec::Vec; -use core::marker::PhantomData; -use core::ptr::NonNull; -use acpi::{AcpiHandler, AcpiTables, InterruptModel, PhysicalMapping}; -use acpi::platform::interrupt::InterruptSourceOverride; -use cstr_core::CString; -use limine::{LimineBootInfoRequest, LimineKernelAddressRequest, LimineMemmapRequest, LimineTerminalRequest, LimineTerminalResponse, LimineRsdpRequest, LimineSmpRequest, LimineModuleRequest}; -use crate::{debug, println}; - -#[cfg(feature = "f_multiboot2")] -use multiboot2::{load, MemoryMapTag, BootInformation}; -use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, Translate}; -use x86_64::VirtAddr; -use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize, read_phys_memory32, VIRT_MEM_OFFSET}; -use crate::serial::terminal::ST; - -pub static BOOTLOADER_INFO: LimineBootInfoRequest = LimineBootInfoRequest::new(0); -pub static TERMINAL_REQUEST: LimineTerminalRequest = LimineTerminalRequest::new(0); -pub static MEM_MAP: LimineMemmapRequest = LimineMemmapRequest::new(0); -pub static RSDP_REQUEST: LimineRsdpRequest = LimineRsdpRequest::new(0); -pub static KERNEL_ADDRESS: LimineKernelAddressRequest = LimineKernelAddressRequest::new(0); -pub static SMP_REQUEST: LimineSmpRequest = LimineSmpRequest::new(0); -pub static MOD_REQUEST: LimineModuleRequest = LimineModuleRequest::new(0); - -#[derive(Clone)] -struct Handler; -impl AcpiHandler for Handler { - unsafe fn map_physical_region(&self, physical_address: usize, size: usize) -> PhysicalMapping { // todo! check if size is too big - // only get lower 32 bits of physical address - let physical_address = physical_address as u32; - debug!("mapping physical region: {:x} - {:x}", physical_address, physical_address + size as u32); - let _ = read_phys_memory32(physical_address as u32) as usize; - PhysicalMapping::new( - physical_address as usize, - NonNull::new_unchecked(physical_address as *mut T), - size, size, - Self) - } - - fn unmap_physical_region(region: &PhysicalMapping) { - // get page - let page: Page = Page::containing_address(VirtAddr::new(region.physical_start() as u64)); - // unmap page - let res = unsafe { MEM_MAPPER.lock().as_mut().unwrap().unmap(page) }; - // it isn't *that* important if we don't unmap successfully at the moment, so just write a warning if we fail - - if let Err(e) = res { - debug!("(THIS IS NORMAL) failed to unmap physical region: {:?}", e); - } - } -} - -pub struct LimineWriter; - -impl core::fmt::Write for LimineWriter { - fn write_str(&mut self, s: &str) -> core::fmt::Result { - static mut CACHED: Option<&'static LimineTerminalResponse> = None; - unsafe { - if let Some(writer) = CACHED { - let terminal = &writer.terminals()[0]; - writer.write().unwrap()(terminal, s); - } else { - let response = TERMINAL_REQUEST.get_response().get().unwrap(); - let terminal = &response.terminals()[0]; - let writer = response.write().unwrap(); - writer(terminal, s); - - CACHED = Some(response); - } - } - Ok(()) - } -} - -pub fn get_ioapic_info() -> (u32, Vec) { - let rsdp = RSDP_REQUEST.get_response().get().unwrap(); - let rsdp_ptr = rsdp.address.get().unwrap() as *const u8; - let tables = unsafe { AcpiTables::from_rsdp(Handler, rsdp_ptr as usize).unwrap() }; - let platform_info = tables.platform_info().expect("no platform info"); - let interrupt_model = platform_info.interrupt_model; - let apic = match interrupt_model { - InterruptModel::Apic(apic) => apic, - _ => panic!("unsupported interrupt model"), - }; - let ioapic = apic.io_apics.first().expect("no ioapic"); - let address = ioapic.address; - let overrides = apic.interrupt_source_overrides; - (address, overrides) -} - -pub fn get_initwukko() -> Vec { - let mut response = MOD_REQUEST.get_response().get_mut().unwrap(); - let module = &response.modules()[0]; - let path_cstr = module.path.as_ptr().unwrap(); - let path = unsafe { CString::from_raw(path_cstr as *mut _) }; - debug!("initwukko path: {}", path.to_str().unwrap()); - let start = module.base.get().unwrap() as *const _ as usize; - let size = module.length as usize; - let end = start + size; - let mut data = Vec::new(); - for i in start..end { - let byte = unsafe { *(i as *const u8) }; - data.push(byte); - } - data -} \ No newline at end of file +#[cfg(target_arch = "x86_64")] +pub mod x86_64; \ No newline at end of file diff --git a/src/boot/x86_64/mod.rs b/src/boot/x86_64/mod.rs new file mode 100644 index 0000000..74dd7e5 --- /dev/null +++ b/src/boot/x86_64/mod.rs @@ -0,0 +1,106 @@ +use alloc::boxed::Box; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::marker::PhantomData; +use core::ptr::NonNull; +use acpi::{AcpiHandler, AcpiTables, InterruptModel, PhysicalMapping}; +use acpi::platform::interrupt::InterruptSourceOverride; +use cstr_core::CString; +use limine::{LimineBootInfoRequest, LimineKernelAddressRequest, LimineMemmapRequest, LimineTerminalRequest, LimineTerminalResponse, LimineRsdpRequest, LimineSmpRequest, LimineModuleRequest}; +use crate::{debug, println}; + +use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, Translate}; +use x86_64::VirtAddr; +use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize, read_phys_memory32, VIRT_MEM_OFFSET}; +use crate::serial::terminal::ST; + +pub static BOOTLOADER_INFO: LimineBootInfoRequest = LimineBootInfoRequest::new(0); +pub static TERMINAL_REQUEST: LimineTerminalRequest = LimineTerminalRequest::new(0); +pub static MEM_MAP: LimineMemmapRequest = LimineMemmapRequest::new(0); +pub static RSDP_REQUEST: LimineRsdpRequest = LimineRsdpRequest::new(0); +pub static KERNEL_ADDRESS: LimineKernelAddressRequest = LimineKernelAddressRequest::new(0); +pub static SMP_REQUEST: LimineSmpRequest = LimineSmpRequest::new(0); +pub static MOD_REQUEST: LimineModuleRequest = LimineModuleRequest::new(0); + +#[derive(Clone)] +struct Handler; +impl AcpiHandler for Handler { + unsafe fn map_physical_region(&self, physical_address: usize, size: usize) -> PhysicalMapping { // todo! check if size is too big + // only get lower 32 bits of physical address + let physical_address = physical_address as u32; + debug!("mapping physical region: {:x} - {:x}", physical_address, physical_address + size as u32); + let _ = read_phys_memory32(physical_address as u32) as usize; + PhysicalMapping::new( + physical_address as usize, + NonNull::new_unchecked(physical_address as *mut T), + size, size, + Self) + } + + fn unmap_physical_region(region: &PhysicalMapping) { + // get page + let page: Page = Page::containing_address(VirtAddr::new(region.physical_start() as u64)); + // unmap page + let res = unsafe { MEM_MAPPER.lock().as_mut().unwrap().unmap(page) }; + // it isn't *that* important if we don't unmap successfully at the moment, so just write a warning if we fail + + if let Err(e) = res { + debug!("(THIS IS NORMAL) failed to unmap physical region: {:?}", e); + } + } +} + +pub struct LimineWriter; + +impl core::fmt::Write for LimineWriter { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + static mut CACHED: Option<&'static LimineTerminalResponse> = None; + unsafe { + if let Some(writer) = CACHED { + let terminal = &writer.terminals()[0]; + writer.write().unwrap()(terminal, s); + } else { + let response = TERMINAL_REQUEST.get_response().get().unwrap(); + let terminal = &response.terminals()[0]; + let writer = response.write().unwrap(); + writer(terminal, s); + + CACHED = Some(response); + } + } + Ok(()) + } +} + +pub fn get_ioapic_info() -> (u32, Vec) { + let rsdp = RSDP_REQUEST.get_response().get().unwrap(); + let rsdp_ptr = rsdp.address.get().unwrap() as *const u8; + let tables = unsafe { AcpiTables::from_rsdp(Handler, rsdp_ptr as usize).unwrap() }; + let platform_info = tables.platform_info().expect("no platform info"); + let interrupt_model = platform_info.interrupt_model; + let apic = match interrupt_model { + InterruptModel::Apic(apic) => apic, + _ => panic!("unsupported interrupt model"), + }; + let ioapic = apic.io_apics.first().expect("no ioapic"); + let address = ioapic.address; + let overrides = apic.interrupt_source_overrides; + (address, overrides) +} + +pub fn get_initwukko() -> Vec { + let mut response = MOD_REQUEST.get_response().get_mut().unwrap(); + let module = &response.modules()[0]; + let path_cstr = module.path.as_ptr().unwrap(); + let path = unsafe { CString::from_raw(path_cstr as *mut _) }; + debug!("initwukko path: {}", path.to_str().unwrap()); + let start = module.base.get().unwrap() as *const _ as usize; + let size = module.length as usize; + let end = start + size; + let mut data = Vec::new(); + for i in start..end { + let byte = unsafe { *(i as *const u8) }; + data.push(byte); + } + data +} \ No newline at end of file diff --git a/src/internals/cpu/mod.rs b/src/internals/cpu/mod.rs new file mode 100644 index 0000000..388699c --- /dev/null +++ b/src/internals/cpu/mod.rs @@ -0,0 +1,4 @@ +#[cfg(target_arch = "x86_64")] +pub mod x86_64; +#[cfg(target_arch = "powerpc")] +pub mod ppc32; \ No newline at end of file diff --git a/src/internals/cpu/ppc32/mod.rs b/src/internals/cpu/ppc32/mod.rs new file mode 100644 index 0000000..d2929ff --- /dev/null +++ b/src/internals/cpu/ppc32/mod.rs @@ -0,0 +1,25 @@ +use ieee1275::PROM; +use spin::Mutex; +use lazy_static::lazy_static; + +pub struct PromHandle { + pub prom: Option, +} + +unsafe impl Send for PromHandle {} +unsafe impl Sync for PromHandle {} + +lazy_static!{ + pub static ref PROMHNDL: Mutex = Mutex::new(PromHandle { + prom: None, + }); +} + +impl PromHandle { + pub fn set_prom(&mut self, prom: PROM) { + self.prom = Some(prom); + } + pub fn get(&mut self) -> &mut PROM { + self.prom.as_mut().unwrap() + } +} \ No newline at end of file diff --git a/src/internals/cpu.rs b/src/internals/cpu/x86_64/apic.rs similarity index 100% rename from src/internals/cpu.rs rename to src/internals/cpu/x86_64/apic.rs diff --git a/src/internals/errors.rs b/src/internals/cpu/x86_64/errors.rs similarity index 100% rename from src/internals/errors.rs rename to src/internals/cpu/x86_64/errors.rs diff --git a/src/internals/interrupts.rs b/src/internals/cpu/x86_64/interrupts.rs similarity index 100% rename from src/internals/interrupts.rs rename to src/internals/cpu/x86_64/interrupts.rs diff --git a/src/internals/cpu/x86_64/mod.rs b/src/internals/cpu/x86_64/mod.rs new file mode 100644 index 0000000..fe9d485 --- /dev/null +++ b/src/internals/cpu/x86_64/mod.rs @@ -0,0 +1,161 @@ + +use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; +use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor}; +use x86_64::structures::tss::TaskStateSegment; +use x86_64::{PhysAddr, set_general_handler, VirtAddr}; +use x86_64::registers::segmentation::{CS, Segment, SS}; +use x86_64::structures::paging::Translate; +use spin::Mutex; +use crate::{internals, println}; + +use lazy_static::lazy_static; + +pub mod apic; + + +lazy_static! { + static ref GDT: Mutex = { + let mut gdt = GlobalDescriptorTable::new(); + Mutex::new(gdt) + }; + static ref IDT: InterruptDescriptorTable = { + let mut idt = InterruptDescriptorTable::new(); + unsafe { + use internals::errors::unhandled; + set_general_handler!(&mut idt, unhandled); + idt.breakpoint.set_handler_fn(internals::errors::breakpoint_exception).set_stack_index(0); + idt.double_fault.set_handler_fn(internals::errors::double_fault).set_stack_index(0); + idt.page_fault.set_handler_fn(internals::errors::page_fault).set_stack_index(0); + idt[internals::cpu::x86_64::apic::TIMER_IRQ].set_handler_fn(internals::cpu::x86_64::apic::timer).set_stack_index(1); + idt[internals::cpu::x86_64::apic::ERROR_IRQ].set_handler_fn(internals::cpu::x86_64::apic::error).set_stack_index(1); + idt[internals::cpu::x86_64::apic::SPURIOUS_IRQ].set_handler_fn(internals::cpu::x86_64::apic::spurious).set_stack_index(1); + idt[internals::cpu::x86_64::apic::FALLBACK_KEYBOARD_IRQ].set_handler_fn(internals::cpu::x86_64::apic::keyboard_irq).set_stack_index(1); + } + idt + }; +} + + +pub fn init() { + // temporarily disable interrupts + x86_64::instructions::interrupts::disable(); + println!("debug: setup GDT"); + + // load TSS + static mut tss: TaskStateSegment = TaskStateSegment::new(); + { + unsafe { + { + tss.interrupt_stack_table[0] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[1] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[2] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[3] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[4] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[5] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[6] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + } + { + tss.privilege_stack_table[0] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.privilege_stack_table[1] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.privilege_stack_table[2] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + } + // set word at offset 102 to 0x68 and last two bytes of the tss to 0xffff + // this is a hack to make the tss valid + let tss_ptr = &tss as *const TaskStateSegment as *mut u8; + unsafe { + *tss_ptr.add(102) = 0x68; + *tss_ptr.add(104) = 0xff; + *tss_ptr.add(105) = 0xff; + } + } + let kcs = GDT.lock().add_entry(Descriptor::kernel_code_segment()); + let kds = GDT.lock().add_entry(Descriptor::kernel_data_segment()); + let tsss = unsafe { GDT.lock().add_entry(Descriptor::tss_segment(&tss)) }; + // load GDT + unsafe { + GDT.lock().load_unsafe(); + } + println!("debug: GDT loaded"); + // set code segment to kernel code segment + unsafe { + CS::set_reg(kcs); + } + println!("debug: CS set"); + // set data segment to kernel data segment + unsafe { + SS::set_reg(kds); + } + println!("debug: SS set"); + // load TSS + unsafe { + x86_64::instructions::tables::load_tss(tsss); + } + println!("debug: TSS loaded"); + + // load IDT + IDT.load(); + println!("debug: IDT loaded"); + // enable interrupts + x86_64::instructions::interrupts::enable(); + } +} \ No newline at end of file diff --git a/src/internals/mod.rs b/src/internals/mod.rs index 9ef5c0f..8907b96 100644 --- a/src/internals/mod.rs +++ b/src/internals/mod.rs @@ -1,5 +1,3 @@ -pub mod errors; -pub mod interrupts; pub mod cpu; pub mod WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood { diff --git a/src/macros/mod.rs b/src/macros/mod.rs index 9314c60..1d0489e 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -1,7 +1,10 @@ use core::fmt; -use limine::LimineTerminalResponse; -use crate::boot::LimineWriter; -use crate::serial::terminal::ST; +use core::fmt::Write; +#[cfg(target_arch = "x86_64")] +use crate::boot::x86_64::LimineWriter; +use crate::internals::cpu::ppc32::PROMHNDL; +#[cfg(target_arch = "x86_64")] +use crate::serial::x86_64::terminal::ST; #[macro_export] macro_rules! print { @@ -21,25 +24,61 @@ macro_rules! debug { #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use core::fmt::Write; - ST.writer.lock().write_fmt(args).unwrap(); + #[cfg(target_arch = "powerpc")] + { + use core::fmt::Write; + use crate::internals::cpu::ppc32::PROMHNDL; + struct OFPrinter; + impl Write for OFPrinter { + fn write_str(&mut self, s: &str) -> fmt::Result { + unsafe { PROMHNDL.lock().get().write_line(s) }; + Ok(()) + } + } + OFPrinter.write_fmt(args).unwrap(); + } - let mut limine_writer = LimineWriter; - limine_writer.write_fmt(args).unwrap(); + #[cfg(target_arch = "apic")] + { + use core::fmt::Write; + ST.writer.lock().write_fmt(args).unwrap(); + + let mut limine_writer = LimineWriter; + limine_writer.write_fmt(args).unwrap(); + } } #[doc(hidden)] pub fn _debug(args: fmt::Arguments) { - use core::fmt::Write; - #[cfg(feature = "f_debug_verbose")] + #[cfg(target_arch = "powerpc")] { - ST.log("[debug] "); - ST.writer.lock().write_fmt(args).unwrap(); - ST.logln(""); + use core::fmt::Write; + use crate::internals::cpu::ppc32::PROMHNDL; + struct OFPrinter; + impl Write for OFPrinter { + fn write_str(&mut self, s: &str) -> fmt::Result { + unsafe { PROMHNDL.lock().get().write_line(s) }; + Ok(()) + } + } + OFPrinter.write_str("[debug] ").unwrap(); + OFPrinter.write_fmt(args).unwrap(); + OFPrinter.write_str("\n").unwrap(); + } - let mut limine_writer = LimineWriter; - limine_writer.write_str("[debug] ").unwrap(); - limine_writer.write_fmt(args).unwrap(); - limine_writer.write_str("\n").unwrap(); + #[cfg(target_arch = "apic")] + { + use core::fmt::Write; + #[cfg(feature = "f_debug_verbose")] + { + ST.log("[debug] "); + ST.writer.lock().write_fmt(args).unwrap(); + ST.logln(""); + + let mut limine_writer = LimineWriter; + limine_writer.write_str("[debug] ").unwrap(); + limine_writer.write_fmt(args).unwrap(); + limine_writer.write_str("\n").unwrap(); + } } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 3b3e254..78af803 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,18 +21,8 @@ use lazy_static::lazy_static; use core::panic::PanicInfo; use libfar::farlib; use libfar::farlib::{FarArchive, FarFileInfo}; -use limine::{LimineBootInfoRequest, LimineMemmapRequest, LimineTerminalRequest}; use spin::Mutex; -use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; -use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor}; -use x86_64::structures::tss::TaskStateSegment; -use x86_64::{PhysAddr, set_general_handler, VirtAddr}; -use x86_64::registers::segmentation::{CS, Segment, SS}; -use x86_64::structures::paging::Translate; -use crate::boot::{get_initwukko, get_ioapic_info, KERNEL_ADDRESS}; use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*; -use crate::memory::{FRAME_ALLOC, MEM_MAPPER}; -use crate::serial::terminal::ST; mod font; mod serial; @@ -45,27 +35,6 @@ mod macros; pub type InitWukko = FarArchive; lazy_static! { - //pub static ref KERN_INFO: Mutex> = Mutex::new(None); - static ref GDT: Mutex = { - let mut gdt = GlobalDescriptorTable::new(); - Mutex::new(gdt) - }; - static ref IDT: InterruptDescriptorTable = { - let mut idt = InterruptDescriptorTable::new(); - unsafe { - use internals::errors::unhandled; - set_general_handler!(&mut idt, unhandled); - idt.breakpoint.set_handler_fn(internals::errors::breakpoint_exception).set_stack_index(0); - idt.double_fault.set_handler_fn(internals::errors::double_fault).set_stack_index(0); - idt.page_fault.set_handler_fn(internals::errors::page_fault).set_stack_index(0); - idt[internals::cpu::TIMER_IRQ].set_handler_fn(internals::cpu::timer).set_stack_index(1); - idt[internals::cpu::ERROR_IRQ].set_handler_fn(internals::cpu::error).set_stack_index(1); - idt[internals::cpu::SPURIOUS_IRQ].set_handler_fn(internals::cpu::spurious).set_stack_index(1); - idt[internals::cpu::FALLBACK_KEYBOARD_IRQ].set_handler_fn(internals::cpu::keyboard_irq).set_stack_index(1); - } - idt - }; - static ref INITWUKKO: Mutex> = Mutex::new(None); } @@ -78,6 +47,10 @@ fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! { } #[panic_handler] +fn panic_wrapper(info: &PanicInfo) -> ! { + panic(info) +} + fn panic(info: &PanicInfo) -> ! { println!("---KERNEL FUCKY WUKKY UWU (panic)---"); if let Some(s) = info.payload().downcast_ref::<&str>() { @@ -85,7 +58,7 @@ fn panic(info: &PanicInfo) -> ! { } else { println!("no panic payload") }; - if let Some(msg) = info.message() { + if let Some(msg) = info.message() { println!("panic msg: {}", msg) } else { println!("no message"); @@ -98,144 +71,54 @@ fn panic(info: &PanicInfo) -> ! { loop {} } +#[cfg(target_arch = "powerpc")] +use ieee1275::prom_init; +#[cfg(target_arch = "powerpc")] +use ieee1275::services::Args; + +#[cfg(target_arch = "powerpc")] +#[no_mangle] +#[link_section = ".text"] +pub extern "C" fn _start(_r3: u32, _r4: u32, entry: extern "C" fn(*mut Args) -> usize) -> isize { + use internals::cpu::ppc32::PROMHNDL; + { + let mut prom = PROMHNDL.lock(); + prom.set_prom(prom_init(entry)); + } + + kernel_main(); + + PROMHNDL.lock().get().exit() +} + #[no_mangle] pub extern "C" fn kernel_main() -> ! { + // ppc32 stuff for now + //#[cfg(target_arch = "powerpc")] + { + + } + debug!("entry point"); - // initialise serial - let mut serial_ports = serial::init_serial(); - let mut console_port = None; - for (i, enabled) in serial_ports.ports_enabled.iter().enumerate() { - if *enabled { - console_port = Some(i); - } - } - - if let Some(i) = console_port { - let port = &serial_ports.ports[i]; - ST.init_from_port(*port); - println!("using serial port {} as console", i); - } - - // temporarily disable interrupts - x86_64::instructions::interrupts::disable(); - println!("debug: setup GDT"); - // load TSS - static mut tss: TaskStateSegment = TaskStateSegment::new(); + #[cfg(target_arch = "x86_64")] { - unsafe { - { - tss.interrupt_stack_table[0] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end - }; - tss.interrupt_stack_table[1] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end - }; - tss.interrupt_stack_table[2] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end - }; - tss.interrupt_stack_table[3] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end - }; - tss.interrupt_stack_table[4] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end - }; - tss.interrupt_stack_table[5] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end - }; - tss.interrupt_stack_table[6] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end - }; - } - { - tss.privilege_stack_table[0] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end - }; - tss.privilege_stack_table[1] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end - }; - tss.privilege_stack_table[2] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end - }; - } - // set word at offset 102 to 0x68 and last two bytes of the tss to 0xffff - // this is a hack to make the tss valid - let tss_ptr = &tss as *const TaskStateSegment as *mut u8; - unsafe { - *tss_ptr.add(102) = 0x68; - *tss_ptr.add(104) = 0xff; - *tss_ptr.add(105) = 0xff; + // initialise serial + let mut serial_ports = serial::init_serial(); + let mut console_port = None; + for (i, enabled) in serial_ports.ports_enabled.iter().enumerate() { + if *enabled { + console_port = Some(i); } } - let kcs = GDT.lock().add_entry(Descriptor::kernel_code_segment()); - let kds = GDT.lock().add_entry(Descriptor::kernel_data_segment()); - let tsss = unsafe { GDT.lock().add_entry(Descriptor::tss_segment(&tss)) }; - // load GDT - unsafe { - GDT.lock().load_unsafe(); - } - println!("debug: GDT loaded"); - // set code segment to kernel code segment - unsafe { - CS::set_reg(kcs); - } - println!("debug: CS set"); - // set data segment to kernel data segment - unsafe { - SS::set_reg(kds); - } - println!("debug: SS set"); - // load TSS - unsafe { - x86_64::instructions::tables::load_tss(tsss); - } - println!("debug: TSS loaded"); - // load IDT - IDT.load(); - println!("debug: IDT loaded"); - // enable interrupts - x86_64::instructions::interrupts::enable(); + if let Some(i) = console_port { + let port = &serial_ports.ports[i]; + ST.init_from_port(*port); + println!("using serial port {} as console", i); + } + + internals::cpu::x86_64::init(); } @@ -245,6 +128,8 @@ pub extern "C" fn kernel_main() -> ! { println!("welcome to wukkOS!"); println!("(c) 2022 Real Microsoft, LLC"); + /* + // memory stuff { print!("initialising mapper..."); @@ -296,7 +181,7 @@ pub extern "C" fn kernel_main() -> ! { unsafe { internals::cpu::setup_ioapic(addr, isos) }; println!("[OK]"); // enable interrupts - //x86_64::instructions::interrupts::enable(); + //apic::instructions::interrupts::enable(); } // initwukko stuff @@ -323,8 +208,12 @@ pub extern "C" fn kernel_main() -> ! { println!("[OK]"); } + */ loop { - x86_64::instructions::hlt(); + #[cfg(target_arch = "apic")] + { + x86_64::instructions::hlt(); + } } } \ No newline at end of file diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 053eaf5..eda38e7 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -1,148 +1,2 @@ -pub mod allocator; - -use alloc::boxed::Box; -use alloc::sync::Arc; -use lazy_static::lazy_static; -use limine::LimineMemoryMapEntryType; -use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PageTableFlags, PhysFrame, Size4KiB, Translate}; -use x86_64::{PhysAddr, VirtAddr}; - -lazy_static!{ - pub static ref MEM_MAPPER: Mutex>> = Mutex::new(None); - pub static ref FRAME_ALLOC: Mutex> = Mutex::new(None); -} - -pub const VIRT_MEM_OFFSET: u64 = 0xffffffff80000000; - -pub type PageSize = Size4KiB; - -pub struct Locked { - inner: spin::Mutex, -} - -impl Locked { - pub const fn new(inner: A) -> Self { - Locked { - inner: spin::Mutex::new(inner), - } - } - - pub fn lock(&self) -> spin::MutexGuard { - self.inner.lock() - } -} - -pub unsafe fn init(phys_mem_offset: VirtAddr) -> OffsetPageTable<'static> { - let level_4_table = active_level_4_table(phys_mem_offset); - OffsetPageTable::new(level_4_table, phys_mem_offset) -} - -unsafe fn active_level_4_table(phys_mem_offset: VirtAddr) -> &'static mut PageTable { - use x86_64::registers::control::Cr3; - - let (level_4_table_frame, _) = Cr3::read(); - - let phys = level_4_table_frame.start_address(); - let virt = phys_mem_offset + phys.as_u64(); - let page_table_ptr: *mut PageTable = virt.as_mut_ptr(); - - unsafe { &mut *page_table_ptr } // unsafe -} - -use spin::Mutex; -use crate::{debug, print, println}; -use crate::boot::{KERNEL_ADDRESS, MEM_MAP}; - -pub struct BootInfoFrameAllocator { - next: usize, -} - -impl BootInfoFrameAllocator { - pub unsafe fn init() -> Self { - Self { - next: 0, - } - } -} - -unsafe impl FrameAllocator for BootInfoFrameAllocator { - fn allocate_frame(&mut self) -> Option { - #[cfg(feature = "f_limine")] { - let mmap = MEM_MAP.get_response().get().expect("failed to get memory map") - .memmap(); - let mut usable_frames = mmap.iter() - .filter(|entry| entry.typ == LimineMemoryMapEntryType::Usable) - .map(|area| { - let frame_addr = area.base; - let frame_end = area.base + area.len; - let frame_size = frame_end - frame_addr; - let num_frames = frame_size / 4096; - let start_frame = PhysFrame::containing_address(PhysAddr::new(frame_addr)); - (0..num_frames).map(move |i| start_frame + i) - }) - .flatten(); - let frame = usable_frames.nth(self.next).clone(); - self.next += 1; - - frame - } - } -} - -pub fn read_phys_memory32(addr: u32) -> u32 { - let initaladdr = VirtAddr::new(addr as u64); - let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; - if let Some(addr) = addr { - let addr = addr.as_u64() as *const u32; - unsafe { *addr } - } else { - debug!("read_phys_memory32: addr {:x} not mapped", initaladdr.as_u64()); - // map the page - let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap(); - debug!("allocated frame: {:?}", frame); - let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE; - let page = x86_64::structures::paging::Page::containing_address(initaladdr); - debug!("mapped page: {:?}", page); - let map_to_result = unsafe { MEM_MAPPER.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) }; - debug!("map_to_result: {:?}", map_to_result); - if map_to_result.is_err() { - panic!("Failed to map page"); - } - let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; - if let Some(addr) = addr { - let addr = addr.as_u64() as *const u32; - unsafe { *addr } - } else { - panic!("Failed to map page"); - } - } -} - -pub fn write_phys_memory32(addr: u32, value: u32) { - let initaladdr = VirtAddr::new(addr as u64); - let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; - if let Some(addr) = addr { - let addr = addr.as_u64() as *mut u32; - unsafe { *addr = value }; - } else { - debug!("write_phys_memory32: addr {:x} not mapped", initaladdr.as_u64()); - // map the page - let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap(); - debug!("allocated frame: {:?}", frame); - let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE; - let page = x86_64::structures::paging::Page::containing_address(initaladdr); - debug!("mapped page: {:?}", page); - let map_to_result = unsafe { MEM_MAPPER.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) }; - debug!("map_to_result: {:?}", map_to_result); - if map_to_result.is_err() { - panic!("Failed to map page"); - } - let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; - if let Some(addr) = addr { - let addr = addr.as_u64() as *mut u32; - unsafe { *addr = value }; - } else { - panic!("Failed to map page"); - } - } -} \ No newline at end of file +#[cfg(target_arch = "x86_64")] +pub mod x86_64; \ No newline at end of file diff --git a/src/memory/allocator.rs b/src/memory/x86_64/allocator.rs similarity index 100% rename from src/memory/allocator.rs rename to src/memory/x86_64/allocator.rs diff --git a/src/memory/x86_64/mod.rs b/src/memory/x86_64/mod.rs new file mode 100644 index 0000000..6898830 --- /dev/null +++ b/src/memory/x86_64/mod.rs @@ -0,0 +1,149 @@ +pub mod allocator; + +use alloc::boxed::Box; +use alloc::sync::Arc; +use lazy_static::lazy_static; + +use limine::LimineMemoryMapEntryType; +use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PageTableFlags, PhysFrame, Size4KiB, Translate}; +use x86_64::{PhysAddr, VirtAddr}; + +lazy_static!{ + pub static ref MEM_MAPPER: Mutex>> = Mutex::new(None); + pub static ref FRAME_ALLOC: Mutex> = Mutex::new(None); +} + +pub const VIRT_MEM_OFFSET: u64 = 0xffffffff80000000; + +pub type PageSize = Size4KiB; + +pub struct Locked { + inner: spin::Mutex, +} + +impl Locked { + pub const fn new(inner: A) -> Self { + Locked { + inner: spin::Mutex::new(inner), + } + } + + pub fn lock(&self) -> spin::MutexGuard { + self.inner.lock() + } +} + +pub unsafe fn init(phys_mem_offset: VirtAddr) -> OffsetPageTable<'static> { + let level_4_table = active_level_4_table(phys_mem_offset); + OffsetPageTable::new(level_4_table, phys_mem_offset) +} + +unsafe fn active_level_4_table(phys_mem_offset: VirtAddr) -> &'static mut PageTable { + use x86_64::registers::control::Cr3; + + let (level_4_table_frame, _) = Cr3::read(); + + let phys = level_4_table_frame.start_address(); + let virt = phys_mem_offset + phys.as_u64(); + let page_table_ptr: *mut PageTable = virt.as_mut_ptr(); + + unsafe { &mut *page_table_ptr } // unsafe +} + +use spin::Mutex; +use crate::{debug, print, println}; +use crate::boot::{KERNEL_ADDRESS, MEM_MAP}; + +pub struct BootInfoFrameAllocator { + next: usize, +} + +impl BootInfoFrameAllocator { + pub unsafe fn init() -> Self { + Self { + next: 0, + } + } +} + +unsafe impl FrameAllocator for BootInfoFrameAllocator { + fn allocate_frame(&mut self) -> Option { + #[cfg(feature = "f_limine")] { + let mmap = MEM_MAP.get_response().get().expect("failed to get memory map") + .memmap(); + let mut usable_frames = mmap.iter() + .filter(|entry| entry.typ == LimineMemoryMapEntryType::Usable) + .map(|area| { + let frame_addr = area.base; + let frame_end = area.base + area.len; + let frame_size = frame_end - frame_addr; + let num_frames = frame_size / 4096; + let start_frame = PhysFrame::containing_address(PhysAddr::new(frame_addr)); + (0..num_frames).map(move |i| start_frame + i) + }) + .flatten(); + let frame = usable_frames.nth(self.next).clone(); + self.next += 1; + + frame + } + } +} + +pub fn read_phys_memory32(addr: u32) -> u32 { + let initaladdr = VirtAddr::new(addr as u64); + let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; + if let Some(addr) = addr { + let addr = addr.as_u64() as *const u32; + unsafe { *addr } + } else { + debug!("read_phys_memory32: addr {:x} not mapped", initaladdr.as_u64()); + // map the page + let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap(); + debug!("allocated frame: {:?}", frame); + let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE; + let page = x86_64::structures::paging::Page::containing_address(initaladdr); + debug!("mapped page: {:?}", page); + let map_to_result = unsafe { MEM_MAPPER.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) }; + debug!("map_to_result: {:?}", map_to_result); + if map_to_result.is_err() { + panic!("Failed to map page"); + } + let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; + if let Some(addr) = addr { + let addr = addr.as_u64() as *const u32; + unsafe { *addr } + } else { + panic!("Failed to map page"); + } + } +} + +pub fn write_phys_memory32(addr: u32, value: u32) { + let initaladdr = VirtAddr::new(addr as u64); + let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; + if let Some(addr) = addr { + let addr = addr.as_u64() as *mut u32; + unsafe { *addr = value }; + } else { + debug!("write_phys_memory32: addr {:x} not mapped", initaladdr.as_u64()); + // map the page + let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap(); + debug!("allocated frame: {:?}", frame); + let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE; + let page = x86_64::structures::paging::Page::containing_address(initaladdr); + debug!("mapped page: {:?}", page); + let map_to_result = unsafe { MEM_MAPPER.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) }; + debug!("map_to_result: {:?}", map_to_result); + if map_to_result.is_err() { + panic!("Failed to map page"); + } + let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; + if let Some(addr) = addr { + let addr = addr.as_u64() as *mut u32; + unsafe { *addr = value }; + } else { + panic!("Failed to map page"); + } + } +} \ No newline at end of file diff --git a/src/serial/mod.rs b/src/serial/mod.rs index a21e16e..eda38e7 100644 --- a/src/serial/mod.rs +++ b/src/serial/mod.rs @@ -1,174 +1,2 @@ - - -use core::arch::asm; -use core::borrow::{Borrow, BorrowMut}; -use core::ops::Deref; - -pub mod terminal_helpers; -pub mod terminal; -pub mod simplifiers; - -#[derive(Clone, Copy, PartialEq)] -pub enum potential_serial_ports { - COM1 = 0x3F8, - COM2 = 0x2F8, - COM3 = 0x3E8, - COM4 = 0x2E8, - COM5 = 0x5F8, - COM6 = 0x4F8, - COM7 = 0x5E8, - COM8 = 0x4E8, -} - -impl potential_serial_ports { - pub fn to_string<'a>(&self) -> &'a str { - match self { - potential_serial_ports::COM1 => "COM1", - potential_serial_ports::COM2 => "COM2", - potential_serial_ports::COM3 => "COM3", - potential_serial_ports::COM4 => "COM4", - potential_serial_ports::COM5 => "COM5", - potential_serial_ports::COM6 => "COM6", - potential_serial_ports::COM7 => "COM7", - potential_serial_ports::COM8 => "COM8", - _ => { - panic!("Invalid potential_serial_ports"); - } - } - } -} - -enum serial_offsets { - DATA = 0, - INTERRUPT_ID = 1, - FIFO_CTRL = 2, - LINE_CTRL = 3, - MODEM_CTRL = 4, - LINE_STATUS = 5, - MODEM_STATUS = 6, - SCRATCH = 7, -} - -#[derive(Copy, Clone)] -pub struct Port { - pub base: potential_serial_ports, -} - -pub struct SerialPorts { - pub ports_enabled: [bool; 8], - pub ports: [Port; 8], -} - -#[cfg(any(target_arch="x86", target_arch="x86_64"))] -pub fn command(port: u16, data: u8) { - unsafe { - asm!("out dx, al", in("al") data, in("dx") port); - } -} - -#[cfg(any(target_arch="x86", target_arch="x86_64"))] -pub fn read(port: u16) -> u8 { - let mut data: u8; - unsafe { - asm!("in al, dx", out("al") data, in("dx") port); - } - data -} - -// dummy functions for non-x86 -#[cfg(not(any(target_arch="x86", target_arch="x86_64")))] -pub fn command(port: u16, data: u8) { - unimplemented!() -} - -#[cfg(not(any(target_arch="x86", target_arch="x86_64")))] -pub fn read(port: u16) -> u8 { - unimplemented!() -} - -impl Port { - fn is_transmit_empty(&self) -> bool { - let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16); - status & 0x20 == 0x20 - } - - pub fn transmit(&self, data: u8) { - while !self.is_transmit_empty() {} - command(self.base as u16 + serial_offsets::DATA as u16, data); - } - - pub fn transmit_string(&self, data: &str) { - for c in data.chars() { - self.transmit(c as u8); - } - } - - fn is_recv_full(&self) -> bool { - let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16); - status & 0x01 == 0x01 - } - - pub fn receive(&self, mut timeout: u16) -> u8 { - if timeout != 0 { - while !self.is_recv_full() { - timeout -= 1; - if timeout == 0 { - return 0; - } - } - } else { - while !self.is_recv_full() {} - } - read(self.base as u16 + serial_offsets::DATA as u16) - } - - pub fn transrecv(&self, data: u8) -> u8 { - self.transmit(data); - self.receive(0) - } -} - -pub fn test_port(port: potential_serial_ports) -> bool { - let mut port: u16 = port as u16; - command(port + serial_offsets::INTERRUPT_ID as u16, 0x00); // disable interrupts - command(port + serial_offsets::LINE_CTRL as u16, 0x80); // enable DLAB - command(port + serial_offsets::DATA as u16, 0x03); // set divisor to 3 (lo byte) - command(port + serial_offsets::LINE_CTRL as u16, 0x03); // set divisor to 3 (hi byte) - command(port + serial_offsets::FIFO_CTRL as u16, 0xC7); // enable FIFO, clear them, with 14-byte threshold - command(port + serial_offsets::MODEM_CTRL as u16, 0x0B); // IRQs enabled, RTS/DSR set - command(port + serial_offsets::MODEM_CTRL as u16, 0x1E); // loopback mode - - // test serial - command(port + serial_offsets::DATA as u16, 0xAE); - // check if we received the correct byte - if read(port + serial_offsets::DATA as u16) != 0xAE { - return false; - } else { - // set stuffz idk - command(port + serial_offsets::MODEM_CTRL as u16, 0x0F); - return true; - } -} - -pub fn init_serial() -> SerialPorts { - // this is so fucking cursed - let mut ports_tmp : [Port; 8] = [ - Port { base: potential_serial_ports::COM1 }, - Port { base: potential_serial_ports::COM2 }, - Port { base: potential_serial_ports::COM3 }, - Port { base: potential_serial_ports::COM4 }, - Port { base: potential_serial_ports::COM5 }, - Port { base: potential_serial_ports::COM6 }, - Port { base: potential_serial_ports::COM7 }, - Port { base: potential_serial_ports::COM8 }]; - let mut ports_enabled_tmp : [bool; 8] = [false; 8]; - for i in 0..8 { - if test_port(ports_tmp[i].base) { - ports_enabled_tmp[i] = true; - } - } - SerialPorts { - ports_enabled: ports_enabled_tmp, - ports: ports_tmp, - } -} \ No newline at end of file +#[cfg(target_arch = "x86_64")] +pub mod x86_64; \ No newline at end of file diff --git a/src/serial/x86_64/mod.rs b/src/serial/x86_64/mod.rs new file mode 100644 index 0000000..bc76e67 --- /dev/null +++ b/src/serial/x86_64/mod.rs @@ -0,0 +1,174 @@ + + +use core::arch::asm; +use core::borrow::{Borrow, BorrowMut}; +use core::ops::Deref; + +pub mod terminal_helpers; +pub mod terminal; +pub mod simplifiers; + +#[derive(Clone, Copy, PartialEq)] +pub enum potential_serial_ports { + COM1 = 0x3F8, + COM2 = 0x2F8, + COM3 = 0x3E8, + COM4 = 0x2E8, + COM5 = 0x5F8, + COM6 = 0x4F8, + COM7 = 0x5E8, + COM8 = 0x4E8, +} + +impl potential_serial_ports { + pub fn to_string<'a>(&self) -> &'a str { + match self { + potential_serial_ports::COM1 => "COM1", + potential_serial_ports::COM2 => "COM2", + potential_serial_ports::COM3 => "COM3", + potential_serial_ports::COM4 => "COM4", + potential_serial_ports::COM5 => "COM5", + potential_serial_ports::COM6 => "COM6", + potential_serial_ports::COM7 => "COM7", + potential_serial_ports::COM8 => "COM8", + _ => { + panic!("Invalid potential_serial_ports"); + } + } + } +} + +enum serial_offsets { + DATA = 0, + INTERRUPT_ID = 1, + FIFO_CTRL = 2, + LINE_CTRL = 3, + MODEM_CTRL = 4, + LINE_STATUS = 5, + MODEM_STATUS = 6, + SCRATCH = 7, +} + +#[derive(Copy, Clone)] +pub struct Port { + pub base: potential_serial_ports, +} + +pub struct SerialPorts { + pub ports_enabled: [bool; 8], + pub ports: [Port; 8], +} + +#[cfg(any(target_arch="x86", target_arch="apic"))] +pub fn command(port: u16, data: u8) { + unsafe { + asm!("out dx, al", in("al") data, in("dx") port); + } +} + +#[cfg(any(target_arch="x86", target_arch="apic"))] +pub fn read(port: u16) -> u8 { + let mut data: u8; + unsafe { + asm!("in al, dx", out("al") data, in("dx") port); + } + data +} + +// dummy functions for non-x86 +#[cfg(not(any(target_arch="x86", target_arch="apic")))] +pub fn command(port: u16, data: u8) { + unimplemented!() +} + +#[cfg(not(any(target_arch="x86", target_arch="apic")))] +pub fn read(port: u16) -> u8 { + unimplemented!() +} + +impl Port { + fn is_transmit_empty(&self) -> bool { + let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16); + status & 0x20 == 0x20 + } + + pub fn transmit(&self, data: u8) { + while !self.is_transmit_empty() {} + command(self.base as u16 + serial_offsets::DATA as u16, data); + } + + pub fn transmit_string(&self, data: &str) { + for c in data.chars() { + self.transmit(c as u8); + } + } + + fn is_recv_full(&self) -> bool { + let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16); + status & 0x01 == 0x01 + } + + pub fn receive(&self, mut timeout: u16) -> u8 { + if timeout != 0 { + while !self.is_recv_full() { + timeout -= 1; + if timeout == 0 { + return 0; + } + } + } else { + while !self.is_recv_full() {} + } + read(self.base as u16 + serial_offsets::DATA as u16) + } + + pub fn transrecv(&self, data: u8) -> u8 { + self.transmit(data); + self.receive(0) + } +} + +pub fn test_port(port: potential_serial_ports) -> bool { + let mut port: u16 = port as u16; + command(port + serial_offsets::INTERRUPT_ID as u16, 0x00); // disable interrupts + command(port + serial_offsets::LINE_CTRL as u16, 0x80); // enable DLAB + command(port + serial_offsets::DATA as u16, 0x03); // set divisor to 3 (lo byte) + command(port + serial_offsets::LINE_CTRL as u16, 0x03); // set divisor to 3 (hi byte) + command(port + serial_offsets::FIFO_CTRL as u16, 0xC7); // enable FIFO, clear them, with 14-byte threshold + command(port + serial_offsets::MODEM_CTRL as u16, 0x0B); // IRQs enabled, RTS/DSR set + command(port + serial_offsets::MODEM_CTRL as u16, 0x1E); // loopback mode + + // test serial + command(port + serial_offsets::DATA as u16, 0xAE); + // check if we received the correct byte + if read(port + serial_offsets::DATA as u16) != 0xAE { + return false; + } else { + // set stuffz idk + command(port + serial_offsets::MODEM_CTRL as u16, 0x0F); + return true; + } +} + +pub fn init_serial() -> SerialPorts { + // this is so fucking cursed + let mut ports_tmp : [Port; 8] = [ + Port { base: potential_serial_ports::COM1 }, + Port { base: potential_serial_ports::COM2 }, + Port { base: potential_serial_ports::COM3 }, + Port { base: potential_serial_ports::COM4 }, + Port { base: potential_serial_ports::COM5 }, + Port { base: potential_serial_ports::COM6 }, + Port { base: potential_serial_ports::COM7 }, + Port { base: potential_serial_ports::COM8 }]; + let mut ports_enabled_tmp : [bool; 8] = [false; 8]; + for i in 0..8 { + if test_port(ports_tmp[i].base) { + ports_enabled_tmp[i] = true; + } + } + SerialPorts { + ports_enabled: ports_enabled_tmp, + ports: ports_tmp, + } +} \ No newline at end of file diff --git a/src/serial/simplifiers.rs b/src/serial/x86_64/simplifiers.rs similarity index 100% rename from src/serial/simplifiers.rs rename to src/serial/x86_64/simplifiers.rs diff --git a/src/serial/terminal.rs b/src/serial/x86_64/terminal.rs similarity index 100% rename from src/serial/terminal.rs rename to src/serial/x86_64/terminal.rs diff --git a/src/serial/terminal_helpers.rs b/src/serial/x86_64/terminal_helpers.rs similarity index 100% rename from src/serial/terminal_helpers.rs rename to src/serial/x86_64/terminal_helpers.rs