More progress; writing to EGA text framebuffer now works.
This commit is contained in:
parent
461136c643
commit
bc19d1a69d
10 changed files with 148 additions and 35 deletions
|
@ -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.
|
||||
|
|
10
kernel/get_version
Executable file
10
kernel/get_version
Executable file
|
@ -0,0 +1,10 @@
|
|||
set -e
|
||||
|
||||
DIR="${BASH_SOURCE%/*}"
|
||||
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
|
||||
|
||||
. "$DIR/functions"
|
||||
|
||||
get_version
|
||||
|
||||
echo $VERSION
|
Binary file not shown.
|
@ -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
|
||||
}
|
Binary file not shown.
71
kernel/src/include/arch/x86/egatext.rs
Normal file
71
kernel/src/include/arch/x86/egatext.rs
Normal file
|
@ -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(())
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ use core::arch::asm;
|
|||
pub mod interrupts;
|
||||
pub mod ports;
|
||||
pub mod output;
|
||||
pub mod egatext;
|
||||
|
||||
mod constants;
|
||||
|
||||
|
|
|
@ -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())?;
|
||||
|
|
|
@ -26,7 +26,6 @@ impl core::ops::Index<usize> 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.
|
||||
}
|
||||
|
||||
|
|
|
@ -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::<Tag>()) 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!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue