From bc19d1a69d30514a14712142ac390253ef334fe7 Mon Sep 17 00:00:00 2001 From: Arthur Beck Date: Sat, 25 Jan 2025 10:37:46 -0600 Subject: [PATCH] More progress; writing to EGA text framebuffer now works. --- kernel/config.aphro.example | 10 ++-- kernel/get_version | 10 ++++ kernel/grub/boot/aphrodite.kernel | Bin 18992 -> 32544 bytes kernel/grub/boot/grub/grub.cfg | 4 +- kernel/kernel.flat | Bin 18992 -> 32544 bytes kernel/src/include/arch/x86/egatext.rs | 71 +++++++++++++++++++++++++ kernel/src/include/arch/x86/mod.rs | 1 + kernel/src/include/errors.rs | 7 +++ kernel/src/include/multiboot2.rs | 15 +----- kernel/src/internal/arch/x86/entry.rs | 65 ++++++++++++++++------ 10 files changed, 148 insertions(+), 35 deletions(-) create mode 100755 kernel/get_version create mode 100644 kernel/src/include/arch/x86/egatext.rs diff --git a/kernel/config.aphro.example b/kernel/config.aphro.example index 71aa889..3f2e4ec 100644 --- a/kernel/config.aphro.example +++ b/kernel/config.aphro.example @@ -1,5 +1,5 @@ -# config.aphro for aphrodite devel-b3558c2-out-of-tree -CFG_VERSION=devel-b3558c2-out-of-tree +# config.aphro for aphrodite devel-461136c-out-of-tree +CFG_VERSION=devel-461136c-out-of-tree CONT_WITH_DIFFERENT_VERSION=false # Begin metadata @@ -17,9 +17,9 @@ CONFIG_DISABLE_MULTIBOOT2_SUPPORT=false CONFIG_PREUSER_HALT_ON_PANIC=true CONFIG_PREUSER_SPIN_ON_PANIC=false -CONFIG_PREUSER_EXIT_LOOP_ON_INVALID_LENGTH=false -CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH=true -CONFIG_PREUSER_WARN_ON_INVALID_LENGTH=true +CONFIG_PREUSER_EXIT_LOOP_ON_INVALID_LENGTH=true +CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH=false +CONFIG_PREUSER_WARN_ON_INVALID_LENGTH=false CONFIG_PREUSER_ERROR_ON_INVALID_LENGTH=true # Whether to output various levels of messages. diff --git a/kernel/get_version b/kernel/get_version new file mode 100755 index 0000000..9c4aa11 --- /dev/null +++ b/kernel/get_version @@ -0,0 +1,10 @@ +set -e + +DIR="${BASH_SOURCE%/*}" +if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi + +. "$DIR/functions" + +get_version + +echo $VERSION diff --git a/kernel/grub/boot/aphrodite.kernel b/kernel/grub/boot/aphrodite.kernel index 5425ef1536c46d1825237ac12962351e761d6347..4158efc10185a5adab070bd2ce3399ed74628b93 100755 GIT binary patch literal 32544 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 literal 18992 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 literal 18992 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 Result<(), crate::Error<'static>> { + if pos.0>self.width { + return Err(crate::Error::new("Invalid X position", ERR_INVALID_X)); + } + if pos.1>self.height { + return Err(crate::Error::new("Invalid Y position", ERR_INVALID_Y)); + } + unsafe { + let mut addr = self.address as usize; + addr += (pos.1*self.pitch) as usize; + addr += (pos.0*(self.bpp as u32/8)) as usize; + let base_ptr = addr as *mut u16; + (*base_ptr) = ((color as u16)<<8) | (char as u16); + } + 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(self, pos: (u32, u32), str: &str, color: u8) -> Result<(), crate::Error<'static>> { + let (mut x, mut y) = pos; + for char in str.as_bytes() { + self.write_char((x, y), *char, color)?; + x += 1; + if x>self.width { + x -= self.width; + y += 1; + } + } + Ok(()) + } +} \ No newline at end of file diff --git a/kernel/src/include/arch/x86/mod.rs b/kernel/src/include/arch/x86/mod.rs index 18e8515..95d44b0 100644 --- a/kernel/src/include/arch/x86/mod.rs +++ b/kernel/src/include/arch/x86/mod.rs @@ -6,6 +6,7 @@ use core::arch::asm; pub mod interrupts; pub mod ports; pub mod output; +pub mod egatext; mod constants; diff --git a/kernel/src/include/errors.rs b/kernel/src/include/errors.rs index a286ca3..d8fbc17 100644 --- a/kernel/src/include/errors.rs +++ b/kernel/src/include/errors.rs @@ -6,6 +6,13 @@ pub struct Error<'a> { code: i16 } +impl<'a> Error<'a> { + /// Creates a new error. + pub fn new(message: &'a str, code: i16) -> Self { + Error { message, code } + } +} + impl core::fmt::Debug for Error<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str(core::str::from_utf8(&crate::i16_as_u8_slice(self.code)).unwrap())?; diff --git a/kernel/src/include/multiboot2.rs b/kernel/src/include/multiboot2.rs index fd76112..3c73ad3 100644 --- a/kernel/src/include/multiboot2.rs +++ b/kernel/src/include/multiboot2.rs @@ -26,7 +26,6 @@ impl core::ops::Index for CString { /// Used for Multiboot2 tags. This shouldn't be used after a [BootInfo] struct has been initalized, but it still can be used. #[repr(C)] -#[repr(align(1))] // may or may not be necessary, but I'm not taking chances #[derive(Clone)] pub struct Tag { /// The type of the tag. @@ -37,7 +36,6 @@ pub struct Tag { /// The root tag. The official Multiboot2 name is literally the "fixed part" of the tags, so I made a better name. #[repr(C)] -#[repr(align(1))] // may or may not be necessary, but I'm not taking chances #[derive(Clone)] pub struct RootTag { /// The total length between the root tag and the terminating tag. @@ -61,7 +59,6 @@ pub struct Module { /// One memory section provided by a Multiboot2 bootloader. #[repr(C)] -#[repr(align(1))] // may or may not be necessary, but I'm not taking chances #[derive(Clone)] pub struct MemorySection { /// The base address of the section. @@ -78,7 +75,6 @@ pub struct MemorySection { /// The raw memory map provided by a Multiboot2 bootloader. This is interpreted /// into a [MemoryMap]. #[repr(C)] -#[repr(align(1))] // may or may not be necessary, but I'm not taking chances pub struct RawMemoryMap { /// The type of the tag. pub tag_type: u32, @@ -107,7 +103,6 @@ pub struct MemoryMap { /// A color descriptor for [ColorInfo::Palette]. #[repr(C)] -#[repr(align(1))] // may or may not be necessary, but I'm not taking chances #[derive(Clone, Copy)] pub struct PaletteColorDescriptor { /// The red value @@ -120,7 +115,6 @@ pub struct PaletteColorDescriptor { /// Information about color, for use in [FramebufferInfo]. #[repr(u8)] -#[repr(align(1))] // may or may not be necessary, but I'm not taking chances #[derive(Clone, Copy)] pub enum ColorInfo { /// The palette for use on the framebuffer. @@ -153,15 +147,10 @@ pub enum ColorInfo { /// Information about the framebuffer. #[repr(C)] -#[repr(align(1))] // may or may not be necessary, but I'm not taking chances #[derive(Clone)] pub struct FramebufferInfo { - /// The raw pointer to the string. - pub ptr: *const u8, - /// The length of the string, excluding the null byte(\0) at the end. - pub len: usize, /// A pointer to the framebuffer. - pub address: *mut u8, + pub address: u64, /// The pitch of the framebuffer (i.e. the number of bytes in each row). pub pitch: u32, /// The width of the framebuffer. @@ -175,7 +164,7 @@ pub struct FramebufferInfo { /// Reserved space. Ignore. reserved: u8, - // Color info after this; we need separate structs for each colorinfo and + // Color info after this; we need separate structs for each colorinfo as // we have to understand the format the bootloader gives us. } diff --git a/kernel/src/internal/arch/x86/entry.rs b/kernel/src/internal/arch/x86/entry.rs index 04b2de3..5f3314a 100644 --- a/kernel/src/internal/arch/x86/entry.rs +++ b/kernel/src/internal/arch/x86/entry.rs @@ -10,6 +10,8 @@ use core::{arch::asm, ffi::CStr, panic::PanicInfo}; use aphrodite::multiboot2::{BootInfo, CString, ColorInfo, FramebufferInfo, MemoryMap, PaletteColorDescriptor, RawMemoryMap, RootTag, Tag}; use aphrodite::arch::x86::output::*; +use aphrodite::arch::x86::egatext as egatext; +use egatext::*; #[cfg(not(CONFIG_DISABLE_MULTIBOOT2_SUPPORT))] #[unsafe(link_section = ".multiboot2")] @@ -161,33 +163,33 @@ extern "C" fn _start() -> ! { // ...before the BootInfo's bootloader_name is set. }, 8 => { // Framebuffer info - if current_tag.tag_len < 31 { // Unexpected size, something is probably up - panic!("size of framebuffer info tag < 31"); + if current_tag.tag_len < 32 { // Unexpected size, something is probably up + panic!("size of framebuffer info tag < 32"); } - let framebufferinfo: *const FramebufferInfo = ptr as *const FramebufferInfo; + let framebufferinfo: *const FramebufferInfo = (ptr as usize + size_of::()) as *const FramebufferInfo; let colorinfo: ColorInfo; match (*framebufferinfo).fb_type { 0 => { // Indexed colorinfo = ColorInfo::Palette { - num_colors: *((ptr + 40) as *const u32), - palette: (ptr + 44) as *const PaletteColorDescriptor + num_colors: *((ptr + 32) as *const u32), + palette: (ptr + 36) as *const PaletteColorDescriptor }; }, 1 => { // RGB colorinfo = ColorInfo::RGBColor { - red_field_position: *((ptr + 40) as *const u8), - red_mask_size: *((ptr + 41) as *const u8), - green_field_position: *((ptr + 42) as *const u8), - green_mask_size: *((ptr + 43) as *const u8), - blue_field_position: *((ptr + 44) as *const u8), - blue_mask_size: *((ptr + 45) as *const u8) + red_field_position: *((ptr + 32) as *const u8), + red_mask_size: *((ptr + 33) as *const u8), + green_field_position: *((ptr + 34) as *const u8), + green_mask_size: *((ptr + 35) as *const u8), + blue_field_position: *((ptr + 36) as *const u8), + blue_mask_size: *((ptr + 37) as *const u8) } }, 2 => { // EGA Text colorinfo = ColorInfo::EGAText; }, _ => { - unreachable!(); + panic!("unknown color info type") } } BI.framebuffer_info = Some((*framebufferinfo).clone()); @@ -233,6 +235,8 @@ extern "C" fn _start() -> ! { unsafe { if BI.framebuffer_info.clone().is_some() { let framebuffer_info = BI.framebuffer_info.clone().unwrap(); + let color_info = BI.color_info.clone().unwrap(); + sdebugs("Framebuffer width: "); sdebugbnpln(&aphrodite::u32_as_u8_slice(framebuffer_info.width)); sdebugs("Framebuffer height: "); @@ -244,9 +248,40 @@ extern "C" fn _start() -> ! { sdebugs("Framebuffer bpp: "); sdebugbnpln(&aphrodite::u8_as_u8_slice(framebuffer_info.bpp)); sdebugs("Framebuffer type: "); - sdebugbnpln(&aphrodite::u8_as_u8_slice(framebuffer_info.fb_type)); - sdebugs("Framebuffer length: "); - sdebugbnpln(&aphrodite::usize_as_u8_slice(framebuffer_info.len)); + sdebugbnp(&aphrodite::u8_as_u8_slice(framebuffer_info.fb_type)); + + match framebuffer_info.fb_type { + 0 => { // Indexed + sdebugsnpln("(Indexed)"); + let ColorInfo::Palette{num_colors, palette: _} = color_info else { unreachable!() }; + sdebugs("Number of palette colors: "); + sdebugbnpln(&aphrodite::u32_as_u8_slice(num_colors)); + }, + 1 => { // RGB + sdebugsnpln("(RGB)"); + }, + 2 => { // EGA Text + sdebugsnpln("(EGA Text)"); + sdebugsln("Attempting to output to screen(will then loop for 100000000 cycles)..."); + + let ega = egatext::FramebufferInfo { + address: framebuffer_info.address, + pitch: framebuffer_info.pitch, + width: framebuffer_info.width, + height: framebuffer_info.height, + bpp: framebuffer_info.bpp + }; + ega.clear_screen(BLACK_ON_BLACK); + ega.write_str((0, 0), "Test", WHITE_ON_BLACK).unwrap(); + + for _ in 0..100000000 { + asm!("nop") + } + }, + _ => { + unreachable!(); + } + } } }