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 5425ef1..4158efc 100755 Binary files a/kernel/grub/boot/aphrodite.kernel and b/kernel/grub/boot/aphrodite.kernel differ diff --git a/kernel/grub/boot/grub/grub.cfg b/kernel/grub/boot/grub/grub.cfg index bcd56f3..1735de0 100644 --- a/kernel/grub/boot/grub/grub.cfg +++ b/kernel/grub/boot/grub/grub.cfg @@ -1,8 +1,8 @@ set timeout=15 set default=0 -menuentry "Aphrodite" --class aphrodite --class kernel --class os $menuentry_id_option 'aphrodite-basic-devel-b3558c2-out-of-tree' { - echo 'Loading Aphrodite aphrodite-devel-b3558c2-out-of-tree ...' +menuentry "Aphrodite" --class aphrodite --class kernel --class os $menuentry_id_option 'aphrodite-basic-devel-461136c-out-of-tree' { + echo 'Loading Aphrodite aphrodite-devel-461136c-out-of-tree ...' multiboot2 /boot/aphrodite.kernel boot } \ No newline at end of file diff --git a/kernel/kernel.flat b/kernel/kernel.flat index 5425ef1..4158efc 100755 Binary files a/kernel/kernel.flat and b/kernel/kernel.flat differ diff --git a/kernel/src/include/arch/x86/egatext.rs b/kernel/src/include/arch/x86/egatext.rs new file mode 100644 index 0000000..c3be514 --- /dev/null +++ b/kernel/src/include/arch/x86/egatext.rs @@ -0,0 +1,71 @@ +//! Stuff for writing and reading to the EGA text buffer. +#![cfg(any(target_arch = "x86"))] + +/// Information about the framebuffer. +#[derive(Clone, Copy)] +pub struct FramebufferInfo { + /// A pointer to the framebuffer. + 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. + pub width: u32, + /// The height of the framebuffer. + pub height: u32, + /// Bits per pixel. + pub bpp: u8, +} + +/// Returned when the provided position is invalid in the X direction. +pub const ERR_INVALID_X: i16 = -1; +/// Returned when the provided position is invalid in the Y direction. +pub const ERR_INVALID_Y: i16 = -2; + + +/// White text on a black background. +pub const WHITE_ON_BLACK: u8 = 0b00000111; +/// Black text on a black background. +pub const BLACK_ON_BLACK: u8 = 0b00000000; + +impl FramebufferInfo { + /// Writes a character to the screen. + pub fn write_char(self, pos: (u32, u32), char: u8, color: u8) -> 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!(); + } + } } }