Compare commits

..

7 Commits

Author SHA1 Message Date
Philipp Oppermann
18ec73ebf0 Merge branch 'post-05' into post-06 2025-09-03 17:58:33 +02:00
Philipp Oppermann
d788a21b40 Merge branch 'post-04' into post-05 2025-09-03 17:58:33 +02:00
Philipp Oppermann
bb5899e437 Merge branch 'post-03' into post-04 2025-09-03 17:58:33 +02:00
Philipp Oppermann
93d0daa1e0 Merge branch 'post-02' into post-03 2025-09-03 17:58:28 +02:00
Philipp Oppermann
83e6c0bc00 Merge pull request #1436 from phil-opp/post-02-fix-target
Fix: `target-pointer-width` field now expects an integer
2025-09-03 17:56:38 +02:00
Philipp Oppermann
2b11ad8397 Fix: target-pointer-width field now expects an integer 2025-09-03 17:53:14 +02:00
Philipp Oppermann
fa51f3adbf Update to latest bootloader version 2025-09-03 17:52:56 +02:00
9 changed files with 30 additions and 154 deletions

21
Cargo.lock generated
View File

@@ -26,8 +26,6 @@ version = "0.1.0"
dependencies = [
"bootloader",
"lazy_static",
"pc-keyboard",
"pic8259",
"spin 0.5.2",
"uart_16550",
"volatile 0.2.7",
@@ -36,9 +34,9 @@ dependencies = [
[[package]]
name = "bootloader"
version = "0.9.32"
version = "0.9.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ea119c3ed05625c179e09d17d0914570a3753ca09c890a73d98f6b72aea00d2"
checksum = "7bdfddac270bbdd45903296bc1caf29a7fdce6b326aaf0bbab7f04c5f98b7447"
[[package]]
name = "lazy_static"
@@ -49,21 +47,6 @@ dependencies = [
"spin 0.9.8",
]
[[package]]
name = "pc-keyboard"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed089a1fbffe3337a1a345501c981f1eb1e47e69de5a40e852433e12953c3174"
[[package]]
name = "pic8259"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb844b5b01db1e0b17938685738f113bfc903846f18932b378bc0eabfa40e194"
dependencies = [
"x86_64",
]
[[package]]
name = "rustversion"
version = "1.0.22"

View File

@@ -18,8 +18,6 @@ volatile = "0.2.6"
spin = "0.5.2"
x86_64 = "0.14.2"
uart_16550 = "0.2.0"
pic8259 = "0.10.1"
pc-keyboard = "0.7.0"
[dependencies.lazy_static]
version = "1.0"

View File

@@ -1,10 +1,10 @@
# Blog OS (Introduction to Paging)
# Blog OS (Double Faults)
[![Build Status](https://github.com/phil-opp/blog_os/workflows/Code/badge.svg?branch=post-08)](https://github.com/phil-opp/blog_os/actions?query=workflow%3A%22Code%22+branch%3Apost-08)
[![Build Status](https://github.com/phil-opp/blog_os/workflows/Code/badge.svg?branch=post-06)](https://github.com/phil-opp/blog_os/actions?query=workflow%3A%22Code%22+branch%3Apost-06)
This repository contains the source code for the [Introduction to Paging][post] post of the [Writing an OS in Rust](https://os.phil-opp.com) series.
This repository contains the source code for the [Double Faults][post] post of the [Writing an OS in Rust](https://os.phil-opp.com) series.
[post]: https://os.phil-opp.com/paging-introduction/
[post]: https://os.phil-opp.com/double-fault-exceptions/
**Check out the [master branch](https://github.com/phil-opp/blog_os) for more information.**

View File

@@ -1,44 +1,16 @@
use crate::{gdt, hlt_loop, print, println};
use crate::{gdt, println};
use lazy_static::lazy_static;
use pic8259::ChainedPics;
use spin;
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
pub const PIC_1_OFFSET: u8 = 32;
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum InterruptIndex {
Timer = PIC_1_OFFSET,
Keyboard,
}
impl InterruptIndex {
fn as_u8(self) -> u8 {
self as u8
}
fn as_usize(self) -> usize {
usize::from(self.as_u8())
}
}
pub static PICS: spin::Mutex<ChainedPics> =
spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
lazy_static! {
static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
idt.breakpoint.set_handler_fn(breakpoint_handler);
idt.page_fault.set_handler_fn(page_fault_handler);
unsafe {
idt.double_fault
.set_handler_fn(double_fault_handler)
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
}
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
idt
};
}
@@ -51,19 +23,6 @@ extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
}
extern "x86-interrupt" fn page_fault_handler(
stack_frame: InterruptStackFrame,
error_code: PageFaultErrorCode,
) {
use x86_64::registers::control::Cr2;
println!("EXCEPTION: PAGE FAULT");
println!("Accessed Address: {:?}", Cr2::read());
println!("Error Code: {:?}", error_code);
println!("{:#?}", stack_frame);
hlt_loop();
}
extern "x86-interrupt" fn double_fault_handler(
stack_frame: InterruptStackFrame,
_error_code: u64,
@@ -71,47 +30,6 @@ extern "x86-interrupt" fn double_fault_handler(
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
}
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
print!(".");
unsafe {
PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
}
}
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
use pc_keyboard::{DecodedKey, HandleControl, Keyboard, ScancodeSet1, layouts};
use spin::Mutex;
use x86_64::instructions::port::Port;
lazy_static! {
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
Mutex::new(Keyboard::new(
ScancodeSet1::new(),
layouts::Us104Key,
HandleControl::Ignore
));
}
let mut keyboard = KEYBOARD.lock();
let mut port = Port::new(0x60);
let scancode: u8 = unsafe { port.read() };
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
if let Some(key) = keyboard.process_keyevent(key_event) {
match key {
DecodedKey::Unicode(character) => print!("{}", character),
DecodedKey::RawKey(key) => print!("{:?}", key),
}
}
}
unsafe {
PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
}
}
#[test_case]
fn test_breakpoint_exception() {
// invoke a breakpoint exception

View File

@@ -15,8 +15,6 @@ pub mod vga_buffer;
pub fn init() {
gdt::init();
interrupts::init_idt();
unsafe { interrupts::PICS.lock().initialize() };
x86_64::instructions::interrupts::enable();
}
pub trait Testable {
fn run(&self) -> ();
@@ -45,7 +43,7 @@ pub fn test_panic_handler(info: &PanicInfo) -> ! {
serial_println!("[failed]\n");
serial_println!("Error: {}\n", info);
exit_qemu(QemuExitCode::Failed);
hlt_loop();
loop {}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -64,19 +62,13 @@ pub fn exit_qemu(exit_code: QemuExitCode) {
}
}
pub fn hlt_loop() -> ! {
loop {
x86_64::instructions::hlt();
}
}
/// Entry point for `cargo xtest`
#[cfg(test)]
#[unsafe(no_mangle)]
pub extern "C" fn _start() -> ! {
init();
test_main();
hlt_loop();
loop {}
}
#[cfg(test)]

View File

@@ -9,22 +9,22 @@ use core::panic::PanicInfo;
#[unsafe(no_mangle)]
pub extern "C" fn _start() -> ! {
use x86_64::registers::control::Cr3;
println!("Hello World{}", "!");
blog_os::init();
let (level_4_page_table, _) = Cr3::read();
println!(
"Level 4 page table at: {:?}",
level_4_page_table.start_address()
);
fn stack_overflow() {
stack_overflow(); // for each recursion, the return address is pushed
}
// uncomment line below to trigger a stack overflow
// stack_overflow();
#[cfg(test)]
test_main();
println!("It did not crash!");
blog_os::hlt_loop();
loop {}
}
/// This function is called on panic.
@@ -32,7 +32,7 @@ pub extern "C" fn _start() -> ! {
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
println!("{}", info);
blog_os::hlt_loop();
loop {}
}
#[cfg(test)]

View File

@@ -13,14 +13,10 @@ lazy_static! {
#[doc(hidden)]
pub fn _print(args: ::core::fmt::Arguments) {
use core::fmt::Write;
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
SERIAL1
.lock()
.write_fmt(args)
.expect("Printing to serial failed");
});
SERIAL1
.lock()
.write_fmt(args)
.expect("Printing to serial failed");
}
/// Prints to the host through the serial interface.

View File

@@ -163,16 +163,11 @@ macro_rules! println {
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
}
/// Prints the given formatted string to the VGA text buffer
/// through the global `WRITER` instance.
/// Prints the given formatted string to the VGA text buffer through the global `WRITER` instance.
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
use core::fmt::Write;
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
WRITER.lock().write_fmt(args).unwrap();
});
WRITER.lock().write_fmt(args).unwrap();
}
#[test_case]
@@ -189,16 +184,10 @@ fn test_println_many() {
#[test_case]
fn test_println_output() {
use core::fmt::Write;
use x86_64::instructions::interrupts;
let s = "Some test string that fits on a single line";
interrupts::without_interrupts(|| {
let mut writer = WRITER.lock();
writeln!(writer, "\n{}", s).expect("writeln failed");
for (i, c) in s.chars().enumerate() {
let screen_char = writer.buffer.chars[BUFFER_HEIGHT - 2][i].read();
assert_eq!(char::from(screen_char.ascii_character), c);
}
});
println!("{}", s);
for (i, c) in s.chars().enumerate() {
let screen_char = WRITER.lock().buffer.chars[BUFFER_HEIGHT - 2][i].read();
assert_eq!(char::from(screen_char.ascii_character), c);
}
}

View File

@@ -3,7 +3,7 @@
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-pointer-width": 64,
"target-c-int-width": 32,
"os": "none",
"executables": true,