From b75a7bc7ad401f38419e65b43fcc42b587fb486e Mon Sep 17 00:00:00 2001 From: c0repwn3r Date: Mon, 30 Jan 2023 20:59:44 -0500 Subject: [PATCH] partially working tty system --- Cargo.toml | 1 + Makefile | 4 +- src/lib.rs | 60 ++++++++---------------- src/macros.rs | 9 ++++ src/tty.rs | 126 ++++++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 144 insertions(+), 56 deletions(-) create mode 100644 src/macros.rs diff --git a/Cargo.toml b/Cargo.toml index 924c98c..c22ca9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["staticlib"] [dependencies] lazy_static = {version = "1.4.0", features = ["spin_no_std"]} +spin = "0.9.4" [profile.dev] panic = "abort" diff --git a/Makefile b/Makefile index 98f0678..594d353 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ ASMARGS := -f elf64 LD := x86_64-elf-ld LDARGS := --nmagic -CARGO_ENV := debug -CARGO_EXTRA_ARG := #--release +CARGO_ENV := release +CARGO_EXTRA_ARG := --release .PHONY = target clean run rustc build debug default: build diff --git a/src/lib.rs b/src/lib.rs index 1c847cd..9c89f74 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,66 +2,44 @@ #![feature(error_in_core)] #![feature(panic_info_message)] +#[macro_use] +pub mod macros; pub mod tty; pub mod drivers; pub mod unsafe_utils; use core::panic::PanicInfo; -use crate::drivers::tty::vga::VGATTYDriver; -use crate::tty::{Color, TTY, TTYCharacter, TTYDriver, TTYDriverError}; +use lazy_static::lazy_static; + +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 #[panic_handler] fn kpanic(_info: &PanicInfo) -> ! { - let panic_str = _info.location().unwrap(); + // Completley reinitialize the tty system to ensure we can get the kpanic log out to vga. + println!(); + println!("==== start kernel panic ===="); + println!("{}", _info); + println!("==== end kernel panic ===="); loop {} } +use spin::Mutex; + +lazy_static! { + pub static ref ttys: Mutex> = Mutex::new(TTY::new()); +} + #[no_mangle] pub extern fn kmain() -> ! { // initialize ttys and the kernel buffer // just one for now - let vga_driver = VGATTYDriver {}; - let mut ttys: TTY<2> = TTY::new(); - ttys.select(0); - ttys.ttys[ttys.selected].screen_buffer[0][0] = TTYCharacter::new('s', Color::White, Color::Black); - ttys.ttys[ttys.selected].screen_buffer[0][1] = TTYCharacter::new('h', Color::White, Color::Black); - ttys.ttys[ttys.selected].screen_buffer[0][2] = TTYCharacter::new('a', Color::White, Color::Black); - ttys.ttys[ttys.selected].screen_buffer[0][3] = TTYCharacter::new('d', Color::White, Color::Black); - ttys.ttys[ttys.selected].screen_buffer[0][4] = TTYCharacter::new('e', Color::White, Color::Black); + ttys.lock().select(0); - ttys.select(1); - ttys.ttys[ttys.selected].screen_buffer[0][0] = TTYCharacter::new('o', Color::White, Color::Black); - ttys.ttys[ttys.selected].screen_buffer[0][1] = TTYCharacter::new('s', Color::White, Color::Black); - ttys.ttys[ttys.selected].screen_buffer[0][2] = TTYCharacter::new(' ', Color::White, Color::Black); - ttys.ttys[ttys.selected].screen_buffer[0][3] = TTYCharacter::new(':', Color::White, Color::Black); - ttys.ttys[ttys.selected].screen_buffer[0][4] = TTYCharacter::new(')', Color::White, Color::Black); + println!("hello from println"); - match ttys.select_and_update(0, &vga_driver) { - Ok(_) => {} - Err(e) => { - match e { - TTYDriverError::ColOutOfBounds { got } => { - vga_driver.set_char(0, 5, TTYCharacter::new('y', Color::Red, Color::Black)).unwrap(); - loop {} - }, - TTYDriverError::RowOutOfBounds { got } => { - vga_driver.set_char(0, 5, TTYCharacter::new('y', Color::Red, Color::Black)).unwrap(); - loop {} - } - } - } - } - - for i in 0..2000000 { - continue; - } - - ttys.select_and_update(1, &vga_driver).unwrap(); - - //vga_driver.set_char(0, 0, TTYCharacter::new('s', Color::White, Color::Black)).unwrap(); - //vga_driver.set_char(0, 1, TTYCharacter::new('h', Color::White, Color::Black)).unwrap(); + panic!("kpanic test"); loop{} } \ No newline at end of file diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..1fa14af --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,9 @@ +#[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)*))) +} \ No newline at end of file diff --git a/src/tty.rs b/src/tty.rs index 435478a..e182840 100644 --- a/src/tty.rs +++ b/src/tty.rs @@ -1,9 +1,18 @@ use core::error::Error; -use core::fmt::{Display, Formatter}; +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 { pub ttys: [VirtualTTY; C], - pub selected: usize + pub selected: usize, + driver: VGATTYDriver } impl TTY { pub fn new() -> TTY { @@ -11,25 +20,34 @@ impl TTY { ttys: [ VirtualTTY::new(); C ], - selected: 0 + selected: 0, + driver: VGATTYDriver {} } } pub fn select(&mut self, new: usize) { self.selected = new; } - pub fn update(&self, driver: &impl TTYDriver) -> Result<(), TTYDriverError> { + 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() { - driver.set_char(row_num, col_num, *col)?; + self.driver.set_char(row_num, col_num, *col)?; } } Ok(()) } - pub fn select_and_update(&mut self, new: usize, driver: &impl TTYDriver) -> Result<(), TTYDriverError> { + 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(driver) + self.update() } } @@ -67,7 +85,7 @@ impl TTYCharacter { pub fn from(char: char) -> Self { Self { format: 0x0fu8, char }} pub fn new(char: char, fg: Color, bg: Color) -> Self { Self { - format: (fg as u8) << 4 | bg as u8, + format: (bg as u8) << 4 | fg as u8, char } } @@ -80,16 +98,26 @@ pub const ROWS_IN_TTY: usize = 80; #[derive(Copy, Clone)] pub struct VirtualTTY { - pub full_buffer: VirtualTTYBuffer, - pub screen_buffer: VirtualTTYBuffer, - pub line_offset: usize + full_buffer: VirtualTTYBuffer, + full_buffer_copy: VirtualTTYBuffer, + screen_buffer: VirtualTTYBuffer, + 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, } } } @@ -97,6 +125,69 @@ 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 = [[TTYCharacter; C]; R]; @@ -104,13 +195,15 @@ type VirtualTTYBuffer = [[TTYCharacter; C]; R]; #[derive(Debug)] pub enum TTYDriverError { RowOutOfBounds { got: usize }, - ColOutOfBounds { 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::ColOutOfBounds { got } => write!(f, "Character write out of bounds: col {} too high", got), + Self::CannotScrollTooFar => write!(f, "Cannot scroll outside line buffer") } } } @@ -118,4 +211,11 @@ impl Error for TTYDriverError {} pub trait TTYDriver { fn set_char(&self, row: usize, col: usize, char: TTYCharacter) -> Result<(), TTYDriverError>; +} + +impl Write for TTY { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.handle_mut().putstr(s); + Ok(()) + } } \ No newline at end of file