continuing to chug along, working on arch-independence

This commit is contained in:
Arthur Beck 2025-01-25 18:22:32 -06:00
parent 6a2a677cde
commit dd168ab5fd
14 changed files with 313 additions and 32 deletions

View file

@ -17,6 +17,10 @@ panic = "abort"
name = "entrypoint"
path = "src/internal/arch/x86/entry.rs"
[[bin]]
name = "main"
path = "src/internal/main.rs"
[lib]
name = "aphrodite"
path = "src/include/mod.rs"

View file

@ -4,8 +4,8 @@ fn main() {
// Begin checks
println!(r#"cargo:rustc-check-cfg=cfg(CONFIG_DISABLE_MULTIBOOT2_SUPPORT, values("true", "false", none()))"#);
println!(r#"cargo:rustc-check-cfg=cfg(CONFIG_PREUSER_HALT_ON_PANIC, values("true", "false", none()))"#);
println!(r#"cargo:rustc-check-cfg=cfg(CONFIG_PREUSER_SPIN_ON_PANIC, values("true", "false", none()))"#);
println!(r#"cargo:rustc-check-cfg=cfg(CONFIG_HALT_ON_PANIC, values("true", "false", none()))"#);
println!(r#"cargo:rustc-check-cfg=cfg(CONFIG_SPIN_ON_PANIC, values("true", "false", none()))"#);
println!(r#"cargo:rustc-check-cfg=cfg(CONFIG_PREUSER_EXIT_LOOP_ON_INVALID_LENGTH, values("true", "false", none()))"#);
println!(r#"cargo:rustc-check-cfg=cfg(CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH, values("true", "false", none()))"#);

View file

@ -1,5 +1,5 @@
# config.aphro for aphrodite devel-2df6e24-out-of-tree
CFG_VERSION=devel-2df6e24-out-of-tree
# config.aphro for aphrodite devel-6a2a677-out-of-tree
CFG_VERSION=devel-6a2a677-out-of-tree
CONT_WITH_DIFFERENT_VERSION=false
# Begin metadata
@ -14,8 +14,8 @@ VERSION=generate
CONFIG_DISABLE_MULTIBOOT2_SUPPORT=false
# Panic behavior. When debugging, generally halt on panic is more useful.
CONFIG_PREUSER_HALT_ON_PANIC=true
CONFIG_PREUSER_SPIN_ON_PANIC=false
CONFIG_HALT_ON_PANIC=true
CONFIG_SPIN_ON_PANIC=false
CONFIG_PREUSER_EXIT_LOOP_ON_INVALID_LENGTH=true
CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH=false

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-2df6e24-out-of-tree' {
echo 'Loading Aphrodite aphrodite-devel-2df6e24-out-of-tree ...'
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 ...'
multiboot2 /boot/aphrodite.kernel
boot
}

Binary file not shown.

View file

@ -0,0 +1,115 @@
//! The main code for the kernel.
#![warn(missing_docs)]
#![allow(unexpected_cfgs)]
#![allow(static_mut_refs)]
use crate::arch::x86::output::*;
use crate::arch::x86::egatext as egatext;
use crate::multiboot2::BootInfo;
use egatext::*;
/// The real entrypoint to the kernel. `internel/arch/*/entry.rs` files eventually call this.
#[allow(non_snake_case)]
pub fn _entry(ega: Option<crate::arch::x86::egatext::FramebufferInfo>, BI: &BootInfo) -> ! {
if ega.is_some() {
let ega = ega.unwrap();
ega.clear_screen(WHITE_ON_BLACK);
sreset();
let extended_functions = crate::arch::x86::cpuid_extended_functions();
if extended_functions {
binfosln("This CPU supports extended functions", ega).unwrap();
let longmode_support = crate::arch::x86::cpuid(0x80000001).1 & (1<<29) > 1;
if longmode_support {
binfosln("This CPU supports long mode", ega).unwrap();
} else {
binfosln("This CPU does NOT support long mode!", ega).unwrap();
bdebugs("Long mode CPUID: ", ega).unwrap();
bdebugbnpln(&crate::u32_as_u8_slice(crate::arch::x86::cpuid(0x80000001).1), ega).unwrap();
}
} else {
binfosln("This CPU does NOT support extended functions or long mode!", ega).unwrap();
}
if BI.bootloader_name.is_some() {
binfos("Kernel booted by ", ega).unwrap();
binfosnpln(BI.bootloader_name.unwrap().into(), ega).unwrap();
}
if BI.cmdline.is_some() {
binfos("Command line passed: \"", ega).unwrap();
binfosnp(BI.cmdline.unwrap().into(), ega).unwrap();
binfosnpln("\"", ega).unwrap();
}
if BI.mem_lower.is_some() {
binfos("Amount of lower memory: ", ega).unwrap();
binfobnpln(&crate::u32_as_u8_slice(BI.mem_lower.unwrap()), ega).unwrap();
}
if BI.mem_upper.is_some() {
binfos("Amount of upper memory: ", ega).unwrap();
binfobnpln(&crate::u32_as_u8_slice(BI.mem_upper.unwrap()), ega).unwrap();
}
if BI.memory_map.is_some() {
binfos("Recieved memory map from bootloader with ", ega).unwrap();
binfobnp(&crate::usize_as_u8_slice(BI.memory_map.unwrap().sections.len()), ega).unwrap();
binfosnpln(" sections", ega).unwrap();
let mut i = 0;
for ele in BI.memory_map.unwrap().sections {
binfos("Section #", ega).unwrap();
binfobnp(&crate::usize_as_u8_slice(i), ega).unwrap();
binfosnp(": ", ega).unwrap();
match ele.mem_type {
1 => {
binfosnp("Available RAM", ega).unwrap();
},
2 => {
binfosnp("Reserved by hardware", ega).unwrap();
}
3 => {
binfosnp("ACPI information", ega).unwrap();
},
4 => {
binfosnp("Reserved memory", ega).unwrap();
},
5 => {
binfosnp("Defective", ega).unwrap();
},
_ => {
binfosnp("Reserved/unknown (type=", ega).unwrap();
binfobnp(&crate::u32_as_u8_slice(ele.mem_type), ega).unwrap();
binfosnp(")", ega).unwrap();
}
}
binfosnp(", starting at ", ega).unwrap();
binfobnp(&crate::u64_as_u8_slice(ele.base_addr), ega).unwrap();
binfosnp(" and running for ", ega).unwrap();
binfobnp(&crate::u64_as_u8_slice(ele.length), ega).unwrap();
binfosnpln(" bytes", ega).unwrap();
i += 1;
}
}
} else {
if BI.bootloader_name.is_some() {
sinfos("Kernel booted by ");
sinfosnpln(BI.bootloader_name.unwrap().into());
}
if BI.cmdline.is_some() {
sinfos("Command line passed: \"");
sinfosnp(BI.cmdline.unwrap().into());
sinfosnpln("\"");
}
if BI.memory_map.is_some() {
sinfosln("Recieved memory map from bootloader");
}
if BI.mem_lower.is_some() {
sinfos("Amount of lower memory: ");
sinfobnpln(&crate::u32_as_u8_slice(BI.mem_lower.unwrap()));
}
if BI.mem_upper.is_some() {
sinfos("Amount of upper memory: ");
sinfobnpln(&crate::u32_as_u8_slice(BI.mem_upper.unwrap()));
}
}
loop {}
}

View file

@ -14,6 +14,8 @@ pub struct FramebufferInfo {
pub height: u32,
/// Bits per pixel.
pub bpp: u8,
/// Whether to change the cursor position after outputting text.
pub change_cursor: bool,
}
/// Returned when the provided position is invalid in the X direction.
@ -29,7 +31,7 @@ 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>> {
pub fn write_char(self, mut 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));
}
@ -43,6 +45,10 @@ impl FramebufferInfo {
let base_ptr = addr as *mut u16;
(*base_ptr) = ((color as u16)<<8) | (char as u16);
}
pos.1 += 1;
if self.change_cursor {
self.set_cursor_location(pos);
}
Ok(())
}
@ -56,30 +62,52 @@ impl FramebufferInfo {
}
/// Writes a &str to the screen.
pub fn write_str(self, pos: (u32, u32), str: &str, color: u8) -> Result<(u32, u32), crate::Error<'static>> {
pub fn write_str(mut self, pos: (u32, u32), str: &str, color: u8) -> Result<(u32, u32), crate::Error<'static>> {
let (mut x, mut y) = pos;
let change_cursor = self.change_cursor;
if change_cursor {
self.change_cursor = false;
}
for char in str.as_bytes() {
self.write_char((x, y), *char, color)?;
if *char == 0 {
continue
}
x += 1;
while x>self.width {
x -= self.width;
y += 1;
}
}
if change_cursor {
self.change_cursor = true;
self.set_cursor_location((x, y));
}
Ok((x, y))
}
/// Writes a &\[u8] to the screen.
pub fn write_bytes(self, pos: (u32, u32), str: &[u8], color: u8) -> Result<(u32, u32), crate::Error<'static>> {
pub fn write_bytes(mut self, pos: (u32, u32), str: &[u8], color: u8) -> Result<(u32, u32), crate::Error<'static>> {
let (mut x, mut y) = pos;
let change_cursor = self.change_cursor;
if change_cursor {
self.change_cursor = false;
}
for char in str {
self.write_char((x, y), *char, color)?;
if *char == 0 {
continue
}
x += 1;
while x>self.width {
x -= self.width;
y += 1;
}
}
if change_cursor {
self.change_cursor = true;
self.set_cursor_location((x, y));
}
Ok((x, y))
}
@ -107,4 +135,17 @@ impl FramebufferInfo {
super::ports::outb(0x3D4, 0x0E);
super::ports::outb(0x3D5, ((addr >> 8) & 0xFF) as u8);
}
/// Gets the cursor's location.
pub fn get_cursor_location(self) -> (u32, u32) {
let mut addr: u32 = 0;
super::ports::outb(0x3D4, 0x0F);
addr |= super::ports::inb(0x3D5) as u32;
super::ports::outb(0x3D4, 0x0E);
addr |= (super::ports::inb(0x3D5) as u32) << 8;
return (addr % self.width, addr / self.width);
}
}

View file

@ -17,11 +17,22 @@ pub use constants::*;
pub fn cpuid(id: u32) -> (u32, u32, u32) {
let mut out = (0u32, 0u32, 0u32);
unsafe {
// ebx is moved into eax as apparently ebx is used internally by LLVM
asm!(
"cpuid",
"mov eax, ebx", in("eax") id, lateout("eax") out.0, out("edx") out.1, out("ecx") out.2
"cpuid", in("eax") id, out("ebx") out.0, out("edx") out.1, out("ecx") out.2
)
}
out
}
/// Returns whether extended functions are available
/// (more specifically, 0x80000001 or higher)
pub fn cpuid_extended_functions() -> bool {
let out: u32;
unsafe {
asm!(
"mov eax, 0x80000000",
"cpuid", out("eax") out
)
}
out >= 0x80000001
}

View file

@ -233,6 +233,79 @@ macro_rules! message_funcs {
}
Ok(())
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
/// Outputs a $func_name message &str to the terminal.
pub fn [< b $func_name s >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
[< s $func_name s >](s);
[< t $func_name s >](s, info)?;
Ok(())
}
/// Outputs a $func_name message &str and a newline to the terminal.
pub fn [< b $func_name sln >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
[< s $func_name sln >](s);
[< t $func_name sln >](s, info)?;
Ok(())
}
/// Outputs a $func_name message &\[u8] to the terminal.
pub fn [< b $func_name b >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
[< s $func_name b >](s);
[< t $func_name b >](s, info)?;
Ok(())
}
/// Outputs a $func_name message &\[u8] and a newline to the terminal.
pub fn [< b $func_name bln >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
[< s $func_name bln >](s);
[< t $func_name bln >](s, info)?;
Ok(())
}
/// Outputs a(n) $func_name message u8 to the terminal.
pub fn [< b $func_name u >](s: u8, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
[< s $func_name u >](s);
[< t $func_name u >](s, info)?;
Ok(())
}
///////////////////////////////////////////////////////////////
/// Outputs a $func_name message &str to the terminal without a prefix.
pub fn [< b $func_name snp >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
[< s $func_name snp >](s);
[< t $func_name snp >](s, info)?;
Ok(())
}
/// Outputs a $func_name message &str and a newline to the terminal without a prefix.
pub fn [< b $func_name snpln >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
[< s $func_name snpln >](s);
[< t $func_name snpln >](s, info)?;
Ok(())
}
/// Outputs a $func_name message &\[u8] to the terminal without a prefix.
pub fn [< b $func_name bnp >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
[< s $func_name bnp >](s);
[< t $func_name bnp >](s, info)?;
Ok(())
}
/// Outputs a $func_name message &\[u8] and a newline to the terminal without a prefix.
pub fn [< b $func_name bnpln >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
[< s $func_name bnpln >](s);
[< t $func_name bnpln >](s, info)?;
Ok(())
}
/// Outputs a(n) $func_name message u8 to the terminal without a prefix.
pub fn [< b $func_name unp >](s: u8, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
[< s $func_name unp >](s);
[< t $func_name unp >](s, info)?;
Ok(())
}
}
}
}
@ -244,3 +317,10 @@ message_funcs!(error, "[ERROR] ", CONFIG_PREUSER_OUTPUT_ERROR);
message_funcs!(fatal, "[FATAL] ", CONFIG_PREUSER_OUTPUT_FATAL);
message_funcs!(output, "", NONE);
/// Resets the position of output to the screen.
pub fn sreset() {
unsafe {
OUTPUT_TERM_POSITION = (0, 0);
}
}

