some work
This commit is contained in:
parent
b75a7bc7ad
commit
da94093efc
17
Cargo.toml
17
Cargo.toml
|
@ -1,16 +1,7 @@
|
||||||
[package]
|
[workspace]
|
||||||
name = "shadeos"
|
members = [
|
||||||
version = "0.1.0"
|
"shadeos-kernel"
|
||||||
edition = "2021"
|
]
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
crate-type = ["staticlib"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
lazy_static = {version = "1.4.0", features = ["spin_no_std"]}
|
|
||||||
spin = "0.9.4"
|
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
12
Makefile
12
Makefile
|
@ -10,13 +10,15 @@ CARGO_EXTRA_ARG := --release
|
||||||
.PHONY = target clean run rustc build debug
|
.PHONY = target clean run rustc build debug
|
||||||
default: build
|
default: build
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
cargo clean
|
cargo clean
|
||||||
|
|
||||||
build: target/shade.iso
|
build: target/shade.iso
|
||||||
|
|
||||||
rustc:
|
rustc:
|
||||||
RUST_TARGET_PATH=$(shell pwd) cargo build $(CARGO_EXTRA_ARG)
|
RUST_TARGET_PATH=$(shell pwd) cargo build -p shadeos-kernel $(CARGO_EXTRA_ARG)
|
||||||
|
|
||||||
run: target/shade.iso
|
run: target/shade.iso
|
||||||
qemu-system-x86_64 -cdrom target/shade.iso
|
qemu-system-x86_64 -cdrom target/shade.iso
|
||||||
|
@ -37,9 +39,9 @@ target/llb.a: target/llb/mb2_header.o target/llb/entry32.o
|
||||||
mkdir -p target/llb
|
mkdir -p target/llb
|
||||||
ar rvs target/llb.a target/llb/mb2_header.o target/llb/entry32.o
|
ar rvs target/llb.a target/llb/mb2_header.o target/llb/entry32.o
|
||||||
|
|
||||||
target/llb/mb2_header.o: src/llb/mb2_header.asm
|
target/llb/mb2_header.o: shadeos-llb/src
|
||||||
mkdir -p target/llb
|
mkdir -p target/llb
|
||||||
$(ASM) $(ASMARGS) src/llb/mb2_header.asm -o target/llb/mb2_header.o
|
$(ASM) $(ASMARGS) shadeos-llb/src/mb2_header.asm -o target/llb/mb2_header.o
|
||||||
target/llb/entry32.o: src/llb/entry32.asm
|
target/llb/entry32.o: shadeos-llb/src
|
||||||
mkdir -p target/llb
|
mkdir -p target/llb
|
||||||
$(ASM) $(ASMARGS) src/llb/entry32.asm -o target/llb/entry32.o
|
$(ASM) $(ASMARGS) shadeos-llb/src/entry32.asm -o target/llb/entry32.o
|
|
@ -0,0 +1,18 @@
|
||||||
|
[package]
|
||||||
|
name = "shadeos-kernel"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
spin = "0.9.7"
|
||||||
|
lazy_static = { version = "1.0", features = ["spin_no_std"] }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
|
@ -0,0 +1,139 @@
|
||||||
|
use core::fmt;
|
||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
|
use core::ptr::write_volatile;
|
||||||
|
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::White, Color::Black),
|
||||||
|
buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(u8)]
|
||||||
|
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(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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for ColorCode {
|
||||||
|
fn default() -> Self {
|
||||||
|
ColorCode::new(Color::White, Color::Black)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ScreenChar {
|
||||||
|
ascii_character: u8,
|
||||||
|
color_code: ColorCode
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const BUFFER_HEIGHT: usize = 25;
|
||||||
|
pub const BUFFER_WIDTH: usize = 80;
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Buffer {
|
||||||
|
chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Writer {
|
||||||
|
pub(crate) column_position: usize,
|
||||||
|
pub(crate) color_code: ColorCode,
|
||||||
|
pub(crate) 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;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
write_volatile((&mut self.buffer.chars[row][col] as *mut ScreenChar), ScreenChar {
|
||||||
|
ascii_character: byte,
|
||||||
|
color_code,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
let character = self.buffer.chars[row][col];
|
||||||
|
unsafe {
|
||||||
|
write_volatile((&mut self.buffer.chars[row-1][col] as *mut ScreenChar), character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
write_volatile((&mut self.buffer.chars[row][col] as *mut ScreenChar), blank);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl fmt::Write for Writer {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
self.write_string(s);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,40 +4,31 @@
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
pub mod tty;
|
|
||||||
pub mod drivers;
|
pub mod drivers;
|
||||||
pub mod unsafe_utils;
|
|
||||||
|
|
||||||
|
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use lazy_static::lazy_static;
|
use core::fmt::Write;
|
||||||
|
use crate::drivers::tty::{Buffer, Color, ColorCode, Writer};
|
||||||
|
|
||||||
use crate::tty::{ROWS_IN_TTY, TTY};
|
|
||||||
|
|
||||||
/// This is our kpanic function. This will eventually use any functioning video driver to dump the kernel, but for now it just hangs
|
/// This is our kpanic function. This will eventually use any functioning video driver to dump the kernel, but for now it just hangs
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn kpanic(_info: &PanicInfo) -> ! {
|
fn kpanic(_info: &PanicInfo) -> ! {
|
||||||
// Completley reinitialize the tty system to ensure we can get the kpanic log out to vga.
|
// Completley reinitialize the tty system to ensure we can get the kpanic log out to vga.
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
println!("==== start kernel panic ====");
|
println!("==== start kernel panic ====");
|
||||||
println!("{}", _info);
|
println!("{}", _info);
|
||||||
println!("==== end kernel panic ====");
|
println!("==== end kernel panic ====");
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
use spin::Mutex;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
pub static ref ttys: Mutex<TTY<1>> = Mutex::new(TTY::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn kmain() -> ! {
|
pub extern fn kmain() -> ! {
|
||||||
// initialize ttys and the kernel buffer
|
|
||||||
// just one for now
|
|
||||||
ttys.lock().select(0);
|
|
||||||
|
|
||||||
println!("hello from println");
|
println!("hello from println");
|
||||||
|
println!("hello from println pt2");
|
||||||
|
|
||||||
panic!("kpanic test");
|
panic!("kpanic test");
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
use core::fmt;
|
||||||
|
use crate::drivers::tty::WRITER;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => ($crate::macros::_print(format_args!($($arg)*)))
|
||||||
|
}
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println {
|
||||||
|
() => ($crate::print!("\n"));
|
||||||
|
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _print(args: fmt::Arguments) {
|
||||||
|
use core::fmt::Write;
|
||||||
|
WRITER.lock().write_fmt(args).unwrap();
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
pub mod vga;
|
|
|
@ -1,28 +0,0 @@
|
||||||
use crate::tty::{TTYCharacter, TTYDriver, TTYDriverError};
|
|
||||||
use crate::unsafe_utils::writes::write_dword;
|
|
||||||
|
|
||||||
/// Implementation of TTYDriver for 0xb8000 VGA Text Mode
|
|
||||||
|
|
||||||
pub struct VGATTYDriver {}
|
|
||||||
impl TTYDriver for VGATTYDriver {
|
|
||||||
fn set_char(&self, row: usize, col: usize, char: TTYCharacter) -> Result<(), TTYDriverError> {
|
|
||||||
if row > 25 {
|
|
||||||
return Err(TTYDriverError::RowOutOfBounds { got: row })
|
|
||||||
}
|
|
||||||
if col > 80 {
|
|
||||||
return Err(TTYDriverError::ColOutOfBounds { got: col })
|
|
||||||
}
|
|
||||||
// calculate the memory offset
|
|
||||||
let write_location = 0xb8000 + (row * 80 + col) * 2;
|
|
||||||
|
|
||||||
// convert the TTYCharacter into a raw u16 to be written to memory
|
|
||||||
let raw_char = (char.format as u16) << 8 | char.char as u16;
|
|
||||||
|
|
||||||
// and then write it using unsafe_utils
|
|
||||||
unsafe {
|
|
||||||
write_dword(raw_char, write_location);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
#[macro_export]
|
|
||||||
macro_rules! print {
|
|
||||||
($($arg:tt)*) => ($crate::tty::_print(format_args!($($arg)*)))
|
|
||||||
}
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! println {
|
|
||||||
() => ($crate::print!("\n"));
|
|
||||||
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)))
|
|
||||||
}
|
|
221
src/tty.rs
221
src/tty.rs
|
@ -1,221 +0,0 @@
|
||||||
use core::error::Error;
|
|
||||||
use core::fmt;
|
|
||||||
use core::fmt::{Display, Formatter, Write};
|
|
||||||
use crate::drivers::tty::vga::VGATTYDriver;
|
|
||||||
use crate::ttys;
|
|
||||||
|
|
||||||
pub fn _print(args: fmt::Arguments) {
|
|
||||||
ttys.lock().write_fmt(args).unwrap();
|
|
||||||
ttys.lock().update().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TTY<const C: usize> {
|
|
||||||
pub ttys: [VirtualTTY; C],
|
|
||||||
pub selected: usize,
|
|
||||||
driver: VGATTYDriver
|
|
||||||
}
|
|
||||||
impl<const C: usize> TTY<C> {
|
|
||||||
pub fn new() -> TTY<C> {
|
|
||||||
Self {
|
|
||||||
ttys: [
|
|
||||||
VirtualTTY::new(); C
|
|
||||||
],
|
|
||||||
selected: 0,
|
|
||||||
driver: VGATTYDriver {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select(&mut self, new: usize) { self.selected = new; }
|
|
||||||
|
|
||||||
pub fn update(&self) -> Result<(), TTYDriverError> {
|
|
||||||
let selected_tty = &self.ttys[self.selected];
|
|
||||||
for (row_num, row) in selected_tty.screen_buffer.iter().enumerate() {
|
|
||||||
for (col_num, col) in row.iter().enumerate() {
|
|
||||||
self.driver.set_char(row_num, col_num, *col)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle(&self) -> &VirtualTTY {
|
|
||||||
&self.ttys[self.selected]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_mut(&mut self) -> &mut VirtualTTY {
|
|
||||||
&mut self.ttys[self.selected]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select_and_update(&mut self, new: usize) -> Result<(), TTYDriverError> {
|
|
||||||
self.select(new);
|
|
||||||
self.update()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
#[repr(u8)]
|
|
||||||
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(Copy, Clone)]
|
|
||||||
pub struct TTYCharacter {
|
|
||||||
pub format: u8,
|
|
||||||
pub char: char
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TTYCharacter {
|
|
||||||
pub fn blank() -> Self { Self { format: 0u8, char: ' ' } }
|
|
||||||
pub fn from(char: char) -> Self { Self { format: 0x0fu8, char }}
|
|
||||||
pub fn new(char: char, fg: Color, bg: Color) -> Self {
|
|
||||||
Self {
|
|
||||||
format: (bg as u8) << 4 | fg as u8,
|
|
||||||
char
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const ROWS_ON_SCREEN: usize = 25;
|
|
||||||
pub const COLS: usize = 80;
|
|
||||||
|
|
||||||
pub const ROWS_IN_TTY: usize = 80;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct VirtualTTY {
|
|
||||||
full_buffer: VirtualTTYBuffer<ROWS_IN_TTY, COLS>,
|
|
||||||
full_buffer_copy: VirtualTTYBuffer<ROWS_IN_TTY, COLS>,
|
|
||||||
screen_buffer: VirtualTTYBuffer<ROWS_ON_SCREEN, COLS>,
|
|
||||||
line_offset: usize,
|
|
||||||
cursor_col: usize,
|
|
||||||
cursor_row: usize,
|
|
||||||
current_color_fg: Color,
|
|
||||||
current_color_bg: Color
|
|
||||||
}
|
|
||||||
impl Default for VirtualTTY {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
full_buffer: [[TTYCharacter::blank(); COLS]; ROWS_IN_TTY],
|
|
||||||
full_buffer_copy: [[TTYCharacter::blank(); COLS]; ROWS_IN_TTY],
|
|
||||||
screen_buffer: [[TTYCharacter::blank(); COLS]; ROWS_ON_SCREEN],
|
|
||||||
line_offset: ROWS_IN_TTY - ROWS_ON_SCREEN, // assume we are scrolled all the way down
|
|
||||||
cursor_row: ROWS_IN_TTY - ROWS_ON_SCREEN,
|
|
||||||
current_color_fg: Color::White,
|
|
||||||
cursor_col: 0,
|
|
||||||
current_color_bg: Color::Black,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl VirtualTTY {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_color(&mut self, fg: Color, bg: Color) {
|
|
||||||
self.current_color_bg = bg;
|
|
||||||
self.current_color_fg = fg;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setcur(&mut self, cursor_x: usize, cursor_y: usize) {
|
|
||||||
self.cursor_row = cursor_y;
|
|
||||||
self.cursor_col = cursor_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn putchar(&mut self, character: char) {
|
|
||||||
match character {
|
|
||||||
'\n' => {
|
|
||||||
self.print_newline();
|
|
||||||
self.cursor_col = 0;
|
|
||||||
self.cursor_row += 1;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
if self.cursor_col > COLS {
|
|
||||||
self.print_newline();
|
|
||||||
self.cursor_col = 0;
|
|
||||||
self.cursor_row += 1;
|
|
||||||
}
|
|
||||||
self._putchar(character);
|
|
||||||
self.cursor_col += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn putstr(&mut self, str: &str) {
|
|
||||||
for char in str.chars() {
|
|
||||||
self.putchar(char);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _putchar(&mut self, character: char) {
|
|
||||||
self.full_buffer[self.cursor_row][self.cursor_col] = TTYCharacter::new(character, self.current_color_fg, self.current_color_bg);
|
|
||||||
self.update_screenbuf()
|
|
||||||
}
|
|
||||||
|
|
||||||
// shifts everything up one
|
|
||||||
fn print_newline(&mut self) {
|
|
||||||
for (line_no, line) in self.full_buffer.iter().skip(1).enumerate() {
|
|
||||||
self.full_buffer_copy[line_no] = *line;
|
|
||||||
}
|
|
||||||
self.full_buffer = self.full_buffer_copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_screen_offset(&mut self, new_offset: usize) -> Result<(), ()> {
|
|
||||||
if new_offset > (ROWS_IN_TTY - ROWS_ON_SCREEN) {
|
|
||||||
return Err(())
|
|
||||||
}
|
|
||||||
self.line_offset = new_offset;
|
|
||||||
self.update_screenbuf();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_screenbuf(&mut self) {
|
|
||||||
for (line_no, line) in self.full_buffer.iter().skip(self.line_offset).enumerate() {
|
|
||||||
self.screen_buffer[line_no] = *line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type VirtualTTYBuffer<const R: usize, const C: usize> = [[TTYCharacter; C]; R];
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum TTYDriverError {
|
|
||||||
RowOutOfBounds { got: usize },
|
|
||||||
ColOutOfBounds { got: usize },
|
|
||||||
CannotScrollTooFar
|
|
||||||
}
|
|
||||||
impl Display for TTYDriverError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::RowOutOfBounds { got } => write!(f, "Character write out of bounds: row {} too high", got),
|
|
||||||
Self::ColOutOfBounds { got } => write!(f, "Character write out of bounds: col {} too high", got),
|
|
||||||
Self::CannotScrollTooFar => write!(f, "Cannot scroll outside line buffer")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Error for TTYDriverError {}
|
|
||||||
|
|
||||||
pub trait TTYDriver {
|
|
||||||
fn set_char(&self, row: usize, col: usize, char: TTYCharacter) -> Result<(), TTYDriverError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const C: usize> Write for TTY<C> {
|
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
||||||
self.handle_mut().putstr(s);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
/// Unsafe utility functions
|
|
||||||
pub mod writes;
|
|
|
@ -1,5 +0,0 @@
|
||||||
/// Write the given dword to any arbitrary memory location. This is an inherently unsafe operation; hence the function is unsafe
|
|
||||||
pub unsafe fn write_dword(dword: u16, at: usize) {
|
|
||||||
let ptr = at as *mut u16;
|
|
||||||
*ptr = dword;
|
|
||||||
}
|
|
Loading…
Reference in New Issue