From b945416665dd7f0b45ae0e7ca607054e40bac51c Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Tue, 25 Feb 2025 02:53:28 +0000 Subject: [PATCH 1/6] Add qemu UEFI firmware support. --- README.md | 23 ++++++++++++++++++++--- scripts/run_debug.sh | 18 ++++++++++++++++++ scripts/run_release.sh | 17 +++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 23f7e26..21d5158 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ git clone https://git.zxq5.dev/OsDev/FoundryOS.git * latest rust nightly release * all necessary rust components installed * xorriso: creates ISO images to be booted from. -* (Optional / Recommended) Qemu: to run the kernel. (this may be packaged as qemu-desktop) +* (Optional / Recommended) qemu: to run the kernel. (this may be packaged as qemu-desktop) * (Optional) GDB: for debugging the kernel. ```sh @@ -20,12 +20,29 @@ rustup component add rust-src rustup component add llvm-tools-preview ``` -## Building & Running in Qemu: +## Building & Running in qemu ```sh cargo run ``` -## Running in GDB: +## Running in GDB ```sh USE_GDB=1 cargo run ``` + +## Build errors + +If you see a qemu error like this: + +``` +qemu-system-x86_64: -drive if=pflash,format=raw,readonly=on,file=/home/jacob/Desktop/Code/FoundryOS/build/OVMF_CODE.fd: Could not open '/home/jacob/Desktop/Code/FoundryOS/build/OVMF_CODE.fd': No such file or directory +``` + +Simply delete the ./build directory and try to rebuild the program. Using the runner script or `cargo run` will download the required files for you, this is because the script only checks for the presence of one file and not the VARS file. + +Alternatively, you may disable using a UEFI firmware with qemu like so: +```sh +USE_LEGACY_BIOS=1 cargo run +``` + +If you have any other issues, feel free to create an issue or a PR. \ No newline at end of file diff --git a/scripts/run_debug.sh b/scripts/run_debug.sh index b538ce7..91bcdb6 100755 --- a/scripts/run_debug.sh +++ b/scripts/run_debug.sh @@ -135,6 +135,23 @@ else debug_flags="" fi +if [ $USE_LEGACY_BIOS ]; then + boot_flags="" +else +# Check for the presence of the OVMF firmware. + if [ ! -f $build_dir/RELEASEX64_OVMF_CODE.fd ]; then + info "Downloading OVMF UEFI firmware for QEMU" + info "To disable this, set USE_LEGACY_BIOS=1." + pushd $build_dir + curl https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF_CODE.fd -LO || error "failed to download OVMF firmware for UEFI" + curl https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF_VARS.fd -LO || error "failed to download OVMF firmware for UEFI" + popd + fi + + boot_flags="-drive if=pflash,format=raw,readonly=on,file=$build_dir/RELEASEX64_OVMF_CODE.fd \ + -drive if=pflash,format=raw,file=$build_dir/RELEASEX64_OVMF_VARS.fd" +fi + # Set up test-specific flags if [ $is_test -eq 1 ]; then test_flags="-device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none" @@ -189,5 +206,6 @@ qemu-system-x86_64 -M q35 \ -no-reboot \ ${test_flags} \ ${debug_flags} \ + ${boot_flags} \ ${QEMU_FLAGS:-} diff --git a/scripts/run_release.sh b/scripts/run_release.sh index 97f6134..c410362 100755 --- a/scripts/run_release.sh +++ b/scripts/run_release.sh @@ -131,6 +131,23 @@ fi # I'm lazy but I just remove GDB flags when running this script. debug_flags="" +if [ $USE_LEGACY_BIOS ]; then + boot_flags="" +else +# Check for the presence of the OVMF firmware. + if [ ! -f $build_dir/RELEASEX64_OVMF_CODE.fd ]; then + info "Downloading OVMF UEFI firmware for QEMU" + info "To disable this, set USE_LEGACY_BIOS=1." + pushd $build_dir + curl https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF_CODE.fd -LO || error "failed to download OVMF firmware for UEFI" + curl https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF_VARS.fd -LO || error "failed to download OVMF firmware for UEFI" + popd + fi + + boot_flags="-drive if=pflash,format=raw,readonly=on,file=$build_dir/RELEASEX64_OVMF_CODE.fd \ + -drive if=pflash,format=raw,file=$build_dir/RELEASEX64_OVMF_VARS.fd" +fi + # Set up test-specific flags if [ $is_test -eq 1 ]; then test_flags="-device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none" From 375c5aa561386156c23251e708dc4b63580f1c3e Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Tue, 25 Feb 2025 02:54:19 +0000 Subject: [PATCH 2/6] Update limine.conf to boot up faster --- config/limine.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/limine.conf b/config/limine.conf index 0988692..33e4a36 100644 --- a/config/limine.conf +++ b/config/limine.conf @@ -1,5 +1,5 @@ # Timeout in seconds that Limine will use before automatically booting. -timeout: 1 +timeout: 0 # The entry name that will be displayed in the boot menu. /foundry-os From 177fddcf7dc65a392ce0934ff6ed0616b41cd0ac Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Tue, 25 Feb 2025 02:55:52 +0000 Subject: [PATCH 3/6] Add warnings to hardware script (dd implies 'doubly dangerous') --- scripts/hardware.sh | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/scripts/hardware.sh b/scripts/hardware.sh index 5070e47..cd03a7c 100755 --- a/scripts/hardware.sh +++ b/scripts/hardware.sh @@ -1,2 +1,24 @@ #!/bin/bash -sudo dd if=./build/image.iso of="$1" + +# Colors +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +BOLD='\033[1m' +NC='\033[0m' # No Color + +info() { + echo -e "${BLUE}${BOLD}info${NC}: $1" +} + +warning() { + echo -e "${YELLOW}${BOLD}warning${NC}: $1" >&2 +} + +warning "This script will OVERWRITE whatever media you throw at it\nwith the built ISO." +info "sudo ./hardware.sh /dev/yourdisk" + +if echo "$1" | grep -q "/dev"; then + dd if=./build/image.iso of="$1" +fi From e294a13a91224d23aa66411025c2e05076e46e39 Mon Sep 17 00:00:00 2001 From: nullndvoid Date: Tue, 25 Feb 2025 02:59:55 +0000 Subject: [PATCH 4/6] Cleanup the README a little more --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 21d5158..fe03e6b 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ USE_GDB=1 cargo run If you see a qemu error like this: ``` -qemu-system-x86_64: -drive if=pflash,format=raw,readonly=on,file=/home/jacob/Desktop/Code/FoundryOS/build/OVMF_CODE.fd: Could not open '/home/jacob/Desktop/Code/FoundryOS/build/OVMF_CODE.fd': No such file or directory +qemu-system-x86_64: -drive if=pflash,format=raw,readonly=on,file=<...>/OVMF_CODE.fd: Could not open '<...>/OVMF_CODE.fd': No such file or directory ``` Simply delete the ./build directory and try to rebuild the program. Using the runner script or `cargo run` will download the required files for you, this is because the script only checks for the presence of one file and not the VARS file. From 4fe6109e5b37b36283c6f4026212c764ec70fa98 Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Tue, 25 Feb 2025 03:18:12 +0000 Subject: [PATCH 5/6] Rename scheduling to 'async_io', general cleanup --- kernel/src/main.rs | 2 +- .../drivers/{scheduling => async_io}/mod.rs | 0 .../drivers/{scheduling => async_io}/task.rs | 5 + libk/src/drivers/mod.rs | 2 +- libk/src/lib.rs | 8 +- libk/src/std/application.rs | 5 +- libk/src/std/{io => }/io.rs | 0 libk/src/std/io/mod.rs | 2 - libk/src/threads.rs | 113 ++++++++++++++++++ libk/src/util/shell.rs | 2 +- 10 files changed, 127 insertions(+), 12 deletions(-) rename libk/src/drivers/{scheduling => async_io}/mod.rs (100%) rename libk/src/drivers/{scheduling => async_io}/task.rs (95%) rename libk/src/std/{io => }/io.rs (100%) delete mode 100644 libk/src/std/io/mod.rs create mode 100644 libk/src/threads.rs diff --git a/kernel/src/main.rs b/kernel/src/main.rs index d81265e..1eb77f5 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -5,8 +5,8 @@ extern crate alloc; use libk::{ drivers::{ + async_io::task::{Executor, Task}, io, - scheduling::task::{Executor, Task}, }, prelude::*, util::shell::shell, diff --git a/libk/src/drivers/scheduling/mod.rs b/libk/src/drivers/async_io/mod.rs similarity index 100% rename from libk/src/drivers/scheduling/mod.rs rename to libk/src/drivers/async_io/mod.rs diff --git a/libk/src/drivers/scheduling/task.rs b/libk/src/drivers/async_io/task.rs similarity index 95% rename from libk/src/drivers/scheduling/task.rs rename to libk/src/drivers/async_io/task.rs index 392638b..6076917 100644 --- a/libk/src/drivers/scheduling/task.rs +++ b/libk/src/drivers/async_io/task.rs @@ -1,3 +1,8 @@ +//! Allows creation of asynchronous IO bound tasks. +//! +//! Written by @zxq5 for the most part with code from +//! [here](https://github.com/phil-opp/blog_os/). +//! use crate::prelude::*; use alloc::collections::BTreeMap; use alloc::sync::Arc; diff --git a/libk/src/drivers/mod.rs b/libk/src/drivers/mod.rs index 61ec870..f60a9af 100644 --- a/libk/src/drivers/mod.rs +++ b/libk/src/drivers/mod.rs @@ -1,3 +1,3 @@ +pub mod async_io; pub mod io; pub mod kalloc; -pub mod scheduling; diff --git a/libk/src/lib.rs b/libk/src/lib.rs index 1846161..db0af38 100644 --- a/libk/src/lib.rs +++ b/libk/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![allow(async_fn_in_trait)] +// #![allow(async_fn_in_trait)] #![warn(tail_expr_drop_order)] #![warn( clippy::correctness, @@ -12,15 +12,11 @@ rustdoc::missing_panics_doc )] -// alloc -// io : serial, framebuffer, ascii(?), keyboard -// ????? -// scheduling / tasks : async - extern crate alloc; pub mod drivers; pub mod resources; +pub mod threads; pub mod util; #[allow(unused)] // We aren't using much of this right now. diff --git a/libk/src/std/application.rs b/libk/src/std/application.rs index 44c2651..59ce535 100644 --- a/libk/src/std/application.rs +++ b/libk/src/std/application.rs @@ -7,7 +7,10 @@ mod window; pub trait Application { type Output; - async fn run(&mut self, args: Vec) -> Result; + fn run( + &mut self, + args: Vec, + ) -> impl core::future::Future> + Send; } #[derive(Debug)] diff --git a/libk/src/std/io/io.rs b/libk/src/std/io.rs similarity index 100% rename from libk/src/std/io/io.rs rename to libk/src/std/io.rs diff --git a/libk/src/std/io/mod.rs b/libk/src/std/io/mod.rs deleted file mode 100644 index 608d4e1..0000000 --- a/libk/src/std/io/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod io; -pub use io::*; diff --git a/libk/src/threads.rs b/libk/src/threads.rs new file mode 100644 index 0000000..76c2c13 --- /dev/null +++ b/libk/src/threads.rs @@ -0,0 +1,113 @@ +use core::arch::asm; + +#[repr(C)] +pub struct Thread { + id: usize, + /// This shall be default before the program is interrupted, otherwise it will store + /// CPU registers etc to be restored on context switch. + ctx: ThreadContext, +} + +/// CPU state to be saved on context switches. +#[repr(C)] +#[derive(Default)] +pub struct ThreadContext { + /// Accumulator register. + rax: u64, + /// Base register. + rbx: u64, + /// Counter register. + rcx: u64, + /// Data register. + rdx: u64, + /// Source index register. + rsi: u64, + /// Destination index register. + rdi: u64, + /// Base pointer register. + rbp: u64, + /// Stack pointer register. + rsp: u64, + /// An extended register. + r8: u64, + /// An extended register. + r9: u64, + /// An extended register. + r10: u64, + /// An extended register. + r11: u64, + /// An extended register. + r12: u64, + /// An extended register. + r13: u64, + /// An extended register. + r14: u64, + /// An extended register. + r15: u64, + /// The instruction pointer. + rip: u64, + /// RFLAGS register. + rflags: u64, +} + +impl ThreadContext { + /// Saves the current registers of the CPU before a context switch + /// to be restored later. + /// + /// # Notes + /// + /// This function should ONLY be called in interrupt handlers such + /// as that of the timer. This will then save registers as required + /// + /// + /// # Safety + /// + /// This function is unsafe because of the usage of inline ASM. + #[inline(always)] + pub unsafe fn save_registers() -> Self { + let mut context = Self::default(); + unsafe { + asm!( + "mov {0}, rax", + "mov {1}, rbx", + "mov {2}, rcx", + "mov {3}, rdx", + "mov {4}, rsi", + "mov {5}, rdi", + "mov {6}, rbp", + "mov {7}, rsp", + "mov {8}, r8", + "mov {9}, r9", + "mov {10}, r10", + "mov {11}, r11", + "mov {12}, r12", + "mov {13}, r13", + "mov {14}, r14", + "mov {15}, r15", + "lea {16}, [rip]", + "pushf", + "pop {17}", + out(reg) context.rax, + out(reg) context.rbx, + out(reg) context.rcx, + out(reg) context.rdx, + out(reg) context.rsi, + out(reg) context.rdi, + out(reg) context.rbp, + out(reg) context.rsp, + out(reg) context.r8, + out(reg) context.r9, + out(reg) context.r10, + out(reg) context.r11, + out(reg) context.r12, + out(reg) context.r13, + out(reg) context.r14, + out(reg) context.r15, + out(reg) context.rip, + out(reg) context.rflags, + ); + } + + context + } +} diff --git a/libk/src/util/shell.rs b/libk/src/util/shell.rs index fceb8ee..cf851de 100644 --- a/libk/src/util/shell.rs +++ b/libk/src/util/shell.rs @@ -1,4 +1,4 @@ -use x86_64::registers::rflags::read; +// use x86_64::registers::rflags::read; use crate::{drivers::io::ascii::clear_screen, prelude::stdin::read_line, print, println}; From b7397d8a1b42ca984c3b0633e6c821d4cc2220c9 Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Tue, 25 Feb 2025 03:20:05 +0000 Subject: [PATCH 6/6] Remove unused clippy lints --- libk/src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libk/src/lib.rs b/libk/src/lib.rs index db0af38..57f60cb 100644 --- a/libk/src/lib.rs +++ b/libk/src/lib.rs @@ -1,6 +1,4 @@ #![no_std] -// #![allow(async_fn_in_trait)] -#![warn(tail_expr_drop_order)] #![warn( clippy::correctness, clippy::nursery, @@ -9,7 +7,8 @@ clippy::suspicious, clippy::perf, rustdoc::missing_errors_doc, - rustdoc::missing_panics_doc + rustdoc::missing_panics_doc, + tail_expr_drop_order )] extern crate alloc;