This commit is contained in:
Piotr Siuszko 2021-09-26 19:37:21 +02:00
commit 692e770cf2
9 changed files with 323 additions and 0 deletions

9
.cargo/config.toml Normal file
View File

@ -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"

14
.gitignore vendored Normal file
View File

@ -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

21
Cargo.toml Normal file
View File

@ -0,0 +1,21 @@
[package]
name = "chrustos"
version = "0.1.0"
authors = ["Piotr <siuszko@zoho.com>"]
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={}"
]

10
Makefile Normal file
View File

@ -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

15
chrustos.json Normal file
View File

@ -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"
}

31
src/color.rs Normal file
View File

@ -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))
}
}

54
src/cursor.rs Normal file
View File

@ -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(())
}
}

50
src/main.rs Normal file
View File

@ -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();
}
}

119
src/vga_buffer.rs Normal file
View File

@ -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<Writer> = 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();
}