interlude

This commit is contained in:
janis 2026-07-16 15:33:01 +02:00
parent 83d1ce9b98
commit f1570c06b1
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
6 changed files with 95 additions and 2 deletions

View file

@ -345,4 +345,57 @@ If we now run =cargo run=, cargo will build our kernel and automatically start q
Unfortunately, since our kernel currently does nothing, this is hard to discern. Unfortunately, since our kernel currently does nothing, this is hard to discern.
Therefore, our next goal will be to get some output from our kernel, which we will do by making use of limines framebuffer. Therefore, our next goal will be to get some output from our kernel, which we will do by making use of limines framebuffer.
* Interlude: Welcome to kernel-land
If you have an aggressive LSP client, or you ran the =cargo clippy= command on our current crate, you may have noticed a warning telling you that an empty loop wastes CPU cycles.
This is true, and is in fact the very reason why we use it!
However, now that we have arrived in kernel-land, we can actually do a little better: the =hlt= instruction which, according to the Intel manual, stops execution of a logical processor until further notice.
Further notice here may be an interrupt, which means we will want to run the =hlt= instruction in a loop.
=hlt= is one of a handful of privileged instructions that when attempted to be executed in user-space will cause a general protection fault and terminate the program.
We start by creating a =lib.rs= file in the =src= directory, which will contain our kernel library code.
Just line in our =main.rs=, we will need to tell the compiler that we want to opt out of the standard library:
#+begin_src rust
#![no_std]
#+end_src
Since the =hlt= instruction is specific to the x86 architecture and not available in the =core::arch::x86_64= module of the core library, we will need to write our own wrapper around some inline assembly to execute the instruction.
We create a new =x86_64= module in our new library to house this and future x86-64 specific code:
#+begin_src rust
#![no_std]
pbu mod x86_64;
#+end_src
#+begin_src rust
#![cfg(target_arch = "x86_64")]
#[inline]
pub fn hlt() {
unsafe {
core::arch::asm!("hlt", options(nomem, nostack, preserves_flags));
}
}
pub fn halt_loop() -> ! {
loop {
hlt();
}
}
#+end_src
For a detailed explanation of the =asm!= macro, see the [[https://doc.rust-lang.org/nightly/reference/inline-assembly.html][Rust reference]].
In our =main.rs=, we can now replace the infinite loop with a call to our new =halt_loop= function:
#+begin_src rust
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
kernel::x86_64::halt_loop()
}
#[unsafe(no_mangle)]
fn _start() -> ! {
kernel::x86_64::halt_loop()
}
#+end_src
* Getting the Framebuffer * Getting the Framebuffer

1
kernel/.dir-locals.el Normal file
View file

@ -0,0 +1 @@
((nil . ((eglot-workspace-configuration . (:rust-analyzer (:cargo (:extraEnv ((CARGO_UNSTABLE_JSON_TARGET_SPEC . "true")))))))))

View file

@ -3,4 +3,14 @@ name = "kernel"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
[[bin]]
name = "kernel"
path = "src/main.rs"
test = false
bench = false
[lib]
test = false
bench = false
[dependencies] [dependencies]

15
kernel/src/lib.rs Normal file
View file

@ -0,0 +1,15 @@
#![no_std]
pub mod x86_64;
/// # Safety
pub unsafe fn volatile_copy<T: Sized>(src: *const T, dst: *mut T, count: usize) {
unsafe {
for i in 0..count {
let src_ptr = src.add(i);
let dst_ptr = dst.add(i);
let val = src_ptr.read_volatile();
dst_ptr.write_volatile(val);
}
}
}

View file

@ -3,10 +3,10 @@
#[panic_handler] #[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! { fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {} kernel::x86_64::halt_loop()
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
fn _start() -> ! { fn _start() -> ! {
loop {} kernel::x86_64::halt_loop()
} }

14
kernel/src/x86_64.rs Normal file
View file

@ -0,0 +1,14 @@
#![cfg(target_arch = "x86_64")]
#[inline]
pub fn hlt() {
unsafe {
core::arch::asm!("hlt", options(nomem, nostack, preserves_flags));
}
}
pub fn halt_loop() -> ! {
loop {
hlt();
}
}