Add simple uart driver, more functionality etc etc etc
This commit is contained in:
12
kernel/Cargo.lock
generated
12
kernel/Cargo.lock
generated
@@ -5,3 +5,15 @@ version = 4
|
||||
[[package]]
|
||||
name = "kernel"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"uefi",
|
||||
"x86_drivers",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uefi"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "x86_drivers"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -4,3 +4,5 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
uefi = {path = "../uefi"}
|
||||
x86_drivers = {path = "../x86_drivers"}
|
||||
|
||||
10
kernel/run.sh
Executable file
10
kernel/run.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
mkdir -p esp/EFI/BOOT
|
||||
cargo b --target x86_64-unknown-uefi --release
|
||||
cp target/x86_64-unknown-uefi/release/kernel.efi esp/EFI/BOOT/BOOTX64.EFI
|
||||
|
||||
qemu-system-x86_64 \
|
||||
-drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd \
|
||||
-drive if=pflash,format=raw,file=OVMF_VARS.4m.fd \
|
||||
-drive format=raw,file=fat:rw:esp \
|
||||
-net none \
|
||||
-serial stdio
|
||||
64
kernel/src/lib.rs
Normal file
64
kernel/src/lib.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
#![no_std]
|
||||
#![deny(clippy::perf, clippy::all, clippy::pedantic)]
|
||||
|
||||
use core::{
|
||||
mem::MaybeUninit,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
use uefi::EfiSystemTable;
|
||||
pub use x86_drivers::prelude::*;
|
||||
use x86_drivers::uart::Uart1;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
($($tt:tt)+) => {
|
||||
#[allow(static_mut_refs)]
|
||||
'body: {
|
||||
use core::fmt::Write as _;
|
||||
if let Some(uart) = $crate::uart_is_init() {
|
||||
let _ = core::write!(uart, $($tt)*);
|
||||
break 'body;
|
||||
}
|
||||
let table = unsafe { $crate::TABLE.assume_init().as_mut().unwrap_unchecked() };
|
||||
let _ = core::write!(table.std_out(), $($tt)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
/// Panics if the UART `MaybeUninit` pointer is null (should never happen).
|
||||
#[allow(static_mut_refs)]
|
||||
pub fn uart_is_init() -> Option<&'static mut Uart<Uart1>> {
|
||||
unsafe {
|
||||
UART.0
|
||||
.load(Ordering::Relaxed)
|
||||
.then_some(UART.1.as_mut_ptr().as_mut().expect("uart ptr is non-null"))
|
||||
}
|
||||
}
|
||||
|
||||
pub static mut TABLE: MaybeUninit<*mut EfiSystemTable> = MaybeUninit::uninit();
|
||||
static mut UART: (AtomicBool, MaybeUninit<Uart<Uart1>>) =
|
||||
(AtomicBool::new(false), MaybeUninit::uninit());
|
||||
|
||||
#[repr(align(8))]
|
||||
pub struct Aligned<T>(pub T);
|
||||
|
||||
#[used]
|
||||
pub static mut MEMORY_MAP_ARENA: Aligned<[u8; 32 * 1_024]> = Aligned([0; _]);
|
||||
|
||||
/// # Panics
|
||||
/// Panics if UART has already been specified.
|
||||
#[allow(static_mut_refs)]
|
||||
pub fn specify_uart(uart: Uart<Uart1>) {
|
||||
let is_specified = unsafe { UART.0.load(Ordering::Acquire) };
|
||||
assert!(!is_specified, "Uart already specified");
|
||||
unsafe { UART.1.write(uart) };
|
||||
unsafe { UART.0.store(true, Ordering::Release) };
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
print!("PANIC: {:?}\r\n", info);
|
||||
loop {}
|
||||
}
|
||||
@@ -1,3 +1,109 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![deny(clippy::perf, clippy::all, clippy::pedantic)]
|
||||
|
||||
use uefi::{EfiMemoryType, EfiSystemTable, ExitBootServicesKey, Handle, UefiStatus};
|
||||
|
||||
use kernel::print;
|
||||
use x86_drivers::gdt::{DPL, GdtEntry, GdtPointer, GdtSelector};
|
||||
pub use x86_drivers::prelude::*;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "efiapi" fn efi_main(handle: Handle, table: *mut EfiSystemTable) -> UefiStatus {
|
||||
let peripherals = x86_drivers::core::Core::take();
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe {
|
||||
kernel::TABLE.write(table)
|
||||
};
|
||||
let table = unsafe { table.as_mut().expect("efi table ptr is non-null") };
|
||||
let res = table.std_out().print("Hello world\r\n");
|
||||
if let Err(Some(e)) = res {
|
||||
return e;
|
||||
}
|
||||
|
||||
kernel::specify_uart(peripherals.uart1.init());
|
||||
|
||||
print!("Hello from uart!\r\n");
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
let arena = unsafe { &mut kernel::MEMORY_MAP_ARENA.0 };
|
||||
let (_key, map, _version) = table
|
||||
.boot_services()
|
||||
.memory_map(arena)
|
||||
.expect("memory map failed");
|
||||
for el in map
|
||||
.filter_map(|segment| segment.memory_type.interpret().map(|f| (f, segment)))
|
||||
.filter(|(t, _segment)| *t == EfiMemoryType::ConventionalMemory)
|
||||
{
|
||||
print!("Map element {:?}\r\n", el);
|
||||
}
|
||||
|
||||
let default = ExitBootServicesKey::default();
|
||||
print!("Default {:?}", default);
|
||||
|
||||
let boot_services = table.boot_services();
|
||||
boot_services
|
||||
.exit_boot_services(handle, arena)
|
||||
.expect("exit boot services failed");
|
||||
print!("Exited boot services!\r\n");
|
||||
|
||||
print!("kernel_code: {:#018x}\r\n", GdtEntry::kernel_code().raw());
|
||||
print!("kernel_data: {:#018x}\r\n", GdtEntry::kernel_data().raw());
|
||||
|
||||
print!(
|
||||
"Initiating GDT to {:?}, CODE_SEL: {:?}, DATA SEL: {:?}",
|
||||
GDT_TABLE, GDT_KERNEL_CODE_SELECTOR, GDT_KERNEL_DATA_SELECTOR
|
||||
);
|
||||
gdt_init();
|
||||
print!("Initiated GDT");
|
||||
#[allow(clippy::empty_loop)]
|
||||
loop {}
|
||||
}
|
||||
|
||||
static GDT_TABLE: [GdtEntry; 3] = [
|
||||
GdtEntry::null(),
|
||||
GdtEntry::kernel_code(),
|
||||
GdtEntry::kernel_data(),
|
||||
];
|
||||
|
||||
static GDT_KERNEL_CODE_SELECTOR: GdtSelector = GdtSelector::new(DPL::Kernel, &GDT_TABLE, 1);
|
||||
static GDT_KERNEL_DATA_SELECTOR: GdtSelector = GdtSelector::new(DPL::Kernel, &GDT_TABLE, 2);
|
||||
|
||||
fn gdt_init() {
|
||||
let ptr = GdtPointer::new(&GDT_TABLE);
|
||||
print!("GDTR: {:?}\r\n", ptr,);
|
||||
print!("GDT_TABLE addr: {:#x}\r\n", &GDT_TABLE as *const _ as u64);
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"lgdt [{}]",
|
||||
in(reg) &ptr,
|
||||
options(readonly, nostack, preserves_flags)
|
||||
);
|
||||
}
|
||||
print!("Passed lgdt");
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"push {code_sel}",
|
||||
"lea {tmp}, [rip + 2f]",
|
||||
"push {tmp}",
|
||||
"retfq",
|
||||
"2:",
|
||||
code_sel = const GDT_KERNEL_CODE_SELECTOR.raw() as u64,
|
||||
tmp = out(reg) _,
|
||||
);
|
||||
}
|
||||
print!("CS reloaded\r\n");
|
||||
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"mov ds, {data_sel:x}",
|
||||
"mov es, {data_sel:x}",
|
||||
"mov fs, {data_sel:x}",
|
||||
"mov gs, {data_sel:x}",
|
||||
"mov ss, {data_sel:x}",
|
||||
data_sel = in(reg) GDT_KERNEL_DATA_SELECTOR.raw(),
|
||||
);
|
||||
}
|
||||
print!("data segments reloaded\r\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user