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"
|
||||
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
|
||||
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(static_mut_refs)]
|
||||
|
||||
use crate::arch::x86::output::*;
|
||||
use crate::arch::x86::egatext as egatext;
|
||||
use crate::multiboot2::BootInfo;
|
||||
use egatext::*;
|
||||
use crate::output::*;
|
||||
|
||||
/// The real entrypoint to the kernel. `internel/arch/*/entry.rs` files eventually call this.
|
||||
#[allow(non_snake_case)]
|
||||
pub fn _entry(ega: Option<crate::arch::x86::egatext::FramebufferInfo>, BI: &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()));
|
||||
}
|
||||
}
|
||||
pub fn _entry(display: Option<&dyn crate::TextDisplay>, BI: &crate::boot::BootInfo) -> ! {
|
||||
loop {}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
//! 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.
|
||||
#![cfg(any(target_arch = "x86"))]
|
||||
|
||||
use crate::Color;
|
||||
|
||||
/// Information about the framebuffer.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FramebufferInfo {
|
||||
|
@ -29,9 +31,9 @@ pub const WHITE_ON_BLACK: u8 = 0b00000111;
|
|||
/// Black text on a black background.
|
||||
pub const BLACK_ON_BLACK: u8 = 0b00000000;
|
||||
|
||||
impl FramebufferInfo {
|
||||
impl crate::TextDisplay for FramebufferInfo {
|
||||
/// 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 {
|
||||
return Err(crate::Error::new("Invalid X position", ERR_INVALID_X));
|
||||
}
|
||||
|
@ -51,66 +53,13 @@ impl FramebufferInfo {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Clears the screen.
|
||||
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))
|
||||
fn get_size(&self) -> (u32, u32) {
|
||||
(self.width, self.height)
|
||||
}
|
||||
}
|
||||
|
||||
impl FramebufferInfo {
|
||||
|
||||
/// Disables the cursor.
|
||||
pub fn disable_cursor(self) {
|
||||
super::ports::outb(0x3D4, 0x0A);
|
||||
|
|
|
@ -7,10 +7,13 @@ pub mod interrupts;
|
|||
pub mod ports;
|
||||
pub mod output;
|
||||
pub mod egatext;
|
||||
pub mod paging;
|
||||
|
||||
mod constants;
|
||||
|
||||
pub use constants::*;
|
||||
use interrupts::{pop_irq, restore_irq};
|
||||
use ports::{inb, outb};
|
||||
|
||||
/// Returns information from the CPUID command in the form
|
||||
/// (ebx, edx, ecx).
|
||||
|
@ -35,4 +38,136 @@ pub fn cpuid_extended_functions() -> bool {
|
|||
)
|
||||
}
|
||||
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"))]
|
||||
|
||||
use super::ports;
|
||||
use super::egatext::*;
|
||||
|
||||
use paste::paste;
|
||||
|
||||
static mut OUTPUT_TERM_POSITION: (u32, u32) = (0, 0);
|
||||
|
||||
macro_rules! message_funcs {
|
||||
($func_name:ident, $prefix:literal, $level:ident) => {
|
||||
paste! {
|
||||
|
@ -97,215 +93,6 @@ macro_rules! message_funcs {
|
|||
}
|
||||
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!(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;
|
||||
mod errors;
|
||||
pub mod _entry;
|
||||
mod traits;
|
||||
pub mod output;
|
||||
pub mod boot;
|
||||
|
||||
#[allow(unused_imports)] // if there are no constants, then it gives a warning
|
||||
pub use constants::*;
|
||||
|
||||
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