add IDT and GDT initialization
This commit is contained in:
@@ -0,0 +1,147 @@
|
|||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
#[repr(C, align(8))]
|
||||||
|
struct Gdt {
|
||||||
|
entries: [u64; 5],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gdt {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self { entries: [0; 5] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
struct GdtPointer {
|
||||||
|
limit: u16,
|
||||||
|
base: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
struct TaskStateSegment {
|
||||||
|
reserved_0: u32,
|
||||||
|
privilege_stacks: [u64; 3],
|
||||||
|
reserved_1: u64,
|
||||||
|
interrupt_stacks: [u64; 7],
|
||||||
|
reserved_2: u64,
|
||||||
|
reserved_3: u16,
|
||||||
|
iomap_base: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TaskStateSegment {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
reserved_0: 0,
|
||||||
|
privilege_stacks: [0; 3],
|
||||||
|
reserved_1: 0,
|
||||||
|
interrupt_stacks: [0; 7],
|
||||||
|
reserved_2: 0,
|
||||||
|
reserved_3: 0,
|
||||||
|
iomap_base: core::mem::size_of::<TaskStateSegment>() as u16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 16 KiB
|
||||||
|
const DOUBLE_FAULT_STACK_SIZE: usize = 16 * 1024;
|
||||||
|
|
||||||
|
pub(super) const KERNEL_CODE_SELECTOR: u16 = 1 * 8;
|
||||||
|
pub(super) const KERNEL_DATA_SELECTOR: u16 = 2 * 8;
|
||||||
|
pub(super) const TSS_SELECTOR: u16 = 3 * 8;
|
||||||
|
|
||||||
|
#[repr(align(16))]
|
||||||
|
struct ExceptionStack([u8; DOUBLE_FAULT_STACK_SIZE]);
|
||||||
|
|
||||||
|
static mut GDT: Gdt = Gdt::new();
|
||||||
|
static mut TSS: TaskStateSegment = TaskStateSegment::new();
|
||||||
|
static mut DOUBLE_FAULT_STACK: ExceptionStack = ExceptionStack([0; DOUBLE_FAULT_STACK_SIZE]);
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
const _: () = assert!(core::mem::size_of::<TaskStateSegment>() == 104);
|
||||||
|
const _: () = assert!(core::mem::size_of::<GdtPointer>() == 10);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let stack_bottom = core::ptr::addr_of_mut!(DOUBLE_FAULT_STACK) as u64;
|
||||||
|
let stack_top = stack_bottom + DOUBLE_FAULT_STACK_SIZE as u64;
|
||||||
|
|
||||||
|
TSS.interrupt_stacks[0] = stack_top;
|
||||||
|
|
||||||
|
let [tss_low, tss_high] = tss_descriptor(core::ptr::addr_of!(TSS));
|
||||||
|
|
||||||
|
let gdt = Gdt {
|
||||||
|
entries: [
|
||||||
|
0,
|
||||||
|
kernel_code_descriptor(),
|
||||||
|
kernel_data_descriptor(),
|
||||||
|
tss_low,
|
||||||
|
tss_high,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
core::ptr::addr_of_mut!(GDT).write(gdt);
|
||||||
|
|
||||||
|
gdt_reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gdt_reload() {
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"lgdt [{gdt_pointer}]",
|
||||||
|
|
||||||
|
"push {code_selector}",
|
||||||
|
"lea rax, [rip + 2f]",
|
||||||
|
"push rax",
|
||||||
|
"retfq",
|
||||||
|
"2:",
|
||||||
|
|
||||||
|
"mov ax, {data_selector}",
|
||||||
|
"mov ds, ax",
|
||||||
|
"mov es, ax",
|
||||||
|
"mov fs, ax",
|
||||||
|
"mov gs, ax",
|
||||||
|
"mov ss, ax",
|
||||||
|
|
||||||
|
"mov ax, {tss_selector}",
|
||||||
|
"ltr ax",
|
||||||
|
|
||||||
|
gdt_pointer = in(reg) &GdtPointer {
|
||||||
|
limit: (core::mem::size_of::<Gdt>() - 1) as u16,
|
||||||
|
base: core::ptr::addr_of!(GDT) as u64,
|
||||||
|
},
|
||||||
|
code_selector = const KERNEL_CODE_SELECTOR,
|
||||||
|
data_selector = const KERNEL_DATA_SELECTOR,
|
||||||
|
tss_selector = const TSS_SELECTOR,
|
||||||
|
lateout("rax") _,
|
||||||
|
options(preserves_flags)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PRESENT: u64 = 1 << 47;
|
||||||
|
const USER_DESCRIPTOR: u64 = 1 << 44;
|
||||||
|
const EXECUTABLE: u64 = 1 << 43;
|
||||||
|
const READ_WRITE: u64 = 1 << 41;
|
||||||
|
const LONG_MODE: u64 = 1 << 53;
|
||||||
|
|
||||||
|
fn kernel_code_descriptor() -> u64 {
|
||||||
|
PRESENT | USER_DESCRIPTOR | EXECUTABLE | READ_WRITE | LONG_MODE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kernel_data_descriptor() -> u64 {
|
||||||
|
PRESENT | USER_DESCRIPTOR | READ_WRITE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tss_descriptor(tss: *const TaskStateSegment) -> [u64; 2] {
|
||||||
|
let base = tss as u64;
|
||||||
|
let limit = (core::mem::size_of::<TaskStateSegment>() - 1) as u64;
|
||||||
|
|
||||||
|
let low = (limit & 0xFFFF)
|
||||||
|
| ((base & 0x00FF_FFFF) << 16)
|
||||||
|
| (0x09 << 40)
|
||||||
|
| (1 << 47)
|
||||||
|
| (((limit >> 16) & 0x0F) << 48)
|
||||||
|
| (((base >> 24) & 0xFF) << 56);
|
||||||
|
|
||||||
|
let high = base >> 32;
|
||||||
|
[low, high]
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
use super::idt::{self, InterruptStackFrame};
|
||||||
|
use crate::{hcf, println};
|
||||||
|
|
||||||
|
macro_rules! fatal_without_error_code {
|
||||||
|
($handler:ident, $name:literal) => {
|
||||||
|
extern "x86-interrupt" fn $handler(frame: InterruptStackFrame) {
|
||||||
|
fatal_exception($name, &frame, None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! fatal_with_error_code {
|
||||||
|
($handler:ident, $name:literal) => {
|
||||||
|
extern "x86-interrupt" fn $handler(frame: InterruptStackFrame, error_code: u64) {
|
||||||
|
fatal_exception($name, &frame, Some(error_code));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn debug_handler(frame: InterruptStackFrame) {
|
||||||
|
fatal_exception("DEBUG EXCEPTION", &frame, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn non_maskable_interrupt_handler(frame: InterruptStackFrame) {
|
||||||
|
fatal_exception("NON-MASKABLE INTERRUPT", &frame, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn breakpoint_handler(frame: InterruptStackFrame) {
|
||||||
|
report_exception("BREAKPOINT", &frame, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn double_fault_handler(frame: InterruptStackFrame, error_code: u64) {
|
||||||
|
fatal_exception("DOUBLE FAULT", &frame, Some(error_code));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn page_fault_handler(frame: InterruptStackFrame, error_code: u64) {
|
||||||
|
report_exception("PAGE FAULT", &frame, Some(error_code));
|
||||||
|
println!("Faulting address: {:#X}", read_cr2());
|
||||||
|
print_page_fault_error(error_code);
|
||||||
|
hcf();
|
||||||
|
}
|
||||||
|
|
||||||
|
fatal_without_error_code!(divide_error_handler, "DIVIDE ERROR");
|
||||||
|
fatal_without_error_code!(invalid_opcode_handler, "INVALID OPCODE");
|
||||||
|
fatal_without_error_code!(device_not_available_handler, "DEVICE NOT AVAILABLE");
|
||||||
|
fatal_without_error_code!(x87_floating_point_handler, "X87 FLOATING-POINT EXCEPTION");
|
||||||
|
fatal_without_error_code!(machine_check_handler, "MACHINE CHECK");
|
||||||
|
fatal_without_error_code!(simd_floating_point_handler, "SIMD FLOATING-POINT EXCEPTION");
|
||||||
|
|
||||||
|
fatal_with_error_code!(invalid_tss_handler, "INVALID TSS");
|
||||||
|
fatal_with_error_code!(segment_not_present_handler, "SEGMENT NOT PRESENT");
|
||||||
|
fatal_with_error_code!(stack_segment_fault_handler, "STACK-SEGMENT FAULT");
|
||||||
|
fatal_with_error_code!(general_protection_handler, "GENERAL PROTECTION FAULT");
|
||||||
|
fatal_with_error_code!(alignment_check_handler, "ALIGNMENT CHECK");
|
||||||
|
|
||||||
|
pub(super) fn install(idt: &mut idt::Idt) {
|
||||||
|
idt.set_handler(0, divide_error_handler, 0);
|
||||||
|
idt.set_handler(1, debug_handler, 0);
|
||||||
|
idt.set_handler(2, non_maskable_interrupt_handler, 0);
|
||||||
|
idt.set_handler(3, breakpoint_handler, 0);
|
||||||
|
idt.set_handler(6, invalid_opcode_handler, 0);
|
||||||
|
idt.set_handler(7, device_not_available_handler, 0);
|
||||||
|
idt.set_error_code_handler(8, double_fault_handler, 1);
|
||||||
|
idt.set_error_code_handler(10, invalid_tss_handler, 0);
|
||||||
|
idt.set_error_code_handler(11, segment_not_present_handler, 0);
|
||||||
|
idt.set_error_code_handler(12, stack_segment_fault_handler, 0);
|
||||||
|
idt.set_error_code_handler(13, general_protection_handler, 0);
|
||||||
|
idt.set_error_code_handler(14, page_fault_handler, 0);
|
||||||
|
idt.set_handler(16, x87_floating_point_handler, 0);
|
||||||
|
idt.set_error_code_handler(17, alignment_check_handler, 0);
|
||||||
|
idt.set_handler(18, machine_check_handler, 0);
|
||||||
|
idt.set_handler(19, simd_floating_point_handler, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_cr2() -> u64 {
|
||||||
|
let value: u64;
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"mov {}, cr2",
|
||||||
|
out(reg) value,
|
||||||
|
options(nomem, nostack, preserves_flags),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_page_fault_error(error_code: u64) {
|
||||||
|
let present = error_code & (1 << 0) != 0;
|
||||||
|
let write = error_code & (1 << 1) != 0;
|
||||||
|
let user = error_code & (1 << 2) != 0;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Cause: {}",
|
||||||
|
if present {
|
||||||
|
"protection violation"
|
||||||
|
} else {
|
||||||
|
"page not present"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
println!("Access: {}", if write { "write" } else { "read" });
|
||||||
|
println!("Mode: {}", if user { "user" } else { "supervisor" });
|
||||||
|
|
||||||
|
if error_code & (1 << 3) != 0 {
|
||||||
|
println!("Reserved page-table bit was set");
|
||||||
|
}
|
||||||
|
|
||||||
|
if error_code & (1 << 4) != 0 {
|
||||||
|
println!("Access was an instruction fetch");
|
||||||
|
}
|
||||||
|
|
||||||
|
if error_code & (1 << 5) != 0 {
|
||||||
|
println!("Protection-key violation");
|
||||||
|
}
|
||||||
|
|
||||||
|
if error_code & (1 << 6) != 0 {
|
||||||
|
println!("Shadow-stack access");
|
||||||
|
}
|
||||||
|
|
||||||
|
if error_code & (1 << 15) != 0 {
|
||||||
|
println!("Software Guard Extensions violation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_exception(name: &'static str, frame: &InterruptStackFrame, error_code: Option<u64>) {
|
||||||
|
println!();
|
||||||
|
println!("========= {name} =========");
|
||||||
|
println!(
|
||||||
|
"Origin: {}",
|
||||||
|
if frame.code_segment & 0b11 == 3 {
|
||||||
|
"user"
|
||||||
|
} else {
|
||||||
|
"kernel"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
println!("RIP: {:#X}", frame.instruction_pointer.as_u64());
|
||||||
|
println!("CS: {:#X}", frame.code_segment);
|
||||||
|
println!("FLAGS: {:#X}", frame.cpu_flags);
|
||||||
|
println!("RSP: {:#X}", frame.stack_pointer.as_u64());
|
||||||
|
println!("SS: {:#X}", frame.stack_segment);
|
||||||
|
|
||||||
|
if let Some(error_code) = error_code {
|
||||||
|
println!("ERROR: {:#X}", error_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fatal_exception(name: &'static str, frame: &InterruptStackFrame, error_code: Option<u64>) -> ! {
|
||||||
|
report_exception(name, frame, error_code);
|
||||||
|
hcf()
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
use super::exceptions;
|
||||||
|
use crate::{arch::x86_64::gdt::KERNEL_CODE_SELECTOR, memory::VirtualAddr};
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct IdtEntry {
|
||||||
|
offset_low: u16,
|
||||||
|
code_selector: u16,
|
||||||
|
ist: u8,
|
||||||
|
attributes: u8,
|
||||||
|
offset_middle: u16,
|
||||||
|
offset_high: u32,
|
||||||
|
reserved: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdtEntry {
|
||||||
|
const fn missing() -> Self {
|
||||||
|
return Self {
|
||||||
|
offset_low: 0,
|
||||||
|
code_selector: 0x08,
|
||||||
|
ist: 0,
|
||||||
|
attributes: 0,
|
||||||
|
offset_middle: 0,
|
||||||
|
offset_high: 0,
|
||||||
|
reserved: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
struct IdtPointer {
|
||||||
|
limit: u16,
|
||||||
|
base: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub(super) struct InterruptStackFrame {
|
||||||
|
pub instruction_pointer: VirtualAddr,
|
||||||
|
pub code_segment: u64,
|
||||||
|
pub cpu_flags: u64,
|
||||||
|
pub stack_pointer: VirtualAddr,
|
||||||
|
pub stack_segment: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
const INTERRUPT_GATE: u8 = 0b1110;
|
||||||
|
const PRESENT: u8 = 1 << 7;
|
||||||
|
const KERNEL_INTERRUPT_GATE: u8 = PRESENT | INTERRUPT_GATE;
|
||||||
|
|
||||||
|
pub(super) type Handler = extern "x86-interrupt" fn(InterruptStackFrame);
|
||||||
|
pub(super) type ErrorCodeHandler = extern "x86-interrupt" fn(InterruptStackFrame, u64);
|
||||||
|
|
||||||
|
pub(super) struct Idt {
|
||||||
|
entries: [IdtEntry; 256],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Idt {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
entries: [IdtEntry::missing(); 256],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn set_handler(&mut self, vector: u8, handler: Handler, ist: u8) {
|
||||||
|
self.set_handler_address(vector, handler as usize, ist);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn set_error_code_handler(
|
||||||
|
&mut self,
|
||||||
|
vector: u8,
|
||||||
|
handler: ErrorCodeHandler,
|
||||||
|
ist: u8,
|
||||||
|
) {
|
||||||
|
self.set_handler_address(vector, handler as usize, ist);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_handler_address(&mut self, vector: u8, address: usize, ist: u8) {
|
||||||
|
self.entries[vector as usize] = IdtEntry {
|
||||||
|
offset_low: address as u16,
|
||||||
|
offset_middle: (address >> 16) as u16,
|
||||||
|
offset_high: (address >> 32) as u32,
|
||||||
|
code_selector: KERNEL_CODE_SELECTOR,
|
||||||
|
ist: ist & 0b111,
|
||||||
|
attributes: KERNEL_INTERRUPT_GATE,
|
||||||
|
reserved: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut IDT: Idt = Idt::new();
|
||||||
|
|
||||||
|
pub fn idt_init() {
|
||||||
|
const _: () = assert!(core::mem::size_of::<IdtEntry>() == 16);
|
||||||
|
const _: () = assert!(core::mem::size_of::<IdtPointer>() == 10);
|
||||||
|
const _: () = assert!(core::mem::size_of::<InterruptStackFrame>() == 40);
|
||||||
|
|
||||||
|
let mut idt = Idt::new();
|
||||||
|
|
||||||
|
exceptions::install(&mut idt);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
core::ptr::addr_of_mut!(IDT).write(idt);
|
||||||
|
|
||||||
|
let pointer = IdtPointer {
|
||||||
|
limit: (core::mem::size_of::<Idt>() - 1) as u16,
|
||||||
|
base: core::ptr::addr_of!(IDT) as u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
core::arch::asm!(
|
||||||
|
"lidt [{}]",
|
||||||
|
in(reg) core::ptr::addr_of!(pointer),
|
||||||
|
options(readonly, nostack, preserves_flags),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
mod exceptions;
|
||||||
|
mod idt;
|
||||||
|
|
||||||
|
pub use idt::idt_init as init;
|
||||||
|
|
||||||
|
pub fn disable_interrupts() {
|
||||||
|
unsafe {
|
||||||
|
asm!("cli");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,23 @@
|
|||||||
|
mod gdt;
|
||||||
|
mod interrupts;
|
||||||
pub mod port;
|
pub mod port;
|
||||||
|
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
pub use interrupts::disable_interrupts;
|
||||||
|
|
||||||
|
use crate::println;
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
disable_interrupts();
|
||||||
|
println!("Loading GDT...");
|
||||||
|
gdt::init();
|
||||||
|
println!("Loading IDT...");
|
||||||
|
interrupts::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn halt() {
|
||||||
|
unsafe {
|
||||||
|
asm!("hlt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+80
-4
@@ -1,5 +1,7 @@
|
|||||||
use limine::request::FramebufferRequest;
|
use ::limine as limine_api;
|
||||||
use limine::{BaseRevision, RequestsEndMarker, RequestsStartMarker};
|
|
||||||
|
use limine_api::request::{ExecutableAddressRequest, HhdmRequest, MemmapRequest};
|
||||||
|
use limine_api::{BaseRevision, RequestsEndMarker, RequestsStartMarker};
|
||||||
|
|
||||||
/// Sets the base revision to the latest revision supported by the crate.
|
/// Sets the base revision to the latest revision supported by the crate.
|
||||||
/// See specification for further info.
|
/// See specification for further info.
|
||||||
@@ -7,11 +9,19 @@ use limine::{BaseRevision, RequestsEndMarker, RequestsStartMarker};
|
|||||||
#[used]
|
#[used]
|
||||||
// The .requests section allows limine to find the requests faster and more safely.
|
// The .requests section allows limine to find the requests faster and more safely.
|
||||||
#[unsafe(link_section = ".requests")]
|
#[unsafe(link_section = ".requests")]
|
||||||
pub static BASE_REVISION: BaseRevision = BaseRevision::new();
|
static BASE_REVISION: BaseRevision = BaseRevision::new();
|
||||||
|
|
||||||
#[used]
|
#[used]
|
||||||
#[unsafe(link_section = ".requests")]
|
#[unsafe(link_section = ".requests")]
|
||||||
pub static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
|
static KERNEL_ADDRESS_REQUEST: ExecutableAddressRequest = ExecutableAddressRequest::new();
|
||||||
|
|
||||||
|
#[used]
|
||||||
|
#[unsafe(link_section = ".requests")]
|
||||||
|
static HHDM_REQUEST: HhdmRequest = HhdmRequest::new();
|
||||||
|
|
||||||
|
#[used]
|
||||||
|
#[unsafe(link_section = ".requests")]
|
||||||
|
static MEMMAP_REQUEST: MemmapRequest = MemmapRequest::new();
|
||||||
|
|
||||||
/// Define the stand and end markers for Limine requests.
|
/// Define the stand and end markers for Limine requests.
|
||||||
#[used]
|
#[used]
|
||||||
@@ -20,3 +30,69 @@ static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new();
|
|||||||
#[used]
|
#[used]
|
||||||
#[unsafe(link_section = ".requests_end_marker")]
|
#[unsafe(link_section = ".requests_end_marker")]
|
||||||
static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new();
|
static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new();
|
||||||
|
|
||||||
|
pub struct BootInfo {
|
||||||
|
pub kernel_address: crate::memory::PhysicalAddr,
|
||||||
|
pub hhdm_offset: u64,
|
||||||
|
entries: &'static [&'static limine_api::memmap::Entry],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BootInfo {
|
||||||
|
pub fn memory_regions(&self) -> impl Iterator<Item = crate::memory::MemoryRegion> + '_ {
|
||||||
|
use crate::memory::{MemoryRegion, MemoryRegionKind};
|
||||||
|
self.entries.iter().map(|&entry| MemoryRegion {
|
||||||
|
start: crate::memory::PhysicalAddr::new(entry.base),
|
||||||
|
length: entry.length,
|
||||||
|
kind: match entry.type_ {
|
||||||
|
limine_api::memmap::MEMMAP_USABLE => MemoryRegionKind::Usable,
|
||||||
|
limine_api::memmap::MEMMAP_RESERVED => MemoryRegionKind::Reserved,
|
||||||
|
limine_api::memmap::MEMMAP_ACPI_RECLAIMABLE => MemoryRegionKind::AcpiReclaimable,
|
||||||
|
limine_api::memmap::MEMMAP_ACPI_NVS => MemoryRegionKind::AcpiNvs,
|
||||||
|
limine_api::memmap::MEMMAP_BAD_MEMORY => MemoryRegionKind::BadMemory,
|
||||||
|
limine_api::memmap::MEMMAP_BOOTLOADER_RECLAIMABLE => {
|
||||||
|
MemoryRegionKind::BootloaderReclaimable
|
||||||
|
}
|
||||||
|
limine_api::memmap::MEMMAP_EXECUTABLE_AND_MODULES => {
|
||||||
|
MemoryRegionKind::KernelAndModules
|
||||||
|
}
|
||||||
|
limine_api::memmap::MEMMAP_FRAMEBUFFER => MemoryRegionKind::Framebuffer,
|
||||||
|
limine_api::memmap::MEMMAP_MAPPED_RESERVED => MemoryRegionKind::MappedReserved,
|
||||||
|
_ => MemoryRegionKind::Reserved,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BootError {
|
||||||
|
UnsupportedBaseRevision,
|
||||||
|
FailedToGetKernelAddress,
|
||||||
|
FailedToGetHHDMAddress,
|
||||||
|
FailedToGetMemmap,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_boot_info() -> Result<BootInfo, BootError> {
|
||||||
|
if !BASE_REVISION.is_supported() {
|
||||||
|
return Err(BootError::UnsupportedBaseRevision);
|
||||||
|
}
|
||||||
|
|
||||||
|
let kernel_address = KERNEL_ADDRESS_REQUEST
|
||||||
|
.response()
|
||||||
|
.ok_or(BootError::FailedToGetKernelAddress)?
|
||||||
|
.physical_base;
|
||||||
|
let hhdm_offset = HHDM_REQUEST
|
||||||
|
.response()
|
||||||
|
.ok_or(BootError::FailedToGetHHDMAddress)?
|
||||||
|
.offset;
|
||||||
|
|
||||||
|
let memmap = MEMMAP_REQUEST
|
||||||
|
.response()
|
||||||
|
.ok_or(BootError::FailedToGetMemmap)?
|
||||||
|
.entries();
|
||||||
|
|
||||||
|
Ok(BootInfo {
|
||||||
|
kernel_address: crate::memory::PhysicalAddr::new(kernel_address),
|
||||||
|
hhdm_offset,
|
||||||
|
entries: memmap,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
+3
-1
@@ -1 +1,3 @@
|
|||||||
pub mod limine;
|
mod limine;
|
||||||
|
|
||||||
|
pub use limine::{BootError, BootInfo, load_boot_info};
|
||||||
|
|||||||
@@ -169,11 +169,11 @@ pub fn print(args: core::fmt::Arguments) {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! print {
|
macro_rules! print {
|
||||||
($($arg:tt)*) => ($crate::drivers::serial::print(format_args!($($arg)*)));
|
($($arg:tt)*) => ($crate::debug::serial::print(format_args!($($arg)*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! println {
|
macro_rules! println {
|
||||||
() => ($crate::drivers::serial::print(format_args!("\n")));
|
() => ($crate::debug::serial::print(format_args!("\n")));
|
||||||
($($arg:tt)*) => ($crate::drivers::serial::print(format_args!("{}\n", format_args!($($arg)*))));
|
($($arg:tt)*) => ($crate::debug::serial::print(format_args!("{}\n", format_args!($($arg)*))));
|
||||||
}
|
}
|
||||||
+15
-41
@@ -1,66 +1,40 @@
|
|||||||
#![feature(abi_x86_interrupt, negative_impls)]
|
#![feature(abi_x86_interrupt)]
|
||||||
#![allow(clippy::needless_return)]
|
#![allow(clippy::needless_return)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
mod arch;
|
mod arch;
|
||||||
mod boot;
|
mod boot;
|
||||||
mod drivers;
|
mod debug;
|
||||||
|
mod memory;
|
||||||
|
|
||||||
use boot::limine::{BASE_REVISION, FRAMEBUFFER_REQUEST};
|
use crate::debug::serial;
|
||||||
|
|
||||||
use crate::drivers::serial;
|
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "C" fn _start() -> ! {
|
pub extern "C" fn _start() -> ! {
|
||||||
serial::init().unwrap();
|
serial::init().unwrap();
|
||||||
|
|
||||||
assert!(BASE_REVISION.is_supported());
|
arch::init();
|
||||||
|
let _boot_info = boot::load_boot_info().unwrap();
|
||||||
|
|
||||||
draw_gradient();
|
let addr = 0xDEADBEEF as *mut u32;
|
||||||
|
unsafe {
|
||||||
|
*addr = 0xDEADBEEF;
|
||||||
|
}
|
||||||
|
|
||||||
hcf();
|
hcf();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_gradient() {
|
|
||||||
if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.response() {
|
|
||||||
if let Some(&framebuffer) = framebuffer_response.framebuffers().first() {
|
|
||||||
let buffer = unsafe {
|
|
||||||
core::slice::from_raw_parts_mut(
|
|
||||||
framebuffer.address().cast::<u32>(),
|
|
||||||
framebuffer.size() / 4,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
for y in 0..framebuffer.height {
|
|
||||||
for x in 0..framebuffer.width {
|
|
||||||
let r = (255 * x) / (framebuffer.width - 1);
|
|
||||||
let g = (255 * y) / (framebuffer.height - 1);
|
|
||||||
let b = 255 - r;
|
|
||||||
|
|
||||||
let pixel = ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
|
|
||||||
buffer
|
|
||||||
[(((y * framebuffer.pitch) / (framebuffer.bpp as u64 / 8)) + x) as usize] =
|
|
||||||
pixel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
println!("Uh oh, something went wrong!");
|
||||||
|
println!("{}", info);
|
||||||
|
|
||||||
hcf();
|
hcf();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hcf() -> ! {
|
pub fn hcf() -> ! {
|
||||||
loop {
|
loop {
|
||||||
unsafe {
|
arch::halt();
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
||||||
core::arch::asm!("hlt");
|
|
||||||
|
|
||||||
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
|
||||||
core::arch::asm!("wfi");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct PhysicalAddr(u64);
|
||||||
|
|
||||||
|
impl PhysicalAddr {
|
||||||
|
pub fn new(addr: u64) -> Self {
|
||||||
|
Self(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn as_u64(self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct VirtualAddr(u64);
|
||||||
|
|
||||||
|
impl VirtualAddr {
|
||||||
|
pub fn new(addr: u64) -> Self {
|
||||||
|
Self(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn as_u64(self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn as_mut_ptr<T>(self) -> *mut T {
|
||||||
|
self.as_u64() as *mut T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum MemoryRegionKind {
|
||||||
|
Usable,
|
||||||
|
Reserved,
|
||||||
|
AcpiReclaimable,
|
||||||
|
AcpiNvs,
|
||||||
|
BadMemory,
|
||||||
|
BootloaderReclaimable,
|
||||||
|
KernelAndModules,
|
||||||
|
Framebuffer,
|
||||||
|
MappedReserved,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct MemoryRegion {
|
||||||
|
pub start: PhysicalAddr,
|
||||||
|
pub length: u64,
|
||||||
|
pub kind: MemoryRegionKind,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user