View file

@ -2,12 +2,14 @@
#![no_std]
#![warn(missing_docs)]
#![feature(ptr_metadata)]
#![feature(const_trait_impl)]
mod constants;
mod util;
pub mod multiboot2;
pub mod arch;
mod errors;
pub mod _entry;
#[allow(unused_imports)] // if there are no constants, then it gives a warning
pub use constants::*;

View file

@ -1,7 +1,7 @@
//! Definitions of structs for multiboot2 information. Mostly used during pre-userspace.
/// Used when a CString is passed. Move into separate file?
#[derive(Clone)]
#[derive(Clone, Copy)]
pub struct CString {
/// The raw pointer to the string.
pub ptr: *const u8,
@ -24,6 +24,15 @@ impl core::ops::Index<usize> for CString {
}
}
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)]
@ -89,16 +98,14 @@ pub struct RawMemoryMap {
}
/// A full memory map provided by a Multiboot2 bootloader.
#[derive(Clone)]
#[derive(Clone, Copy)]
pub struct MemoryMap {
/// The version of the memory map. Should be disregarded as it's 0.
pub version: u32, // currently is 0, future Multiboot2 versions may increment
/// Size of one entry(one [MemorySection] for Aphrodite)
pub entry_size: u32,
/// A pointer to the first section.
pub sections: *const MemorySection,
/// The number of sections.
pub sections_len: usize
/// All sections.
pub sections: &'static [MemorySection],
}
/// A color descriptor for [ColorInfo::Palette].
@ -190,13 +197,13 @@ pub struct BootInfo {
// 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.
// Multiboot2 bootloaders may provide us with ELF symbols, but I'm feeling lazy and right now the kernel is a
// flat binary, so I don't care. Sorry if you are affected by this.
// Multiboot2 bootloaders may provide us with ELF symbols, but I'm feeling lazy and right now it's mostly
// unnecessary, so I don't care. Sorry if you are affected by this.
/// The memory map provided by the bootloader.
pub memory_map: Option<MemoryMap>,
/// The name of the bootloader(for example, "GRUB"). C-style UTF-8(null-terminated UTF-8) string.
/// 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>,

View file

@ -72,3 +72,20 @@ pub fn usize_as_u8_slice(mut value: usize) -> [u8; 20] {
}
buf
}
/// Converts an u64 to an [u8; 10].
pub fn u64_as_u8_slice(mut value: u64) -> [u8; 20] {
let mut buf = [0u8; 20];
let mut i = 19;
if value == 0 {
buf[0] = b'0';
}
while value > 0 {
let digit = value%10;
let char = b'0' + digit as u8;
buf[i] = char;
value = value / 10;
i -= 1;
}
buf
}

