diff --git a/.gitignore b/.gitignore index 7adf114..1d1b46b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,11 @@ Cargo.lock # Generated grub files kernel/grub/ aphrodite-grub.iso -aphrodite.iso \ No newline at end of file +aphrodite.iso + +# Generated files +kernel.flat +config.aphro.tmp + +# Per-developer files +config.aphro \ No newline at end of file diff --git a/kernel/build b/kernel/build index 818018b..6efcc47 100755 --- a/kernel/build +++ b/kernel/build @@ -7,6 +7,10 @@ if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi get_version +cp config.aphro config.aphro.tmp + +export $(grep -Ev '^#' config.aphro.tmp | xargs) + cd ../kernel cargo build --target i686-unknown-none.json --release -Zbuild-std --bin entrypoint @@ -15,13 +19,17 @@ cargo build --target i686-unknown-none.json --release -Zbuild-std --bin entrypoi cp target/i686-unknown-none/release/entrypoint kernel.flat # copy it out -rm -rf grub +rm -rf grub aphrodite.iso aphrodite-grub.iso -cp -r ./grub_template ./grub +if [[ $CONFIG_BUILD_GRUB = "true" ]]; then + cp -r ./grub_template ./grub -cp kernel.flat ./grub/boot/aphrodite.kernel + cp kernel.flat ./grub/boot/aphrodite.kernel -sed -i "s@%{VERSION}@$VERSION@g" ./grub/boot/grub/grub.cfg + sed -i "s@%{VERSION}@$VERSION@g" ./grub/boot/grub/grub.cfg -grub-mkrescue -o aphrodite-grub.iso grub -cp aphrodite-grub.iso aphrodite.iso \ No newline at end of file + grub-mkrescue -o aphrodite-grub.iso grub + cp aphrodite-grub.iso aphrodite.iso +fi + +reset_version_vars \ No newline at end of file diff --git a/kernel/build.rs b/kernel/build.rs new file mode 100644 index 0000000..59a6e75 --- /dev/null +++ b/kernel/build.rs @@ -0,0 +1,26 @@ +fn main() { + let env = std::env::vars(); + + // 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_PREUSER_OUTPUT_DEBUG, values("true", "false", none()))"#); + println!(r#"cargo:rustc-check-cfg=cfg(CONFIG_PREUSER_OUTPUT_INFO, values("true", "false", none()))"#); + println!(r#"cargo:rustc-check-cfg=cfg(CONFIG_PREUSER_OUTPUT_WARN, values("true", "false", none()))"#); + println!(r#"cargo:rustc-check-cfg=cfg(CONFIG_PREUSER_OUTPUT_ERROR, values("true", "false", none()))"#); + println!(r#"cargo:rustc-check-cfg=cfg(CONFIG_PREUSER_OUTPUT_FATAL, values("true", "false", none()))"#); + // End checks + + // Configuration name used when a config is required but should always evaluate to true + println!(r#"cargo:rustc-check-cfg=cfg(NONE, values("false", none()))"#); + + for (var, val) in env { + if !var.starts_with("CONFIG_") { + continue + } + println!("cargo:rerun-if-env-changed={}", var); + println!("cargo:rustc-cfg={}=\"{}\"", var, val); + } +} \ No newline at end of file diff --git a/kernel/config.aphro.example b/kernel/config.aphro.example new file mode 100644 index 0000000..6a856b8 --- /dev/null +++ b/kernel/config.aphro.example @@ -0,0 +1,23 @@ +# config.aphro for aphrodite devel-83f6c5c-out-of-tree + +# Begin metadata + +# Set VERSION=generate to attempt to autogenerate a version based on git information +VERSION=generate +# SUFFIX is unset + +# End metadata + +# Begin configs +CONFIG_DISABLE_MULTIBOOT2_SUPPORT=false +CONFIG_PREUSER_HALT_ON_PANIC=false +CONFIG_PREUSER_SPIN_ON_PANIC=true + +CONFIG_PREUSER_OUTPUT_DEBUG=true +CONFIG_PREUSER_OUTPUT_INFO=true +CONFIG_PREUSER_OUTPUT_WARN=true +CONFIG_PREUSER_OUTPUT_ERROR=true +CONFIG_PREUSER_OUTPUT_FATAL=true + +CONFIG_BUILD_GRUB=true +# End configs \ No newline at end of file diff --git a/kernel/functions b/kernel/functions index e2d2f1a..f5fc796 100644 --- a/kernel/functions +++ b/kernel/functions @@ -1,10 +1,10 @@ function get_version() { local TEMP_SUFFIX + if [[ $VERSION = "generate" ]]; then + unset VERSION + fi if git diff-index HEAD -- 2>&1 > /dev/null then - echo -n - # N/A - else TEMP_SUFFIX="-out-of-tree" fi SUFFIX="$SUFFIX$TEMP_SUFFIX" diff --git a/kernel/grub/boot/aphrodite.kernel b/kernel/grub/boot/aphrodite.kernel index f2713ed..b8503b0 100755 Binary files a/kernel/grub/boot/aphrodite.kernel and b/kernel/grub/boot/aphrodite.kernel differ diff --git a/kernel/grub/boot/grub/grub.cfg b/kernel/grub/boot/grub/grub.cfg index 99a2758..bd79404 100644 --- a/kernel/grub/boot/grub/grub.cfg +++ b/kernel/grub/boot/grub/grub.cfg @@ -1,8 +1,8 @@ set timeout=15 set default=0 -menuentry "Aphrodite" --class aphrodite --class kernel --class os $menuentry_id_option 'aphrodite-basic-devel-0b87ccb' { - echo 'Loading Aphrodite aphrodite-devel-0b87ccb ...' +menuentry "Aphrodite" --class aphrodite --class kernel --class os $menuentry_id_option 'aphrodite-basic-generate' { + echo 'Loading Aphrodite aphrodite-generate ...' multiboot2 /boot/aphrodite.kernel boot } \ No newline at end of file diff --git a/kernel/kernel.flat b/kernel/kernel.flat index f2713ed..b8503b0 100755 Binary files a/kernel/kernel.flat and b/kernel/kernel.flat differ diff --git a/kernel/src/include/arch/x86/interrupts.rs b/kernel/src/include/arch/x86/interrupts.rs index 46c1c61..ab69402 100644 --- a/kernel/src/include/arch/x86/interrupts.rs +++ b/kernel/src/include/arch/x86/interrupts.rs @@ -15,6 +15,13 @@ pub fn interrupts_enabled() -> bool { (flags & (1 << 9)) == 0 } +/// Disables interrupts. +pub fn disable_interrupts() { + unsafe { + asm!("cli") + } +} + /// Disables interrupts and returns the value of them. pub fn pop_irq() -> u32 { let flags: u32; diff --git a/kernel/src/include/arch/x86/output.rs b/kernel/src/include/arch/x86/output.rs index 8ab15c5..4ccdddf 100644 --- a/kernel/src/include/arch/x86/output.rs +++ b/kernel/src/include/arch/x86/output.rs @@ -6,31 +6,102 @@ use super::ports; use paste::paste; macro_rules! message_funcs { - ($func_name:ident, $prefix:literal) => { + ($func_name:ident, $prefix:literal, $level:ident) => { paste! { /// Outputs a $func_name message &str to the debug serial port. pub fn [< s $func_name s >](s: &str) { + if cfg!($level = "false") { + return + } ports::outbs(super::DEBUG_PORT, $prefix.as_bytes()); ports::outbs(super::DEBUG_PORT, s.as_bytes()); } + /// Outputs a $func_name message &str and a newline to the debug serial port. + pub fn [< s $func_name sln >](s: &str) { + if cfg!($level = "false") { + return + } + ports::outbs(super::DEBUG_PORT, $prefix.as_bytes()); + ports::outbs(super::DEBUG_PORT, s.as_bytes()); + ports::outb(super::DEBUG_PORT, b'\n'); + } + /// Outputs a $func_name message &\[u8] to the debug serial port. pub fn [< s $func_name b >](s: &[u8]) { + if cfg!($level = "false") { + return + } ports::outbs(super::DEBUG_PORT, $prefix.as_bytes()); ports::outbs(super::DEBUG_PORT, s); } + /// Outputs a $func_name message &\[u8] and a newline to the debug serial port. + pub fn [< s $func_name bln >](s: &[u8]) { + if cfg!($level = "false") { + return + } + ports::outbs(super::DEBUG_PORT, $prefix.as_bytes()); + ports::outbs(super::DEBUG_PORT, s); + ports::outb(super::DEBUG_PORT, b'\n'); + } + /// Outputs a(n) $func_name message u8 to the debug serial port. pub fn [< s $func_name u >](s: u8) { + if cfg!($level = "false") { + return + } ports::outbs(super::DEBUG_PORT, $prefix.as_bytes()); ports::outb(super::DEBUG_PORT, s); } + + /////////////////////////////////////////////////////////////// + + /// Outputs a $func_name message &str to the debug serial port without a prefix. + pub fn [< s $func_name snp >](s: &str) { + if cfg!($level = "false") { + return + } + ports::outbs(super::DEBUG_PORT, s.as_bytes()); + } + /// Outputs a $func_name message &str and a newline to the debug serial port without a prefix. + pub fn [< s $func_name snpln >](s: &str) { + if cfg!($level = "false") { + return + } + ports::outbs(super::DEBUG_PORT, s.as_bytes()); + ports::outb(super::DEBUG_PORT, b'\n'); + } + + /// Outputs a $func_name message &\[u8] to the debug serial port without a prefix. + pub fn [< s $func_name bnp >](s: &[u8]) { + if cfg!($level = "false") { + return + } + ports::outbs(super::DEBUG_PORT, s); + } + /// Outputs a $func_name message &\[u8] and a newline to the debug serial port without a prefix. + pub fn [< s $func_name bnpln >](s: &[u8]) { + if cfg!($level = "false") { + return + } + ports::outbs(super::DEBUG_PORT, s); + ports::outb(super::DEBUG_PORT, b'\n'); + } + + /// Outputs a(n) $func_name message u8 to the debug serial port without a prefix. + pub fn [< s $func_name unp >](s: u8) { + if cfg!($level = "false") { + return + } + ports::outb(super::DEBUG_PORT, s); + } } } } -message_funcs!(debug, "[DEBUG] "); -message_funcs!(info, "[INFO] "); -message_funcs!(warning, "[WARN] "); -message_funcs!(error, "[ERROR] "); -message_funcs!(fatal, "[FATAL] "); -message_funcs!(output, ""); +message_funcs!(debug, "[DEBUG] ", CONFIG_PREUSER_OUTPUT_DEBUG); +message_funcs!(info, "[INFO] ", CONFIG_PREUSER_OUTPUT_INFO); +message_funcs!(warning, "[WARN] ", CONFIG_PREUSER_OUTPUT_WARN); +message_funcs!(error, "[ERROR] ", CONFIG_PREUSER_OUTPUT_ERROR); +message_funcs!(fatal, "[FATAL] ", CONFIG_PREUSER_OUTPUT_FATAL); +message_funcs!(output, "", NONE); diff --git a/kernel/src/internal/arch/x86/entry.rs b/kernel/src/internal/arch/x86/entry.rs index a04d06a..ad4b76b 100644 --- a/kernel/src/internal/arch/x86/entry.rs +++ b/kernel/src/internal/arch/x86/entry.rs @@ -2,12 +2,14 @@ #![no_std] #![no_main] #![warn(missing_docs)] +#![allow(unexpected_cfgs)] #![feature(ptr_metadata)] use core::{arch::asm, ffi::CStr, panic::PanicInfo}; use aphrodite::multiboot2::{BootInfo, CString, ColorInfo, FramebufferInfo, MemoryMap, PaletteColorDescriptor, RawMemoryMap, RootTag, Tag}; use aphrodite::arch::x86::output::*; +#[cfg(not(CONFIG_DISABLE_MULTIBOOT2_SUPPORT))] #[unsafe(link_section = ".multiboot2")] #[unsafe(no_mangle)] static MULTIBOOT2_HEADER: [u8; 29] = [ @@ -17,7 +19,7 @@ static MULTIBOOT2_HEADER: [u8; 29] = [ 0xe9, 0x55, 0x00, 0x00, 0x00 ]; -// The root tag, provided directly from the multiboot bootloader. +// 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 { @@ -40,30 +42,36 @@ static mut MAGIC: u32 = 0xFFFFFFFF; #[unsafe(no_mangle)] extern "C" fn _start() -> ! { 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. + // we force using ebx and eax as the output of an empty assembly block to let it know. asm!( - "mov ebx, ebx", out("ebx") O, // Bootloader-specific data(ebx) - out("eax") MAGIC, // Magic number(eax) + "", out("ebx") O, // Bootloader-specific data(ebx) + out("eax") MAGIC, // Magic number(eax) options(nomem, nostack, preserves_flags, pure) ); } unsafe { match MAGIC { + #[cfg(not(CONFIG_DISABLE_MULTIBOOT2_SUPPORT))] 0x36D76289 => { // Multiboot2 RT = O as *const RootTag; // This is unsafe rust! We can do whatever we want! *manical laughter* - sdebugs("Total boot info length: "); - soutputb(&aphrodite::u32_as_u8_slice((*RT).total_len)); - soutputu(b'\n'); + sdebugs("Total boot info length is "); + sdebugbnp(&aphrodite::u32_as_u8_slice((*RT).total_len)); + sdebugunp(b'\n'); - sdebugs("Root tag address is: "); - soutputb(&aphrodite::usize_as_u8_slice(O as usize)); - soutputu(b'\n'); + sdebugs("Root tag address is "); + sdebugbnp(&aphrodite::usize_as_u8_slice(O as usize)); + sdebugunp(b'\n'); if (*RT).total_len<16 { // Size of root tag+size of terminating tag. Something's up. panic!("total length < 16") } - soutputu(b'\n'); + let end_addr = O as usize+(*RT).total_len as usize; + + sdebugunp(b'\n'); let mut ptr = O as usize; ptr += size_of::(); @@ -71,19 +79,14 @@ extern "C" fn _start() -> ! { let mut current_tag = core::ptr::read_volatile(ptr as *const Tag); loop { - sdebugs("Tag address is: "); - soutputb(&aphrodite::usize_as_u8_slice(ptr)); - soutputu(b'\n'); + sdebugs("Tag address is "); + sdebugbnpln(&aphrodite::usize_as_u8_slice(ptr)); - sdebugs("Tag type is: "); - soutputb(&aphrodite::u32_as_u8_slice(current_tag.tag_type)); - soutputu(b'\n'); + sdebugs("Tag type is "); + sdebugbnpln(&aphrodite::u32_as_u8_slice(current_tag.tag_type)); - sdebugs("Tag length is: "); - soutputb(&aphrodite::u32_as_u8_slice(current_tag.tag_len)); - soutputu(b'\n'); - - soutputu(b'\n'); + sdebugs("Tag length is "); + sdebugbnpln(&aphrodite::u32_as_u8_slice(current_tag.tag_len)); match current_tag.tag_type { 0 => { // Ending tag @@ -188,14 +191,16 @@ extern "C" fn _start() -> ! { BI.framebuffer_info = Some((*framebufferinfo).clone()); BI.color_info = Some(colorinfo); }, - 4294967295 => { // oh no, THIS bug happened - panic!("your code is fucked up") - }, _ => { // Unknown/unimplemented tag type, ignore - // TODO: Add info message + sinfos("Unknown tag type "); + sinfobnpln(&aphrodite::u32_as_u8_slice(current_tag.tag_type)); } } + sinfounp(b'\n'); ptr = ptr + current_tag.tag_len as usize; + if ptr>end_addr { + panic!("current tag length would put pointer out-of-bounds") + } current_tag = core::ptr::read_volatile(ptr as *const Tag); } }, @@ -210,13 +215,28 @@ extern "C" fn _start() -> ! { #[unsafe(link_section = ".panic")] #[panic_handler] -fn handle_panic(info: &PanicInfo) -> ! { +#[cfg(not(CONFIG_PREUSER_HALT_ON_PANIC = "false"))] +fn halt_on_panic(info: &PanicInfo) -> ! { let message = info.message().as_str().unwrap_or(""); if message != "" { sfatals(message); aphrodite::arch::x86::ports::outb(aphrodite::arch::x86::DEBUG_PORT, b'\n'); } + aphrodite::arch::x86::interrupts::disable_interrupts(); unsafe { asm!("hlt", options(noreturn)); } +} + +#[unsafe(link_section = ".panic")] +#[panic_handler] +#[cfg(all(CONFIG_PREUSER_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 != "" { + sfatals(message); + aphrodite::arch::x86::ports::outb(aphrodite::arch::x86::DEBUG_PORT, b'\n'); + } + aphrodite::arch::x86::interrupts::disable_interrupts(); + loop {} } \ No newline at end of file