wow i did a lot of stuff silly :3
This commit is contained in:
parent
c7cc51427b
commit
69855525cb
23 changed files with 1499 additions and 83 deletions
8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"rust-analyzer.cargo.allTargets": false,
|
||||
"rust-analyzer.check.allTargets": false,
|
||||
"rust-analyzer.linkedProjects": [
|
||||
"kernel/Cargo.toml",
|
||||
"patcher/Cargo.toml"
|
||||
]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Subproject commit fd6f101699b11129be91c1ac8cb67bebb65a5c9b
|
5
kernel/.cargo/config.toml
Normal file
5
kernel/.cargo/config.toml
Normal file
|
@ -0,0 +1,5 @@
|
|||
[build]
|
||||
target = "i686-unknown-none.json"
|
||||
|
||||
[unstable]
|
||||
build-std = ["core"]
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
paste = "1.0.15"
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z"
|
||||
|
@ -18,4 +19,8 @@ path = "src/internal/arch/x86/entry.rs"
|
|||
|
||||
[lib]
|
||||
name = "aphrodite"
|
||||
path = "src/include/mod.rs"
|
||||
path = "src/include/mod.rs"
|
||||
|
||||
[[test]]
|
||||
name = "test_aphrodite"
|
||||
path = "src/include/test.rs"
|
||||
|
|
10
kernel/build
10
kernel/build
|
@ -1,4 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
RUSTFLAGS='-Clink-arg=--script=link.x' cargo build --target i686-unknown-none.json --release -Zbuild-std
|
||||
cp target/i686-unknown-none/release/kernel kernel.flat
|
||||
RUSTFLAGS='-Clink-arg=--script=link.x' cargo build --target i686-unknown-none.json --release -Zbuild-std --bin entrypoint
|
||||
# build the kernel's entrypoint
|
||||
|
||||
cp target/i686-unknown-none/release/entrypoint kernel.flat
|
||||
# copy it out
|
||||
|
||||
/home/arthur/aphrodite/patcher/target/release/patcher
|
||||
# run the custom patching program to add the multiboot2 header
|
1076
kernel/disassembly
Normal file
1076
kernel/disassembly
Normal file
File diff suppressed because it is too large
Load diff
3
kernel/expand
Executable file
3
kernel/expand
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
RUSTFLAGS='-Clink-arg=--script=link.x' cargo expand --target i686-unknown-none.json --release -Zbuild-std --bin entrypoint
|
Binary file not shown.
|
@ -4,7 +4,6 @@ OUTPUT_FORMAT(binary)
|
|||
SECTIONS {
|
||||
.text : {
|
||||
. = ALIGN(8);
|
||||
KEEP(*(.multiboot2))
|
||||
KEEP(*(.start))
|
||||
KEEP(*(.text))
|
||||
KEEP(*(.panic))
|
||||
|
|
3
kernel/src/include/arch/mod.rs
Normal file
3
kernel/src/include/arch/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
//! Arch-specific code.
|
||||
|
||||
pub mod x86;
|
5
kernel/src/include/arch/x86/constants.rs
Normal file
5
kernel/src/include/arch/x86/constants.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
//! Constants used throughout kernel code.
|
||||
#![cfg(any(target_arch = "x86"))]
|
||||
|
||||
/// The assembly port number to output debug messages to.
|
||||
pub const DEBUG_PORT: u16 = 0xE9;
|
61
kernel/src/include/arch/x86/interrupts.rs
Normal file
61
kernel/src/include/arch/x86/interrupts.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
//! Provides interrupt-related functions
|
||||
#![cfg(any(target_arch = "x86"))]
|
||||
|
||||
use core::arch::asm;
|
||||
|
||||
/// Returns whether interrupts are enabled or not.
|
||||
pub fn interrupts_enabled() -> bool {
|
||||
let flags: u32;
|
||||
unsafe {
|
||||
asm!(
|
||||
"pushf",
|
||||
"pop {0:e}", out(reg) flags
|
||||
)
|
||||
}
|
||||
(flags & (1 << 9)) == 0
|
||||
}
|
||||
|
||||
/// Disables interrupts and returns the value of them.
|
||||
pub fn pop_irq() -> u32 {
|
||||
let flags: u32;
|
||||
unsafe {
|
||||
asm!(
|
||||
"pushf",
|
||||
"cli",
|
||||
"pop {0:e}", out(reg) flags
|
||||
)
|
||||
}
|
||||
flags
|
||||
}
|
||||
|
||||
/// Restores interrupts after a [pop_irq] call.
|
||||
pub fn restore_irq(flags: u32) {
|
||||
unsafe {
|
||||
asm!(
|
||||
"push {0:e}", in(reg) flags
|
||||
);
|
||||
asm!(
|
||||
"popf"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The IDTR. Used internally in [load_idt].
|
||||
#[repr(C)]
|
||||
struct IDTR {
|
||||
base: *const u8,
|
||||
size: usize
|
||||
}
|
||||
|
||||
/// Loads an interrupt descriptor table.
|
||||
pub fn load_idt(base: *const u8, size: usize) {
|
||||
let idtr = IDTR {
|
||||
base,
|
||||
size
|
||||
};
|
||||
unsafe {
|
||||
asm!(
|
||||
"lidt {}", in(reg) &idtr
|
||||
)
|
||||
}
|
||||
}
|
26
kernel/src/include/arch/x86/mod.rs
Normal file
26
kernel/src/include/arch/x86/mod.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
//! General x86 functions
|
||||
#![cfg(any(target_arch = "x86"))]
|
||||
|
||||
use core::arch::asm;
|
||||
|
||||
pub mod interrupts;
|
||||
pub mod ports;
|
||||
pub mod output;
|
||||
|
||||
mod constants;
|
||||
|
||||
pub use constants::*;
|
||||
|
||||
/// Returns information from the CPUID command in the form
|
||||
/// (ebx, edx, ecx).
|
||||
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
|
||||
)
|
||||
}
|
||||
out
|
||||
}
|
30
kernel/src/include/arch/x86/output.rs
Normal file
30
kernel/src/include/arch/x86/output.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
//! Functions to output to various things
|
||||
#![cfg(any(target_arch = "x86"))]
|
||||
|
||||
use super::ports;
|
||||
|
||||
use paste::paste;
|
||||
|
||||
macro_rules! message_funcs {
|
||||
($func_name:ident, $prefix:literal) => {
|
||||
paste! {
|
||||
/// Outputs a $func_name message &str to the debug serial port.
|
||||
pub fn [< s $func_name s >](s: &str) {
|
||||
ports::outbs(super::DEBUG_PORT, $prefix.as_bytes());
|
||||
ports::outbs(super::DEBUG_PORT, s.as_bytes());
|
||||
}
|
||||
/// Outputs a $func_name message &\[u8] to the debug serial port.
|
||||
pub fn [< s $func_name b >](s: &[u8]) {
|
||||
ports::outbs(super::DEBUG_PORT, $prefix.as_bytes());
|
||||
ports::outbs(super::DEBUG_PORT, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message_funcs!(debug, "[DEBUG] ");
|
||||
message_funcs!(info, "[INFO] ");
|
||||
message_funcs!(warning, "[WARN] ");
|
||||
message_funcs!(error, "[ERROR] ");
|
||||
message_funcs!(fatal, "[FATAL] ");
|
||||
|
39
kernel/src/include/arch/x86/ports.rs
Normal file
39
kernel/src/include/arch/x86/ports.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
//! Provides utilities for interacting with assembly ports
|
||||
#![cfg(any(target_arch = "x86"))]
|
||||
|
||||
use core::arch::asm;
|
||||
|
||||
/// Outputs a byte to an IO port
|
||||
#[inline(always)]
|
||||
pub fn outb(port: u16, val: u8) {
|
||||
unsafe {
|
||||
asm!(
|
||||
"out dx, al", in("dx") port, in("al") val
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Outputs an arbitrary number of bytes to an IO port
|
||||
pub fn outbs(port: u16, val: &[u8]) {
|
||||
for ele in val {
|
||||
outb(port, *ele);
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a byte from an IO port
|
||||
#[inline(always)]
|
||||
pub fn inb(port: u16) -> u8 {
|
||||
let out;
|
||||
unsafe {
|
||||
asm!(
|
||||
"in {}, {1:x}", out(reg_byte) out, in(reg) port
|
||||
)
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Wait a short, indeterminable time
|
||||
#[inline(always)]
|
||||
pub fn io_wait() {
|
||||
outb(0x80, 0);
|
||||
}
|
|
@ -1,4 +1 @@
|
|||
//! Constants used throughout kernel code.
|
||||
|
||||
/// The assembly port number to output debug messages to.
|
||||
pub const DEBUG_PORT: u8 = 0xE9;
|
||||
//! Constants used throughout kernel code.
|
44
kernel/src/include/errors.rs
Normal file
44
kernel/src/include/errors.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
//! Stuff related to errors.
|
||||
|
||||
/// Converts an i16 to an [u8; 6].
|
||||
pub fn i16_as_u8_slice(mut value: i16) -> [u8; 6] {
|
||||
let mut buf = [0u8; 6];
|
||||
let mut i = 0;
|
||||
if value < 0 {
|
||||
buf[i] = b'-';
|
||||
value = -value;
|
||||
}
|
||||
i = 5;
|
||||
while value > 0 {
|
||||
let digit = value%10;
|
||||
let char = b'0' + digit as u8;
|
||||
buf[i] = char;
|
||||
value = value / 10;
|
||||
i -= 1;
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
/// An error used by aphrodite
|
||||
pub struct Error<'a> {
|
||||
message: &'a str,
|
||||
code: i16
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Error<'_> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.write_str(core::str::from_utf8(&i16_as_u8_slice(self.code)).unwrap())?;
|
||||
f.write_str(": ")?;
|
||||
f.write_str(self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for Error<'_> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.write_str(core::str::from_utf8(&i16_as_u8_slice(self.code)).unwrap())?;
|
||||
f.write_str(": ")?;
|
||||
f.write_str(self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::error::Error for Error<'_> {}
|
|
@ -1,9 +1,14 @@
|
|||
//! This provides syscalls(for userspace programs) and types(for userspace and kernelspace programs) for the Aphrodite kernel.
|
||||
|
||||
#![no_std]
|
||||
#![warn(missing_docs)]
|
||||
#![feature(ptr_metadata)]
|
||||
|
||||
mod constants;
|
||||
pub mod multiboot2;
|
||||
pub mod arch;
|
||||
mod errors;
|
||||
|
||||
pub use constants::*;
|
||||
#[allow(unused_imports)] // if there are no constants, then it gives a warning
|
||||
pub use constants::*;
|
||||
|
||||
pub use errors::*;
|
|
@ -1,7 +1,5 @@
|
|||
//! Definitions of structs for multiboot2 information. Mostly used during pre-userspace.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
/// Used when a CString is passed. Move into separate file?
|
||||
#[derive(Clone)]
|
||||
pub struct CString {
|
||||
|
@ -61,30 +59,6 @@ pub struct Module {
|
|||
pub mod_str: CString
|
||||
}
|
||||
|
||||
/// All modules provided by the bootloader. Very similar to [CString].
|
||||
#[derive(Clone)]
|
||||
pub struct Modules {
|
||||
/// A pointer to the first module. All modules should be consecutive.
|
||||
pub ptr: *const Module,
|
||||
/// The number of modules. If zero, [ptr](Modules::ptr) should not be trusted!
|
||||
pub modules_num: usize
|
||||
}
|
||||
|
||||
impl core::ops::Index<usize> for Modules {
|
||||
type Output = Module;
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
unsafe {
|
||||
if index>self.modules_num {
|
||||
panic!("index into Modules too large");
|
||||
}
|
||||
let mut ptr = self.ptr as usize;
|
||||
ptr += index * size_of::<Module>();
|
||||
let ptr = ptr as *const Module;
|
||||
&*ptr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
@ -101,6 +75,23 @@ pub struct MemorySection {
|
|||
reserved: u32,
|
||||
}
|
||||
|
||||
/// 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,
|
||||
/// The length of the tag.
|
||||
pub tag_len: u32,
|
||||
/// Size of one entry(one [MemorySection] for Aphrodite)
|
||||
pub entry_size: u32,
|
||||
/// The version of the memory map. Should be disregarded as it's 0.
|
||||
pub entry_version: u32, // currently is 0, future Multiboot2 versions may increment
|
||||
/// The sections. This is the reason that [Clone] can't be implemented for [RawMemoryMap].
|
||||
pub sections: [MemorySection]
|
||||
}
|
||||
|
||||
/// A full memory map provided by a Multiboot2 bootloader.
|
||||
#[derive(Clone)]
|
||||
pub struct MemoryMap {
|
||||
|
@ -117,6 +108,7 @@ 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
|
||||
pub red: u8,
|
||||
|
@ -127,9 +119,9 @@ pub struct PaletteColorDescriptor {
|
|||
}
|
||||
|
||||
/// Information about color, for use in [FramebufferInfo].
|
||||
#[repr(C)]
|
||||
#[repr(u8)]
|
||||
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ColorInfo {
|
||||
/// The palette for use on the framebuffer.
|
||||
Palette {
|
||||
|
@ -154,7 +146,9 @@ pub enum ColorInfo {
|
|||
blue_field_position: u8,
|
||||
/// See above.
|
||||
blue_mask_size: u8,
|
||||
}
|
||||
},
|
||||
/// Text information, no metadata
|
||||
EGAText
|
||||
}
|
||||
|
||||
/// Information about the framebuffer.
|
||||
|
@ -162,6 +156,10 @@ pub enum ColorInfo {
|
|||
#[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,
|
||||
/// The pitch of the framebuffer (i.e. the number of bytes in each row).
|
||||
|
@ -176,8 +174,9 @@ pub struct FramebufferInfo {
|
|||
pub fb_type: u8,
|
||||
/// Reserved space. Ignore.
|
||||
reserved: u8,
|
||||
/// Color info. None if [fb_type](FramebufferInfo::fb_type) is 2.
|
||||
pub color_info: Option<ColorInfo>
|
||||
|
||||
// Color info after this; we need separate structs for each colorinfo and
|
||||
// we have to understand the format the bootloader gives us.
|
||||
}
|
||||
|
||||
/// Boot info collected from provided [Tag]s.
|
||||
|
@ -199,8 +198,8 @@ pub struct BootInfo {
|
|||
/// See https://github.com/AverseABFun/aphrodite/wiki/Plan#bootloader (remember to update link later!) for the format.
|
||||
pub cmdline: Option<CString>,
|
||||
|
||||
/// All modules provided by the bootloader.
|
||||
pub modules: Option<Modules>,
|
||||
// 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.
|
||||
|
@ -218,6 +217,8 @@ pub struct BootInfo {
|
|||
|
||||
/// 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.
|
||||
|
|
2
kernel/src/include/test.rs
Normal file
2
kernel/src/include/test.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
//! Tests for the kernel.
|
||||
#![no_std]
|
|
@ -2,23 +2,10 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![warn(missing_docs)]
|
||||
#![feature(ptr_metadata)]
|
||||
|
||||
use core::{arch::asm, ffi::CStr, hint::unreachable_unchecked, panic::PanicInfo};
|
||||
use aphrodite::multiboot2::{BootInfo, CString, RootTag, Tag};
|
||||
|
||||
#[unsafe(link_section = ".multiboot2")]
|
||||
static MULTIBOOT_HEADER: [u16; 14] = [
|
||||
// Magic fields
|
||||
0xE852, 0x50D6, // Magic number
|
||||
0x0000, 0x0000, // Architecture, 0=i386
|
||||
0x0000, 0x000E, // length of MULTIBOOT_HEADER
|
||||
0x17AD, 0xAF1C, // checksum=all magic field excluding this+this=0
|
||||
|
||||
// Framebuffer tag- empty flags, no preference for width, height, or bit depth
|
||||
0x0005, 0x0000,
|
||||
0x0014, 0x0000,
|
||||
0x0000, 0x0000,
|
||||
];
|
||||
use core::{arch::asm, ffi::CStr, panic::PanicInfo};
|
||||
use aphrodite::multiboot2::{BootInfo, CString, ColorInfo, FramebufferInfo, MemoryMap, PaletteColorDescriptor, RawMemoryMap, RootTag, Tag};
|
||||
|
||||
// The root tag, provided directly from the multiboot bootloader.
|
||||
static mut RT: *const RootTag = core::ptr::null();
|
||||
|
@ -27,10 +14,10 @@ static mut BI: BootInfo = BootInfo {
|
|||
mem_lower: None,
|
||||
mem_upper: None,
|
||||
cmdline: None,
|
||||
modules: None,
|
||||
memory_map: None,
|
||||
bootloader_name: None,
|
||||
framebuffer_info: None
|
||||
framebuffer_info: None,
|
||||
color_info: None,
|
||||
};
|
||||
|
||||
// The raw pointer to bootloader-specific data.
|
||||
|
@ -64,24 +51,27 @@ extern "C" fn _start() -> ! {
|
|||
match (*current_tag).tag_type {
|
||||
0 => { // Ending tag
|
||||
if (*current_tag).tag_len != 8 { // Unexpected size, something is probably up
|
||||
panic!("Size of ending tag != 8");
|
||||
panic!("size of ending tag != 8");
|
||||
}
|
||||
break
|
||||
},
|
||||
4 => { // Basic memory information
|
||||
if (*current_tag).tag_len != 16 { // Unexpected size, something is probably up
|
||||
panic!("Size of basic memory information tag != 16");
|
||||
panic!("size of basic memory information tag != 16");
|
||||
}
|
||||
|
||||
BI.mem_lower = Some(*((current_tag as usize + 8) as *const u32));
|
||||
BI.mem_upper = Some(*((current_tag as usize + 12) as *const u32));
|
||||
// The end result of the above is adding an offset to a pointer and retrieving the value at that pointer
|
||||
|
||||
current_tag = (current_tag as usize + 16) as *const Tag;
|
||||
},
|
||||
5 => { // BIOS boot device, ignore
|
||||
if (*current_tag).tag_len != 20 { // Unexpected size, something is probably up
|
||||
panic!("size of bios boot device tag != 20");
|
||||
}
|
||||
},
|
||||
1 => { // Command line
|
||||
if (*current_tag).tag_len < 8 { // Unexpected size, something is probably up
|
||||
panic!("Size of command line tag < 8");
|
||||
panic!("size of command line tag < 8");
|
||||
}
|
||||
let cstring = CStr::from_ptr((current_tag as usize + 8) as *const i8);
|
||||
// creates a &core::ffi::CStr from the start of the command line...
|
||||
|
@ -92,35 +82,100 @@ extern "C" fn _start() -> ! {
|
|||
};
|
||||
// ...which can then be converted to a aphrodite::multiboot2::CString...
|
||||
|
||||
current_tag = (current_tag as usize + 8 + cstring.len) as *const Tag;
|
||||
// ...before the current_tag is incremented to prevent ownership issues...
|
||||
|
||||
BI.cmdline = Some(cstring);
|
||||
// ...before lastly the BootInfo's commandline is set.
|
||||
// ...before the BootInfo's commandline is set.
|
||||
},
|
||||
_ => { // Unknown tag type
|
||||
todo!("Implement tag");
|
||||
6 => { // Memory map tag
|
||||
if (*current_tag).tag_len < 16 { // Unexpected size, something is probably up
|
||||
panic!("size of memory map tag < 16");
|
||||
}
|
||||
let rawmemorymap: *const RawMemoryMap = core::ptr::from_raw_parts(
|
||||
current_tag, ((*current_tag).tag_len / *((current_tag as usize + 8usize) as *const u32)) as usize
|
||||
);
|
||||
// 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 {
|
||||
version: (*rawmemorymap).entry_version,
|
||||
entry_size: (*rawmemorymap).entry_size,
|
||||
sections: &(*rawmemorymap).sections[0],
|
||||
sections_len: (*rawmemorymap).sections.len()
|
||||
});
|
||||
},
|
||||
2 => { // Bootloader name
|
||||
if (*current_tag).tag_len < 8 { // Unexpected size, something is probably up
|
||||
panic!("size of command line tag < 8");
|
||||
}
|
||||
let cstring = CStr::from_ptr((current_tag as usize + 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);
|
||||
// ...before the BootInfo's bootloader_name is set.
|
||||
},
|
||||
8 => { // Framebuffer info
|
||||
if (*current_tag).tag_len < 40 { // Unexpected size, something is probably up
|
||||
panic!("size of framebuffer info tag < 40");
|
||||
}
|
||||
let framebufferinfo: *const FramebufferInfo = current_tag as *const FramebufferInfo;
|
||||
let colorinfo: ColorInfo;
|
||||
match (*framebufferinfo).fb_type {
|
||||
0 => { // Indexed
|
||||
colorinfo = ColorInfo::Palette {
|
||||
num_colors: *((current_tag as usize + 40) as *const u32),
|
||||
palette: (current_tag as usize + 44) as *const PaletteColorDescriptor
|
||||
};
|
||||
},
|
||||
1 => { // RGB
|
||||
colorinfo = ColorInfo::RGBColor {
|
||||
red_field_position: *((current_tag as usize + 40) as *const u8),
|
||||
red_mask_size: *((current_tag as usize + 41) as *const u8),
|
||||
green_field_position: *((current_tag as usize + 42) as *const u8),
|
||||
green_mask_size: *((current_tag as usize + 43) as *const u8),
|
||||
blue_field_position: *((current_tag as usize + 44) as *const u8),
|
||||
blue_mask_size: *((current_tag as usize + 45) as *const u8)
|
||||
}
|
||||
},
|
||||
2 => { // EGA Text
|
||||
colorinfo = ColorInfo::EGAText;
|
||||
},
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
BI.framebuffer_info = Some((*framebufferinfo).clone());
|
||||
BI.color_info = Some(colorinfo);
|
||||
},
|
||||
_ => { // Unknown/unimplemented tag type, ignore
|
||||
// TODO: Add info message
|
||||
}
|
||||
}
|
||||
current_tag = (current_tag as usize + (*current_tag).tag_len as usize) as *const Tag;
|
||||
}
|
||||
},
|
||||
_ => { // Unknown bootloader, triple fault
|
||||
asm!(
|
||||
"lidt 0", // Make interrupt table invalid(may or may not be invalid, depending on the bootloader, but we don't know)
|
||||
"int 0h" // Try to perform an interrupt
|
||||
// CPU then triple faults, thus restarting it
|
||||
)
|
||||
_ => { // Unknown bootloader, panic
|
||||
panic!("unknown bootloader");
|
||||
}
|
||||
}
|
||||
}
|
||||
loop {}
|
||||
|
||||
panic!("kernel exited");
|
||||
}
|
||||
|
||||
#[unsafe(link_section = ".panic")]
|
||||
#[panic_handler]
|
||||
fn handle_panic(_: &PanicInfo) -> ! {
|
||||
fn handle_panic(info: &PanicInfo) -> ! {
|
||||
let message = info.message().as_str().unwrap_or("");
|
||||
if message != "" {
|
||||
aphrodite::arch::x86::output::sfatals(message);
|
||||
aphrodite::arch::x86::ports::outb(aphrodite::arch::x86::DEBUG_PORT, b'\n');
|
||||
}
|
||||
unsafe {
|
||||
asm!("hlt");
|
||||
unreachable_unchecked();
|
||||
asm!("hlt", options(noreturn));
|
||||
}
|
||||
}
|
6
patcher/Cargo.toml
Normal file
6
patcher/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "patcher"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
41
patcher/src/main.rs
Normal file
41
patcher/src/main.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use std::{fs, io::Write};
|
||||
|
||||
static MULTIBOOT_HEADER: [u16; 14] = [
|
||||
// Magic fields
|
||||
0xE852, 0x50D6, // Magic number
|
||||
0x0000, 0x0000, // Architecture, 0=i386
|
||||
0x0000, 0x000E, // length of MULTIBOOT_HEADER
|
||||
0x17AD, 0xAF1C, // checksum=all magic field excluding this+this=0
|
||||
|
||||
// Framebuffer tag- empty flags, no preference for width, height, or bit depth
|
||||
0x0005, 0x0000,
|
||||
0x0014, 0x0000,
|
||||
0x0000, 0x0000
|
||||
];
|
||||
|
||||
fn from_u16(from: &mut [u16]) -> &[u8] {
|
||||
if cfg!(target_endian = "little") {
|
||||
for byte in from.iter_mut() {
|
||||
*byte = byte.to_be();
|
||||
}
|
||||
}
|
||||
|
||||
let len = from.len().checked_mul(2).unwrap();
|
||||
let ptr: *const u8 = from.as_ptr().cast();
|
||||
unsafe { std::slice::from_raw_parts(ptr, len) }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let path = "./kernel.flat";
|
||||
let mut buf = fs::read(path).unwrap();
|
||||
buf = [
|
||||
from_u16(&mut (MULTIBOOT_HEADER.clone())).to_vec(),
|
||||
buf
|
||||
].concat();
|
||||
fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.open(path)
|
||||
.unwrap()
|
||||
.write(buf.as_mut_slice())
|
||||
.unwrap();
|
||||
}
|
Loading…
Add table
Reference in a new issue