42-archive/kernel-rs/src/vga/mod.rs
2018-02-21 14:09:31 +01:00

183 lines
4.9 KiB
Rust

#[macro_use]
pub mod color;
pub use self::color::{Color, ColorCode};
use ::context::CONTEXT;
use cpuio;
use ::console;
#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct ScreenChar {
ascii_character: u8,
color_code: ColorCode,
}
macro_rules! print {
($($arg:tt)*) => ({
$crate::vga::print(format_args!($($arg)*));
});
}
macro_rules! println {
($fmt:expr) => (print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}
pub fn print(args: fmt::Arguments) {
use core::fmt::Write;
unsafe { CONTEXT.current_term().write_fmt(args).unwrap() };
unsafe { CONTEXT.current_term().flush() };
}
extern crate core;
const BUFFER_ROWS: usize = 25;
const BUFFER_COLS: usize = 80 * 2;
pub struct Writer {
pub buffer_pos: usize,
pub color_code: ColorCode,
buffer: [u8; BUFFER_ROWS * BUFFER_COLS],
command: [u8; 10],
command_len: usize,
}
impl Writer {
pub const fn new() -> Writer {
Writer {
buffer_pos: 0,
color_code: ColorCode::new(Color::White, Color::Black),
buffer: [0; BUFFER_ROWS * BUFFER_COLS],
command: [b'\0'; 10],
command_len: 0,
}
}
pub fn prompt(&mut self) {
let color_code_save = self.color_code;
self.color_code = ColorCode::new(Color::Blue, Color::Black);
self.write_str("> ");
self.color_code = color_code_save;
}
pub fn backspace(&mut self) {
if self.command_len > 0 {
self.command_len -= 1;
self.erase_byte();
}
}
pub fn keypress(&mut self, ascii: u8) {
match ascii {
b'\n' => {
self.write_byte(b'\n');
{
let command: &str = &core::str::from_utf8(&self.command).unwrap()[..self.command_len];
match command {
"shutdown" | "halt" => console::shutdown(),
"reboot" => console::reboot(),
"stack" => console::print_kernel_stack(),
_ => {
let color_code_save = self.color_code;
self.color_code = ColorCode::new(Color::Red, Color::Black);
println!("`{}': Command unknown ", command);
self.color_code = color_code_save;
}
}
}
self.command_len = 0;
self.prompt();
}
byte => {
if self.command_len >= 10 { return };
self.command[self.command_len] = byte;
self.write_byte(byte);
self.command_len += 1;
}
}
self.flush();
}
pub fn erase_byte(&mut self) {
self.buffer_pos -= 2;
let i = self.buffer_pos;
self.buffer[i] = b' ';
self.buffer[i + 1] = 0;
self.flush();
}
pub fn write_byte(&mut self, byte: u8) {
let i = self.buffer_pos;
match byte {
b'\n' => {
let current_line = self.buffer_pos / (BUFFER_COLS);
self.buffer_pos = (current_line + 1) * BUFFER_COLS;
}
byte => {
self.buffer[i] = byte;
self.buffer[i + 1] = self.color_code.0;
self.buffer_pos += 2;
}
}
if self.buffer_pos >= self.buffer.len() {
self.scroll();
}
}
fn write_str(&mut self, s: &str) {
for byte in s.bytes() {
self.write_byte(byte)
}
}
fn flush_cursor(&self)
{
let cursor_position = self.buffer_pos / 2;
// 14 awaits the rightmost 8bits
cpuio::outb(14, 0x3D4);
cpuio::outb((cursor_position >> 8) as u8, 0x3D5);
// 15 awaits the leftmost 8bits
cpuio::outb(15, 0x3D4);
cpuio::outb((cursor_position >> 0) as u8 & 0x00ff, 0x3D5);
}
pub fn flush(&mut self) {
let slice = unsafe { core::slice::from_raw_parts_mut(0xb8000 as *mut u8, 4000) };
slice.as_mut().clone_from_slice(&self.buffer);
self.flush_cursor();
}
fn scroll(&mut self) {
for row in 1..BUFFER_ROWS {
for col in 0..BUFFER_COLS {
let prev_position = ((row - 1) * BUFFER_COLS) + col;
let current_position = (row * BUFFER_COLS) + col;
self.buffer[prev_position] = self.buffer[current_position];
}
}
for col in 0..BUFFER_COLS/2 {
self.buffer[((BUFFER_ROWS - 1) * BUFFER_COLS) + (col * 2)] = b' ';
}
self.buffer_pos = (BUFFER_ROWS - 1) * BUFFER_COLS;
}
}
// trait needed by formatting macros
use core::fmt;
impl fmt::Write for Writer {
fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
for byte in s.bytes() {
self.write_byte(byte)
}
Ok(())
}
}