arch-independent stuff working, x86 renamed to x86_asmp because missile

This commit is contained in:
Arthur Beck 2025-01-25 19:32:03 -06:00
parent 86a85b8b0d
commit e39bd7bf6e
16 changed files with 158 additions and 154 deletions

View file

@ -15,7 +15,7 @@ panic = "abort"
[[bin]]
name = "entrypoint"
path = "src/internal/arch/x86/entry.rs"
path = "src/internal/arch/x86_asmp/entry.rs"
[[bin]]
name = "main"

Binary file not shown.

View file

@ -1,8 +1,8 @@
set timeout=15
set default=0
menuentry "Aphrodite" --class aphrodite --class kernel --class os $menuentry_id_option 'aphrodite-basic-devel-6a2a677-out-of-tree' {
echo 'Loading Aphrodite aphrodite-devel-6a2a677-out-of-tree ...'
menuentry "Aphrodite" --class aphrodite --class kernel --class os $menuentry_id_option 'aphrodite-basic-devel-86a85b8-out-of-tree' {
echo 'Loading Aphrodite aphrodite-devel-86a85b8-out-of-tree ...'
multiboot2 /boot/aphrodite.kernel
boot
}

Binary file not shown.

View file

@ -1,5 +1,5 @@
//! Arch-specific code.
mod x86;
mod x86_asmp;
pub use x86::*;
pub use x86_asmp::*;

View file

@ -9,6 +9,8 @@
pub enum MemoryType {
/// Free RAM with no use.
Free,
/// RAM used by the kernel
Kernel,
/// Reserved by something.
Reserved,
/// Reserved by something on the hardware.
@ -19,7 +21,9 @@ pub enum MemoryType {
Unknown,
/// Hardware-specific use. The boolean argument states
/// whether memory can be allocated in this region.
HardwareSpecific(u32, bool)
HardwareSpecific(u32, bool),
/// Flash/semi-permanent memory. Generally used in embedded systems.
Permanent
}
/// A single memory mapping for [MemoryMap].
@ -27,17 +31,20 @@ 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;
fn get_start(&self) -> u64;
/// Returns the length of the memory.
fn get_length(&self) -> usize;
fn get_length(&self) -> u64;
}
/// Memory mapping.
pub trait MemoryMap<'a>: core::iter::Iterator<Item = &'a dyn MemoryMapping> + core::ops::Index<usize, Output = &'a dyn MemoryMapping> {
pub trait _MemoryMap: core::iter::Iterator<Item = &'static dyn MemoryMapping> + core::ops::Index<usize, Output = dyn MemoryMapping> {
/// Returns the number of [MemoryMapping]s in the MemoryMap. This is total, not remainder.
fn len(&self) -> usize;
}
/// Memory mapping. Used so that we can downcast.
pub trait MemoryMap: _MemoryMap + core::any::Any {}
/// Bootloader-independent information.
#[derive(Clone)]
pub struct BootInfo<'a> {
@ -46,7 +53,7 @@ pub struct BootInfo<'a> {
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>>,
pub memory_map: Option<&'a dyn MemoryMap>,
/// The name of the bootloader(for example, "GRUB 2.12").
pub bootloader_name: Option<&'static str>,

View file

