From 692e770cf239d57ac0f872dadf29c9ce458a97d6 Mon Sep 17 00:00:00 2001 From: Piotr Siuszko Date: Sun, 26 Sep 2021 19:37:21 +0200 Subject: [PATCH] Init --- .cargo/config.toml | 9 ++++ .gitignore | 14 ++++++ Cargo.toml | 21 ++++++++ Makefile | 10 ++++ chrustos.json | 15 ++++++ src/color.rs | 31 ++++++++++++ src/cursor.rs | 54 ++++++++++++++++++++ src/main.rs | 50 +++++++++++++++++++ src/vga_buffer.rs | 119 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 323 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 Makefile create mode 100644 chrustos.json create mode 100644 src/color.rs create mode 100644 src/cursor.rs create mode 100644 src/main.rs create mode 100644 src/vga_buffer.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..154597d --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,9 @@ +[build] +target = "chrustos.json" + +[unstable] +build-std = ["core", "compiler_builtins"] +build-std-features = ["compiler-builtins-mem"] + +[target.'cfg(target_os = "none")'] +runner = "bootimage runner" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ada8be9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..df18e5f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "chrustos" +version = "0.1.0" +authors = ["Piotr "] +edition = "2018" + +[dependencies] +bootloader = "0.9.19" +x86_64 = "0.14.6" +spin = "0.5.2" + +[dependencies.lazy_static] +version = "1.0" +features = ["spin_no_std"] + +[package.metadata.bootimage] +build-command = ["build"] + +run-command = [ + "qemu-system-x86_64", "-drive", "format=raw,file={}" +] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4eafc34 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +all: + bootimage run --target=chrustos.json + +tree: + tree -A -I target + +clean: + rm -f Cargo.lock + rm -f chrustos.bin + cargo clean diff --git a/chrustos.json b/chrustos.json new file mode 100644 index 0000000..a24b987 --- /dev/null +++ b/chrustos.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", + "linker": "rust-lld", + "linker-flavor": "ld.lld", + "executables": true, + "features": "-mmx,-sse,+soft-float", + "disable-redzone": true, + "panic-strategy": "abort" +} diff --git a/src/color.rs b/src/color.rs new file mode 100644 index 0000000..3c2f532 --- /dev/null +++ b/src/color.rs @@ -0,0 +1,31 @@ +#[allow(unused)] +#[derive(Copy, Clone)] +#[repr(u8)] +pub enum Color { + Black = 0x0, + White = 0xF, + Blue = 0x1, + BrightBlue = 0x9, + Green = 0x2, + BrightGreen = 0xA, + Cyan = 0x3, + BrightCyan = 0xB, + Red = 0x4, + BrightRed = 0xC, + Magenta = 0x5, + BrightMagenta = 0xD, + Brown = 0x6, + Yellow = 0xE, + Gray = 0x7, + DarkGray = 0x8, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(transparent)] +pub struct ColorCode(u8); + +impl ColorCode { + pub fn new(foreground: Color, background: Color) -> ColorCode { + ColorCode((background as u8) << 4 | (foreground as u8)) + } +} diff --git a/src/cursor.rs b/src/cursor.rs new file mode 100644 index 0000000..d51b8af --- /dev/null +++ b/src/cursor.rs @@ -0,0 +1,54 @@ +use crate::color::Color; +use core::fmt; + +pub struct Cursor { + pub position: isize, + pub foreground: Color, + pub background: Color, +} + +impl Cursor { + pub fn color(&self) -> u8 { + let fg = self.foreground as u8; + let bg = (self.background as u8) << 4; + fg | bg + } + + pub fn print(&mut self, text: &[u8]) { + let color = self.color(); + + let framebuffer = 0xb8000 as *mut u8; + + for &character in text { + unsafe { + framebuffer.offset(self.position).write_volatile(character); + framebuffer.offset(self.position + 1).write_volatile(color); + } + self.position += 2; + } + } + pub fn clr(&mut self) { + self.position = 0; + for _ in 0..(80 * 25) { + self.print(b" "); + } + self.position = 0; + } +} + +impl Default for Cursor { + fn default() -> Self { + Cursor { + position: 0, + foreground: Color::Green, + background: Color::DarkGray, + } + } +} + +impl fmt::Write for Cursor { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.print(s.as_bytes()); + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..6e00621 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,50 @@ +#![feature(core_intrinsics)] +#![feature(lang_items)] +#![no_std] +#![no_main] + +use core::fmt::Write; +use core::panic::PanicInfo; + +use x86_64::instructions::hlt; + +mod color; +mod cursor; +mod vga_buffer; +use color::{Color, ColorCode}; +use cursor::Cursor; +use vga_buffer::*; + +pub fn print_something() { + let mut writer = Writer { + column_position: 0, + color_code: ColorCode::new(Color::Yellow, Color::Black), + buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, + }; + + writer.write_byte(b'H'); + writer.write_string("ello "); + writer.write_string("Wörld!\n"); + writer.write_string("Awruk!\n"); +} + +#[panic_handler] +#[no_mangle] +pub fn panic(info: &PanicInfo) -> ! { + println!("{}", info); + + loop { + hlt(); + } +} + +#[no_mangle] +pub extern "C" fn _start() -> ! { + print_something(); + println!("DSADSA"); + println!("Test {}", 5132.31); + // panic!("help!"); + loop { + hlt(); + } +} diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs new file mode 100644 index 0000000..9564302 --- /dev/null +++ b/src/vga_buffer.rs @@ -0,0 +1,119 @@ +use crate::color::{Color, ColorCode}; +use core::fmt; +use lazy_static::lazy_static; +use spin::Mutex; + +lazy_static! { + pub static ref WRITER: Mutex = Mutex::new(Writer { + column_position: 0, + color_code: ColorCode::new(Color::Yellow, Color::Black), + buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, + }); +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(C)] +pub struct ScreenChar { + ascii_character: u8, + color_code: ColorCode, +} + +const BUFFER_HEIGHT: usize = 25; +const BUFFER_WIDTH: usize = 80; + +#[repr(transparent)] +pub struct Buffer { + chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], +} + +pub struct Writer { + pub column_position: usize, + pub color_code: ColorCode, + pub buffer: &'static mut Buffer, +} + +impl Writer { + pub fn write_byte(&mut self, byte: u8) { + match byte { + b'\n' => self.new_line(), + byte => { + if self.column_position >= BUFFER_WIDTH { + self.new_line(); + } + + let row = BUFFER_HEIGHT - 1; + let col = self.column_position; + + let color_code = self.color_code; + let screen_char = ScreenChar { + ascii_character: byte, + color_code, + }; + unsafe { + core::ptr::write_volatile(&mut self.buffer.chars[row][col], screen_char); + } + self.column_position += 1; + } + } + } + + pub fn write_string(&mut self, s: &str) { + for byte in s.bytes() { + match byte { + // printable ASCII byte or newline + 0x20..=0x7e | b'\n' => self.write_byte(byte), + // not part of printable ASCII range + _ => self.write_byte(0xfe), + } + } + } + + fn new_line(&mut self) { + for row in 1..BUFFER_HEIGHT { + for col in 0..BUFFER_WIDTH { + unsafe { + let screen_char = core::ptr::read_volatile(&self.buffer.chars[row][col]); + core::ptr::write_volatile(&mut self.buffer.chars[row - 1][col], screen_char); + } + } + } + self.clear_row(BUFFER_HEIGHT - 1); + self.column_position = 0; + } + + fn clear_row(&mut self, row: usize) { + let blank = ScreenChar { + ascii_character: b' ', + color_code: self.color_code, + }; + for col in 0..BUFFER_WIDTH { + unsafe { + core::ptr::write_volatile(&mut self.buffer.chars[row][col], blank); + } + } + } +} + +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write_string(s); + Ok(()) + } +} + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::vga_buffer::_print(format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); +} + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + use core::fmt::Write; + WRITER.lock().write_fmt(args).unwrap(); +}