Apparently this wasn't committed previously?
This commit is contained in:
parent
dd168ab5fd
commit
86a85b8b0d
12 changed files with 440 additions and 415 deletions
|
@ -1,6 +1,7 @@
|
||||||
display_library: x, options="gui_debug"
|
display_library: x, options="gui_debug"
|
||||||
port_e9_hack: enabled=1
|
port_e9_hack: enabled=1
|
||||||
cpu: reset_on_triple_fault=0
|
cpu: reset_on_triple_fault=0, model=tigerlake
|
||||||
|
magic_break: enabled=1
|
||||||
|
|
||||||
ata0-master: type=cdrom, path=../kernel/aphrodite.iso, status=inserted
|
ata0-master: type=cdrom, path=../kernel/aphrodite.iso, status=inserted
|
||||||
boot: cdrom
|
boot: cdrom
|
|
@ -1,26 +0,0 @@
|
||||||
# bx_enh_dbg_ini
|
|
||||||
SeeReg[0] = TRUE
|
|
||||||
SeeReg[1] = TRUE
|
|
||||||
SeeReg[2] = TRUE
|
|
||||||
SeeReg[3] = TRUE
|
|
||||||
SeeReg[4] = FALSE
|
|
||||||
SeeReg[5] = FALSE
|
|
||||||
SeeReg[6] = FALSE
|
|
||||||
SeeReg[7] = FALSE
|
|
||||||
SingleCPU = FALSE
|
|
||||||
ShowIOWindows = TRUE
|
|
||||||
ShowButtons = TRUE
|
|
||||||
SeeRegColors = TRUE
|
|
||||||
ignoreNxtT = TRUE
|
|
||||||
ignSSDisasm = TRUE
|
|
||||||
UprCase = 0
|
|
||||||
DumpInAsciiMode = 3
|
|
||||||
isLittleEndian = TRUE
|
|
||||||
DefaultAsmLines = 512
|
|
||||||
DumpWSIndex = 0
|
|
||||||
DockOrder = 0x123
|
|
||||||
ListWidthPix[0] = 354
|
|
||||||
ListWidthPix[1] = 411
|
|
||||||
ListWidthPix[2] = 512
|
|
||||||
MainWindow = 0, 0, 895, 500
|
|
||||||
FontName = Normal
|
|
|
@ -3,113 +3,10 @@
|
||||||
#![allow(unexpected_cfgs)]
|
#![allow(unexpected_cfgs)]
|
||||||
#![allow(static_mut_refs)]
|
#![allow(static_mut_refs)]
|
||||||
|
|
||||||
use crate::arch::x86::output::*;
|
use crate::output::*;
|
||||||
use crate::arch::x86::egatext as egatext;
|
|
||||||
use crate::multiboot2::BootInfo;
|
|
||||||
use egatext::*;
|
|
||||||
|
|
||||||
/// The real entrypoint to the kernel. `internel/arch/*/entry.rs` files eventually call this.
|
/// The real entrypoint to the kernel. `internel/arch/*/entry.rs` files eventually call this.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn _entry(ega: Option<crate::arch::x86::egatext::FramebufferInfo>, BI: &BootInfo) -> ! {
|
pub fn _entry(display: Option<&dyn crate::TextDisplay>, BI: &crate::boot::BootInfo) -> ! {
|
||||||
if ega.is_some() {
|
|
||||||
let ega = ega.unwrap();
|
|
||||||
ega.clear_screen(WHITE_ON_BLACK);
|
|
||||||
sreset();
|
|
||||||
|
|
||||||
let extended_functions = crate::arch::x86::cpuid_extended_functions();
|
|
||||||
|
|
||||||
if extended_functions {
|
|
||||||
binfosln("This CPU supports extended functions", ega).unwrap();
|
|
||||||
|
|
||||||
let longmode_support = crate::arch::x86::cpuid(0x80000001).1 & (1<<29) > 1;
|
|
||||||
if longmode_support {
|
|
||||||
binfosln("This CPU supports long mode", ega).unwrap();
|
|
||||||
} else {
|
|
||||||
binfosln("This CPU does NOT support long mode!", ega).unwrap();
|
|
||||||
bdebugs("Long mode CPUID: ", ega).unwrap();
|
|
||||||
bdebugbnpln(&crate::u32_as_u8_slice(crate::arch::x86::cpuid(0x80000001).1), ega).unwrap();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binfosln("This CPU does NOT support extended functions or long mode!", ega).unwrap();
|
|
||||||
}
|
|
||||||
if BI.bootloader_name.is_some() {
|
|
||||||
binfos("Kernel booted by ", ega).unwrap();
|
|
||||||
binfosnpln(BI.bootloader_name.unwrap().into(), ega).unwrap();
|
|
||||||
}
|
|
||||||
if BI.cmdline.is_some() {
|
|
||||||
binfos("Command line passed: \"", ega).unwrap();
|
|
||||||
binfosnp(BI.cmdline.unwrap().into(), ega).unwrap();
|
|
||||||
binfosnpln("\"", ega).unwrap();
|
|
||||||
}
|
|
||||||
if BI.mem_lower.is_some() {
|
|
||||||
binfos("Amount of lower memory: ", ega).unwrap();
|
|
||||||
binfobnpln(&crate::u32_as_u8_slice(BI.mem_lower.unwrap()), ega).unwrap();
|
|
||||||
}
|
|
||||||
if BI.mem_upper.is_some() {
|
|
||||||
binfos("Amount of upper memory: ", ega).unwrap();
|
|
||||||
binfobnpln(&crate::u32_as_u8_slice(BI.mem_upper.unwrap()), ega).unwrap();
|
|
||||||
}
|
|
||||||
if BI.memory_map.is_some() {
|
|
||||||
binfos("Recieved memory map from bootloader with ", ega).unwrap();
|
|
||||||
binfobnp(&crate::usize_as_u8_slice(BI.memory_map.unwrap().sections.len()), ega).unwrap();
|
|
||||||
binfosnpln(" sections", ega).unwrap();
|
|
||||||
let mut i = 0;
|
|
||||||
for ele in BI.memory_map.unwrap().sections {
|
|
||||||
binfos("Section #", ega).unwrap();
|
|
||||||
binfobnp(&crate::usize_as_u8_slice(i), ega).unwrap();
|
|
||||||
binfosnp(": ", ega).unwrap();
|
|
||||||
match ele.mem_type {
|
|
||||||
1 => {
|
|
||||||
binfosnp("Available RAM", ega).unwrap();
|
|
||||||
},
|
|
||||||
2 => {
|
|
||||||
binfosnp("Reserved by hardware", ega).unwrap();
|
|
||||||
}
|
|
||||||
3 => {
|
|
||||||
binfosnp("ACPI information", ega).unwrap();
|
|
||||||
},
|
|
||||||
4 => {
|
|
||||||
binfosnp("Reserved memory", ega).unwrap();
|
|
||||||
},
|
|
||||||
5 => {
|
|
||||||
binfosnp("Defective", ega).unwrap();
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
binfosnp("Reserved/unknown (type=", ega).unwrap();
|
|
||||||
binfobnp(&crate::u32_as_u8_slice(ele.mem_type), ega).unwrap();
|
|
||||||
binfosnp(")", ega).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binfosnp(", starting at ", ega).unwrap();
|
|
||||||
binfobnp(&crate::u64_as_u8_slice(ele.base_addr), ega).unwrap();
|
|
||||||
binfosnp(" and running for ", ega).unwrap();
|
|
||||||
binfobnp(&crate::u64_as_u8_slice(ele.length), ega).unwrap();
|
|
||||||
binfosnpln(" bytes", ega).unwrap();
|
|
||||||
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if BI.bootloader_name.is_some() {
|
|
||||||
sinfos("Kernel booted by ");
|
|
||||||
sinfosnpln(BI.bootloader_name.unwrap().into());
|
|
||||||
}
|
|
||||||
if BI.cmdline.is_some() {
|
|
||||||
sinfos("Command line passed: \"");
|
|
||||||
sinfosnp(BI.cmdline.unwrap().into());
|
|
||||||
sinfosnpln("\"");
|
|
||||||
}
|
|
||||||
if BI.memory_map.is_some() {
|
|
||||||
sinfosln("Recieved memory map from bootloader");
|
|
||||||
}
|
|
||||||
if BI.mem_lower.is_some() {
|
|
||||||
sinfos("Amount of lower memory: ");
|
|
||||||
sinfobnpln(&crate::u32_as_u8_slice(BI.mem_lower.unwrap()));
|
|
||||||
}
|
|
||||||
if BI.mem_upper.is_some() {
|
|
||||||
sinfos("Amount of upper memory: ");
|
|
||||||
sinfobnpln(&crate::u32_as_u8_slice(BI.mem_upper.unwrap()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
//! Arch-specific code.
|
//! Arch-specific code.
|
||||||
|
|
||||||
pub mod x86;
|
mod x86;
|
||||||
|
|
||||||
|
pub use x86::*;
|
|
@ -1,6 +1,8 @@
|
||||||
//! Stuff for writing and reading to the EGA text buffer.
|
//! Stuff for writing and reading to the EGA text buffer.
|
||||||
#![cfg(any(target_arch = "x86"))]
|
#![cfg(any(target_arch = "x86"))]
|
||||||
|
|
||||||
|
use crate::Color;
|
||||||
|
|
||||||
/// Information about the framebuffer.
|
/// Information about the framebuffer.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct FramebufferInfo {
|
pub struct FramebufferInfo {
|
||||||
|
@ -29,9 +31,9 @@ pub const WHITE_ON_BLACK: u8 = 0b00000111;
|
||||||
/// Black text on a black background.
|
/// Black text on a black background.
|
||||||
pub const BLACK_ON_BLACK: u8 = 0b00000000;
|
pub const BLACK_ON_BLACK: u8 = 0b00000000;
|
||||||
|
|
||||||
impl FramebufferInfo {
|
impl crate::TextDisplay for FramebufferInfo {
|
||||||
/// Writes a character to the screen.
|
/// Writes a character to the screen.
|
||||||
pub fn write_char(self, mut pos: (u32, u32), char: u8, color: u8) -> Result<(), crate::Error<'static>> {
|
fn write_char(&self, mut pos: (u32, u32), char: u8, color: Color) -> Result<(), crate::Error<'static>> {
|
||||||
if pos.0>self.width {
|
if pos.0>self.width {
|
||||||
return Err(crate::Error::new("Invalid X position", ERR_INVALID_X));
|
return Err(crate::Error::new("Invalid X position", ERR_INVALID_X));
|
||||||
}
|
}
|
||||||
|
@ -51,65 +53,12 @@ impl FramebufferInfo {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
fn get_size(&self) -> (u32, u32) {
|
||||||
|
(self.width, self.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Clears the screen.
|
impl FramebufferInfo {
|
||||||
pub fn clear_screen(self, color: u8) {
|
|
||||||
for x in 0..self.width {
|
|
||||||
for y in 0..self.height {
|
|
||||||
self.write_char((x, y), b' ', color).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes a &str to the screen.
|
|
||||||
pub fn write_str(mut self, pos: (u32, u32), str: &str, color: u8) -> Result<(u32, u32), crate::Error<'static>> {
|
|
||||||
let (mut x, mut y) = pos;
|
|
||||||
let change_cursor = self.change_cursor;
|
|
||||||
if change_cursor {
|
|
||||||
self.change_cursor = false;
|
|
||||||
}
|
|
||||||
for char in str.as_bytes() {
|
|
||||||
self.write_char((x, y), *char, color)?;
|
|
||||||
if *char == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
x += 1;
|
|
||||||
while x>self.width {
|
|
||||||
x -= self.width;
|
|
||||||
y += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if change_cursor {
|
|
||||||
self.change_cursor = true;
|
|
||||||
self.set_cursor_location((x, y));
|
|
||||||
}
|
|
||||||
Ok((x, y))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes a &\[u8] to the screen.
|
|
||||||
pub fn write_bytes(mut self, pos: (u32, u32), str: &[u8], color: u8) -> Result<(u32, u32), crate::Error<'static>> {
|
|
||||||
let (mut x, mut y) = pos;
|
|
||||||
let change_cursor = self.change_cursor;
|
|
||||||
if change_cursor {
|
|
||||||
self.change_cursor = false;
|
|
||||||
}
|
|
||||||
for char in str {
|
|
||||||
self.write_char((x, y), *char, color)?;
|
|
||||||
if *char == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
x += 1;
|
|
||||||
while x>self.width {
|
|
||||||
x -= self.width;
|
|
||||||
y += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if change_cursor {
|
|
||||||
self.change_cursor = true;
|
|
||||||
self.set_cursor_location((x, y));
|
|
||||||
}
|
|
||||||
Ok((x, y))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Disables the cursor.
|
/// Disables the cursor.
|
||||||
pub fn disable_cursor(self) {
|
pub fn disable_cursor(self) {
|
||||||
|
|
|
@ -7,10 +7,13 @@ pub mod interrupts;
|
||||||
pub mod ports;
|
pub mod ports;
|
||||||
pub mod output;
|
pub mod output;
|
||||||
pub mod egatext;
|
pub mod egatext;
|
||||||
|
pub mod paging;
|
||||||
|
|
||||||
mod constants;
|
mod constants;
|
||||||
|
|
||||||
pub use constants::*;
|
pub use constants::*;
|
||||||
|
use interrupts::{pop_irq, restore_irq};
|
||||||
|
use ports::{inb, outb};
|
||||||
|
|
||||||
/// Returns information from the CPUID command in the form
|
/// Returns information from the CPUID command in the form
|
||||||
/// (ebx, edx, ecx).
|
/// (ebx, edx, ecx).
|
||||||
|
@ -36,3 +39,135 @@ pub fn cpuid_extended_functions() -> bool {
|
||||||
}
|
}
|
||||||
out >= 0x80000001
|
out >= 0x80000001
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the a20 gate is enabled.
|
||||||
|
pub fn test_a20() -> bool {
|
||||||
|
let addr0: usize;
|
||||||
|
let addr1: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"mov edi, 0x112345",
|
||||||
|
"mov esi, 0x012345",
|
||||||
|
"mov [esi], esi",
|
||||||
|
"mov [edi], edi",
|
||||||
|
"mov eax, esi",
|
||||||
|
out("eax") addr0, out("edi") addr1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
addr0 != addr1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Waits for a keyboard command to complete.
|
||||||
|
pub fn wait_for_keyboard_cmd() {
|
||||||
|
while inb(0x64)&0b10 > 1 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Waits for there to be data to read from the keyboard.
|
||||||
|
pub fn wait_for_keyboard_data() {
|
||||||
|
while inb(0x64)&0b1 == 0 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sends a keyboard command.
|
||||||
|
pub fn send_keyboard_cmd(byte: u8) {
|
||||||
|
outb(0x64, byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets data from the keyboard.
|
||||||
|
pub fn get_keyboard_data() -> u8 {
|
||||||
|
inb(0x60)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sends data to the keyboard.
|
||||||
|
pub fn send_keyboard_data(data: u8) {
|
||||||
|
outb(0x60, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to enable the a20 gate via the keyboard controller method.
|
||||||
|
pub fn enable_a20_keyboard() {
|
||||||
|
let irq = pop_irq();
|
||||||
|
|
||||||
|
wait_for_keyboard_cmd();
|
||||||
|
send_keyboard_cmd(0xAD); // disable keyboard
|
||||||
|
|
||||||
|
wait_for_keyboard_cmd();
|
||||||
|
send_keyboard_cmd(0xD0); // read from input
|
||||||
|
|
||||||
|
wait_for_keyboard_cmd();
|
||||||
|
wait_for_keyboard_data();
|
||||||
|
let a = get_keyboard_data();
|
||||||
|
|
||||||
|
wait_for_keyboard_cmd();
|
||||||
|
send_keyboard_cmd(0xD1); // write to output
|
||||||
|
|
||||||
|
wait_for_keyboard_cmd();
|
||||||
|
send_keyboard_data(a|2);
|
||||||
|
|
||||||
|
wait_for_keyboard_cmd();
|
||||||
|
send_keyboard_cmd(0xAE); // enable keyboard
|
||||||
|
|
||||||
|
restore_irq(irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to enable the a20 gate via fast a20.
|
||||||
|
/// Note that this may not work or do something unexpected.
|
||||||
|
pub fn enable_a20_fasta20() {
|
||||||
|
let mut a = inb(0x92);
|
||||||
|
if a&0b10 > 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a |= 0b10;
|
||||||
|
a &= 0xFE;
|
||||||
|
outb(0x92, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to enable the a20 gate by reading from port 0xee.
|
||||||
|
pub fn enable_a20_ee_port() {
|
||||||
|
inb(0xee);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to enable the a20 gate by trying many different methods
|
||||||
|
/// and seeing what sticks.
|
||||||
|
pub fn enable_a20() -> bool {
|
||||||
|
if test_a20() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enable_a20_keyboard();
|
||||||
|
let mut i = 0u32;
|
||||||
|
while (!test_a20()) && i<10000 {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if test_a20() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enable_a20_ee_port();
|
||||||
|
let mut i = 0u32;
|
||||||
|
while (!test_a20()) && i<10000 {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if test_a20() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enable_a20_fasta20();
|
||||||
|
let mut i = 0u32;
|
||||||
|
while (!test_a20()) && i<10000 {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return test_a20();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disables paging by clearing bit 31 in the cr0 register.
|
||||||
|
pub fn disable_paging() {
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"mov eax, cr0",
|
||||||
|
"and eax, 01111111111111111111111111111111b",
|
||||||
|
"mov cr0, eax"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,12 +2,8 @@
|
||||||
#![cfg(any(target_arch = "x86"))]
|
#![cfg(any(target_arch = "x86"))]
|
||||||
|
|
||||||
use super::ports;
|
use super::ports;
|
||||||
use super::egatext::*;
|
|
||||||
|
|
||||||
use paste::paste;
|
use paste::paste;
|
||||||
|
|
||||||
static mut OUTPUT_TERM_POSITION: (u32, u32) = (0, 0);
|
|
||||||
|
|
||||||
macro_rules! message_funcs {
|
macro_rules! message_funcs {
|
||||||
($func_name:ident, $prefix:literal, $level:ident) => {
|
($func_name:ident, $prefix:literal, $level:ident) => {
|
||||||
paste! {
|
paste! {
|
||||||
|
@ -97,215 +93,6 @@ macro_rules! message_funcs {
|
||||||
}
|
}
|
||||||
ports::outb(super::DEBUG_PORT, s);
|
ports::outb(super::DEBUG_PORT, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
/// Outputs a $func_name message &str to the terminal.
|
|
||||||
pub fn [< t $func_name s >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
unsafe {
|
|
||||||
if cfg!($level = "false") {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, WHITE_ON_BLACK)?;
|
|
||||||
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// Outputs a $func_name message &str and a newline to the terminal.
|
|
||||||
pub fn [< t $func_name sln >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
unsafe {
|
|
||||||
if cfg!($level = "false") {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, WHITE_ON_BLACK)?;
|
|
||||||
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?;
|
|
||||||
OUTPUT_TERM_POSITION.1 += 1;
|
|
||||||
OUTPUT_TERM_POSITION.0 = 0;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Outputs a $func_name message &\[u8] to the terminal.
|
|
||||||
pub fn [< t $func_name b >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
unsafe {
|
|
||||||
if cfg!($level = "false") {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, WHITE_ON_BLACK)?;
|
|
||||||
OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// Outputs a $func_name message &\[u8] and a newline to the terminal.
|
|
||||||
pub fn [< t $func_name bln >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
unsafe {
|
|
||||||
if cfg!($level = "false") {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, WHITE_ON_BLACK)?;
|
|
||||||
OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?;
|
|
||||||
OUTPUT_TERM_POSITION.1 += 1;
|
|
||||||
OUTPUT_TERM_POSITION.0 = 0;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Outputs a(n) $func_name message u8 to the terminal.
|
|
||||||
pub fn [< t $func_name u >](s: u8, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
unsafe {
|
|
||||||
if cfg!($level = "false") {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, WHITE_ON_BLACK)?;
|
|
||||||
info.write_char(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?;
|
|
||||||
OUTPUT_TERM_POSITION.0 += 1;
|
|
||||||
while OUTPUT_TERM_POSITION.0 > info.width {
|
|
||||||
OUTPUT_TERM_POSITION.0 -= info.width;
|
|
||||||
OUTPUT_TERM_POSITION.1 += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/// Outputs a $func_name message &str to the terminal without a prefix.
|
|
||||||
pub fn [< t $func_name snp >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
unsafe {
|
|
||||||
if cfg!($level = "false") {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// Outputs a $func_name message &str and a newline to the terminal without a prefix.
|
|
||||||
pub fn [< t $func_name snpln >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
unsafe {
|
|
||||||
if cfg!($level = "false") {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?;
|
|
||||||
OUTPUT_TERM_POSITION.1 += 1;
|
|
||||||
OUTPUT_TERM_POSITION.0 = 0;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Outputs a $func_name message &\[u8] to the terminal without a prefix.
|
|
||||||
pub fn [< t $func_name bnp >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
unsafe {
|
|
||||||
if cfg!($level = "false") {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// Outputs a $func_name message &\[u8] and a newline to the terminal without a prefix.
|
|
||||||
pub fn [< t $func_name bnpln >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
unsafe {
|
|
||||||
if cfg!($level = "false") {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?;
|
|
||||||
OUTPUT_TERM_POSITION.1 += 1;
|
|
||||||
OUTPUT_TERM_POSITION.0 = 0;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Outputs a(n) $func_name message u8 to the terminal without a prefix.
|
|
||||||
pub fn [< t $func_name unp >](s: u8, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
unsafe {
|
|
||||||
if cfg!($level = "false") {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
info.write_char(OUTPUT_TERM_POSITION, s, WHITE_ON_BLACK)?;
|
|
||||||
OUTPUT_TERM_POSITION.0 += 1;
|
|
||||||
while OUTPUT_TERM_POSITION.0 > info.width {
|
|
||||||
OUTPUT_TERM_POSITION.0 -= info.width;
|
|
||||||
OUTPUT_TERM_POSITION.1 += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
/// Outputs a $func_name message &str to the terminal.
|
|
||||||
pub fn [< b $func_name s >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
[< s $func_name s >](s);
|
|
||||||
[< t $func_name s >](s, info)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// Outputs a $func_name message &str and a newline to the terminal.
|
|
||||||
pub fn [< b $func_name sln >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
[< s $func_name sln >](s);
|
|
||||||
[< t $func_name sln >](s, info)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Outputs a $func_name message &\[u8] to the terminal.
|
|
||||||
pub fn [< b $func_name b >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
[< s $func_name b >](s);
|
|
||||||
[< t $func_name b >](s, info)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// Outputs a $func_name message &\[u8] and a newline to the terminal.
|
|
||||||
pub fn [< b $func_name bln >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
[< s $func_name bln >](s);
|
|
||||||
[< t $func_name bln >](s, info)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Outputs a(n) $func_name message u8 to the terminal.
|
|
||||||
pub fn [< b $func_name u >](s: u8, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
[< s $func_name u >](s);
|
|
||||||
[< t $func_name u >](s, info)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/// Outputs a $func_name message &str to the terminal without a prefix.
|
|
||||||
pub fn [< b $func_name snp >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
[< s $func_name snp >](s);
|
|
||||||
[< t $func_name snp >](s, info)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// Outputs a $func_name message &str and a newline to the terminal without a prefix.
|
|
||||||
pub fn [< b $func_name snpln >](s: &str, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
[< s $func_name snpln >](s);
|
|
||||||
[< t $func_name snpln >](s, info)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Outputs a $func_name message &\[u8] to the terminal without a prefix.
|
|
||||||
pub fn [< b $func_name bnp >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
[< s $func_name bnp >](s);
|
|
||||||
[< t $func_name bnp >](s, info)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// Outputs a $func_name message &\[u8] and a newline to the terminal without a prefix.
|
|
||||||
pub fn [< b $func_name bnpln >](s: &[u8], info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
[< s $func_name bnpln >](s);
|
|
||||||
[< t $func_name bnpln >](s, info)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Outputs a(n) $func_name message u8 to the terminal without a prefix.
|
|
||||||
pub fn [< b $func_name unp >](s: u8, info: FramebufferInfo) -> Result<(), crate::Error<'static>> {
|
|
||||||
[< s $func_name unp >](s);
|
|
||||||
[< t $func_name unp >](s, info)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,10 +104,3 @@ message_funcs!(error, "[ERROR] ", CONFIG_PREUSER_OUTPUT_ERROR);
|
||||||
message_funcs!(fatal, "[FATAL] ", CONFIG_PREUSER_OUTPUT_FATAL);
|
message_funcs!(fatal, "[FATAL] ", CONFIG_PREUSER_OUTPUT_FATAL);
|
||||||
message_funcs!(output, "", NONE);
|
message_funcs!(output, "", NONE);
|
||||||
|
|
||||||
/// Resets the position of output to the screen.
|
|
||||||
pub fn sreset() {
|
|
||||||
unsafe {
|
|
||||||
OUTPUT_TERM_POSITION = (0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
1
kernel/src/include/arch/x86/paging.rs
Normal file
1
kernel/src/include/arch/x86/paging.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
//! Functions and types related to paging.
|
56
kernel/src/include/boot.rs
Normal file
56
kernel/src/include/boot.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
//! General bootloader-independent stuff.
|
||||||
|
|
||||||
|
/// A type of memory, for use in [MemoryMapping]s.
|
||||||
|
/// The memory allocator will ignore all memory
|
||||||
|
/// except for memory with type [MemoryType::Free]
|
||||||
|
/// or [MemoryType::HardwareSpecific] memory with
|
||||||
|
/// the boolean argument set.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum MemoryType {
|
||||||
|
/// Free RAM with no use.
|
||||||
|
Free,
|
||||||
|
/// Reserved by something.
|
||||||
|
Reserved,
|
||||||
|
/// Reserved by something on the hardware.
|
||||||
|
HardwareReserved,
|
||||||
|
/// Faulty RAM modules.
|
||||||
|
Faulty,
|
||||||
|
/// Unknown use.
|
||||||
|
Unknown,
|
||||||
|
/// Hardware-specific use. The boolean argument states
|
||||||
|
/// whether memory can be allocated in this region.
|
||||||
|
HardwareSpecific(u32, bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A single memory mapping for [MemoryMap].
|
||||||
|
pub trait MemoryMapping {
|
||||||
|
/// Returns the type of the memory.
|
||||||
|
fn get_type(&self) -> MemoryType;
|
||||||
|
/// Returns the beginning of the memory.
|
||||||
|
fn get_start(&self) -> usize;
|
||||||
|
/// Returns the length of the memory.
|
||||||
|
fn get_length(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Memory mapping.
|
||||||
|
pub trait MemoryMap<'a>: core::iter::Iterator<Item = &'a dyn MemoryMapping> + core::ops::Index<usize, Output = &'a dyn MemoryMapping> {
|
||||||
|
/// Returns the number of [MemoryMapping]s in the MemoryMap. This is total, not remainder.
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bootloader-independent information.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct BootInfo<'a> {
|
||||||
|
/// The commandline of the kernel.
|
||||||
|
/// See https://github.com/AverseABFun/aphrodite/wiki/Plan#bootloader (remember to update link later!) for the format.
|
||||||
|
pub cmdline: Option<&'static str>,
|
||||||
|
|
||||||
|
/// The memory map provided by the bootloader. If None, the kernel will attempt to generate it.
|
||||||
|
pub memory_map: Option<&'a dyn MemoryMap<'a>>,
|
||||||
|
|
||||||
|
/// The name of the bootloader(for example, "GRUB 2.12").
|
||||||
|
pub bootloader_name: Option<&'static str>,
|
||||||
|
|
||||||
|
/// Provides a way to display text.
|
||||||
|
pub output: Option<&'a dyn crate::TextDisplay>,
|
||||||
|
}
|
|
@ -10,9 +10,13 @@ pub mod multiboot2;
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
mod errors;
|
mod errors;
|
||||||
pub mod _entry;
|
pub mod _entry;
|
||||||
|
mod traits;
|
||||||
|
pub mod output;
|
||||||
|
pub mod boot;
|
||||||
|
|
||||||
#[allow(unused_imports)] // if there are no constants, then it gives a warning
|
#[allow(unused_imports)] // if there are no constants, then it gives a warning
|
||||||
pub use constants::*;
|
pub use constants::*;
|
||||||
|
|
||||||
pub use errors::*;
|
pub use errors::*;
|
||||||
pub use util::*;
|
pub use util::*;
|
||||||
|
pub use traits::*;
|
159
kernel/src/include/output.rs
Normal file
159
kernel/src/include/output.rs
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
//! Architecture-independent output functions.
|
||||||
|
|
||||||
|
use paste::paste;
|
||||||
|
use crate::COLOR_DEFAULT;
|
||||||
|
|
||||||
|
static mut OUTPUT_TERM_POSITION: (u32, u32) = (0, 0);
|
||||||
|
|
||||||
|
macro_rules! message_funcs {
|
||||||
|
($func_name:ident, $prefix:literal, $level:ident) => {
|
||||||
|
paste! {
|
||||||
|
/// Outputs a $func_name message &str to the terminal.
|
||||||
|
pub fn [< t $func_name s >](s: &str, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> {
|
||||||
|
unsafe {
|
||||||
|
if cfg!($level = "false") {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, COLOR_DEFAULT)?;
|
||||||
|
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/// Outputs a $func_name message &str and a newline to the terminal.
|
||||||
|
pub fn [< t $func_name sln >](s: &str, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> {
|
||||||
|
unsafe {
|
||||||
|
if cfg!($level = "false") {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, COLOR_DEFAULT)?;
|
||||||
|
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?;
|
||||||
|
OUTPUT_TERM_POSITION.1 += 1;
|
||||||
|
OUTPUT_TERM_POSITION.0 = 0;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Outputs a $func_name message &\[u8] to the terminal.
|
||||||
|
pub fn [< t $func_name b >](s: &[u8], info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> {
|
||||||
|
unsafe {
|
||||||
|
if cfg!($level = "false") {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, COLOR_DEFAULT)?;
|
||||||
|
OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/// Outputs a $func_name message &\[u8] and a newline to the terminal.
|
||||||
|
pub fn [< t $func_name bln >](s: &[u8], info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> {
|
||||||
|
unsafe {
|
||||||
|
if cfg!($level = "false") {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, COLOR_DEFAULT)?;
|
||||||
|
OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?;
|
||||||
|
OUTPUT_TERM_POSITION.1 += 1;
|
||||||
|
OUTPUT_TERM_POSITION.0 = 0;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Outputs a(n) $func_name message u8 to the terminal.
|
||||||
|
pub fn [< t $func_name u >](s: u8, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> {
|
||||||
|
let (width, _) = info.get_size();
|
||||||
|
unsafe {
|
||||||
|
if cfg!($level = "false") {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, $prefix, COLOR_DEFAULT)?;
|
||||||
|
info.write_char(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?;
|
||||||
|
OUTPUT_TERM_POSITION.0 += 1;
|
||||||
|
while OUTPUT_TERM_POSITION.0 > width {
|
||||||
|
OUTPUT_TERM_POSITION.0 -= width;
|
||||||
|
OUTPUT_TERM_POSITION.1 += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// Outputs a $func_name message &str to the terminal without a prefix.
|
||||||
|
pub fn [< t $func_name snp >](s: &str, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> {
|
||||||
|
unsafe {
|
||||||
|
if cfg!($level = "false") {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/// Outputs a $func_name message &str and a newline to the terminal without a prefix.
|
||||||
|
pub fn [< t $func_name snpln >](s: &str, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> {
|
||||||
|
unsafe {
|
||||||
|
if cfg!($level = "false") {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
OUTPUT_TERM_POSITION = info.write_str(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?;
|
||||||
|
OUTPUT_TERM_POSITION.1 += 1;
|
||||||
|
OUTPUT_TERM_POSITION.0 = 0;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Outputs a $func_name message &\[u8] to the terminal without a prefix.
|
||||||
|
pub fn [< t $func_name bnp >](s: &[u8], info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> {
|
||||||
|
unsafe {
|
||||||
|
if cfg!($level = "false") {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/// Outputs a $func_name message &\[u8] and a newline to the terminal without a prefix.
|
||||||
|
pub fn [< t $func_name bnpln >](s: &[u8], info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> {
|
||||||
|
unsafe {
|
||||||
|
if cfg!($level = "false") {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
OUTPUT_TERM_POSITION = info.write_bytes(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?;
|
||||||
|
OUTPUT_TERM_POSITION.1 += 1;
|
||||||
|
OUTPUT_TERM_POSITION.0 = 0;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Outputs a(n) $func_name message u8 to the terminal without a prefix.
|
||||||
|
pub fn [< t $func_name unp >](s: u8, info: &dyn crate::TextDisplay) -> Result<(), crate::Error<'static>> {
|
||||||
|
let (width, _) = info.get_size();
|
||||||
|
unsafe {
|
||||||
|
if cfg!($level = "false") {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
info.write_char(OUTPUT_TERM_POSITION, s, COLOR_DEFAULT)?;
|
||||||
|
OUTPUT_TERM_POSITION.0 += 1;
|
||||||
|
while OUTPUT_TERM_POSITION.0 > width {
|
||||||
|
OUTPUT_TERM_POSITION.0 -= width;
|
||||||
|
OUTPUT_TERM_POSITION.1 += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message_funcs!(debug, "[DEBUG] ", CONFIG_PREUSER_OUTPUT_DEBUG);
|
||||||
|
message_funcs!(info, "[INFO] ", CONFIG_PREUSER_OUTPUT_INFO);
|
||||||
|
message_funcs!(warning, "[WARN] ", CONFIG_PREUSER_OUTPUT_WARN);
|
||||||
|
message_funcs!(error, "[ERROR] ", CONFIG_PREUSER_OUTPUT_ERROR);
|
||||||
|
message_funcs!(fatal, "[FATAL] ", CONFIG_PREUSER_OUTPUT_FATAL);
|
||||||
|
message_funcs!(output, "", NONE);
|
||||||
|
|
||||||
|
/// Resets the position of output to the screen.
|
||||||
|
pub fn sreset() {
|
||||||
|
unsafe {
|
||||||
|
OUTPUT_TERM_POSITION = (0, 0);
|
||||||
|
}
|
||||||
|
}
|
67
kernel/src/include/traits.rs
Normal file
67
kernel/src/include/traits.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
//! General traits. Mostly implemented in arch/*.
|
||||||
|
|
||||||
|
/// A type used for color in the functions of [TextDisplay].
|
||||||
|
pub type Color = u8;
|
||||||
|
|
||||||
|
/// Black-on-black.
|
||||||
|
pub const COLOR_BLACK: Color = 0;
|
||||||
|
|
||||||
|
/// Should be whatever colors commonly used for status messages.
|
||||||
|
/// Generally should be white-on-black.
|
||||||
|
pub const COLOR_DEFAULT: Color = 1;
|
||||||
|
|
||||||
|
/// Some form of display that can be written too with text.
|
||||||
|
pub trait TextDisplay {
|
||||||
|
/// Writes a single character to the specified position.
|
||||||
|
fn write_char(&self, pos: (u32, u32), char: u8, color: Color) -> Result<(), crate::Error<'static>>;
|
||||||
|
/// Gets the size of the screen.
|
||||||
|
fn get_size(&self) -> (u32, u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dyn TextDisplay + '_ {
|
||||||
|
/// Clears the screen.
|
||||||
|
pub fn clear_screen(&self, color: Color) {
|
||||||
|
let (width, height) = self.get_size();
|
||||||
|
for x in 0..width {
|
||||||
|
for y in 0..height {
|
||||||
|
self.write_char((x, y), b' ', color).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes a &str to the screen.
|
||||||
|
pub fn write_str(&self, pos: (u32, u32), str: &str, color: Color) -> Result<(u32, u32), crate::Error<'static>> {
|
||||||
|
let (width, _) = self.get_size();
|
||||||
|
let (mut x, mut y) = pos;
|
||||||
|
for char in str.as_bytes() {
|
||||||
|
self.write_char((x, y), *char, color)?;
|
||||||
|
if *char == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
x += 1;
|
||||||
|
while x>width {
|
||||||
|
x -= width;
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((x, y))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes a &\[u8] to the screen.
|
||||||
|
pub fn write_bytes(&self, pos: (u32, u32), str: &[u8], color: Color) -> Result<(u32, u32), crate::Error<'static>> {
|
||||||
|
let (width, _) = self.get_size();
|
||||||
|
let (mut x, mut y) = pos;
|
||||||
|
for char in str {
|
||||||
|
self.write_char((x, y), *char, color)?;
|
||||||
|
if *char == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
x += 1;
|
||||||
|
while x>width {
|
||||||
|
x -= width;
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((x, y))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue