worked on stuff
Some checks failed
Format code / Format the kernel (push) Waiting to run
Continuous Integration / ci (push) Has been cancelled

This commit is contained in:
Arthur Beck 2025-04-05 16:35:35 -05:00
parent ded4ea603e
commit d5f31ecce7
Signed by: ArthurB
GPG key ID: CA200B389F0F6BC9
10 changed files with 250 additions and 127 deletions

View file

@ -15,7 +15,6 @@ use core::fmt::Debug;
use core::panic::PanicInfo;
use aphrodite::arch::egatext;
use aphrodite::arch::enable_a20;
use aphrodite::arch::output::*;
use aphrodite::boot::{BootInfo, MemoryMapping};
use aphrodite::display::COLOR_DEFAULT;
@ -27,11 +26,20 @@ use aphrodite::output::*;
#[cfg(not(CONFIG_DISABLE_MULTIBOOT2_SUPPORT))]
#[unsafe(link_section = ".bootheader")]
#[unsafe(no_mangle)]
static MULTIBOOT2_HEADER: [u8; 24] = [
static MULTIBOOT2_HEADER: [u8; 48] = [
0xd6, 0x50, 0x52, 0xe8, // Magic number
0x00, 0x00, 0x00, 0x00, // Architecture
0x18, 0x00, 0x00, 0x00, // Size
0x12, 0xaf, 0xad, 0x17, // Checksum
0x0A, 0x00, // Relocatable tag
0x00, 0x00, // Flags,
0x18, 0x00, 0x00, 0x00, // Size of tag
0x00, 0x00, 0x00, 0xB0, // Starting minimum location
0xFF, 0xFF, 0xFF, 0xFF, // Ending maximum location: End of 32-bit address space
0x00, 0x00, 0x00, 0x00, // Image alignment
0x01, 0x00, 0x00, 0x00, // Loading preference: lowest possible
0x00, 0x00, // End tag
0x00, 0x00, // Flags
0x08, 0x00, 0x00, 0x00, // Size
@ -85,6 +93,7 @@ extern "C" fn _start() -> ! {
memory_map: None,
bootloader_name: None,
output: None,
load_base: None,
};
unsafe {
match MAGIC {
@ -135,7 +144,7 @@ extern "C" fn _start() -> ! {
break;
},
4 => {
// Basic memory information
// Basic memory information, ignore
if current_tag.tag_len != 16 {
// Unexpected size, something is probably up
panic!("size of basic memory information tag != 16");
@ -177,7 +186,7 @@ extern "C" fn _start() -> ! {
let memorysections: &'static mut [aphrodite::multiboot2::MemorySection] = &mut *core::ptr::from_raw_parts_mut((&mut (*rawmemorymap).sections[0]) as &mut MemorySection, (*rawmemorymap).sections.len());
// Above is a bit hard to understand, but what it does is transmute
// rawmemorymap's sections into a pointer to those sections.
// rawmemorymap's sections into a pointer to those sections
for ele in &mut *memorysections {
(*ele) = core::mem::transmute::<
@ -252,6 +261,20 @@ extern "C" fn _start() -> ! {
};
BI.output = Some(&FBI)
},
21 => {
// Image load base physical address
if current_tag.tag_len != 12 {
panic!("size of image load base physical address tag != 12");
}
let ptr = (ptr + size_of::<Tag>()) as *const u32;
sdebugs("ptr: ");
sdebugbnp(&aphrodite::usize_as_u8_slice(ptr as usize));
sdebugsnp(" value: ");
sdebugbnpln(&aphrodite::u32_as_u8_slice(*ptr));
BI.load_base = Some(*ptr);
},
_ => {
// Unknown/unimplemented tag type, ignore
swarnings("Unknown tag type ");
@ -292,10 +315,7 @@ extern "C" fn _start() -> ! {
sdebugsln("Bootloader information has been successfully loaded");
sdebugunp(b'\n');
if !enable_a20() {
panic!("failed to enable a20 gate");
}
initalize_rtc();
aphrodite::arch::initalize_rtc();
unsafe {
if BI.output.clone().is_some() {
@ -318,7 +338,7 @@ extern "C" fn _start() -> ! {
let ega: &dyn aphrodite::display::TextDisplay = &framebuffer_info;
framebuffer_info.disable_cursor();
ega.clear_screen(COLOR_DEFAULT);
ega.clear_screen(COLOR_DEFAULT).unwrap();
toutputsln("Testing EGA Text framebuffer...", ega).unwrap();
toutputsln("Testing EGA Text framebuffer...", ega).unwrap();
toutputsln("Testing EGA Text framebuffer...", ega).unwrap();

View file

@ -2,9 +2,25 @@
#![cfg(target_arch = "x86")]
use core::alloc::Layout;
use core::arch::asm;
use alloc::vec::Vec;
/// The GDTR. Used internally in [activate_gdt].
#[repr(C, packed)]
struct Gdtr {
base: *const u8,
size: usize,
}
pub unsafe fn activate_gdt(ptr: *const [u8]) {
let gdtr = Gdtr {
base: ptr as *const u8,
size: ptr.len(),
};
unsafe { asm!("lgdt {}", in(reg) (&gdtr) as *const Gdtr as usize) }
}
/// Writes a series of GDT entries to an allocated section of memory and returns
/// a pointer.
pub unsafe fn write_gdt_entries(
@ -34,6 +50,13 @@ pub struct GDTEntry {
pub flags: u8,
}
pub const GDT_NULL_ENTRY: GDTEntry = GDTEntry {
limit: 0,
base: 0,
access: 0,
flags: 0,
};
/// An error returned by [GDTEntry::write_to_addr] when the limit is greater
/// than 0xFFFFF.
const GDT_WRITE_ADDR_INVALID_LIMIT: i16 = -1;

View file

@ -2,7 +2,6 @@
#![cfg(target_arch = "x86")]
#![allow(static_mut_refs)]
use core::alloc::{Allocator, Layout};
use core::arch::asm;
use core::mem::MaybeUninit;
@ -70,29 +69,125 @@ struct Idtr {
size: usize,
}
unsafe impl Send for Idtr {}
unsafe impl Sync for Idtr {}
/// Loads an interrupt descriptor table.
fn load_idt(base: *const u8, size: usize) {
static mut IDTR: MaybeUninit<Idtr> = MaybeUninit::uninit();
unsafe {
IDTR.write(Idtr { base, size });
}
unsafe { asm!("lidt {}", in(reg) IDTR.as_ptr() as usize) }
unsafe fn load_idt(base: *const u8, size: usize) {
let idtr = Idtr { base, size };
unsafe { asm!("lidt {}", in(reg) (&idtr) as *const Idtr as usize) }
}
/// Activate an IDT.
#[derive(Clone, Copy)]
pub(super) struct IdtEntry {
pub offset_high: u16,
pub data: u16,
pub segment: u16,
pub offset_low: u16,
pub vector: u16,
}
#[repr(C, packed)]
struct RawIdtEntry {
pub offset_high: u16,
pub data: u16,
pub segment: u16,
pub offset_low: u16,
}
impl From<IdtEntry> for RawIdtEntry {
fn from(value: IdtEntry) -> Self {
RawIdtEntry {
offset_high: value.offset_high,
data: value.data,
segment: value.segment,
offset_low: value.offset_low,
}
}
}
/// Activate an IDT. Requires that all handlers can properly handle the calling
/// convention and are in GDT segment 1.
///
/// # Panics
/// Panics if the global allocator has not been setup
#[aphrodite_proc_macros::kernel_item(ActivateIDT)]
fn activate_idt(idt: Idt, alloc: crate::mem::MemoryMapAlloc) {
let mem = alloc
.allocate(unsafe { Layout::from_size_align_unchecked(8 * idt.len, 1) })
.unwrap()
.as_mut_ptr();
fn activate_idt(idt: Idt) {
let mut entries = alloc::vec::Vec::new();
for i in 0..idt.len {
let _vector = idt.vectors[i];
let _func = unsafe { idt.funcs[i].assume_init() } as usize as u64;
let _user_callable = idt.user_callable[i];
if idt.using_raw[i] {
entries.push(idt.raw_entries[i]);
continue;
}
let vector = idt.vectors[i];
let func = unsafe { idt.funcs[i].assume_init() } as usize as u32;
let user_callable = idt.user_callable[i];
let exception = idt.exception[i];
let mut entry = IdtEntry {
offset_high: (func & 0xFFFF0000) as u16,
data: 0b1000000000000000,
segment: 1,
offset_low: (func & 0xFFFF) as u16,
vector,
};
if user_callable {
entry.data |= 0b110000000000000;
}
if exception {
entry.data |= 0b111100000000;
} else {
entry.data |= 0b111000000000;
}
entries.push(entry);
}
entries.sort_by(|ele1: &IdtEntry, ele2: &IdtEntry| ele1.vector.cmp(&ele2.vector));
let mut last_vector = 0u16;
let mut start = true;
let mut entries2 = alloc::vec::Vec::new();
for entry in &entries {
if start {
let mut vector = entry.vector;
while vector > 0 {
entries2.push(IdtEntry {
offset_high: 0,
data: 0,
segment: 0,
offset_low: 0,
vector: 0,
});
vector -= 1;
}
last_vector = entry.vector;
entries2.push(*entry);
start = false;
continue;
}
if entry.vector - last_vector > 0 {
let mut vector = entry.vector - last_vector;
while vector > 0 {
entries2.push(IdtEntry {
offset_high: 0,
data: 0,
segment: 0,
offset_low: 0,
vector: 0,
});
vector -= 1;
}
}
last_vector = entry.vector;
entries2.push(*entry);
}
let mut raw_entries: alloc::vec::Vec<RawIdtEntry, _> = alloc::vec::Vec::new();
for entry in &entries2 {
raw_entries.push(RawIdtEntry::from(*entry));
}
let raw_entries = raw_entries.into_raw_parts();
unsafe {
load_idt(raw_entries.0 as *const u8, (idt.len * 8) - 1);
}
}
@ -102,6 +197,9 @@ pub struct Idt {
vectors: [u16; 256],
funcs: [MaybeUninit<fn()>; 256],
user_callable: [bool; 256],
exception: [bool; 256],
raw_entries: [IdtEntry; 256],
using_raw: [bool; 256],
len: usize,
}
@ -111,6 +209,9 @@ pub struct IdtBuilder {
vectors: [u16; 256],
funcs: [MaybeUninit<fn()>; 256],
user_callable: [bool; 256],
exception: [bool; 256],
raw_entries: [IdtEntry; 256],
using_raw: [bool; 256],
idx: usize,
}
@ -121,14 +222,38 @@ impl IdtBuilder {
vectors: [0; 256],
funcs: [MaybeUninit::uninit(); 256],
user_callable: [false; 256],
exception: [false; 256],
raw_entries: [IdtEntry {
offset_high: 0,
data: 0,
segment: 0,
offset_low: 0,
vector: 0,
}; 256],
using_raw: [false; 256],
idx: 0,
}
}
/// Add a function to this IdtBuilder.
pub fn add_fn(&mut self, vector: u16, func: fn(), user_callable: bool) -> &mut Self {
pub fn add_fn(
&mut self,
vector: u16,
func: fn(),
user_callable: bool,
exception: bool,
) -> &mut Self {
self.vectors[self.idx] = vector;
self.funcs[self.idx].write(func);
self.user_callable[self.idx] = user_callable;
self.exception[self.idx] = exception;
self.using_raw[self.idx] = false;
self.idx += 1;
self
}
pub fn add_raw(&mut self, vector: u16, raw_entry: IdtEntry) -> &mut Self {
self.vectors[self.idx] = vector;
self.raw_entries[self.idx] = raw_entry;
self.using_raw[self.idx] = true;
self.idx += 1;
self
}
@ -138,18 +263,14 @@ impl IdtBuilder {
vectors: self.vectors,
funcs: self.funcs,
user_callable: self.user_callable,
raw_entries: self.raw_entries,
using_raw: self.using_raw,
exception: self.exception,
len: self.idx,
}
}
}
impl Default for IdtBuilder {
fn default() -> Self {
IdtBuilder {
vectors: [0; 256],
funcs: [MaybeUninit::uninit(); 256],
user_callable: [false; 256],
idx: 0,
}
}
fn default() -> Self { Self::new() }
}

View file

@ -13,7 +13,9 @@ pub mod ports;
mod constants;
use alloc::vec;
use constants::*;
use gdt::GDTEntry;
use interrupts::{pop_irq, restore_irq};
use ports::{inb, outb};
@ -77,83 +79,6 @@ pub fn get_keyboard_data() -> u8 { inb(0x60) }
/// Sends data to the keyboard.
pub fn send_keyboard_data(data: u8) { outb(0x60, data); }
/// Tries to enable the a20 gate via the keyboard controller method.
pub fn enable_a20_keyboard() {
let irq = pop_irq();
wait_for_keyboard_cmd();
send_keyboard_cmd(0xAD); // disable keyboard
wait_for_keyboard_cmd();
send_keyboard_cmd(0xD0); // read from input
wait_for_keyboard_cmd();
wait_for_keyboard_data();
let a = get_keyboard_data();
wait_for_keyboard_cmd();
send_keyboard_cmd(0xD1); // write to output
wait_for_keyboard_cmd();
send_keyboard_data(a | 2);
wait_for_keyboard_cmd();
send_keyboard_cmd(0xAE); // enable keyboard
restore_irq(irq);
}
/// Tries to enable the a20 gate via fast a20.
/// Note that this may not work or do something unexpected.
pub fn enable_a20_fasta20() {
let mut a = inb(0x92);
if a & 0b10 > 0 {
return;
}
a |= 0b10;
a &= 0xFE;
outb(0x92, a);
}
/// Tries to enable the a20 gate by reading from port 0xee.
pub fn enable_a20_ee_port() { inb(0xee); }
/// Tries to enable the a20 gate by trying many different methods
/// and seeing what sticks.
pub fn enable_a20() -> bool {
if test_a20() {
return true;
}
enable_a20_keyboard();
let mut i = 0u32;
while (!test_a20()) && i < 10000 {
i += 1;
}
if test_a20() {
return true;
}
enable_a20_ee_port();
let mut i = 0u32;
while (!test_a20()) && i < 10000 {
i += 1;
}
if test_a20() {
return true;
}
enable_a20_fasta20();
let mut i = 0u32;
while (!test_a20()) && i < 10000 {
i += 1;
}
return test_a20();
}
static mut RTC_INITALIZED: bool = false;
pub fn initalize_rtc() {
@ -167,10 +92,27 @@ pub fn initalize_rtc() {
unsafe { RTC_INITALIZED = true }
}
pub fn sleep(seconds: u32) {
initalize_rtc();
}
pub fn sleep(seconds: u32) { initalize_rtc(); }
pub fn alloc_available_boot() {
let irq = pop_irq();
let mut entries = vec![];
entries.push(gdt::GDT_NULL_ENTRY);
entries.push(GDTEntry {
limit: 0,
base: 0,
access: 0b10011011,
flags: 0b1100,
}); // kernel code segment
entries.push(GDTEntry {
limit: 0,
base: 0,
access: 0b10010011,
flags: 0b1100,
}); //
unsafe {
gdt::activate_gdt(gdt::write_gdt_entries(entries).unwrap());
}
restore_irq(irq);
}

View file

@ -135,7 +135,6 @@ impl core::iter::Iterator for MemoryMap {
#[derive(Clone)]
pub struct BootInfo<'a> {
/// The commandline of the kernel.
/// See <https://aphrodite-os.github.io/book/command-line.html> for the format.
pub cmdline: Option<&'static str>,
/// The memory map provided by the bootloader. If None, the kernel will
@ -147,4 +146,7 @@ pub struct BootInfo<'a> {
/// Provides a way to display text.
pub output: Option<&'a dyn crate::display::TextDisplay>,
/// The base address of the kernel
pub load_base: Option<u32>,
}

View file

@ -3,6 +3,7 @@
#![allow(unexpected_cfgs)]
#![allow(static_mut_refs)]
use crate::arch::output::*;
use crate::display::{COLOR_DEFAULT, NoneTextDisplay};
use crate::output::*;
@ -37,5 +38,14 @@ fn indep_boot_entry(
tinfosln("Successfully ran all configured power on tests", display).unwrap();
}
if cfg!(CONFIG_PREUSER_OUTPUT_DEBUG = "true") {
if let Some(load_base) = BI.load_base {
sdebugs("Image load base address is ");
sdebugbnpln(&crate::u32_as_u8_slice(load_base));
} else {
sdebugsln("Image load base address was not provided");
}
}
loop {}
}

View file

@ -69,9 +69,9 @@ static mut ALLOCATOR_INITALIZED: bool = false;
pub fn get_allocator() -> Option<&'static MemoryMapAlloc<'static>> {
if unsafe { ALLOCATOR_INITALIZED } {
#[allow(static_mut_refs)]
return Some(unsafe { ALLOCATOR.assume_init_ref() });
Some(unsafe { ALLOCATOR.assume_init_ref() })
} else {
return None;
None
}
}

View file

@ -19,6 +19,7 @@
#![feature(ptr_as_uninit)]
#![allow(internal_features)]
#![feature(core_intrinsics)]
#![feature(vec_into_raw_parts)]
extern crate alloc;

View file

@ -197,7 +197,6 @@ pub struct Multiboot2BootInfo {
// If you need it, good luck.
/// 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://aphrodite-os.github.io/book/command-line.html> for the format.
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
@ -220,14 +219,16 @@ pub struct Multiboot2BootInfo {
// it.
/// Provides information on the framebuffer.
pub framebuffer_info: Option<FramebufferInfo>,
/// Color info, stored separately from [FramebufferInfo] because rust
pub color_info: Option<ColorInfo>,
// Even though SMBIOS is documented for Multiboot2, we're not using it and will instead search
// for it ourselves. This is because right now I cannot figure out what format it provides
// the SMBIOS table in.
// EFI memory map and image handle pointers are not included for portability.
// "Image load base physical address" is not included as at the moment the kernel is not
// relocatable.
// EFI memory map and image handle pointers are not included for portability. Yeah, that's what
// I'm calling it.
/// Base address of the kernel
pub load_base: Option<u32>,
}

View file

@ -1,4 +1,7 @@
#![cfg(all(not(CONFIG_POWERON_TESTS = "false"), not(CONFIG_POWERON_TEST_ALLOC = "false")))]
#![cfg(all(
not(CONFIG_POWERON_TESTS = "false"),
not(CONFIG_POWERON_TEST_ALLOC = "false")
))]
use crate::display::TextDisplay;
use crate::output::*;