Inital work. Long way to go; does not boot yet.
This commit is contained in:
parent
0a1c2e1bb1
commit
f18846b32e
10 changed files with 371 additions and 0 deletions
3
emulation/bochsrc
Normal file
3
emulation/bochsrc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
display_library: x, options="gui_debug"
|
||||||
|
port_e9_hack: enabled=1
|
||||||
|
cpu: reset_on_triple_fault=0
|
21
kernel/Cargo.toml
Normal file
21
kernel/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "kernel"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = "z"
|
||||||
|
strip = true
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "entrypoint"
|
||||||
|
path = "src/internal/arch/x86/entry.rs"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "aphrodite"
|
||||||
|
path = "src/include/mod.rs"
|
4
kernel/build
Executable file
4
kernel/build
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/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
|
24
kernel/i686-unknown-none.json
Normal file
24
kernel/i686-unknown-none.json
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"cpu": "i686",
|
||||||
|
"data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128",
|
||||||
|
"llvm-target": "i686-unknown-none",
|
||||||
|
"target-endian": "little",
|
||||||
|
"target-pointer-width": "32",
|
||||||
|
"target-c-int-width": "32",
|
||||||
|
"features": "-mmx,-sse,+soft-float",
|
||||||
|
"os": "none",
|
||||||
|
"arch": "x86",
|
||||||
|
"panic-strategy": "abort",
|
||||||
|
"disable-redzone": true,
|
||||||
|
"code-model": "kernel",
|
||||||
|
"crt-objects-fallback": "false",
|
||||||
|
"linker": "rust-lld",
|
||||||
|
"linker-flavor": "gnu-lld",
|
||||||
|
"max-atomic-width": 32,
|
||||||
|
"metadata": {
|
||||||
|
"description": "Freestanding/bare-metal i686 softfloat",
|
||||||
|
"host_tools": false,
|
||||||
|
"std": false,
|
||||||
|
"tier": 3
|
||||||
|
}
|
||||||
|
}
|
BIN
kernel/kernel.flat
Executable file
BIN
kernel/kernel.flat
Executable file
Binary file not shown.
12
kernel/link.x
Normal file
12
kernel/link.x
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
ENTRY(_start)
|
||||||
|
OUTPUT_FORMAT(binary)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
.text : {
|
||||||
|
. = ALIGN(8);
|
||||||
|
KEEP(*(.multiboot2))
|
||||||
|
KEEP(*(.start))
|
||||||
|
KEEP(*(.text))
|
||||||
|
KEEP(*(.panic))
|
||||||
|
}
|
||||||
|
}
|
4
kernel/src/include/constants.rs
Normal file
4
kernel/src/include/constants.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
//! Constants used throughout kernel code.
|
||||||
|
|
||||||
|
/// The assembly port number to output debug messages to.
|
||||||
|
pub const DEBUG_PORT: u8 = 0xE9;
|
9
kernel/src/include/mod.rs
Normal file
9
kernel/src/include/mod.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
//! This provides syscalls(for userspace programs) and types(for userspace and kernelspace programs) for the Aphrodite kernel.
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
mod constants;
|
||||||
|
pub mod multiboot2;
|
||||||
|
|
||||||
|
pub use constants::*;
|
229
kernel/src/include/multiboot2.rs
Normal file
229
kernel/src/include/multiboot2.rs
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
//! 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 {
|
||||||
|
/// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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(align(1))] // may or may not be necessary, but I'm not taking chances
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Tag {
|
||||||
|
/// The type of the tag.
|
||||||
|
pub tag_type: u32,
|
||||||
|
/// The length of the tag.
|
||||||
|
pub tag_len: u32,
|
||||||
|
/// A pointer to after [tag_len](Tag::tag_len). This is where most type-specific data is.
|
||||||
|
pub data_ptr: *const u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The root tag. The official Multiboot2 name is literally the "fixed part" of the tags, so I made a better name.
|
||||||
|
#[repr(C)]
|
||||||
|
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RootTag {
|
||||||
|
/// The total length between the root tag and the terminating tag.
|
||||||
|
/// You can also search for the tag that has a type of 0 and a length of 8.
|
||||||
|
pub total_len: u32,
|
||||||
|
/// Reserved space. Unused for anything.
|
||||||
|
reserved: u32,
|
||||||
|
/// A pointer to right after the reserved space. Should be a pointer to the next tag.
|
||||||
|
pub tag_ptr: *const u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Multiboot2 module. See https://github.com/AverseABFun/aphrodite/wiki/Plan/#Bootloader-modules (remember to update link later!).
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Module {
|
||||||
|
/// A pointer to the start of the module
|
||||||
|
pub mod_start: *const u8,
|
||||||
|
/// A pointer to the end of the 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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct MemorySection {
|
||||||
|
/// The base address of the section.
|
||||||
|
pub base_addr: u64,
|
||||||
|
/// The length of the section.
|
||||||
|
pub length: u64,
|
||||||
|
/// The type of the section. Name is changed from the one provided in the Multiboot2 docs
|
||||||
|
/// as "type" is a keyword in rust.
|
||||||
|
pub mem_type: u32,
|
||||||
|
/// Reserved space. Should be ignored.
|
||||||
|
reserved: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A full memory map provided by a Multiboot2 bootloader.
|
||||||
|
#[derive(Clone)]
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A color descriptor for [ColorInfo::Palette].
|
||||||
|
#[repr(C)]
|
||||||
|
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
||||||
|
pub struct PaletteColorDescriptor {
|
||||||
|
/// The red value
|
||||||
|
pub red: u8,
|
||||||
|
/// The green value
|
||||||
|
pub green: u8,
|
||||||
|
/// The blue value
|
||||||
|
pub blue: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information about color, for use in [FramebufferInfo].
|
||||||
|
#[repr(C)]
|
||||||
|
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum ColorInfo {
|
||||||
|
/// The palette for use on the framebuffer.
|
||||||
|
Palette {
|
||||||
|
/// The number of colors in the palette.
|
||||||
|
num_colors: u32,
|
||||||
|
/// The first color in the palette.
|
||||||
|
palette: *const PaletteColorDescriptor
|
||||||
|
},
|
||||||
|
/// RGB information for use on the framebuffer.
|
||||||
|
RGBColor {
|
||||||
|
/// Red color information.
|
||||||
|
red_field_position: u8,
|
||||||
|
/// See above.
|
||||||
|
red_mask_size: u8,
|
||||||
|
|
||||||
|
/// Green color information.
|
||||||
|
green_field_position: u8,
|
||||||
|
/// See above.
|
||||||
|
green_mask_size: u8,
|
||||||
|
|
||||||
|
/// Blue color information.
|
||||||
|
blue_field_position: u8,
|
||||||
|
/// See above.
|
||||||
|
blue_mask_size: u8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information about the framebuffer.
|
||||||
|
#[repr(C)]
|
||||||
|
#[repr(align(1))] // may or may not be necessary, but I'm not taking chances
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct FramebufferInfo {
|
||||||
|
/// A pointer to the framebuffer.
|
||||||
|
pub address: *mut u8,
|
||||||
|
/// 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,
|
||||||
|
/// The type of the framebuffer. 0=indexed, 1=RGB, 2=text.
|
||||||
|
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>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Boot info collected from provided [Tag]s.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct BootInfo {
|
||||||
|
/// 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".
|
||||||
|
pub mem_lower: Option<u32>,
|
||||||
|
/// See above
|
||||||
|
pub mem_upper: Option<u32>,
|
||||||
|
|
||||||
|
// Multiboot2 bootloaders may provide us with the BIOS device and partition, but we're not interested.
|
||||||
|
// To ensure future developers don't get any ideas, I'm leaving it out here.
|
||||||
|
// 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://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>,
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
/// This should contain the original pointer provided by the bootloader.
|
||||||
|
pub bootloader_name: Option<CString>,
|
||||||
|
|
||||||
|
// APM table is ignored as APM has been superseded by ACPI. If your system doesn't support ACPI, good luck.
|
||||||
|
|
||||||
|
// VBE table is ignored for a similar reason to above: it's deprecated. Good luck if you need it.
|
||||||
|
|
||||||
|
pub framebuffer_info: Option<FramebufferInfo>,
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
|
}
|
65
kernel/src/internal/arch/x86/entry.rs
Normal file
65
kernel/src/internal/arch/x86/entry.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
//! The entrypoint to the kernel; placed before all other code.
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
use core::{arch::asm, hint::unreachable_unchecked, panic::PanicInfo};
|
||||||
|
use aphrodite::multiboot2::{BootInfo, 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,
|
||||||
|
];
|
||||||
|
|
||||||
|
static mut RT: *const RootTag = core::ptr::null();
|
||||||
|
static mut BI: *const BootInfo = core::ptr::null();
|
||||||
|
static mut O: *const u8 = core::ptr::null();
|
||||||
|
static mut MAGIC: u32 = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
#[unsafe(link_section = ".start")]
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn _start() -> ! {
|
||||||
|
unsafe { // Copy values provided by the bootloader out
|
||||||
|
asm!(
|
||||||
|
"mov {0:e}, eax", out(reg) MAGIC // Magic number
|
||||||
|
);
|
||||||
|
asm!(
|
||||||
|
"mov {0:e}, ebx", out(reg) O // Bootloader-specific data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
match MAGIC {
|
||||||
|
0x36d76289 => { // Multiboot2
|
||||||
|
RT = O as *const RootTag; // This is unsafe rust! We can do whatever we want! *manical laughter*
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
_ => { // 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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(link_section = ".panic")]
|
||||||
|
#[panic_handler]
|
||||||
|
fn handle_panic(_: &PanicInfo) -> ! {
|
||||||
|
unsafe {
|
||||||
|
asm!("hlt");
|
||||||
|
unreachable_unchecked();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue