From 86a85b8b0dced2e649f9c59409a5b59e3ebe3d9a Mon Sep 17 00:00:00 2001 From: Arthur Beck Date: Sat, 25 Jan 2025 18:22:59 -0600 Subject: [PATCH] Apparently this wasn't committed previously? --- emulation/bochsrc | 3 +- emulation/bx_enh_dbg.ini | 26 --- kernel/src/include/_entry.rs | 107 +----------- kernel/src/include/arch/mod.rs | 4 +- kernel/src/include/arch/x86/egatext.rs | 69 +------- kernel/src/include/arch/x86/mod.rs | 137 ++++++++++++++- kernel/src/include/arch/x86/output.rs | 220 ------------------------- kernel/src/include/arch/x86/paging.rs | 1 + kernel/src/include/boot.rs | 56 +++++++ kernel/src/include/mod.rs | 6 +- kernel/src/include/output.rs | 159 ++++++++++++++++++ kernel/src/include/traits.rs | 67 ++++++++ 12 files changed, 440 insertions(+), 415 deletions(-) delete mode 100644 emulation/bx_enh_dbg.ini create mode 100644 kernel/src/include/arch/x86/paging.rs create mode 100644 kernel/src/include/boot.rs create mode 100644 kernel/src/include/output.rs create mode 100644 kernel/src/include/traits.rs diff --git a/emulation/bochsrc b/emulation/bochsrc index 2b51c95..150fedb 100644 --- a/emulation/bochsrc +++ b/emulation/bochsrc @@ -1,6 +1,7 @@ display_library: x, options="gui_debug" port_e9_hack: enabled=1 -cpu: reset_on_triple_fault=0 +cpu: reset_on_triple_fault=0, model=tigerlake +magic_break: enabled=1 ata0-master: type=cdrom, path=../kernel/aphrodite.iso, status=inserted boot: cdrom \ No newline at end of file diff --git a/emulation/bx_enh_dbg.ini b/emulation/bx_enh_dbg.ini deleted file mode 100644 index 6fb0bbe..0000000 --- a/emulation/bx_enh_dbg.ini +++ /dev/null @@ -1,26 +0,0 @@ -# bx_enh_dbg_ini -SeeReg[0] = TRUE -SeeReg[1] = TRUE -SeeReg[2] = TRUE -SeeReg[3] = TRUE -SeeReg[4] = FALSE -SeeReg[5] = FALSE -SeeReg[6] = FALSE -SeeReg[7] = FALSE -SingleCPU = FALSE -ShowIOWindows = TRUE -ShowButtons = TRUE -SeeRegColors = TRUE -ignoreNxtT = TRUE -ignSSDisasm = TRUE -UprCase = 0 -DumpInAsciiMode = 3 -isLittleEndian = TRUE -DefaultAsmLines = 512 -DumpWSIndex = 0 -DockOrder = 0x123 -ListWidthPix[0] = 354 -ListWidthPix[1] = 411 -ListWidthPix[2] = 512 -MainWindow = 0, 0, 895, 500 -FontName = Normal diff --git a/kernel/src/include/_entry.rs b/kernel/src/include/_entry.rs index fbdf07e..dd22713 100644 --- a/kernel/src/include/_entry.rs +++ b/kernel/src/include/_entry.rs @@ -3,113 +3,10 @@ #![allow(unexpected_cfgs)] #![allow(static_mut_refs)] -use crate::arch::x86::output::*; -use crate::arch::x86::egatext as egatext; -use crate::multiboot2::BootInfo; -use egatext::*; +use crate::output::*; /// The real entrypoint to the kernel. `internel/arch/*/entry.rs` files eventually call this. #[allow(non_snake_case)] -pub fn _entry(ega: Option, BI: &BootInfo) -> ! { - if ega.is_some() { - let ega = ega.unwrap(); - ega.clear_screen(WHITE_ON_BLACK); - sreset(); - - let extended_functions = crate::arch::x86::cpuid_extended_functions(); - - if extended_functions { - binfosln("This CPU supports extended functions", ega).unwrap(); - - let longmode_support = crate::arch::x86::cpuid(0x80000001).1 & (1<<29) > 1; - if longmode_support { - binfosln("This CPU supports long mode", ega).unwrap(); - } else { - binfosln("This CPU does NOT support long mode!", ega).unwrap(); - bdebugs("Long mode CPUID: ", ega).unwrap(); - bdebugbnpln(&crate::u32_as_u8_slice(crate::arch::x86::cpuid(0x80000001).1), ega).unwrap(); - } - } else { - binfosln("This CPU does NOT support extended functions or long mode!", ega).unwrap(); - } - if BI.bootloader_name.is_some() { - binfos("Kernel booted by ", ega).unwrap(); - binfosnpln(BI.bootloader_name.unwrap().into(), ega).unwrap(); - } - if BI.cmdline.is_some() { - binfos("Command line passed: \"", ega).unwrap(); - binfosnp(BI.cmdline.unwrap().into(), ega).unwrap(); - binfosnpln("\"", ega).unwrap(); - } - if BI.mem_lower.is_some() { - binfos("Amount of lower memory: ", ega).unwrap(); - binfobnpln(&crate::u32_as_u8_slice(BI.mem_lower.unwrap()), ega).unwrap(); - } - if BI.mem_upper.is_some() { - binfos("Amount of upper memory: ", ega).unwrap(); - binfobnpln(&crate::u32_as_u8_slice(BI.mem_upper.unwrap()), ega).unwrap(); - } - if BI.memory_map.is_some() { - binfos("Recieved memory map from bootloader with ", ega).unwrap(); - binfobnp(&crate::usize_as_u8_slice(BI.memory_map.unwrap().sections.len()), ega).unwrap(); - binfosnpln(" sections", ega).unwrap(); - let mut i = 0; - for ele in BI.memory_map.unwrap().sections { - binfos("Section #", ega).unwrap(); - binfobnp(&crate::usize_as_u8_slice(i), ega).unwrap(); - binfosnp(": ", ega).unwrap(); - match ele.mem_type { - 1 => { - binfosnp("Available RAM", ega).unwrap(); - }, - 2 => { - binfosnp("Reserved by hardware", ega).unwrap(); - } - 3 => { - binfosnp("ACPI information", ega).unwrap(); - }, - 4 => { - binfosnp("Reserved memory", ega).unwrap(); - }, - 5 => { - binfosnp("Defective", ega).unwrap(); - }, - _ => { - binfosnp("Reserved/unknown (type=", ega).unwrap(); - binfobnp(&crate::u32_as_u8_slice(ele.mem_type), ega).unwrap(); - binfosnp(")", ega).unwrap(); - } - } - binfosnp(", starting at ", ega).unwrap(); - binfobnp(&crate::u64_as_u8_slice(ele.base_addr), ega).unwrap(); - binfosnp(" and running for ", ega).unwrap(); - binfobnp(&crate::u64_as_u8_slice(ele.length), ega).unwrap(); - binfosnpln(" bytes", ega).unwrap(); - - i += 1; - } - } - } else { - if BI.bootloader_name.is_some() { - sinfos("Kernel booted by "); - sinfosnpln(BI.bootloader_name.unwrap().into()); - } - if BI.cmdline.is_some() { - sinfos("Command line passed: \""); - sinfosnp(BI.cmdline.unwrap().into()); - sinfosnpln("\""); - } - if BI.memory_map.is_some() { - sinfosln("Recieved memory map from bootloader"); - } - if BI.mem_lower.is_some() { - sinfos("Amount of lower memory: "); - sinfobnpln(&crate::u32_as_u8_slice(BI.mem_lower.unwrap())); - } - if BI.mem_upper.is_some() { - sinfos("Amount of upper memory: "); - sinfobnpln(&crate::u32_as_u8_slice(BI.mem_upper.unwrap())); - } - } +pub fn _entry(display: Option<&dyn crate::TextDisplay>, BI: &crate::boot::BootInfo) -> ! { loop {} } \ No newline at end of file diff --git a/kernel/src/include/arch/mod.rs b/kernel/src/include/arch/mod.rs index a1e13a5..7bfed5f 100644 --- a/kernel/src/include/arch/mod.rs +++ b/kernel/src/include/arch/mod.rs @@ -1,3 +1,5 @@ //! Arch-specific code. -pub mod x86; \ No newline at end of file +mod x86; + +pub use x86::*; \ No newline at end of file diff --git a/kernel/src/include/arch/x86/egatext.rs b/kernel/src/include/arch/x86/egatext.rs index 9214fd3..9c3725d 100644 --- a/kernel/src/include/arch/x86/egatext.rs +++ b/kernel/src/include/arch/x86/egatext.rs @@ -1,6 +1,8 @@ //! Stuff for writing and reading to the EGA text buffer. #![cfg(any(target_arch = "x86"))] +use crate::Color; + /// Information about the framebuffer. #[derive(Clone, Copy)] pub struct FramebufferInfo { @@ -29,9 +31,9 @@ pub const WHITE_ON_BLACK: u8 = 0b00000111; /// Black text on a black background. pub const BLACK_ON_BLACK: u8 = 0b00000000; -impl FramebufferInfo { +impl crate::TextDisplay for FramebufferInfo { /// Writes a character to the screen. - pub fn write_char(self, mut pos: (u32, u32), char: u8, color: u8) -> Result<(), crate::Error<'static>> { + fn write_char(&self, mut pos: (u32, u32), char: u8, color: Color) -> Result<(), crate::Error<'static>> { if pos.0>self.width { return Err(crate::Error::new("Invalid X position", ERR_INVALID_X)); } @@ -51,66 +53,13 @@ impl FramebufferInfo { } Ok(()) } - - /// Clears the screen. - pub fn clear_screen(self, color: u8) { - for x in 0..self.width { - for y in 0..self.height { - self.write_char((x, y), b' ', color).unwrap(); - } - } - } - - /// Writes a &str to the screen. - pub fn write_str(mut self, pos: (u32, u32), str: &str, color: u8) -> Result<(u32, u32), crate::Error<'static>> { - let (mut x, mut y) = pos; - let change_cursor = self.change_cursor; - if change_cursor { - self.change_cursor = false; - } - for char in str.as_bytes() { - self.write_char((x, y), *char, color)?; - if *char == 0 { - continue - } - x += 1; - while x>self.width { - x -= self.width; - y += 1; - } - } - if change_cursor { - self.change_cursor = true; - self.set_cursor_location((x, y)); - } - Ok((x, y)) - } - - /// Writes a &\[u8] to the screen. - pub fn write_bytes(mut self, pos: (u32, u32), str: &[u8], color: u8) -> Result<(u32, u32), crate::Error<'static>> { - let (mut x, mut y) = pos; - let change_cursor = self.change_cursor; - if change_cursor { - self.change_cursor = false; - } - for char in str { - self.write_char((x, y), *char, color)?; - if *char == 0 { - continue - } - x += 1; - while x>self.width { - x -= self.width; - y += 1; - } - } - if change_cursor { - self.change_cursor = true; - self.set_cursor_location((x, y)); - } - Ok((x, y)) + fn get_size(&self) -> (u32, u32) { + (self.width, self.height) } +} +impl FramebufferInfo { + /// Disables the cursor. pub fn disable_cursor(self) { super::ports::outb(0x3D4, 0x0A); diff --git a/kernel/src/include/arch/x86/mod.rs b/kernel/src/include/arch/x86/mod.rs index 5079c8f..2311461 100644 --- a/kernel/src/include/arch/x86/mod.rs +++ b/kernel/src/include/arch/x86/mod.rs @@ -7,10 +7,13 @@ pub mod interrupts; pub mod ports; pub mod output; pub mod egatext; +pub mod paging; mod constants; pub use constants::*; +use interrupts::{pop_irq, restore_irq}; +use ports::{inb, outb}; /// Returns information from the CPUID command in the form /// (ebx, edx, ecx). @@ -35,4 +38,136 @@ pub fn cpuid_extended_functions() -> bool { ) } out >= 0x80000001 -} \ No newline at end of file +} + +/// Returns whether the a20 gate is enabled. +pub fn test_a20() -> bool { + let addr0: usize; + let addr1: usize; + unsafe { + asm!( + "mov edi, 0x112345", + "mov esi, 0x012345", + "mov [esi], esi", + "mov [edi], edi", + "mov eax, esi", + out("eax") addr0, out("edi") addr1 + ) + } + addr0 != addr1 +} + +/// Waits for a keyboard command to complete. +pub fn wait_for_keyboard_cmd() { + while inb(0x64)&0b10 > 1 {} +} + +/// Waits for there to be data to read from the keyboard. +pub fn wait_for_keyboard_data() { + while inb(0x64)&0b1 == 0 {} +} + +/// Sends a keyboard command. +pub fn send_keyboard_cmd(byte: u8) { + outb(0x64, byte); +} + +/// Gets data from the keyboard. +pub fn get_keyboard_data() -> u8 { + inb(0x60) +} + +/// Sends data to the keyboard. +pub fn send_keyboard_data(data: u8) { + outb(0x60, data); +} + +/// Tries to enable the a20 gate via the keyboard controller method. +pub fn enable_a20_keyboard() { + let irq = pop_irq(); + + wait_for_keyboard_cmd(); + send_keyboard_cmd(0xAD); // disable keyboard + + wait_for_keyboard_cmd(); + send_keyboard_cmd(0xD0); // read from input + + wait_for_keyboard_cmd(); + wait_for_keyboard_data(); + let a = get_keyboard_data(); + + wait_for_keyboard_cmd(); + send_keyboard_cmd(0xD1); // write to output + + wait_for_keyboard_cmd(); + send_keyboard_data(a|2); + + wait_for_keyboard_cmd(); + send_keyboard_cmd(0xAE); // enable keyboard + + restore_irq(irq); +} + +/// Tries to enable the a20 gate via fast a20. +/// Note that this may not work or do something unexpected. +pub fn enable_a20_fasta20() { + let mut a = inb(0x92); + if a&0b10 > 0 { + return + } + a |= 0b10; + a &= 0xFE; + outb(0x92, a); +} + +/// Tries to enable the a20 gate by reading from port 0xee. +pub fn enable_a20_ee_port() { + inb(0xee); +} + +/// Tries to enable the a20 gate by trying many different methods +/// and seeing what sticks. +pub fn enable_a20() -> bool { + if test_a20() { + return true; + } + + enable_a20_keyboard(); + let mut i = 0u32; + while (!test_a20()) && i<10000 { + i += 1; + } + + if test_a20() { + return true; + } + + enable_a20_ee_port(); + let mut i = 0u32; + while (!test_a20()) && i<10000 { + i += 1; + } + + if test_a20() { + return true; + } + + enable_a20_fasta20(); + let mut i = 0u32; + while (!test_a20()) && i<10000 { + i += 1; + } + + return test_a20(); +} + +/// Disables paging by clearing bit 31 in the cr0 register. +pub fn disable_paging() { + unsafe { + asm!( + "mov eax, cr0", + "and eax, 01111111111111111111111111111111b", + "mov cr0, eax" + ) + } +} diff --git a/kernel/src/include/arch/x86/output.rs b/kernel/src/include/arch/x86/output.rs index 6150c5f..f194121 100644 --- a/kernel/src/include/arch/x86/output.rs +++ b/kernel/src/include/arch/x86/output.rs @@ -2,12 +2,8 @@ #![cfg(any(target_arch = "x86"))] use super::ports; -use super::egatext::*; - use paste::paste; -static mut OUTPUT_TERM_POSITION: (u32, u32) = (0, 0); - macro_rules! message_funcs { ($func_name:ident, $prefix:literal, $level:ident) => { paste! { @@ -97,215 +93,6 @@ macro_rules! message_funcs { } ports::outb(super::DEBUG_PORT, s); } - - - - /////////////////////////////////////////////////////////////////////////////////////////////////////// - - - /// Outputs a $func_name message &str to the terminal. - pub fn [< t $func_name s >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - unsafe { - if cfg!($level = "false") { - return Ok(()); - } - OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, WHITE_ON_BLACK)?; - OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?; - } - Ok(()) - } - /// Outputs a $func_name message &str and a newline to the terminal. - pub fn [< t $func_name sln >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - unsafe { - if cfg!($level = "false") { - return Ok(()); - } - OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, WHITE_ON_BLACK)?; - OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?; - OUTPUT_TERM_POSITION.1 += 1; - OUTPUT_TERM_POSITION.0 = 0; - } - Ok(()) - } - - /// Outputs a $func_name message &\[u8] to the terminal. - pub fn [< t $func_name b >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - unsafe { - if cfg!($level = "false") { - return Ok(()); - } - OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, WHITE_ON_BLACK)?; - OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?; - } - Ok(()) - } - /// Outputs a $func_name message &\[u8] and a newline to the terminal. - pub fn [< t $func_name bln >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - unsafe { - if cfg!($level = "false") { - return Ok(()); - } - OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, WHITE_ON_BLACK)?; - OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?; - OUTPUT_TERM_POSITION.1 += 1; - OUTPUT_TERM_POSITION.0 = 0; - } - Ok(()) - } - - /// Outputs a(n) $func_name message u8 to the terminal. - pub fn [< t $func_name u >](s: u8, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - unsafe { - if cfg!($level = "false") { - return Ok(()); - } - OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, WHITE_ON_BLACK)?; - info.write_char(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?; - OUTPUT_TERM_POSITION.0 += 1; - while OUTPUT_TERM_POSITION.0 > info.width { - OUTPUT_TERM_POSITION.0 -= info.width; - OUTPUT_TERM_POSITION.1 += 1; - } - } - Ok(()) - } - - /////////////////////////////////////////////////////////////// - - /// Outputs a $func_name message &str to the terminal without a prefix. - pub fn [< t $func_name snp >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - unsafe { - if cfg!($level = "false") { - return Ok(()); - } - OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?; - } - Ok(()) - } - /// Outputs a $func_name message &str and a newline to the terminal without a prefix. - pub fn [< t $func_name snpln >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - unsafe { - if cfg!($level = "false") { - return Ok(()); - } - OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?; - OUTPUT_TERM_POSITION.1 += 1; - OUTPUT_TERM_POSITION.0 = 0; - } - Ok(()) - } - - /// Outputs a $func_name message &\[u8] to the terminal without a prefix. - pub fn [< t $func_name bnp >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - unsafe { - if cfg!($level = "false") { - return Ok(()); - } - OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?; - } - Ok(()) - } - /// Outputs a $func_name message &\[u8] and a newline to the terminal without a prefix. - pub fn [< t $func_name bnpln >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - unsafe { - if cfg!($level = "false") { - return Ok(()); - } - OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?; - OUTPUT_TERM_POSITION.1 += 1; - OUTPUT_TERM_POSITION.0 = 0; - } - Ok(()) - } - - /// Outputs a(n) $func_name message u8 to the terminal without a prefix. - pub fn [< t $func_name unp >](s: u8, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - unsafe { - if cfg!($level = "false") { - return Ok(()); - } - info.write_char(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?; - OUTPUT_TERM_POSITION.0 += 1; - while OUTPUT_TERM_POSITION.0 > info.width { - OUTPUT_TERM_POSITION.0 -= info.width; - OUTPUT_TERM_POSITION.1 += 1; - } - } - Ok(()) - } - - - - /////////////////////////////////////////////////////////////////////////////////////////////////////// - - - /// Outputs a $func_name message &str to the terminal. - pub fn [< b $func_name s >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - [< s $func_name s >](s); - [< t $func_name s >](s, info)?; - Ok(()) - } - /// Outputs a $func_name message &str and a newline to the terminal. - pub fn [< b $func_name sln >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - [< s $func_name sln >](s); - [< t $func_name sln >](s, info)?; - Ok(()) - } - - /// Outputs a $func_name message &\[u8] to the terminal. - pub fn [< b $func_name b >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - [< s $func_name b >](s); - [< t $func_name b >](s, info)?; - Ok(()) - } - /// Outputs a $func_name message &\[u8] and a newline to the terminal. - pub fn [< b $func_name bln >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - [< s $func_name bln >](s); - [< t $func_name bln >](s, info)?; - Ok(()) - } - - /// Outputs a(n) $func_name message u8 to the terminal. - pub fn [< b $func_name u >](s: u8, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - [< s $func_name u >](s); - [< t $func_name u >](s, info)?; - Ok(()) - } - - /////////////////////////////////////////////////////////////// - - /// Outputs a $func_name message &str to the terminal without a prefix. - pub fn [< b $func_name snp >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - [< s $func_name snp >](s); - [< t $func_name snp >](s, info)?; - Ok(()) - } - /// Outputs a $func_name message &str and a newline to the terminal without a prefix. - pub fn [< b $func_name snpln >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - [< s $func_name snpln >](s); - [< t $func_name snpln >](s, info)?; - Ok(()) - } - - /// Outputs a $func_name message &\[u8] to the terminal without a prefix. - pub fn [< b $func_name bnp >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - [< s $func_name bnp >](s); - [< t $func_name bnp >](s, info)?; - Ok(()) - } - /// Outputs a $func_name message &\[u8] and a newline to the terminal without a prefix. - pub fn [< b $func_name bnpln >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - [< s $func_name bnpln >](s); - [< t $func_name bnpln >](s, info)?; - Ok(()) - } - - /// Outputs a(n) $func_name message u8 to the terminal without a prefix. - pub fn [< b $func_name unp >](s: u8, info: FramebufferInfo) -> Result<(), crate::Error<'static>> { - [< s $func_name unp >](s); - [< t $func_name unp >](s, info)?; - Ok(()) - } } } } @@ -317,10 +104,3 @@ message_funcs!(error, "[ERROR] ", CONFIG_PREUSER_OUTPUT_ERROR); message_funcs!(fatal, "[FATAL] ", CONFIG_PREUSER_OUTPUT_FATAL); message_funcs!(output, "", NONE); -/// Resets the position of output to the screen. -pub fn sreset() { - unsafe { - OUTPUT_TERM_POSITION = (0, 0); - } -} - diff --git a/kernel/src/include/arch/x86/paging.rs b/kernel/src/include/arch/x86/paging.rs new file mode 100644 index 0000000..f1cd5df --- /dev/null +++ b/kernel/src/include/arch/x86/paging.rs @@ -0,0 +1 @@ +//! Functions and types related to paging. \ No newline at end of file diff --git a/kernel/src/include/boot.rs b/kernel/src/include/boot.rs new file mode 100644 index 0000000..b2b32fc --- /dev/null +++ b/kernel/src/include/boot.rs @@ -0,0 +1,56 @@ +//! General bootloader-independent stuff. + +/// A type of memory, for use in [MemoryMapping]s. +/// The memory allocator will ignore all memory +/// except for memory with type [MemoryType::Free] +/// or [MemoryType::HardwareSpecific] memory with +/// the boolean argument set. +#[derive(Clone, Copy)] +pub enum MemoryType { + /// Free RAM with no use. + Free, + /// Reserved by something. + Reserved, + /// Reserved by something on the hardware. + HardwareReserved, + /// Faulty RAM modules. + Faulty, + /// Unknown use. + Unknown, + /// Hardware-specific use. The boolean argument states + /// whether memory can be allocated in this region. + HardwareSpecific(u32, bool) +} + +/// A single memory mapping for [MemoryMap]. +pub trait MemoryMapping { + /// Returns the type of the memory. + fn get_type(&self) -> MemoryType; + /// Returns the beginning of the memory. + fn get_start(&self) -> usize; + /// Returns the length of the memory. + fn get_length(&self) -> usize; +} + +/// Memory mapping. +pub trait MemoryMap<'a>: core::iter::Iterator + core::ops::Index { + /// Returns the number of [MemoryMapping]s in the MemoryMap. This is total, not remainder. + fn len(&self) -> usize; +} + +/// Bootloader-independent information. +#[derive(Clone)] +pub struct BootInfo<'a> { + /// The commandline of the kernel. + /// See https://github.com/AverseABFun/aphrodite/wiki/Plan#bootloader (remember to update link later!) for the format. + pub cmdline: Option<&'static str>, + + /// The memory map provided by the bootloader. If None, the kernel will attempt to generate it. + pub memory_map: Option<&'a dyn MemoryMap<'a>>, + + /// The name of the bootloader(for example, "GRUB 2.12"). + pub bootloader_name: Option<&'static str>, + + /// Provides a way to display text. + pub output: Option<&'a dyn crate::TextDisplay>, +} \ No newline at end of file diff --git a/kernel/src/include/mod.rs b/kernel/src/include/mod.rs index 6fc216c..3ab85f5 100644 --- a/kernel/src/include/mod.rs +++ b/kernel/src/include/mod.rs @@ -10,9 +10,13 @@ pub mod multiboot2; pub mod arch; mod errors; pub mod _entry; +mod traits; +pub mod output; +pub mod boot; #[allow(unused_imports)] // if there are no constants, then it gives a warning pub use constants::*; pub use errors::*; -pub use util::*; \ No newline at end of file +pub use util::*; +pub use traits::*; \ No newline at end of file diff --git a/kernel/src/include/output.rs b/kernel/src/include/output.rs new file mode 100644 index 0000000..7b93c3c --- /dev/null +++ b/kernel/src/include/output.rs @@ -0,0 +1,159 @@ +//! Architecture-independent output functions. + +use paste::paste; +use crate::COLOR_DEFAULT; + +static mut OUTPUT_TERM_POSITION: (u32, u32) = (0, 0); + +macro_rules! message_funcs { + ($func_name:ident, $prefix:literal, $level:ident) => { + paste! { + /// Outputs a $func_name message &str to the terminal. + pub fn [< t $func_name s >](s: &str, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> { + unsafe { + if cfg!($level = "false") { + return Ok(()); + } + OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, COLOR_DEFAULT)?; + OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?; + } + Ok(()) + } + /// Outputs a $func_name message &str and a newline to the terminal. + pub fn [< t $func_name sln >](s: &str, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> { + unsafe { + if cfg!($level = "false") { + return Ok(()); + } + OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, COLOR_DEFAULT)?; + OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?; + OUTPUT_TERM_POSITION.1 += 1; + OUTPUT_TERM_POSITION.0 = 0; + } + Ok(()) + } + + /// Outputs a $func_name message &\[u8] to the terminal. + pub fn [< t $func_name b >](s: &[u8], info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> { + unsafe { + if cfg!($level = "false") { + return Ok(()); + } + OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, COLOR_DEFAULT)?; + OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?; + } + Ok(()) + } + /// Outputs a $func_name message &\[u8] and a newline to the terminal. + pub fn [< t $func_name bln >](s: &[u8], info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> { + unsafe { + if cfg!($level = "false") { + return Ok(()); + } + OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, COLOR_DEFAULT)?; + OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?; + OUTPUT_TERM_POSITION.1 += 1; + OUTPUT_TERM_POSITION.0 = 0; + } + Ok(()) + } + + /// Outputs a(n) $func_name message u8 to the terminal. + pub fn [< t $func_name u >](s: u8, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> { + let (width, _) = info.get_size(); + unsafe { + if cfg!($level = "false") { + return Ok(()); + } + OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, COLOR_DEFAULT)?; + info.write_char(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?; + OUTPUT_TERM_POSITION.0 += 1; + while OUTPUT_TERM_POSITION.0 > width { + OUTPUT_TERM_POSITION.0 -= width; + OUTPUT_TERM_POSITION.1 += 1; + } + } + Ok(()) + } + + /////////////////////////////////////////////////////////////// + + /// Outputs a $func_name message &str to the terminal without a prefix. + pub fn [< t $func_name snp >](s: &str, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> { + unsafe { + if cfg!($level = "false") { + return Ok(()); + } + OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?; + } + Ok(()) + } + /// Outputs a $func_name message &str and a newline to the terminal without a prefix. + pub fn [< t $func_name snpln >](s: &str, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> { + unsafe { + if cfg!($level = "false") { + return Ok(()); + } + OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?; + OUTPUT_TERM_POSITION.1 += 1; + OUTPUT_TERM_POSITION.0 = 0; + } + Ok(()) + } + + /// Outputs a $func_name message &\[u8] to the terminal without a prefix. + pub fn [< t $func_name bnp >](s: &[u8], info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> { + unsafe { + if cfg!($level = "false") { + return Ok(()); + } + OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?; + } + Ok(()) + } + /// Outputs a $func_name message &\[u8] and a newline to the terminal without a prefix. + pub fn [< t $func_name bnpln >](s: &[u8], info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> { + unsafe { + if cfg!($level = "false") { + return Ok(()); + } + OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?; + OUTPUT_TERM_POSITION.1 += 1; + OUTPUT_TERM_POSITION.0 = 0; + } + Ok(()) + } + + /// Outputs a(n) $func_name message u8 to the terminal without a prefix. + pub fn [< t $func_name unp >](s: u8, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> { + let (width, _) = info.get_size(); + unsafe { + if cfg!($level = "false") { + return Ok(()); + } + info.write_char(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?; + OUTPUT_TERM_POSITION.0 += 1; + while OUTPUT_TERM_POSITION.0 > width { + OUTPUT_TERM_POSITION.0 -= width; + OUTPUT_TERM_POSITION.1 += 1; + } + } + Ok(()) + } + } + } +} + +message_funcs!(debug, "[DEBUG] ", CONFIG_PREUSER_OUTPUT_DEBUG); +message_funcs!(info, "[INFO] ", CONFIG_PREUSER_OUTPUT_INFO); +message_funcs!(warning, "[WARN] ", CONFIG_PREUSER_OUTPUT_WARN); +message_funcs!(error, "[ERROR] ", CONFIG_PREUSER_OUTPUT_ERROR); +message_funcs!(fatal, "[FATAL] ", CONFIG_PREUSER_OUTPUT_FATAL); +message_funcs!(output, "", NONE); + +/// Resets the position of output to the screen. +pub fn sreset() { + unsafe { + OUTPUT_TERM_POSITION = (0, 0); + } +} \ No newline at end of file diff --git a/kernel/src/include/traits.rs b/kernel/src/include/traits.rs new file mode 100644 index 0000000..17a589d --- /dev/null +++ b/kernel/src/include/traits.rs @@ -0,0 +1,67 @@ +//! General traits. Mostly implemented in arch/*. + +/// A type used for color in the functions of [TextDisplay]. +pub type Color = u8; + +/// Black-on-black. +pub const COLOR_BLACK: Color = 0; + +/// Should be whatever colors commonly used for status messages. +/// Generally should be white-on-black. +pub const COLOR_DEFAULT: Color = 1; + +/// Some form of display that can be written too with text. +pub trait TextDisplay { + /// Writes a single character to the specified position. + fn write_char(&self, pos: (u32, u32), char: u8, color: Color) -> Result<(), crate::Error<'static>>; + /// Gets the size of the screen. + fn get_size(&self) -> (u32, u32); +} + +impl dyn TextDisplay + '_ { + /// Clears the screen. + pub fn clear_screen(&self, color: Color) { + let (width, height) = self.get_size(); + for x in 0..width { + for y in 0..height { + self.write_char((x, y), b' ', color).unwrap(); + } + } + } + + /// Writes a &str to the screen. + pub fn write_str(&self, pos: (u32, u32), str: &str, color: Color) -> Result<(u32, u32), crate::Error<'static>> { + let (width, _) = self.get_size(); + let (mut x, mut y) = pos; + for char in str.as_bytes() { + self.write_char((x, y), *char, color)?; + if *char == 0 { + continue + } + x += 1; + while x>width { + x -= width; + y += 1; + } + } + Ok((x, y)) + } + + /// Writes a &\[u8] to the screen. + pub fn write_bytes(&self, pos: (u32, u32), str: &[u8], color: Color) -> Result<(u32, u32), crate::Error<'static>> { + let (width, _) = self.get_size(); + let (mut x, mut y) = pos; + for char in str { + self.write_char((x, y), *char, color)?; + if *char == 0 { + continue + } + x += 1; + while x>width { + x -= width; + y += 1; + } + } + Ok((x, y)) + } +} \ No newline at end of file