partially working tty system
This commit is contained in:
parent
b5aea81535
commit
b75a7bc7ad
|
@ -10,6 +10,7 @@ crate-type = ["staticlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lazy_static = {version = "1.4.0", features = ["spin_no_std"]}
|
lazy_static = {version = "1.4.0", features = ["spin_no_std"]}
|
||||||
|
spin = "0.9.4"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -4,8 +4,8 @@ ASMARGS := -f elf64
|
||||||
LD := x86_64-elf-ld
|
LD := x86_64-elf-ld
|
||||||
LDARGS := --nmagic
|
LDARGS := --nmagic
|
||||||
|
|
||||||
CARGO_ENV := debug
|
CARGO_ENV := release
|
||||||
CARGO_EXTRA_ARG := #--release
|
CARGO_EXTRA_ARG := --release
|
||||||
|
|
||||||
.PHONY = target clean run rustc build debug
|
.PHONY = target clean run rustc build debug
|
||||||
default: build
|
default: build
|
||||||
|
|
60
src/lib.rs
60
src/lib.rs
|
@ -2,66 +2,44 @@
|
||||||
#![feature(error_in_core)]
|
#![feature(error_in_core)]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod macros;
|
||||||
pub mod tty;
|
pub mod tty;
|
||||||
pub mod drivers;
|
pub mod drivers;
|
||||||
pub mod unsafe_utils;
|
pub mod unsafe_utils;
|
||||||
|
|
||||||
|
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use crate::drivers::tty::vga::VGATTYDriver;
|
use lazy_static::lazy_static;
|
||||||
use crate::tty::{Color, TTY, TTYCharacter, TTYDriver, TTYDriverError};
|
|
||||||
|
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) -> ! {
|
||||||
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 {}
|
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
|
// initialize ttys and the kernel buffer
|
||||||
// just one for now
|
// just one for now
|
||||||
let vga_driver = VGATTYDriver {};
|
ttys.lock().select(0);
|
||||||
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.select(1);
|
println!("hello from println");
|
||||||
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);
|
|
||||||
|
|
||||||
match ttys.select_and_update(0, &vga_driver) {
|
panic!("kpanic test");
|
||||||
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();
|
|
||||||
|
|
||||||
loop{}
|
loop{}
|
||||||
}
|
}
|
|
@ -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)*)))
|
||||||
|
}
|
126
src/tty.rs
126
src/tty.rs
|
@ -1,9 +1,18 @@
|
||||||
use core::error::Error;
|
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<const C: usize> {
|
pub struct TTY<const C: usize> {
|
||||||
pub ttys: [VirtualTTY; C],
|
pub ttys: [VirtualTTY; C],
|
||||||
pub selected: usize
|
pub selected: usize,
|
||||||
|
driver: VGATTYDriver
|
||||||
}
|
}
|
||||||
impl<const C: usize> TTY<C> {
|
impl<const C: usize> TTY<C> {
|
||||||
pub fn new() -> TTY<C> {
|
pub fn new() -> TTY<C> {
|
||||||
|
@ -11,25 +20,34 @@ impl<const C: usize> TTY<C> {
|
||||||
ttys: [
|
ttys: [
|
||||||
VirtualTTY::new(); C
|
VirtualTTY::new(); C
|
||||||
],
|
],
|
||||||
selected: 0
|
selected: 0,
|
||||||
|
driver: VGATTYDriver {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(&mut self, new: usize) { self.selected = new; }
|
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];
|
let selected_tty = &self.ttys[self.selected];
|
||||||
for (row_num, row) in selected_tty.screen_buffer.iter().enumerate() {
|
for (row_num, row) in selected_tty.screen_buffer.iter().enumerate() {
|
||||||
for (col_num, col) in row.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(())
|
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.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 from(char: char) -> Self { Self { format: 0x0fu8, char }}
|
||||||
pub fn new(char: char, fg: Color, bg: Color) -> Self {
|
pub fn new(char: char, fg: Color, bg: Color) -> Self {
|
||||||
Self {
|
Self {
|
||||||
format: (fg as u8) << 4 | bg as u8,
|
format: (bg as u8) << 4 | fg as u8,
|
||||||
char
|
char
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,16 +98,26 @@ pub const ROWS_IN_TTY: usize = 80;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct VirtualTTY {
|
pub struct VirtualTTY {
|
||||||
pub full_buffer: VirtualTTYBuffer<ROWS_IN_TTY, COLS>,
|
full_buffer: VirtualTTYBuffer<ROWS_IN_TTY, COLS>,
|
||||||
pub screen_buffer: VirtualTTYBuffer<ROWS_ON_SCREEN, COLS>,
|
full_buffer_copy: VirtualTTYBuffer<ROWS_IN_TTY, COLS>,
|
||||||
pub line_offset: usize
|
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 {
|
impl Default for VirtualTTY {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
full_buffer: [[TTYCharacter::blank(); COLS]; ROWS_IN_TTY],
|
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],
|
screen_buffer: [[TTYCharacter::blank(); COLS]; ROWS_ON_SCREEN],
|
||||||
line_offset: ROWS_IN_TTY - ROWS_ON_SCREEN, // assume we are scrolled all the way down
|
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 {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
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];
|
type VirtualTTYBuffer<const R: usize, const C: usize> = [[TTYCharacter; C]; R];
|
||||||
|
@ -104,13 +195,15 @@ type VirtualTTYBuffer<const R: usize, const C: usize> = [[TTYCharacter; C]; R];
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TTYDriverError {
|
pub enum TTYDriverError {
|
||||||
RowOutOfBounds { got: usize },
|
RowOutOfBounds { got: usize },
|
||||||
ColOutOfBounds { got: usize }
|
ColOutOfBounds { got: usize },
|
||||||
|
CannotScrollTooFar
|
||||||
}
|
}
|
||||||
impl Display for TTYDriverError {
|
impl Display for TTYDriverError {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::RowOutOfBounds { got } => write!(f, "Character write out of bounds: row {} too high", got),
|
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 {
|
pub trait TTYDriver {
|
||||||
fn set_char(&self, row: usize, col: usize, char: TTYCharacter) -> Result<(), TTYDriverError>;
|
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(())
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue