Testing, remove cursor, print logo
This commit is contained in:
parent
692e770cf2
commit
172c967095
|
|
@ -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
|
||||||
|
|
@ -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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
64
src/main.rs
64
src/main.rs
|
|
@ -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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn trivial_assertion() {
|
||||||
|
assert_eq!(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
#[no_mangle]
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
pub fn panic(info: &PanicInfo) -> ! {
|
|
||||||
println!("{}", info);
|
println!("{}", info);
|
||||||
|
loop {}
|
||||||
loop {
|
|
||||||
hlt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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();
|
||||||
|
|
|
||||||
|
|
@ -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)*));
|
||||||
|
}
|
||||||
|
|
@ -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]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
@ -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)*)));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue