Files
low-level-programming/rust_experiments/src/lib.rs
greg b5e78209e6 Move PIC offsets
Can't make this work from within rust for some reason, use asm
2015-11-23 02:17:45 -08:00

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 {}}