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
|
# config.aphro for aphrodite devel-461136c-out-of-tree
|
||||||
CFG_VERSION=devel-b3558c2-out-of-tree
|
CFG_VERSION=devel-461136c-out-of-tree
|
||||||
CONT_WITH_DIFFERENT_VERSION=false
|
CONT_WITH_DIFFERENT_VERSION=false
|
||||||
|
|
||||||
# Begin metadata
|
# Begin metadata
|
||||||
|
@ -17,9 +17,9 @@ CONFIG_DISABLE_MULTIBOOT2_SUPPORT=false
|
||||||
CONFIG_PREUSER_HALT_ON_PANIC=true
|
CONFIG_PREUSER_HALT_ON_PANIC=true
|
||||||
CONFIG_PREUSER_SPIN_ON_PANIC=false
|
CONFIG_PREUSER_SPIN_ON_PANIC=false
|
||||||
|
|
||||||
CONFIG_PREUSER_EXIT_LOOP_ON_INVALID_LENGTH=false
|
CONFIG_PREUSER_EXIT_LOOP_ON_INVALID_LENGTH=true
|
||||||
CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH=true
|
CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH=false
|
||||||
CONFIG_PREUSER_WARN_ON_INVALID_LENGTH=true
|
CONFIG_PREUSER_WARN_ON_INVALID_LENGTH=false
|
||||||
CONFIG_PREUSER_ERROR_ON_INVALID_LENGTH=true
|
CONFIG_PREUSER_ERROR_ON_INVALID_LENGTH=true
|
||||||
|
|
||||||
# Whether to output various levels of messages.
|
# 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 timeout=15
|
||||||
set default=0
|
set default=0
|
||||||
|
|
||||||
menuentry "Aphrodite" --class aphrodite --class kernel --class os $menuentry_id_option 'aphrodite-basic-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-b3558c2-out-of-tree ...'
|
echo 'Loading Aphrodite aphrodite-devel-461136c-out-of-tree ...'
|
||||||
multiboot2 /boot/aphrodite.kernel
|
multiboot2 /boot/aphrodite.kernel
|
||||||
boot
|
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 interrupts;
|
||||||
pub mod ports;
|
pub mod ports;
|
||||||
pub mod output;
|
pub mod output;
|
||||||
|
pub mod egatext;
|
||||||
|
|
||||||
mod constants;
|
mod constants;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,13 @@ pub struct Error<'a> {
|
||||||
code: i16
|
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<'_> {
|
impl core::fmt::Debug for Error<'_> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
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())?;
|
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.
|
/// 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(C)]
|
||||||
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Tag {
|
pub struct Tag {
|
||||||
/// The type of the 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.
|
/// The root tag. The official Multiboot2 name is literally the "fixed part" of the tags, so I made a better name.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RootTag {
|
pub struct RootTag {
|
||||||
/// The total length between the root tag and the terminating tag.
|
/// 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.
|
/// One memory section provided by a Multiboot2 bootloader.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MemorySection {
|
pub struct MemorySection {
|
||||||
/// The base address of the section.
|
/// 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
|
/// The raw memory map provided by a Multiboot2 bootloader. This is interpreted
|
||||||
/// into a [MemoryMap].
|
/// into a [MemoryMap].
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
|
||||||
pub struct RawMemoryMap {
|
pub struct RawMemoryMap {
|
||||||
/// The type of the tag.
|
/// The type of the tag.
|
||||||
pub tag_type: u32,
|
pub tag_type: u32,
|
||||||
|
@ -107,7 +103,6 @@ pub struct MemoryMap {
|
||||||
|
|
||||||
/// A color descriptor for [ColorInfo::Palette].
|
/// A color descriptor for [ColorInfo::Palette].
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct PaletteColorDescriptor {
|
pub struct PaletteColorDescriptor {
|
||||||
/// The red value
|
/// The red value
|
||||||
|
@ -120,7 +115,6 @@ pub struct PaletteColorDescriptor {
|
||||||
|
|
||||||
/// Information about color, for use in [FramebufferInfo].
|
/// Information about color, for use in [FramebufferInfo].
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum ColorInfo {
|
pub enum ColorInfo {
|
||||||
/// The palette for use on the framebuffer.
|
/// The palette for use on the framebuffer.
|
||||||
|
@ -153,15 +147,10 @@ pub enum ColorInfo {
|
||||||
|
|
||||||
/// Information about the framebuffer.
|
/// Information about the framebuffer.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FramebufferInfo {
|
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.
|
/// 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).
|
/// The pitch of the framebuffer (i.e. the number of bytes in each row).
|
||||||
pub pitch: u32,
|
pub pitch: u32,
|
||||||
/// The width of the framebuffer.
|
/// The width of the framebuffer.
|
||||||
|
@ -175,7 +164,7 @@ pub struct FramebufferInfo {
|
||||||
/// Reserved space. Ignore.
|
/// Reserved space. Ignore.
|
||||||
reserved: u8,
|
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.
|
// we have to understand the format the bootloader gives us.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
use core::{arch::asm, ffi::CStr, panic::PanicInfo};
|
use core::{arch::asm, ffi::CStr, panic::PanicInfo};
|
||||||
use aphrodite::multiboot2::{BootInfo, CString, ColorInfo, FramebufferInfo, MemoryMap, PaletteColorDescriptor, RawMemoryMap, RootTag, Tag};
|
use aphrodite::multiboot2::{BootInfo, CString, ColorInfo, FramebufferInfo, MemoryMap, PaletteColorDescriptor, RawMemoryMap, RootTag, Tag};
|
||||||
use aphrodite::arch::x86::output::*;
|
use aphrodite::arch::x86::output::*;
|
||||||
|
use aphrodite::arch::x86::egatext as egatext;
|
||||||
|
use egatext::*;
|
||||||
|
|
||||||
#[cfg(not(CONFIG_DISABLE_MULTIBOOT2_SUPPORT))]
|
#[cfg(not(CONFIG_DISABLE_MULTIBOOT2_SUPPORT))]
|
||||||
#[unsafe(link_section = ".multiboot2")]
|
#[unsafe(link_section = ".multiboot2")]
|
||||||
|
@ -161,33 +163,33 @@ extern "C" fn _start() -> ! {
|
||||||
// ...before the BootInfo's bootloader_name is set.
|
// ...before the BootInfo's bootloader_name is set.
|
||||||
},
|
},
|
||||||
8 => { // Framebuffer info
|
8 => { // Framebuffer info
|
||||||
if current_tag.tag_len < 31 { // Unexpected size, something is probably up
|
if current_tag.tag_len < 32 { // Unexpected size, something is probably up
|
||||||
panic!("size of framebuffer info tag < 31");
|
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;
|
let colorinfo: ColorInfo;
|
||||||
match (*framebufferinfo).fb_type {
|
match (*framebufferinfo).fb_type {
|
||||||
0 => { // Indexed
|
0 => { // Indexed
|
||||||
colorinfo = ColorInfo::Palette {
|
colorinfo = ColorInfo::Palette {
|
||||||
num_colors: *((ptr + 40) as *const u32),
|
num_colors: *((ptr + 32) as *const u32),
|
||||||
palette: (ptr + 44) as *const PaletteColorDescriptor
|
palette: (ptr + 36) as *const PaletteColorDescriptor
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
1 => { // RGB
|
1 => { // RGB
|
||||||
colorinfo = ColorInfo::RGBColor {
|
colorinfo = ColorInfo::RGBColor {
|
||||||
red_field_position: *((ptr + 40) as *const u8),
|
red_field_position: *((ptr + 32) as *const u8),
|
||||||
red_mask_size: *((ptr + 41) as *const u8),
|
red_mask_size: *((ptr + 33) as *const u8),
|
||||||
green_field_position: *((ptr + 42) as *const u8),
|
green_field_position: *((ptr + 34) as *const u8),
|
||||||
green_mask_size: *((ptr + 43) as *const u8),
|
green_mask_size: *((ptr + 35) as *const u8),
|
||||||
blue_field_position: *((ptr + 44) as *const u8),
|
blue_field_position: *((ptr + 36) as *const u8),
|
||||||
blue_mask_size: *((ptr + 45) as *const u8)
|
blue_mask_size: *((ptr + 37) as *const u8)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
2 => { // EGA Text
|
2 => { // EGA Text
|
||||||
colorinfo = ColorInfo::EGAText;
|
colorinfo = ColorInfo::EGAText;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!();
|
panic!("unknown color info type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BI.framebuffer_info = Some((*framebufferinfo).clone());
|
BI.framebuffer_info = Some((*framebufferinfo).clone());
|
||||||
|
@ -233,6 +235,8 @@ extern "C" fn _start() -> ! {
|
||||||
unsafe {
|
unsafe {
|
||||||
if BI.framebuffer_info.clone().is_some() {
|
if BI.framebuffer_info.clone().is_some() {
|
||||||
let framebuffer_info = BI.framebuffer_info.clone().unwrap();
|
let framebuffer_info = BI.framebuffer_info.clone().unwrap();
|
||||||
|
let color_info = BI.color_info.clone().unwrap();
|
||||||
|
|
||||||
sdebugs("Framebuffer width: ");
|
sdebugs("Framebuffer width: ");
|
||||||
sdebugbnpln(&aphrodite::u32_as_u8_slice(framebuffer_info.width));
|
sdebugbnpln(&aphrodite::u32_as_u8_slice(framebuffer_info.width));
|
||||||
sdebugs("Framebuffer height: ");
|
sdebugs("Framebuffer height: ");
|
||||||
|
@ -244,9 +248,40 @@ extern "C" fn _start() -> ! {
|
||||||
sdebugs("Framebuffer bpp: ");
|
sdebugs("Framebuffer bpp: ");
|
||||||
sdebugbnpln(&aphrodite::u8_as_u8_slice(framebuffer_info.bpp));
|
sdebugbnpln(&aphrodite::u8_as_u8_slice(framebuffer_info.bpp));
|
||||||
sdebugs("Framebuffer type: ");
|
sdebugs("Framebuffer type: ");
|
||||||
sdebugbnpln(&aphrodite::u8_as_u8_slice(framebuffer_info.fb_type));
|
sdebugbnp(&aphrodite::u8_as_u8_slice(framebuffer_info.fb_type));
|
||||||
sdebugs("Framebuffer length: ");
|
|
||||||
sdebugbnpln(&aphrodite::usize_as_u8_slice(framebuffer_info.len));
|
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