Testing, remove cursor, print logo

This commit is contained in:
Piotr Siuszko 2021-09-26 20:50:57 +02:00
parent 692e770cf2
commit 172c967095
7 changed files with 138 additions and 86 deletions

View File

@ -7,7 +7,8 @@ edition = "2018"
[dependencies] [dependencies]
bootloader = "0.9.19" bootloader = "0.9.19"
x86_64 = "0.14.6" x86_64 = "0.14.6"
spin = "0.5.2" spin = "0.9.2"
uart_16550 = "0.2.0"
[dependencies.lazy_static] [dependencies.lazy_static]
version = "1.0" version = "1.0"
@ -15,7 +16,9 @@ features = ["spin_no_std"]
[package.metadata.bootimage] [package.metadata.bootimage]
build-command = ["build"] build-command = ["build"]
test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-serial", "stdio",
"-display", "none"]
run-command = [ run-command = [
"qemu-system-x86_64", "-drive", "format=raw,file={}" "qemu-system-x86_64", "-drive", "format=raw,file={}"
] ]
test-success-exit-code = 33 # (0x10 << 1) | 1

View File

@ -1,54 +0,0 @@
use crate::color::Color;
use core::fmt;
pub struct Cursor {
pub position: isize,
pub foreground: Color,
pub background: Color,
}
impl Cursor {
pub fn color(&self) -> u8 {
let fg = self.foreground as u8;
let bg = (self.background as u8) << 4;
fg | bg
}
pub fn print(&mut self, text: &[u8]) {
let color = self.color();
let framebuffer = 0xb8000 as *mut u8;
for &character in text {
unsafe {
framebuffer.offset(self.position).write_volatile(character);
framebuffer.offset(self.position + 1).write_volatile(color);
}
self.position += 2;
}
}
pub fn clr(&mut self) {
self.position = 0;
for _ in 0..(80 * 25) {
self.print(b" ");
}
self.position = 0;
}
}
impl Default for Cursor {
fn default() -> Self {
Cursor {
position: 0,
foreground: Color::Green,
background: Color::DarkGray,
}
}
}
impl fmt::Write for Cursor {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.print(s.as_bytes());
Ok(())
}
}

View File

@ -1,48 +1,62 @@
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(lang_items)] #![feature(lang_items)]
#![feature(custom_test_frameworks)]
#![test_runner(crate::test_runner)]
#![reexport_test_harness_main = "test_main"]
#![no_std] #![no_std]
#![no_main] #![no_main]
use core::fmt::Write;
use core::panic::PanicInfo; use core::panic::PanicInfo;
use x86_64::instructions::hlt; use x86_64::instructions::hlt;
mod color; mod color;
mod cursor; mod serial;
mod vga_buffer; mod vga_buffer;
use color::{Color, ColorCode}; mod testable;
use cursor::Cursor; mod utils;
use vga_buffer::*;
pub fn print_something() { #[cfg(test)]
let mut writer = Writer { fn test_runner(tests: &[&dyn Fn()]) {
column_position: 0, serial_println!("Running {} tests", tests.len());
color_code: ColorCode::new(Color::Yellow, Color::Black), for test in tests {
buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, use testable::Testable;
}; test.run();
}
writer.write_byte(b'H'); utils::exit_qemu(utils::QemuExitCode::Success);
writer.write_string("ello ");
writer.write_string("Wörld!\n");
writer.write_string("Awruk!\n");
} }
#[panic_handler] #[test_case]
#[no_mangle] fn trivial_assertion() {
pub fn panic(info: &PanicInfo) -> ! { assert_eq!(1, 1);
println!("{}", info); }
loop {
hlt(); #[cfg(not(test))]
} #[panic_handler]
fn panic(info: &PanicInfo) -> ! {
println!("{}", info);
loop {}
}
#[cfg(test)]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
serial_println!("[failed]\n");
serial_println!("Error: {}\n", info);
utils::exit_qemu(utils::QemuExitCode::Failed);
loop {}
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn _start() -> ! { pub extern "C" fn _start() -> ! {
print_something(); utils::print_logo();
println!("DSADSA"); println!("");
println!("Test {}", 5132.31); println!("Welcome!");
println!("Awruk!");
println!("Test value: {}\n", 5132.31);
#[cfg(test)]
test_main();
// panic!("help!"); // panic!("help!");
loop { loop {
hlt(); hlt();

37
src/serial.rs Normal file
View File

@ -0,0 +1,37 @@
use lazy_static::lazy_static;
use spin::Mutex;
use uart_16550::SerialPort;
lazy_static! {
pub static ref SERIAL1: Mutex<SerialPort> = {
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
serial_port.init();
Mutex::new(serial_port)
};
}
#[doc(hidden)]
pub fn _print(args: ::core::fmt::Arguments) {
use core::fmt::Write;
SERIAL1
.lock()
.write_fmt(args)
.expect("Printing to serial failed");
}
/// Prints to the host through the serial interface.
#[macro_export]
macro_rules! serial_print {
($($arg:tt)*) => {
$crate::serial::_print(format_args!($($arg)*));
};
}
/// Prints to the host through the serial interface, appending a newline.
#[macro_export]
macro_rules! serial_println {
() => ($crate::serial_print!("\n"));
($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => ($crate::serial_print!(
concat!($fmt, "\n"), $($arg)*));
}

16
src/testable.rs Normal file
View File

@ -0,0 +1,16 @@
use crate::{serial_print,serial_println};
pub trait Testable {
fn run(&self) -> ();
}
impl<T> Testable for T
where
T: Fn(),
{
fn run(&self) {
serial_print!("{}...\t", core::any::type_name::<T>());
self();
serial_println!("[ok]");
}
}

29
src/utils.rs Normal file
View File

@ -0,0 +1,29 @@
use crate::println;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum QemuExitCode {
Success = 0x10,
Failed = 0x11,
}
pub fn exit_qemu(exit_code: QemuExitCode) {
use x86_64::instructions::port::Port;
unsafe {
let mut port = Port::new(0xf4);
port.write(exit_code as u32);
}
}
pub fn print_logo() {
let text = r###"
_ _ __
_ |_ |_) _ _|_/ \(_
(_ | || \|_|_> |_\_/__)
"###;
crate::vga_buffer::change_color(crate::color::Color::BrightRed);
println!("{}", text);
crate::vga_buffer::reset_color();
}

View File

@ -6,7 +6,7 @@ use spin::Mutex;
lazy_static! { lazy_static! {
pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer { pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer {
column_position: 0, column_position: 0,
color_code: ColorCode::new(Color::Yellow, Color::Black), color_code: ColorCode::new(Color::White, Color::Black),
buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
}); });
} }
@ -44,10 +44,9 @@ impl Writer {
let row = BUFFER_HEIGHT - 1; let row = BUFFER_HEIGHT - 1;
let col = self.column_position; let col = self.column_position;
let color_code = self.color_code;
let screen_char = ScreenChar { let screen_char = ScreenChar {
ascii_character: byte, ascii_character: byte,
color_code, color_code: self.color_code,
}; };
unsafe { unsafe {
core::ptr::write_volatile(&mut self.buffer.chars[row][col], screen_char); core::ptr::write_volatile(&mut self.buffer.chars[row][col], screen_char);
@ -101,6 +100,14 @@ impl fmt::Write for Writer {
} }
} }
pub fn change_color(color : Color) {
WRITER.lock().color_code = ColorCode::new(color, Color::Black);
}
pub fn reset_color() {
WRITER.lock().color_code = ColorCode::new(Color::White, Color::Black);
}
#[macro_export] #[macro_export]
macro_rules! print { macro_rules! print {
($($arg:tt)*) => ($crate::vga_buffer::_print(format_args!($($arg)*))); ($($arg:tt)*) => ($crate::vga_buffer::_print(format_args!($($arg)*)));