From c9ad4e9e5810fa11e10446aa7e1aee95636a2562 Mon Sep 17 00:00:00 2001 From: Jack Halford Date: Sun, 20 Jan 2019 22:11:14 +0100 Subject: [PATCH] lspci, console refactor --- kernel-rs/src/acpi/mod.rs | 46 ++-- kernel-rs/src/allocator/mod.rs | 2 +- kernel-rs/src/arch/x86/devices/cpu.rs | 6 +- kernel-rs/src/arch/x86/mod.rs | 31 ++- kernel-rs/src/console.rs | 304 +++++--------------------- kernel-rs/src/lib.rs | 4 +- kernel-rs/src/memory/mod.rs | 60 +++++ kernel-rs/src/pci/mod.rs | 85 +++++-- kernel-rs/src/time.rs | 5 + kernel-rs/src/vga/mod.rs | 34 +-- 10 files changed, 250 insertions(+), 327 deletions(-) diff --git a/kernel-rs/src/acpi/mod.rs b/kernel-rs/src/acpi/mod.rs index 55f86984..6a2f1f4b 100644 --- a/kernel-rs/src/acpi/mod.rs +++ b/kernel-rs/src/acpi/mod.rs @@ -126,17 +126,9 @@ impl Iterator for ACPISDTIter { } } -fn is_init() -> Result<(), &'static str> { - if unsafe { ACPI.valid } { - Ok(()) - } else { - Err("ACPI is not initialized") - } -} - /// Initalized the ACPI module pub fn init() -> Result<(), &'static str> { - if let Ok(()) = is_init() { + if unsafe{ACPI.valid} { return Ok(()); } unsafe { ACPI.init() } @@ -144,7 +136,7 @@ pub fn init() -> Result<(), &'static str> { /// Load the ACPI module, addr given is a ptr to RSDP pub fn load(rsdp_addr: u32) -> Result<(), &'static str> { - if let Ok(()) = is_init() { + if unsafe{ACPI.valid} { return Ok(()); } unsafe { ACPI.load(rsdp_addr) } @@ -152,32 +144,30 @@ pub fn load(rsdp_addr: u32) -> Result<(), &'static str> { /// Proceed to ACPI shutdown /// This function doesn't work with Virtual Box yet -pub fn shutdown() -> Result<(), &'static str> { - is_init()?; - dsdt::shutdown(fadt::get_controlblock()?) +pub fn shutdown() { + if unsafe{ACPI.valid} { return } + dsdt::shutdown(fadt::get_controlblock().unwrap()); } /// Proceed to ACPI reboot /// This function need ACPI in v2 -pub fn reboot() -> Result<(), &'static str> { - is_init()?; +pub fn reboot() { + if unsafe {!ACPI.valid} { + println!("ACPI not initialized"); + } if unsafe { ACPI.v2 } { - fadt::reboot() + fadt::reboot().unwrap() } else { - Err("ACPI reboot only available in ACPI v2+") + println!("ACPI reboot only available in ACPI v2+"); } } /// Display state of ACPI -pub fn info() -> Result<(), &'static str> { - is_init()?; - println!( - "ACPI STATE:\n {}", - if fadt::is_enable()? { - "ENABLED" - } else { - "DISABLED" - } - ); - Ok(()) +pub fn info() { + if unsafe { !ACPI.valid } { println!("ACPI not initialized"); return } + match fadt::is_enable() { + Ok(True) => println!("ACPI is disabled"), + Ok(False) => println!("ACPI is disabled"), + Err(msg) => println!("error while checking ACPI") + } } diff --git a/kernel-rs/src/allocator/mod.rs b/kernel-rs/src/allocator/mod.rs index baa5135f..6c5fb136 100644 --- a/kernel-rs/src/allocator/mod.rs +++ b/kernel-rs/src/allocator/mod.rs @@ -23,5 +23,5 @@ pub unsafe fn init(active_table: &mut ActivePageTable) { #[alloc_error_handler] fn foo(_: core::alloc::Layout) -> ! { - panic!(); + panic!("alloc_error_handler"); } diff --git a/kernel-rs/src/arch/x86/devices/cpu.rs b/kernel-rs/src/arch/x86/devices/cpu.rs index 079db7d5..111ba009 100644 --- a/kernel-rs/src/arch/x86/devices/cpu.rs +++ b/kernel-rs/src/arch/x86/devices/cpu.rs @@ -1,10 +1,8 @@ extern crate raw_cpuid; -use core::fmt::Result; - use self::raw_cpuid::CpuId; -pub fn cpu_info() -> Result { +pub fn cpu_info() { let cpuid = CpuId::new(); if let Some(info) = cpuid.get_vendor_info() { @@ -285,6 +283,4 @@ pub fn cpu_info() -> Result { }; println!(""); } - - Ok(()) } diff --git a/kernel-rs/src/arch/x86/mod.rs b/kernel-rs/src/arch/x86/mod.rs index 73ae5e38..14cd6855 100644 --- a/kernel-rs/src/arch/x86/mod.rs +++ b/kernel-rs/src/arch/x86/mod.rs @@ -17,10 +17,6 @@ pub unsafe extern "C" fn x86_rust_start(multiboot_info_addr: usize) { // parse multiboot2 info let boot_info = multiboot2::load(multiboot_info_addr); - // println!("{:?}", boot_info); - // flush!(); - // asm!("hlt"); - // ACPI must be intialized BEFORE paging is active if let Some(rsdp) = boot_info.rsdp_v2_tag() { acpi::load(rsdp).expect("ACPI failed"); @@ -116,3 +112,30 @@ pub unsafe fn usermode(ip: u32, sp: u32) -> ! { unreachable!(); } + +/// Dump control registers +pub fn regs() { + use x86::registers::control::*; + use x86::instructions::tables::tr; + use x86::instructions::segmentation::*; + use x86::registers::flags::*; + use x86::structures::gdt; + println!("cr0 = {:?}", Cr0::read()); + println!("cr3 = {:?}", Cr3::read()); + println!("cr4 = {:?}", Cr4::read()); + println!("flags= {:?}", flags()); + println!("tr = {:?}", tr()); + println!("ss = {:?}", ss()); + println!("cs = {:?}", cs()); + println!("ds = {:?}", ds()); + println!("es = {:?}", es()); + println!("fs = {:?}", fs()); + println!("gs = {:?}", gs()); + unsafe { + println!( + "tss = {:#?}", + gdt::Descriptor(::arch::x86::gdt::GDT.table[tr().index() as usize]) + ); + } + flush!(); +} diff --git a/kernel-rs/src/console.rs b/kernel-rs/src/console.rs index b0d7e09a..f5c00bca 100644 --- a/kernel-rs/src/console.rs +++ b/kernel-rs/src/console.rs @@ -1,14 +1,49 @@ extern crate core; // extern crate multiboot2; -use acpi; -use time; -use keyboard::PS2; -use core::char; use vga::*; +use alloc::collections::BTreeMap; pub static mut CONSOLE: Console = self::Console::new(); +lazy_static! { + static ref COMMANDS: BTreeMap<&'static str, fn()> = { + let mut commands = BTreeMap::new(); + commands.insert("help", self::help as fn()); + + // ACPI + commands.insert("acpi", ::acpi::info as fn()); + commands.insert("reboot", ::acpi::reboot as fn()); + commands.insert("shutdown", ::acpi::shutdown as fn()); + + // time + commands.insert("uptime", ::time::uptime as fn()); + + // cpu + use arch::x86; + commands.insert("cpu", x86::devices::cpu::cpu_info as fn()); + commands.insert("regs", x86::regs as fn()); + commands.insert("int3", ::x86::instructions::interrupts::int3 as fn()); + + //memory + commands.insert("stack", ::memory::print_stack as fn()); + commands.insert("page_fault", ::memory::page_fault as fn()); + commands.insert("overflow", ::memory::overflow as fn()); + commands.insert("overflow", ::memory::overflow as fn()); + + //pci + commands.insert("lspci", ::pci::lspci as fn()); + commands + }; +} + +fn help() { + println!("The following commands are available:"); + for (key, val) in COMMANDS.iter() { + println!("{}", key); + } +} + pub struct Console { command: [u8; 10], command_len: usize, @@ -54,11 +89,7 @@ impl Console { } b'\n' => { unsafe { VGA.write_byte(b'\n'); } - if let Err(msg) = self.exec() { - set_color!(Red); - println!("{}", msg); - set_color!(); - } + self.exec(); self.command_len = 0; self.prompt(); } @@ -73,256 +104,27 @@ impl Console { self.command_len += 1; } } - flush!(); + unsafe { VGA.flush(); } } - - fn get_command(&self) -> Result<&str, &'static str> { + fn get_command(&self) -> Result { match core::str::from_utf8(&self.command) { - Ok(y) => Ok(&y[..self.command_len]), + Ok(y) => { + if let Some(command) = COMMANDS.get(&y[..self.command_len]) { + Ok(*command) + } else { + Err("Command not found, try help") + } + }, Err(_) => Err("Command is not utf8"), } } - pub fn exec(&self) -> core::result::Result<(), &'static str> { + pub fn exec(&self) { let command = self.get_command(); - if let Err(msg) = command { - return Err(msg) - } - match command.unwrap() { - "help" | "h" => self::help(), - - // multiboot - // "memory" => self::mb2_memory(), - // "multiboot" => self::mb2_info(), - // "sections" => self::mb2_sections(), - - // ACPI - "acpi" => self::acpi_info(), - "reboot" => self::reboot(), - "shutdown" | "halt" | "q" => self::shutdown(), - - // x86 specific - "stack" => self::print_stack(), - "regs" => self::regs(), - "cpu" => self::cpu(), - "int3" => self::int3(), - "overflow" => self::overflow(), - "page_fault" => self::page_fault(), - - // time - "uptime" => self::uptime(), - - _ => Err("Command unknown. (try help)"), + match command { + Err(msg) => println!("{}", msg), + Ok(func) => (func)(), } } } - -fn help() -> Result<(), &'static str> { - println!("help | h => print this help"); - // println!("memory => Print memory areas"); - // println!("multiboot => Print multiboot information"); - // println!("sections => Print elf sections"); - println!("reboot => reboot"); - println!("shutdown | halt | q => acpi shutdown"); - println!("acpi => acpi state"); - println!("stack => print kernel stack in a fancy way"); - println!("regs => print controle register"); - println!("cpu => print cpu information"); - println!("overflow => triggers a stack overflow"); - println!("page_fault => triggers a page fault on 0xdead"); - flush!(); - Ok(()) -} - -fn uptime() -> Result<(), &'static str> { - let mut offset = time::OFFSET.lock(); - fprintln!("{}s", offset.0 + offset.1 / 1_000_000); - flush!(); - Ok(()) -} - -use x86::instructions::halt; -/// Reboot the kernel -/// -/// If reboot failed, will loop on a halt cmd -/// -fn reboot() -> ! { - match acpi::reboot() { - Err(msg) => println!("{}", msg), - _ => println!("Unable to perform ACPI reboot."), - } - flush!(); - unsafe { PS2.ps2_8042_reset() }; // TODO unsafe - println!("Unable to perform 8042 reboot. Kernel will be halted"); - flush!(); - halt(); -} - -/// Shutdown the kernel -/// -/// If shutdown is performed but failed, will loop on a halt cmd -/// If shutdown cannot be called, return a Err(&str) -/// -fn shutdown() -> ! { - match acpi::shutdown() { - Err(msg) => println!("{}", msg), - _ => println!("Unable to perform ACPI shutdown. Kernel will be halted"), - } - flush!(); - halt(); -} - -fn hexdump(start: usize, end: usize) { - let mut address = 0; - let data = unsafe { core::slice::from_raw_parts_mut(start as *mut u8, end - start) }; - while address <= data.len() { - let next_end = core::cmp::min(address + 16, data.len()); - print_line(&data[address..next_end], address + start); - address = address + 16; - } - println!(""); -} - -fn is_control(c: char) -> bool { - !(c >= ' ' && c <= '~') -} - -fn print_line(line: &[u8], address: usize) { - print!("\n{:#08x}: ", address); - for byte in line { - print!("{:02x} ", *byte); - } - let length: usize = 16 - line.len(); - for _ in 0..length { - print!(" "); - } - print!("|"); - for byte in line { - match is_control(*byte as char) { - true => print!("."), - false => print!("{}", *byte as char), - }; - } - print!("|"); -} - -/// Print the kernel stack -pub fn print_stack() -> Result<(), &'static str> { - let esp: usize; - let ebp: usize; - unsafe { asm!("" : "={esp}"(esp), "={ebp}"(ebp):::) }; - println!("esp = {:#x}", esp); - println!("ebp = {:#x}", ebp); - println!("size = {:#X} bytes", ebp - esp); - hexdump(esp, ebp); - flush!(); - Ok(()) -} - -// fn mb2_memory() -> Result <(), &'static str> { -// let boot_info = ::multiboot2::boot_info(); - -// let memory_map_tag = boot_info.memory_map_tag() -// .expect("Memory map tag required"); - -// println!("memory areas:"); -// for area in memory_map_tag.memory_areas() { -// println!(" start: 0x{:x}, length: 0x{:x}", -// area.start_address(), area.size()); -// } -// Ok(()) -// } - -// fn mb2_sections() -> Result <(), &'static str> { -// let boot_info = ::multiboot2::boot_info(); - -// let elf_sections_tag = boot_info.elf_sections_tag() -// .expect("Elf-sections tag required"); - -// println!("kernel sections:"); -// for section in elf_sections_tag.sections() { -// println!(" {: <10} {:#x}, size: {:#x}, flags: {:#X}", -// section.name(), section.start_address(), section.size(), section.flags()); -// } -// Ok(()) -// } - -// fn mb2_info() -> Result <(), &'static str> { -// let boot_info = context::boot_info(); - -// let command_line_tag = boot_info.command_line_tag() -// .expect("Elf-sections tag required"); - -// let bootloader_tag = boot_info.boot_loader_name_tag() -// .expect("Elf-sections tag required"); - -// println!("bootloader: {}", bootloader_tag.name()); -// if command_line_tag.command_line().len() != 0 { -// println!("command line: {}", command_line_tag.command_line()); -// } -// Ok(()) -// } - -pub fn acpi_info() -> Result<(), &'static str> { - acpi::info()?; - Ok(()) -} - -/// Dump control registers -pub fn regs() -> Result<(), &'static str> { - use x86::registers::control::*; - use x86::instructions::tables::tr; - use x86::instructions::segmentation::*; - use x86::registers::flags::*; - use x86::structures::gdt; - println!("cr0 = {:?}", Cr0::read()); - println!("cr3 = {:?}", Cr3::read()); - println!("cr4 = {:?}", Cr4::read()); - println!("flags= {:?}", flags()); - println!("tr = {:?}", tr()); - println!("ss = {:?}", ss()); - println!("cs = {:?}", cs()); - println!("ds = {:?}", ds()); - println!("es = {:?}", es()); - println!("fs = {:?}", fs()); - println!("gs = {:?}", gs()); - unsafe { - println!( - "tss = {:#?}", - gdt::Descriptor(::arch::x86::gdt::GDT.table[tr().index() as usize]) - ); - } - flush!(); - Ok(()) -} - -/// Dump cpu info, should add power management info -pub fn cpu() -> Result<(), &'static str> { - use arch::x86::devices::cpu; - cpu::cpu_info().expect("cpu info not available"); - flush!(); - Ok(()) -} - -pub fn int3() -> Result<(), &'static str> { - use x86; - x86::instructions::interrupts::int3(); - Ok(()) -} - -#[allow(unconditional_recursion)] -pub fn overflow() -> Result<(), &'static str> { - fn stack_overflow() { - stack_overflow(); - } - stack_overflow(); - Ok(()) -} - -pub fn page_fault() -> Result<(), &'static str> { - unsafe { - *(0xdead as *mut u32) = 42; - }; - Ok(()) -} diff --git a/kernel-rs/src/lib.rs b/kernel-rs/src/lib.rs index c58b1d51..a9ebbbb9 100644 --- a/kernel-rs/src/lib.rs +++ b/kernel-rs/src/lib.rs @@ -51,7 +51,9 @@ pub fn kmain() -> ! { // unsafe VGA unsafe { console::CONSOLE.init(); } - pci::lspci(); + if let Ok(slot) = pci::get_ide1() { + println!("found IDE at slot {}", slot); + } // scheduler WIP // scheduling::schedule(); unreachable!(); diff --git a/kernel-rs/src/memory/mod.rs b/kernel-rs/src/memory/mod.rs index a2af86a5..2279c3e8 100644 --- a/kernel-rs/src/memory/mod.rs +++ b/kernel-rs/src/memory/mod.rs @@ -101,3 +101,63 @@ pub fn init_noncore() { } } } + + +/// for console +#[allow(unconditional_recursion)] +pub fn overflow() { + overflow(); +} + +/// for console +pub fn page_fault() { + unsafe { + *(0xdead as *mut u32) = 42; + }; +} + +/// Print the kernel stack +pub fn print_stack() { + fn hexdump(start: usize, end: usize) { + let mut address = 0; + let data = unsafe { core::slice::from_raw_parts_mut(start as *mut u8, end - start) }; + while address <= data.len() { + let next_end = core::cmp::min(address + 16, data.len()); + print_line(&data[address..next_end], address + start); + address = address + 16; + } + println!(""); + } + + fn is_control(c: char) -> bool { + !(c >= ' ' && c <= '~') + } + + fn print_line(line: &[u8], address: usize) { + print!("\n{:#08x}: ", address); + for byte in line { + print!("{:02x} ", *byte); + } + let length: usize = 16 - line.len(); + for _ in 0..length { + print!(" "); + } + print!("|"); + for byte in line { + match is_control(*byte as char) { + true => print!("."), + false => print!("{}", *byte as char), + }; + } + print!("|"); + } + + let esp: usize; + let ebp: usize; + unsafe { asm!("" : "={esp}"(esp), "={ebp}"(ebp):::) }; + println!("esp = {:#x}", esp); + println!("ebp = {:#x}", ebp); + println!("size = {:#X} bytes", ebp - esp); + hexdump(esp, ebp); + flush!(); +} diff --git a/kernel-rs/src/pci/mod.rs b/kernel-rs/src/pci/mod.rs index 2440fe82..827ffb77 100644 --- a/kernel-rs/src/pci/mod.rs +++ b/kernel-rs/src/pci/mod.rs @@ -1,22 +1,79 @@ // https://wiki.osdev.org/PCI -use x86::devices::io::{Pio}; +use x86::devices::io::{Pio, Io}; -pub static mut PCI_CONFIG_ADDRESS: Pio = Pio::new(0xCF8); -pub static mut PCI_CONFIG_DATA: Pio = Pio::new(0xCFC); +pub static mut PCI_CONFIG_ADDRESS: Pio = Pio::new(0xCF8); +pub static mut PCI_CONFIG_DATA: Pio = Pio::new(0xCFC); + +pub fn get_ide1() -> Result { + let bus = 0; + + for slot in 0..31 { + let vendor = pci_config_read_word(bus, slot, 0, 0); + if vendor == 0xffff { + continue; + } + let class = pci_config_read_byte(bus, slot, 0, 11); + let subclass = pci_config_read_byte(bus, slot, 0, 10); + if class == 0x01 && subclass == 0x01 { + return Ok(slot); + } + } + Err(()) +} pub fn lspci() { - pci_config_read_word(1, 1, 1, 2); + let bus = 0; + + for slot in 0..31 { + let vendor = pci_config_read_word(bus, slot, 0, 0); + if vendor == 0xffff { + continue; + } + let header_type = pci_config_read_byte(bus, slot, 0, 14) ; + if header_type & 0x80 != 0 { + // device has multiple functions + for function in 0..0x7 { + let vendor = pci_config_read_word(bus, slot, function, 0); + if vendor != 0xffff { + pci_display(bus, slot, function); + } + } + } else { + pci_display(bus, slot, 0); + } + } } -pub fn pci_config_read_word(bus: u32, slot: u32, func: u32, offset: u32) { - // let address: u64 = (bus as u32) << 16 - // | (slot as u32) << 11 - // | (func as u32) << 8 - // | (offset as u32) & 0xfc - // | 0x80000000; - let address: u64 = 0x80000000; - println!("{} {} {} {}", bus, slot, func, offset); - println!("{:#x}", address); - println!("{:#b}", address); +pub fn pci_display(bus: u32, slot: u32, function: u32) { + let vendor = pci_config_read_word(bus, slot, function, 0); + let device = pci_config_read_word(bus, slot, function, 2); + let class = pci_config_read_byte(bus, slot, function, 11); + let subclass = pci_config_read_byte(bus, slot, function, 10); + println!("{}:{}.{} {:#x},{:#x}: {:#x} {:#x}", + bus, slot, function, class, subclass, vendor, device); +} + +pub fn pci_access(bus: u32, slot: u32, func: u32, offset: u32) { + let address = (bus as u32) << 16 + | (slot as u32) << 11 + | (func as u32) << 8 + | (offset as u32) & 0xfc + | 0x80000000; + unsafe { PCI_CONFIG_ADDRESS.write(address); } +} + +pub fn pci_config_read_doubleword(bus: u32, slot: u32, func: u32, offset: u32) -> u32 { + pci_access(bus, slot, func, offset); + unsafe { PCI_CONFIG_DATA.read() } +} + +pub fn pci_config_read_word(bus: u32, slot: u32, func: u32, offset: u32) -> u16 { + pci_access(bus, slot, func, offset); + unsafe { (PCI_CONFIG_DATA.read() >> ((offset & 2) * 8)) as u16 } +} + +pub fn pci_config_read_byte(bus: u32, slot: u32, func: u32, offset: u32) -> u8 { + pci_access(bus, slot, func, offset); + unsafe { (PCI_CONFIG_DATA.read() >> ((offset & 3) * 8)) as u8 } } diff --git a/kernel-rs/src/time.rs b/kernel-rs/src/time.rs index 70d1819c..0d29eecf 100644 --- a/kernel-rs/src/time.rs +++ b/kernel-rs/src/time.rs @@ -15,3 +15,8 @@ pub fn realtime() -> (u32, u32) { let sum = start.1 + offset.1; (start.0 + offset.0 + sum / 1_000_000, sum % 1_000_000) } + +pub fn uptime() { + let mut offset = self::OFFSET.lock(); + println!("{}s", offset.0 + offset.1 / 1_000_000); +} diff --git a/kernel-rs/src/vga/mod.rs b/kernel-rs/src/vga/mod.rs index e6df8adc..e4ded8b6 100644 --- a/kernel-rs/src/vga/mod.rs +++ b/kernel-rs/src/vga/mod.rs @@ -4,8 +4,6 @@ pub mod cursor; pub use self::color::{Color, ColorCode}; use self::cursor::CURSOR; -use console; - pub static mut VGA: Writer = self::Writer::new(); #[derive(Debug, Clone, Copy)] @@ -16,6 +14,7 @@ struct ScreenChar { } // print wrapper macro around vga +#[allow(unused_macros)] macro_rules! print { ($($arg:tt)*) => ({ $crate::vga::print(format_args!($($arg)*)); @@ -23,6 +22,7 @@ macro_rules! print { } // flushed print +#[allow(unused_macros)] macro_rules! fprint { ($($arg:tt)*) => ({ print!($($arg)*); @@ -31,12 +31,15 @@ macro_rules! fprint { } // print with a line feed +#[allow(unused_macros)] macro_rules! println { + () => ({print!("\n")}); ($fmt:expr) => (print!(concat!($fmt, "\n"))); ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); } // flushed println +#[allow(unused_macros)] macro_rules! fprintln { ($($arg:tt)*) => ({ println!($($arg)*); @@ -73,8 +76,6 @@ 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 { @@ -83,46 +84,36 @@ impl 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 get_command(&self) -> Result<&str, &'static str> { - match core::str::from_utf8(&self.command) { - Ok(y) => Ok(&y[..self.command_len]), - Err(_) => Err("Command is not utf8 char"), - } - } - - pub fn erase_byte(&mut self) { self.buffer_pos -= 2; let i = self.buffer_pos; self.buffer[i] = b' '; self.buffer[i + 1] = self.color_code.0; self.flush(); - // 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[self.buffer_pos] = byte; + self.buffer[self.buffer_pos + 1] = self.color_code.0; self.buffer_pos += 2; } } if self.buffer_pos >= self.buffer.len() { self.scroll(); + self.flush(); } + // flushing here is correct but slow + // self.flush(); } pub fn write_str(&mut self, s: &str) { @@ -132,9 +123,7 @@ impl Writer { } fn flush_cursor(&self) { - unsafe { - CURSOR.flush(self.buffer_pos / 2); - } + unsafe { CURSOR.flush(self.buffer_pos / 2); } } pub fn flush(&mut self) { @@ -157,7 +146,6 @@ impl Writer { self.buffer[((BUFFER_ROWS - 1) * BUFFER_COLS) + (col + 1)] = ColorCode::new(Color::White, Color::Black).0; } - self.buffer_pos = (BUFFER_ROWS - 1) * BUFFER_COLS; } }