diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..b814980 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,7 @@ +[target.'cfg(target_os = "none")'] +runner = "cargo run --package simple_boot --" + +[alias] +kbuild = "build --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem" +kimage = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem -- --no-run" +krun = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem" \ No newline at end of file diff --git a/.idea/windows.iml b/.idea/windows.iml index c254557..00f776b 100644 --- a/.idea/windows.iml +++ b/.idea/windows.iml @@ -2,6 +2,7 @@ + diff --git a/assembly/boot.asm b/assembly/boot.asm index bf4ebc7..a8bd353 100644 --- a/assembly/boot.asm +++ b/assembly/boot.asm @@ -4,29 +4,20 @@ xor ax, ax mov ds, ax +mov es,ax + +cli +mov ss,bx +mov sp,ax +sti ; set graphics mode mov ax, 00h mov ah, 0x00 int 0x10 -; write string to screen -mov bh, 0 -mov bl, 0b00001111 -mov al, 1 -mov ah, 13h -mov cx, WINDOWS_STR_END - WINDOWS_STR -mov dl, 0 -mov dh, 0 -push cs -pop es -mov bp, WINDOWS_STR -int 0x10 - - - -WINDOWS_STR: db 'microsoft windows', 0 -WINDOWS_STR_END: +; jump after bootloader +jmp 0x07E0:0x0000 times 510-($-$$) db 0 dw 0xAA55 \ No newline at end of file diff --git a/assets/logo.bmp b/assets/logo.bmp new file mode 100644 index 0000000..1ea6ea2 Binary files /dev/null and b/assets/logo.bmp differ diff --git a/simple_boot/Cargo.toml b/simple_boot/Cargo.toml new file mode 100644 index 0000000..5302cdb --- /dev/null +++ b/simple_boot/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "simple_boot" +version = "0.1.0" +authors = ["Philipp Oppermann "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bootloader-locator = "0.0.4" # for locating the `bootloader` dependency on disk +locate-cargo-manifest = "0.2.0" # for locating the kernel's `Cargo.toml` diff --git a/simple_boot/src/main.rs b/simple_boot/src/main.rs new file mode 100644 index 0000000..92814ba --- /dev/null +++ b/simple_boot/src/main.rs @@ -0,0 +1,78 @@ +use std::{ + path::{Path, PathBuf}, + process::Command, +}; + +const RUN_ARGS: &[&str] = &["--no-reboot", "-s"]; + +fn main() { + let mut args = std::env::args().skip(1); // skip executable name + + let kernel_binary_path = { + let path = PathBuf::from(args.next().unwrap()); + path.canonicalize().unwrap() + }; + let no_boot = if let Some(arg) = args.next() { + match arg.as_str() { + "--no-run" => true, + other => panic!("unexpected argument `{}`", other), + } + } else { + false + }; + + let bios = create_disk_images(&kernel_binary_path); + + if no_boot { + println!("Created disk image at `{}`", bios.display()); + return; + } + + let mut run_cmd = Command::new("qemu-system-x86_64"); + run_cmd + .arg("-drive") + .arg(format!("format=raw,file={}", bios.display())); + run_cmd.args(RUN_ARGS); + + let exit_status = run_cmd.status().unwrap(); + if !exit_status.success() { + std::process::exit(exit_status.code().unwrap_or(1)); + } +} + +pub fn create_disk_images(kernel_binary_path: &Path) -> PathBuf { + let bootloader_manifest_path = bootloader_locator::locate_bootloader("bootloader").unwrap(); + let kernel_manifest_path = locate_cargo_manifest::locate_manifest().unwrap(); + + let mut build_cmd = Command::new(env!("CARGO")); + build_cmd.current_dir(bootloader_manifest_path.parent().unwrap()); + build_cmd.arg("builder"); + build_cmd + .arg("--kernel-manifest") + .arg(&kernel_manifest_path); + build_cmd.arg("--kernel-binary").arg(&kernel_binary_path); + build_cmd + .arg("--target-dir") + .arg(kernel_manifest_path.parent().unwrap().join("target")); + build_cmd + .arg("--out-dir") + .arg(kernel_binary_path.parent().unwrap()); + build_cmd.arg("--quiet"); + + if !build_cmd.status().unwrap().success() { + panic!("build failed"); + } + + let kernel_binary_name = kernel_binary_path.file_name().unwrap().to_str().unwrap(); + let disk_image = kernel_binary_path + .parent() + .unwrap() + .join(format!("boot-bios-{}.img", kernel_binary_name)); + if !disk_image.exists() { + panic!( + "Disk image does not exist at {} after bootloader build", + disk_image.display() + ); + } + disk_image +} diff --git a/src/font.rs b/src/font.rs new file mode 100644 index 0000000..b70819d --- /dev/null +++ b/src/font.rs @@ -0,0 +1,134 @@ +#![no_std] + +pub const NOTHING_TO_DISPLAY: [u8; 8] = [0x00; 8]; + +pub const BASIC_LEGACY: [[u8; 8]; 128] = [ + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + NOTHING_TO_DISPLAY, + [0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00], + [0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00], + [0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00], + [0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00], + [0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00], + [0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00], + [0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00], + [0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00], + [0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06], + [0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00], + [0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00], + [0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00], + [0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00], + [0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00], + [0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00], + [0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00], + [0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00], + [0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00], + [0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00], + [0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00], + [0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00], + [0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00], + [0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06], + [0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00], + [0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00], + [0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00], + [0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00], + [0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00], + [0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00], + [0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00], + [0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00], + [0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00], + [0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00], + [0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00], + [0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00], + [0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00], + [0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], + [0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00], + [0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00], + [0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00], + [0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00], + [0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00], + [0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00], + [0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00], + [0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00], + [0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00], + [0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00], + [0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], + [0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00], + [0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00], + [0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00], + [0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00], + [0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00], + [0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00], + [0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00], + [0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00], + [0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00], + [0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF], + [0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00], + [0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00], + [0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00], + [0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00], + [0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00], + [0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00], + [0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00], + [0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F], + [0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00], + [0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], + [0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E], + [0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00], + [0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], + [0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00], + [0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00], + [0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00], + [0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F], + [0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78], + [0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00], + [0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00], + [0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00], + [0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00], + [0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00], + [0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00], + [0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00], + [0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F], + [0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00], + [0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00], + [0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00], + [0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00], + [0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + NOTHING_TO_DISPLAY, +]; diff --git a/src/main.rs b/src/main.rs index a1631bd..c9176ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,22 +1,153 @@ -#!no_std +#![no_std] +#![no_main] -fn print_vga_buffer(string : &str) { - // get address of VGA buffer - let mut vga_buffer = 0xb8000 as *mut u8; +use bootloader::{entry_point, BootInfo, boot_info}; +use core::panic::PanicInfo; +use bootloader::boot_info::{FrameBuffer, FrameBufferInfo, PixelFormat}; - // get length of string - let len = string.len(); +mod font; - // write string to VGA buffer - for i in 0..len { - unsafe { - *vga_buffer = string.as_bytes()[i]; - vga_buffer = vga_buffer.offset(2); + +#[derive(Clone, Copy)] +struct Point { + x: i32, + y: i32, +} + +#[derive(Clone, Copy)] +struct Colour { + r: u8, + g: u8, + b: u8, +} + + + +const RAINBOW : [Colour; 6] = [Colour{r:255,g:0,b:0}, Colour{r:255,g:127,b:0}, Colour{r:255,g:255,b:0}, Colour{r:0,g:255,b:0}, Colour{r:0,g:255,b:255}, Colour{r:0,g:0,b:255}]; + +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +fn put_pixel(x: usize, y: usize, color: Colour, fb: &mut FrameBuffer) { + let pixelwidth = fb.info().bytes_per_pixel; + let pitch = fb.info().stride * pixelwidth; + + let pixel = (y * pitch) + (x * pixelwidth); + + if fb.info().pixel_format == PixelFormat::BGR { + fb.buffer_mut()[pixel + 0] = color.b; + fb.buffer_mut()[pixel + 1] = color.g; + fb.buffer_mut()[pixel + 2] = color.r; + } else if fb.info().pixel_format == PixelFormat::RGB { + fb.buffer_mut()[pixel + 0] = color.r; + fb.buffer_mut()[pixel + 1] = color.g; + fb.buffer_mut()[pixel + 2] = color.b; + } else { + // average values + let avg = (color.r as u16 + color.g as u16 + color.b as u16) / 3; + fb.buffer_mut()[pixel + 0] = avg as u8; + } +} + +fn draw_box(x: usize, y: usize, width: usize, height: usize, color: Colour, fb: &mut FrameBuffer) { + let pixelwidth = fb.info().bytes_per_pixel; + let pitch = fb.info().stride * pixelwidth; + + for i in 0..width { + for j in 0..height { + let pixel = (y * pitch) + (x * pixelwidth) + (i * pixelwidth) + (j * pitch); + if fb.info().pixel_format == PixelFormat::BGR { + fb.buffer_mut()[pixel + 0] = color.b; + fb.buffer_mut()[pixel + 1] = color.g; + fb.buffer_mut()[pixel + 2] = color.r; + } else if fb.info().pixel_format == PixelFormat::RGB { + fb.buffer_mut()[pixel + 0] = color.r; + fb.buffer_mut()[pixel + 1] = color.g; + fb.buffer_mut()[pixel + 2] = color.b; + } else { + // average values + let avg = (color.r as u16 + color.g as u16 + color.b as u16) / 3; + fb.buffer_mut()[pixel + 0] = avg as u8; + } } } } +fn draw_char(x: usize, y: usize, c: char, color: Colour, fb: &mut FrameBuffer) { + let font = font::BASIC_LEGACY; + // font is 8x8, stored in a 2d array of bytes + let char_width = 8; + let char_height = 8; -fn main() { - print_vga_buffer("microsoft"); + let char_index = c as usize; + let char_data = font[char_index]; + + for row in 0..char_height { + for col in 0..char_width { + let bit = (char_data[row] >> col) & 1; + if bit >= 1 { + put_pixel(x + col, y + row, color, fb); + } + } + } +} + +fn draw_string(x: usize, y: usize, s: &str, color: Colour, fb: &mut FrameBuffer) { + let mut x_tmp = x; + let mut y_tmp = y; + + for c in s.chars() { + if c == '\n' { + x_tmp = x; + y_tmp += 8; + } else { + draw_char(x_tmp, y_tmp, c, color, fb); + x_tmp += 8; + } + } +} + +fn draw_rainbow_string(x: usize, y: usize, s: &str, fb: &mut FrameBuffer) { + let mut x_tmp = x; + let mut y_tmp = y; + + let mut i = 0; + + for c in s.chars() { + if c == '\n' { + x_tmp = x; + y_tmp += 8; + } else { + let color = RAINBOW[i % RAINBOW.len() as usize]; + draw_char(x_tmp, y_tmp, c, color, fb); + x_tmp += 8; + i += 1; + } + } +} + +entry_point!(main); + +fn main(boot_info: &'static mut BootInfo) -> ! { + + if let Some(framebuffer) = boot_info.framebuffer.as_mut() { + // cover the screen in a nice blue + draw_box(0, 0, framebuffer.info().horizontal_resolution, framebuffer.info().vertical_resolution, Colour{r:30,g:129,b:176}, framebuffer); + + let fb_width = framebuffer.info().horizontal_resolution; + let fb_height = framebuffer.info().vertical_resolution; + + // draw a test string + //draw_string(20, 20, "i love drinking cum\nnewline test", Colour { r: 255, g: 0, b: 255 }, framebuffer); + //draw_rainbow_string(20, 40, "gay sex", framebuffer); + + draw_string(20,20, "),:\n\n\n\nuh oh! windows error! your computer is not compatible with windows 12\n\ncontact billgate@realmicrosoft.com to fix this issue!", Colour { r: 255, g: 255, b: 255}, framebuffer); + + draw_rainbow_string((fb_width/2) - ((7*8)/2), (fb_height/2) - 4, "gay sex", framebuffer); + + } + + loop{} } \ No newline at end of file diff --git a/x86_64-custom.json b/x86_64-custom.json new file mode 100644 index 0000000..346fefd --- /dev/null +++ b/x86_64-custom.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float" +} \ No newline at end of file