278 lines
6.2 KiB
Rust
278 lines
6.2 KiB
Rust
|
|
#![feature(no_std, lang_items, const_fn, asm)]
|
|
#![no_std]
|
|
|
|
#[cfg(test)]
|
|
#[macro_use]
|
|
extern crate std;
|
|
|
|
extern crate rlibc;
|
|
|
|
extern {
|
|
fn asm_printchar() -> u32;
|
|
fn get_rdtsc() -> u32;
|
|
fn call_interrupt();
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern fn rust_setup_PIC() {
|
|
PIC::setup_PIC();
|
|
}
|
|
|
|
mod PIC {
|
|
use x86_asm::{outb, inb};
|
|
|
|
const PIC1_COMMAND: u16 = 0x20;
|
|
const PIC2_COMMAND: u16 = 0xa0;
|
|
const PIC1_DATA: u16 = 0x21;
|
|
const PIC2_DATA: u16 = 0xa1;
|
|
|
|
const INITIALIZE: u8 = 0x11;
|
|
const ENVIRONMENT: u8 = 0x01; //I don't really know what this does
|
|
pub fn setup_PIC() {
|
|
|
|
let interrupt_mask1: u8 = 0xfc;
|
|
let interrupt_mask2: u8 = 0xff;
|
|
|
|
unsafe {
|
|
asm!("cli");
|
|
|
|
outb(PIC1_COMMAND, INITIALIZE);
|
|
outb(PIC2_COMMAND, INITIALIZE);
|
|
|
|
// change IRQ offsets to int 32-47
|
|
outb(PIC1_DATA, 32);
|
|
outb(PIC2_DATA, 40);
|
|
|
|
outb(PIC1_DATA, 0x4); //master: slave IRQ location (IRQ 2)
|
|
outb(PIC2_DATA, 0x2); //slave: cascade identity
|
|
|
|
outb(PIC1_DATA, ENVIRONMENT);
|
|
outb(PIC2_DATA, ENVIRONMENT);
|
|
|
|
outb(PIC1_DATA, interrupt_mask1);
|
|
outb(PIC2_DATA, interrupt_mask2);
|
|
|
|
asm!("sti");
|
|
}
|
|
}
|
|
}
|
|
|
|
mod x86_asm {
|
|
|
|
pub unsafe fn outb(port: u16, value: u8) {
|
|
asm!("outb %%dx, %%al" : : "dx" (port), "al"(value));
|
|
}
|
|
|
|
pub unsafe fn inb(port: u16) -> u8{
|
|
let inval: u8;
|
|
asm!("inb %dx, %al" : "={al}"(inval) : "{dx}"(port));
|
|
return inval;
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern fn rust_interrupt_handler() {
|
|
checkerboard(vga_buffer::Color::White);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern fn rust_handle_keyboard(x: u8) {
|
|
checkerboard(vga_buffer::Color::Green);
|
|
vga_buffer::print_u32(x as u32, 0);
|
|
}
|
|
|
|
static mut global_timer_count: u64 = 0;
|
|
|
|
#[no_mangle]
|
|
pub extern fn rust_handle_timer() {
|
|
let gtc = unsafe { global_timer_count };
|
|
unsafe {
|
|
global_timer_count += 1;
|
|
}
|
|
|
|
timer_callback(gtc);
|
|
}
|
|
|
|
fn timer_callback(count: u64) {
|
|
if count % 1000 == 0 {
|
|
checkerboard(vga_buffer::Color::White);
|
|
}
|
|
if count % 1000 == 500 {
|
|
checkerboard(vga_buffer::Color::LightCyan);
|
|
}
|
|
|
|
vga_buffer::print_u32(count as u32, 0);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern fn rust_main() {
|
|
clear();
|
|
checkerboard(vga_buffer::Color::Red);
|
|
|
|
loop {
|
|
|
|
}
|
|
}
|
|
|
|
fn clear() {
|
|
use vga_buffer::*;
|
|
|
|
let blank_color = ColorCode::new( Color::White, Color::Black);
|
|
for i in 0..BUFFER_WIDTH {
|
|
for j in 0..BUFFER_HEIGHT {
|
|
write_to_coord(i, j, b' ', blank_color);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn checkerboard(color: vga_buffer::Color) {
|
|
use vga_buffer::*;
|
|
|
|
let active = ColorCode::new(color, color);
|
|
let blank = ColorCode::new(Color::White, Color::Black);
|
|
for i in 0..BUFFER_WIDTH {
|
|
for j in 0..BUFFER_HEIGHT {
|
|
if (i + j) % 2 == 0 {
|
|
write_to_coord(i, j, b' ', active);
|
|
} else {
|
|
write_to_coord(i, j, b' ', blank);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// 123 |3,2,1
|
|
mod util {
|
|
pub fn u32_to_chars(n: u32) -> [u8; 10] {
|
|
let mut accum = [0; 10];
|
|
let mut i = 0;
|
|
let mut val = n;
|
|
loop {
|
|
if val < 10 {
|
|
let ch = b'0' + (val as u8);
|
|
accum[i] = ch;
|
|
break;
|
|
} else {
|
|
let ch = b'0' + ((val % 10) as u8);
|
|
val = val / 10;
|
|
accum[i] = ch;
|
|
i += 1;
|
|
}
|
|
}
|
|
let mut output = [0; 10];
|
|
let mut j = 0;
|
|
loop {
|
|
output[j] = accum[i];
|
|
j += 1;
|
|
if i == 0 { break; }
|
|
i -= 1;
|
|
}
|
|
|
|
output
|
|
}
|
|
|
|
#[test]
|
|
fn test_u32_to_chars() {
|
|
assert_eq!(u32_to_chars(12345), [b'1', b'2', b'3', b'4', b'5', 0, 0, 0, 0, 0]);
|
|
assert_eq!(u32_to_chars(9), [b'9', 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
|
}
|
|
}
|
|
|
|
mod vga_buffer {
|
|
#[repr(u8)]
|
|
#[derive(Clone, Copy)]
|
|
pub enum Color {
|
|
Black = 0,
|
|
Blue = 1,
|
|
Green = 2,
|
|
Cyan = 3,
|
|
Red = 4,
|
|
Magenta = 5,
|
|
Brown = 6,
|
|
LightGray = 7,
|
|
DarkGray = 8,
|
|
LightBlue = 9,
|
|
LightGreen = 10,
|
|
LightCyan = 11,
|
|
LightRed = 12,
|
|
Pink = 13,
|
|
Yellow = 14,
|
|
White = 15,
|
|
}
|
|
|
|
#[derive(Clone, Copy)]
|
|
pub struct ColorCode(u8);
|
|
impl ColorCode {
|
|
pub const fn new(foreground: Color, background: Color) -> ColorCode {
|
|
ColorCode((background as u8) << 4 | (foreground as u8))
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
struct ScreenChar {
|
|
ascii_char: u8,
|
|
color_code: ColorCode
|
|
}
|
|
|
|
pub const BUFFER_HEIGHT: usize = 25;
|
|
pub const BUFFER_WIDTH: usize = 80;
|
|
const BUFFER_PTR: usize = 0xb8000;
|
|
|
|
pub fn charloop() {
|
|
for ch in 32..255 {
|
|
let ptr = BUFFER_PTR + 2*ch as usize;
|
|
let data = ScreenChar {
|
|
ascii_char: ch,
|
|
color_code: ColorCode::new(Color::Black, Color::White)
|
|
};
|
|
|
|
unsafe {
|
|
*(ptr as *mut _) = data;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn print_array(array: [u8; 10], line: usize, color_code: ColorCode) {
|
|
let mut x = 0;
|
|
for ch in array.into_iter() {
|
|
if *ch == 0 {
|
|
break;
|
|
}
|
|
write_to_coord(x, line, *ch, color_code);
|
|
x += 1;
|
|
}
|
|
}
|
|
|
|
pub fn print_u32(num: u32, location: usize) {
|
|
let default_color = ColorCode::new(Color::Black, Color::White);
|
|
let char_array = ::util::u32_to_chars(num);
|
|
print_array(char_array, location, default_color);
|
|
}
|
|
|
|
pub fn write_to_coord(x: usize, y: usize, character: u8, color_code: ColorCode) {
|
|
let ptr = BUFFER_PTR + (2*x as usize) + (BUFFER_WIDTH*2*y as usize);
|
|
let data = ScreenChar {
|
|
ascii_char: character,
|
|
color_code: color_code,
|
|
};
|
|
|
|
if x > BUFFER_WIDTH || y > BUFFER_HEIGHT {
|
|
return;
|
|
}
|
|
|
|
unsafe {
|
|
*(ptr as *mut _) = data;
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(not(test))]
|
|
#[lang = "eh_personality"]
|
|
extern fn eh_personality() {}
|
|
|
|
#[cfg(not(test))]
|
|
#[lang = "panic_fmt"]
|
|
extern fn panic_fmt() -> ! { loop {}}
|