View file

@ -8,7 +8,7 @@
#![feature(cfg_match)]
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, MemorySection, PaletteColorDescriptor, RawMemoryMap, RootTag, Tag};
use aphrodite::arch::x86::output::*;
use aphrodite::arch::x86::egatext as egatext;
use egatext::*;
@ -142,8 +142,7 @@ extern "C" fn _start() -> ! {
BI.memory_map = Some(MemoryMap {
version: (*rawmemorymap).entry_version,
entry_size: (*rawmemorymap).entry_size,
sections: &(*rawmemorymap).sections[0],
sections_len: (*rawmemorymap).sections.len()
sections: &*core::ptr::from_raw_parts((&(*rawmemorymap).sections[0]) as &MemorySection, (*rawmemorymap).sections.len()),
});
},
2 => { // Bootloader name
@ -268,21 +267,24 @@ extern "C" fn _start() -> ! {
},
2 => { // EGA Text
sdebugsnpln("(EGA Text)");
sdebugsln("Attempting to output to screen(will then loop for 100000000 cycles)...");
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
bpp: framebuffer_info.bpp,
change_cursor: true,
};
ega.clear_screen(BLACK_ON_BLACK);
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!();
@ -291,12 +293,14 @@ extern "C" fn _start() -> ! {
}
}
panic!("kernel unexpectedly exited");
unsafe {
aphrodite::_entry::_entry(None, &BI);
}
}
#[unsafe(link_section = ".panic")]
#[panic_handler]
#[cfg(not(CONFIG_PREUSER_HALT_ON_PANIC = "false"))]
#[cfg(not(CONFIG_HALT_ON_PANIC = "false"))]
fn halt_on_panic(info: &PanicInfo) -> ! {
let message = info.message().as_str().unwrap_or("");
if message != "" {
@ -311,7 +315,7 @@ fn halt_on_panic(info: &PanicInfo) -> ! {
#[unsafe(link_section = ".panic")]
#[panic_handler]
#[cfg(all(CONFIG_PREUSER_SPIN_ON_PANIC = "true", CONFIG_PREUSER_HALT_ON_PANIC = "false"))]
#[cfg(all(CONFIG_SPIN_ON_PANIC = "true", CONFIG_PREUSER_HALT_ON_PANIC = "false"))]
fn spin_on_panic(info: &PanicInfo) -> ! {
let message = info.message().as_str().unwrap_or("");
if message != "" {