@ -1,38 +1,5 @@
//! Definitions of structs for multiboot2 information. Mostly used during pre-userspace.
/// Used when a CString is passed. Move into separate file?
#[derive(Clone, Copy)]
pub struct CString {
/// 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,
}
impl core::ops::Index<usize> for CString {
type Output = u8;
fn index(&self, index: usize) -> &Self::Output {
unsafe {
if index>self.len {
panic!("index into CString too large");
}
let mut ptr = self.ptr as usize;
ptr += index * size_of::<u8>();
let ptr = ptr as *const u8;
&*ptr
}
}
}
impl Into<&'static str> for CString {
fn into(self) -> &'static str {
unsafe {
let val: *const str = core::ptr::from_raw_parts(self.ptr, self.len);
return &*val;
}
}
}
/// Used for Multiboot2 tags. This shouldn't be used after a [BootInfo] struct has been initalized, but it still can be used.
#[repr(C)]
#[derive(Clone)]
@ -63,7 +30,7 @@ pub struct Module {
pub mod_end: *const u8,
/// A string that should be in the format `module_name (command line arguments)`.
/// See https://github.com/AverseABFun/aphrodite/wiki/Plan/#Bootloader-modules (remember to update link later!).
pub mod_str: CString
pub mod_str: &'static core::ffi::CStr
}
/// One memory section provided by a Multiboot2 bootloader.
@ -81,6 +48,24 @@ pub struct MemorySection {
reserved: u32,
}
impl crate::boot::MemoryMapping for MemorySection {
fn get_type(&self) -> crate::boot::MemoryType {
match self.mem_type {
1 => crate::boot::MemoryType::Free,
2 => crate::boot::MemoryType::HardwareReserved,
3 => crate::boot::MemoryType::HardwareSpecific(3, false),
5 => crate::boot::MemoryType::Faulty,
_ => crate::boot::MemoryType::Reserved
}
}
fn get_start(&self) -> u64 {
self.base_addr
}
fn get_length(&self) -> u64 {
self.length
}
}
/// The raw memory map provided by a Multiboot2 bootloader. This is interpreted
/// into a [MemoryMap].
#[repr(C)]
@ -106,6 +91,36 @@ pub struct MemoryMap {
pub entry_size: u32,
/// All sections.
pub sections: &'static [MemorySection],
/// Iterator's index.
pub idx: usize,
}
impl crate::boot::MemoryMap for MemoryMap {}
impl crate::boot::_MemoryMap for MemoryMap {
fn len(&self) -> usize {
self.sections.len()
}
}
impl core::ops::Index<usize> for MemoryMap {
type Output = dyn crate::boot::MemoryMapping;
fn index(&self, index: usize) -> &Self::Output {
&self.sections[index] as &'static dyn crate::boot::MemoryMapping
}
}
impl core::iter::Iterator for MemoryMap {
type Item = &'static dyn crate::boot::MemoryMapping;
fn next(&mut self) -> Option<Self::Item> {
self.idx += 1;
if self.sections.len()<=self.idx-1 {
return None;
}
Some(&self.sections[self.idx-1])
}
}
/// A color descriptor for [ColorInfo::Palette].
@ -177,7 +192,7 @@ pub struct FramebufferInfo {
/// Boot info collected from provided [Tag]s.
#[derive(Clone)]
pub struct BootInfo {
pub struct Multiboot2BootInfo {
/// See https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Basic-memory-information.
/// Tl;dr: mem_lower indicates the amount of "lower memory"
/// and mem_upper the amount of "upper memory".
@ -192,7 +207,7 @@ pub struct BootInfo {
/// We're provided with a C-style UTF-8(null-terminated UTF-8) string. This should contain the original pointer provided by
/// the bootloader.
/// See https://github.com/AverseABFun/aphrodite/wiki/Plan#bootloader (remember to update link later!) for the format.
pub cmdline: Option<CString>,
pub cmdline: Option<&'static core::ffi::CStr>,
// Due to the way modules work, it's not easily possible to make a struct that contains all the modules.
// Therefore, they are loaded on the fly.
@ -205,7 +220,7 @@ pub struct BootInfo {
/// The name of the bootloader(for example, "GRUB 2.12"). C-style UTF-8(null-terminated UTF-8) string.
/// This should contain the original pointer provided by the bootloader.
pub bootloader_name: Option<CString>,
pub bootloader_name: Option<&'static core::ffi::CStr>,
// APM table is ignored as APM has been superseded by ACPI. If your system doesn't support ACPI, good luck.

View file

@ -6,8 +6,8 @@ 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.
/// Should be whatever color commonly used for status messages.
/// Generally should be white-on-black. Value is one.
pub const COLOR_DEFAULT: Color = 1;
/// Some form of display that can be written too with text.

View file

@ -8,10 +8,12 @@
#![feature(cfg_match)]
use core::{arch::asm, ffi::CStr, panic::PanicInfo};
use aphrodite::multiboot2::{BootInfo, CString, ColorInfo, FramebufferInfo, MemoryMap, MemorySection, PaletteColorDescriptor, RawMemoryMap, RootTag, Tag};
use aphrodite::arch::x86::output::*;
use aphrodite::arch::x86::egatext as egatext;
use aphrodite::boot::BootInfo;
use aphrodite::multiboot2::{FramebufferInfo, MemoryMap, MemorySection, RawMemoryMap, RootTag, Tag};
use aphrodite::arch::output::*;
use aphrodite::arch::egatext as egatext;
use egatext::*;
use aphrodite::output::*;
#[cfg(not(CONFIG_DISABLE_MULTIBOOT2_SUPPORT))]
#[unsafe(link_section = ".multiboot2")]
@ -25,26 +27,39 @@ static MULTIBOOT2_HEADER: [u8; 29] = [
// The root tag, provided directly from the multiboot2 bootloader.
static mut RT: *const RootTag = core::ptr::null();
// The boot info struct, created from all of the tags.
static mut BI: BootInfo = BootInfo {
mem_lower: None,
mem_upper: None,
cmdline: None,
memory_map: None,
bootloader_name: None,
framebuffer_info: None,
color_info: None,
};
// The raw pointer to bootloader-specific data.
static mut O: *const u8 = core::ptr::null();
static mut MM: MemoryMap = MemoryMap {
entry_size: 0,
version: 0,
sections: &[],
idx: 0,
};
static mut FBI: aphrodite::arch::egatext::FramebufferInfo = aphrodite::arch::egatext::FramebufferInfo {
address: 0,
pitch: 0,
width: 0,
height: 0,
bpp: 0,
change_cursor: false,
};
// The magic number in eax. 0x36D76289 for multiboot2.
static mut MAGIC: u32 = 0xFFFFFFFF;
#[unsafe(link_section = ".start")]
#[unsafe(no_mangle)]
extern "C" fn _start() -> ! {
#[allow(non_snake_case)]
let mut BI: BootInfo<'static> = BootInfo {
cmdline: None,
memory_map: None,
bootloader_name: None,
output: None,
};
unsafe { // Copy values provided by the bootloader out
// Aphrodite bootloaders pass values in eax and ebx, however rust doesn't know that it can't overwrite those.
@ -103,10 +118,6 @@ extern "C" fn _start() -> ! {
if current_tag.tag_len != 16 { // Unexpected size, something is probably up
panic!("size of basic memory information tag != 16");
}
BI.mem_lower = Some(*((ptr + 8) as *const u32));
BI.mem_upper = Some(*((ptr + 12) as *const u32));
// The end result of the above is adding an offset to a pointer and retrieving the value at that pointer
},
5 => { // BIOS boot device, ignore
if current_tag.tag_len != 20 { // Unexpected size, something is probably up
@ -120,13 +131,7 @@ extern "C" fn _start() -> ! {
let cstring = CStr::from_ptr((ptr + 8) as *const i8);
// creates a &core::ffi::CStr from the start of the command line...
let cstring = CString {
ptr: cstring.as_ptr() as *const u8,
len: cstring.to_bytes().len()
};
// ...which can then be converted to a aphrodite::multiboot2::CString...
BI.cmdline = Some(cstring);
BI.cmdline = Some(cstring.to_str().unwrap());
// ...before the BootInfo's commandline is set.
},
6 => { // Memory map tag
@ -139,11 +144,13 @@ extern "C" fn _start() -> ! {
// The end result of the above is creating a *const RawMemoryMap that has the same address as current_tag
// and has all of the [aphrodite::multiboot2::MemorySection]s for the memory map
BI.memory_map = Some(MemoryMap {
MM = MemoryMap {
version: (*rawmemorymap).entry_version,
entry_size: (*rawmemorymap).entry_size,
sections: &*core::ptr::from_raw_parts((&(*rawmemorymap).sections[0]) as &MemorySection, (*rawmemorymap).sections.len()),
});
idx: 0
};
BI.memory_map = Some(&MM);
},
2 => { // Bootloader name
if current_tag.tag_len < 8 { // Unexpected size, something is probably up
@ -152,13 +159,7 @@ extern "C" fn _start() -> ! {
let cstring = CStr::from_ptr((ptr + 8) as *const i8);
// creates a &core::ffi::CStr from the start of the bootloader name...
let cstring = CString {
ptr: cstring.as_ptr() as *const u8,
len: cstring.to_bytes().len()
};
// ...which can then be converted to a aphrodite::multiboot2::CString...
BI.bootloader_name = Some(cstring);
BI.bootloader_name = Some(cstring.to_str().unwrap());
// ...before the BootInfo's bootloader_name is set.
},
8 => { // Framebuffer info
@ -166,33 +167,30 @@ extern "C" fn _start() -> ! {
panic!("size of framebuffer info tag < 32");
}
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 + 32) as *const u32),
palette: (ptr + 36) as *const PaletteColorDescriptor
};
panic!("Indexed color is unimplemented");
},
1 => { // RGB
colorinfo = ColorInfo::RGBColor {
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)
}
panic!("RGB color is unimplemented");
},
2 => { // EGA Text
colorinfo = ColorInfo::EGAText;
},
_ => {
panic!("unknown color info type")
}
}
BI.framebuffer_info = Some((*framebufferinfo).clone());
BI.color_info = Some(colorinfo);
let framebuffer_info = (*framebufferinfo).clone();
FBI = egatext::FramebufferInfo {
address: framebuffer_info.address,
pitch: framebuffer_info.pitch,
width: framebuffer_info.width,
height: framebuffer_info.height,
bpp: framebuffer_info.bpp,
change_cursor: false,
};
BI.output = Some(&FBI)
},
_ => { // Unknown/unimplemented tag type, ignore
swarnings("Unknown tag type ");
@ -232,9 +230,8 @@ extern "C" fn _start() -> ! {
sdebugsln("Bootloader information has been successfully loaded");
soutputu(b'\n');
unsafe {
if BI.framebuffer_info.clone().is_some() {
let framebuffer_info = BI.framebuffer_info.clone().unwrap();
let color_info = BI.color_info.clone().unwrap();
if BI.output.clone().is_some() {
let framebuffer_info = FBI;
sdebugs("Framebuffer width: ");
sdebugbnpln(&aphrodite::u32_as_u8_slice(framebuffer_info.width));
@ -246,68 +243,43 @@ extern "C" fn _start() -> ! {
sdebugbnpln(&aphrodite::usize_as_u8_slice(framebuffer_info.address as usize));
sdebugs("Framebuffer bpp: ");
sdebugbnpln(&aphrodite::u8_as_u8_slice(framebuffer_info.bpp));
sdebugs("Framebuffer type: ");
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));
sfatalsln("Halting CPU; Indexed color unimplemented");
asm!("hlt", options(noreturn));
},
1 => { // RGB
sdebugsnpln("(RGB)");
sfatalsln("Halting CPU; RGB color unimplemented");
asm!("hlt", options(noreturn));
},
2 => { // EGA Text
sdebugsnpln("(EGA Text)");
sdebugsln("Beginning output to screen...");
let ega = egatext::FramebufferInfo {
address: framebuffer_info.address,
pitch: framebuffer_info.pitch,
width: framebuffer_info.width,
height: framebuffer_info.height,
bpp: framebuffer_info.bpp,
change_cursor: true,
};
let ega: &dyn aphrodite::TextDisplay = &framebuffer_info;
framebuffer_info.disable_cursor();
ega.clear_screen(WHITE_ON_BLACK);
ega.enable_cursor(14, 15);
ega.set_cursor_location((0, 0));
tdebugsln("Testing EGA Text framebuffer...", ega).unwrap();
tdebugsln("Testing EGA Text framebuffer...", ega).unwrap();
tdebugsln("Testing EGA Text framebuffer...", ega).unwrap();
aphrodite::_entry::_entry(Some(ega), &BI);
},
_ => {
unreachable!();
}
}
}
}
unsafe {
aphrodite::_entry::_entry(None, &BI);
}
}
#[unsafe(link_section = ".panic")]
#[panic_handler]
#[cfg(not(CONFIG_HALT_ON_PANIC = "false"))]
fn halt_on_panic(info: &PanicInfo) -> ! {
if info.location().is_some() {
sfatals("Panic at ");
sfatalsnp(info.location().unwrap().file());
sfatalsnp(":");
sfatalbnp(&aphrodite::u32_as_u8_slice(info.location().unwrap().line()));
sfatalsnp(":");
sfatalbnp(&aphrodite::u32_as_u8_slice(info.location().unwrap().column()));
sfatalsnp(": ");
} else {
sfatals("Panic: ");
}
let message = info.message().as_str().unwrap_or("");
if message != "" {
sfatals(message);
aphrodite::arch::x86::ports::outb(aphrodite::arch::x86::DEBUG_PORT, b'\n');
sfatalsnpln(message);
}
aphrodite::arch::x86::interrupts::disable_interrupts();
aphrodite::arch::interrupts::disable_interrupts();
unsafe {
asm!("hlt", options(noreturn));
}
@ -317,11 +289,21 @@ fn halt_on_panic(info: &PanicInfo) -> ! {
#[panic_handler]
#[cfg(all(CONFIG_SPIN_ON_PANIC = "true", CONFIG_PREUSER_HALT_ON_PANIC = "false"))]
fn spin_on_panic(info: &PanicInfo) -> ! {
if info.location().is_some() {
sfatals("Panic at ");
sfatalsnp(info.location().unwrap().file());
sfatalsnp(":");
sfatalbnp(&aphrodite::u32_as_u8_slice(info.location().unwrap().line()));
sfatalsnp(":");
sfatalbnp(&aphrodite::u32_as_u8_slice(info.location().unwrap().column()));
sfatalsnp(": ");
} else {
sfatals("Panic: ");
}
let message = info.message().as_str().unwrap_or("");
if message != "" {
sfatals(message);
aphrodite::arch::x86::ports::outb(aphrodite::arch::x86::DEBUG_PORT, b'\n');
sfatalsnpln(message);
}
aphrodite::arch::x86::interrupts::disable_interrupts();
aphrodite::arch::interrupts::disable_interrupts();
loop {}
}