A repository for a long-term OS project titled DasOS (named after the Greek for "forest")

Redoing the whole thing

-283
-2
.cargo/config.toml
··· 1 - [unstable] 2 - bindeps = true
-15
Cargo.toml
··· 1 - [package] 2 - name = "dasos" 3 - version = "0.1.0" 4 - edition = "2024" 5 - default-run = "dasos" 6 - 7 - [workspace] 8 - members = ["kernel"] 9 - 10 - [dependencies] 11 - ovmf-prebuilt = "0.2.4" 12 - 13 - [build-dependencies] 14 - kernel = { path = "kernel", artifact = "bin", target = "x86_64-unknown-none" } 15 - bootloader = "0.11.3"
-20
build.rs
··· 1 - use bootloader::DiskImageBuilder; 2 - use std::{env, path::PathBuf}; 3 - 4 - fn main() { 5 - // set by cargo for the kernel artifact dependency 6 - let kernel_path = env::var("CARGO_BIN_FILE_KERNEL").unwrap(); 7 - let disk_builder = DiskImageBuilder::new(PathBuf::from(kernel_path)); 8 - 9 - // specify output paths 10 - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); 11 - let uefi_path = out_dir.join("dasos-uefi.img"); 12 - let bios_path = out_dir.join("dasos-bios.img"); 13 - 14 - // create the disk images 15 - disk_builder.create_uefi_image(&uefi_path).unwrap(); 16 - disk_builder.create_bios_image(&bios_path).unwrap(); 17 - 18 - println!("cargo:rustc-env=UEFI_IMAGE={}", uefi_path.display()); 19 - println!("cargo:rustc-env=BIOS_IMAGE={}", bios_path.display()); 20 - }
-18
kernel/Cargo.toml
··· 1 - [package] 2 - name = "kernel" 3 - version = "0.1.0" 4 - edition = "2024" 5 - 6 - [dependencies] 7 - bootloader_api = "0.11.2" 8 - embedded-graphics = "0.8.1" 9 - log = { version = "0.4.17", default-features = false } 10 - bootloader-x86_64-common = "0.11.3" 11 - conquer-once = { version = "0.4.0", default-features = false } 12 - x86_64 = "0.15.2" 13 - lazy_static = { version = "1.5.0", features = ["spin_no_std"] } 14 - 15 - [[bin]] 16 - name = "kernel" 17 - test = true 18 - bench = false
-107
kernel/src/framebuffer.rs
··· 1 - use bootloader_api::info::{FrameBuffer, PixelFormat}; 2 - use embedded_graphics::{Pixel, draw_target::DrawTarget, geometry::{OriginDimensions, Size}, pixelcolor::{Rgb888, RgbColor}}; 3 - 4 - #[derive(Debug, Clone, Copy, PartialEq, Eq)] 5 - pub struct Position { 6 - pub x: usize, 7 - pub y: usize 8 - } 9 - 10 - #[derive(Debug, Clone, Copy, PartialEq, Eq)] 11 - pub struct Color { 12 - pub red: u8, 13 - pub green: u8, 14 - pub blue: u8 15 - } 16 - 17 - pub fn set_pixel_in(framebuffer: &mut FrameBuffer, position: Position, color: Color) { 18 - let info = framebuffer.info(); 19 - 20 - // calculate offset to first byte of pixel 21 - let byte_offset = { 22 - // use stride to calculate pixel offset of target line 23 - let line_offset = position.y * info.stride; 24 - // add x position to get the absolute pixel offset in buffer 25 - let pixel_offset = line_offset + position.x; 26 - // convert to byte offest 27 - pixel_offset * info.bytes_per_pixel 28 - }; 29 - 30 - // set pixel based on color format 31 - let pixel_buffer = &mut framebuffer.buffer_mut()[byte_offset..]; 32 - 33 - match info.pixel_format { 34 - PixelFormat::Rgb => { 35 - pixel_buffer[0] = color.red; 36 - pixel_buffer[1] = color.green; 37 - pixel_buffer[2] = color.blue; 38 - }, 39 - PixelFormat::Bgr => { 40 - pixel_buffer[0] = color.blue; 41 - pixel_buffer[1] = color.green; 42 - pixel_buffer[2] = color.red; 43 - }, 44 - PixelFormat::U8 => { 45 - // use a simp;le average-based grayscale transform 46 - let gray = color.red / 3 + color.green / 3 + color.blue / 3; 47 - pixel_buffer[0] = gray; 48 - }, 49 - other => panic!("unknown pixel format {other:?}"), 50 - } 51 - } 52 - 53 - pub struct Display<'f> { 54 - framebuffer: &'f mut FrameBuffer 55 - } 56 - 57 - impl<'f> Display<'f> { 58 - pub fn new(framebuffer: &'f mut FrameBuffer) -> Display<'f> { 59 - Display { framebuffer } 60 - } 61 - 62 - fn draw_pixel(&mut self, Pixel(coordinates, color): Pixel<Rgb888>) { 63 - // ignore any out of bounds pixels 64 - let (width, height) = { 65 - let info = self.framebuffer.info(); 66 - 67 - (info.width, info.height) 68 - }; 69 - 70 - let (x, y) = { 71 - let c: (i32, i32) = coordinates.into(); 72 - (c.0 as usize, c.1 as usize) 73 - }; 74 - 75 - if (0..width).contains(&x) && (0..height).contains(&y) { 76 - let color = Color { red: color.r(), green: color.g(), blue: color.b() }; 77 - 78 - set_pixel_in(self.framebuffer, Position { x, y }, color); 79 - } 80 - } 81 - } 82 - 83 - impl<'f> DrawTarget for Display<'f> { 84 - type Color = Rgb888; 85 - 86 - /// Drawing operations can never fail. 87 - type Error = core::convert::Infallible; 88 - 89 - fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error> 90 - where 91 - I: IntoIterator<Item = Pixel<Self::Color>>, 92 - { 93 - for pixel in pixels.into_iter() { 94 - self.draw_pixel(pixel); 95 - } 96 - 97 - Ok(()) 98 - } 99 - } 100 - 101 - impl<'f> OriginDimensions for Display<'f> { 102 - fn size(&self) -> Size { 103 - let info = self.framebuffer.info(); 104 - 105 - Size::new(info.width as u32, info.height as u32) 106 - } 107 - }
-18
kernel/src/interrupts.rs
··· 1 - use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; 2 - use lazy_static::lazy_static; 3 - 4 - lazy_static! { 5 - static ref IDT: InterruptDescriptorTable = { 6 - let mut idt = InterruptDescriptorTable::new(); 7 - idt.breakpoint.set_handler_fn(breakpoint_handler); 8 - idt 9 - }; 10 - } 11 - 12 - pub fn init_idt() { 13 - IDT.load(); 14 - } 15 - 16 - extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { 17 - log::info!("Exception: Breakpoint\n{:#?}", stack_frame); 18 - }
-53
kernel/src/main.rs
··· 1 - #![no_std] 2 - #![no_main] 3 - #![feature(abi_x86_interrupt)] 4 - 5 - use core::panic::PanicInfo; 6 - use bootloader_api::{BootInfo, info::FrameBufferInfo}; 7 - use conquer_once::spin::OnceCell; 8 - use bootloader_x86_64_common::logger::LockedLogger; 9 - 10 - mod framebuffer; 11 - mod interrupts; 12 - 13 - pub(crate) static LOGGER: OnceCell<LockedLogger> = OnceCell::uninit(); 14 - 15 - #[panic_handler] 16 - fn panic(_info: &PanicInfo) -> ! { 17 - loop {} 18 - } 19 - 20 - pub(crate) fn init_logger(buffer: &'static mut [u8], info: FrameBufferInfo) { 21 - let logger = LOGGER.get_or_init(move || LockedLogger::new(buffer, info, true, false)); 22 - log::set_logger(logger).expect("Logger already set"); 23 - log::set_max_level(log::LevelFilter::Trace); 24 - log::info!("Hello, Kernel Mode!"); 25 - } 26 - 27 - bootloader_api::entry_point!(kernel_main); 28 - 29 - fn kernel_main(boot_info: &'static mut BootInfo) -> ! { 30 - // free the doubly wrapped framebuffer from the boot info struct 31 - let frame_buffer_optional = &mut boot_info.framebuffer; 32 - 33 - // free the wrapped framebuffer from the FFI-safe abstraction provided by bootloader_api 34 - let frame_buffer_option = frame_buffer_optional.as_mut(); 35 - 36 - // unwrap the framebuffer 37 - let frame_buffer_struct = frame_buffer_option.unwrap(); 38 - 39 - // extract the framebuffer info and, to satisfy the borrow checker, clone it 40 - let frame_buffer_info = frame_buffer_struct.info().clone(); 41 - 42 - // get the framebuffer's mutable raw byte slice 43 - let raw_frame_buffer = frame_buffer_struct.buffer_mut(); 44 - 45 - // finally, initialize the logger using the last two variables 46 - init_logger(raw_frame_buffer, frame_buffer_info); 47 - 48 - interrupts::init_idt(); 49 - 50 - x86_64::instructions::interrupts::int3(); 51 - 52 - loop {} 53 - }
-5
rust-toolchain.toml
··· 1 - [toolchain] 2 - channel = "nightly" 3 - profile = "default" 4 - targets = ["x86_64-unknown-none"] 5 - components = ["rust-src", "llvm-tools-preview"]
-11
src/bin/qemu-bios.rs
··· 1 - use std::{env, process::{self, Command}}; 2 - 3 - fn main() { 4 - let mut qemu = Command::new("qemu-system-x86_64"); 5 - qemu.arg("-drive"); 6 - qemu.arg(format!("format=raw,file={}", env!("BIOS_IMAGE"))); 7 - qemu.arg("-serial"); 8 - qemu.arg("stdio"); 9 - let exit_status = qemu.status().unwrap(); 10 - process::exit(exit_status.code().unwrap_or(-1)); 11 - }
-21
src/bin/qemu-uefi.rs
··· 1 - use std::{env, process::{self, Command}}; 2 - use ovmf_prebuilt::{Arch, FileType, Prebuilt, Source}; 3 - 4 - fn main() { 5 - let prebuilt = Prebuilt::fetch(Source::LATEST, "target/ovmf").unwrap(); 6 - let ovmf_code = prebuilt.get_file(Arch::X64, FileType::Code); 7 - let ovmf_vars = prebuilt.get_file(Arch::X64, FileType::Vars); 8 - let mut qemu = Command::new("qemu-system-x86_64"); 9 - qemu.args([ 10 - "-drive", 11 - &format!("format=raw,if=pflash,readonly=on,file={}", ovmf_code.display()), 12 - "-drive", 13 - &format!("format=raw,if=pflash,file={}", ovmf_vars.display()), 14 - "-drive", 15 - &format!("format=raw,file={}", env!("UEFI_IMAGE")), 16 - "-serial", 17 - "stdio" 18 - ]); 19 - let exit_status = qemu.status().unwrap(); 20 - process::exit(exit_status.code().unwrap_or(-1)); 21 - }
-13
src/main.rs
··· 1 - use std::{env, fs}; 2 - 3 - fn main() { 4 - let current_exe = env::current_exe().unwrap(); 5 - let uefi_target = current_exe.with_file_name("uefi.img"); 6 - let bios_target = current_exe.with_file_name("bios.img"); 7 - 8 - fs::copy(env!("UEFI_IMAGE"), &uefi_target).unwrap(); 9 - fs::copy(env!("BIOS_IMAGE"), &bios_target).unwrap(); 10 - 11 - println!("UEFI disk image at {}", uefi_target.display()); 12 - println!("BIOS disk image at {}", bios_target.display()); 13 - }