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;
|
||||
|
||||
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::{BaseRevision, RequestsEndMarker, RequestsStartMarker};
|
||||
use ::limine as limine_api;
|
||||
|
||||
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.
|
||||
/// See specification for further info.
|
||||
@@ -7,11 +9,19 @@ use limine::{BaseRevision, RequestsEndMarker, RequestsStartMarker};
|
||||
#[used]
|
||||
// The .requests section allows limine to find the requests faster and more safely.
|
||||
#[unsafe(link_section = ".requests")]
|
||||
pub static BASE_REVISION: BaseRevision = BaseRevision::new();
|
||||
static BASE_REVISION: BaseRevision = BaseRevision::new();
|
||||
|
||||
#[used]
|
||||
#[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.
|
||||
#[used]
|
||||
@@ -20,3 +30,69 @@ static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new();
|
||||
#[used]
|
||||
#[unsafe(link_section = ".requests_end_marker")]
|
||||
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_rules! print {
|
||||
($($arg:tt)*) => ($crate::drivers::serial::print(format_args!($($arg)*)));
|
||||
($($arg:tt)*) => ($crate::debug::serial::print(format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println {
|
||||
() => ($crate::drivers::serial::print(format_args!("\n")));
|
||||
($($arg:tt)*) => ($crate::drivers::serial::print(format_args!("{}\n", format_args!($($arg)*))));
|
||||
() => ($crate::debug::serial::print(format_args!("\n")));
|
||||
($($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)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
mod arch;
|
||||
mod boot;
|
||||
mod drivers;
|
||||
mod debug;
|
||||
mod memory;
|
||||
|
||||
use boot::limine::{BASE_REVISION, FRAMEBUFFER_REQUEST};
|
||||
|
||||
use crate::drivers::serial;
|
||||
use crate::debug::serial;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
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();
|
||||
}
|
||||
|
||||
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]
|
||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
println!("Uh oh, something went wrong!");
|
||||
println!("{}", info);
|
||||
|
||||
hcf();
|
||||
}
|
||||
|
||||
pub fn hcf() -> ! {
|
||||
loop {
|
||||
unsafe {
|
||||
#[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");
|
||||
}
|
||||
arch::halt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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