Skip to content
Snippets Groups Projects
lib.rs 4.02 KiB
Newer Older
Jeremy Soller's avatar
Jeremy Soller committed
#![no_std]
#![feature(asm)]
Jeremy Soller's avatar
Jeremy Soller committed
#![feature(lang_items)]
#![feature(llvm_asm)]

use core::{
Jeremy Soller's avatar
Jeremy Soller committed

Jeremy Soller's avatar
Jeremy Soller committed
mod panic;

#[derive(Clone, Copy)]
#[repr(packed)]
pub struct ThunkData {
    di: u16,
    si: u16,
    bp: u16,
    sp: u16,
    bx: u16,
    dx: u16,
    cx: u16,
    ax: u16,
}

impl ThunkData {
    pub const STACK: usize = 0x7C00;

    pub fn new() -> Self {
        Self {
            di: 0,
            si: 0,
            bp: 0,
            sp: Self::STACK as u16,
            bx: 0,
            dx: 0,
            cx: 0,
            ax: 0,
        }
    }

    pub unsafe fn save(&self) {
        ptr::write((Self::STACK - 16) as *mut ThunkData, *self);
    }

    pub unsafe fn load(&mut self) {
        *self = ptr::read((Self::STACK - 16) as *const ThunkData);
    }

    pub unsafe fn with(&mut self, f: extern "C" fn()) {
        self.save();
        f();
        self.load();
    }
}

#[derive(Clone, Copy)]
#[repr(packed)]
pub struct VgaTextBlock {
    char: u8,
    color: u8,
}

#[repr(u8)]
pub enum VgaTextColor {
    Black = 0,
    Blue = 1,
    Green = 2,
    Cyan = 3,
    Red = 4,
    Purple = 5,
    Brown = 6,
    Gray = 7,
    DarkGray = 8,
    LightBlue = 9,
    LightGreen = 10,
    LightCyan = 11,
    LightRed = 12,
    LightPurple = 13,
    Yellow = 14,
    White = 15,
}

pub struct Vga {
    blocks: &'static mut [VgaTextBlock],
    width: usize,
    height: usize,
    x: usize,
    y: usize,
}

impl Vga {
    pub unsafe fn new(ptr: *mut VgaTextBlock, width: usize, height: usize) -> Self {
        Self {
            blocks: slice::from_raw_parts_mut(
                ptr,
                width * height
            ),
            width,
            height,
            x: 0,
            y: 0,
        }
    }
}

impl fmt::Write for Vga {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        for c in s.chars() {
            if self.x >= self.width {
                self.x = 0;
                self.y += 1;
            }
            while self.y >= self.height {
                for y in 1..self.height {
                    for x in 0..self.width {
                        let i = y * self.width + x;
                        let j = i - self.width;
                        self.blocks[j] = self.blocks[i];
                        if y + 1 == self.height {
                            self.blocks[i].char = 0;
                        }
                    }
                }
                self.y -= 1;
            }
            match c {
                '\r' => {
                    self.x = 0;
                },
                '\n' => {
                    self.x = 0;
                    self.y += 1;
                },
                _ => {
                    let i = self.y * self.width + self.x;
                    if let Some(block) = self.blocks.get_mut(i) {
                        block.char = c as u8;
                    }
                }
            }
            self.x += 1;
        }

        Ok(())
    }
}

Jeremy Soller's avatar
Jeremy Soller committed
#[no_mangle]
pub unsafe extern "C" fn kstart(
    thunk10: extern "C" fn(),
    thunk13: extern "C" fn(),
    thunk15: extern "C" fn(),
    thunk16: extern "C" fn(),
Jeremy Soller's avatar
Jeremy Soller committed
        // Make sure we are in mode 3 (80x25 text mode)
        let mut data = ThunkData::new();
        data.ax = 0x03;
        data.with(thunk10);
    }

Jeremy Soller's avatar
Jeremy Soller committed
    {
        // Disable cursor
        let mut data = ThunkData::new();
        data.ax = 0x0100;
        data.cx = 0x3F00;
        data.with(thunk10);
    }

    let mut vga = Vga::new(0xb8000 as *mut VgaTextBlock, 80, 25);
Jeremy Soller's avatar
Jeremy Soller committed

    for i in 0..vga.blocks.len() {
        vga.blocks[i].char = 0;
        vga.blocks[i].color =
Jeremy Soller's avatar
Jeremy Soller committed
            ((VgaTextColor::DarkGray as u8) << 4) |
            (VgaTextColor::White as u8);
    }

    writeln!(vga, "Arrow keys and space select mode, enter to continue");
Jeremy Soller's avatar
Jeremy Soller committed

Jeremy Soller's avatar
Jeremy Soller committed
        // Read keypress
        let mut data = ThunkData::new();
        data.with(thunk16);
        writeln!(
            vga,
            "'{}' 0x{:02X}",
            (data.ax as u8) as char,
            (data.ax >> 8) as u8
        );
    }
Jeremy Soller's avatar
Jeremy Soller committed
}