From 7cdd45a8012327de1fa6524d9e5b918e41f6f500 Mon Sep 17 00:00:00 2001 From: Voinea Radu Date: Mon, 7 Oct 2024 22:25:55 +0300 Subject: [PATCH 1/5] Base code to get the basic features of APIC running. Includes frame allocator, interrupt descriptor table and a global descriptor table examples. --- .gitignore | 1 + Cargo.lock | 69 ++++-- Cargo.toml | 1 + docs/apic_example/Cargo.toml | 14 ++ docs/apic_example/src/apic.rs | 264 +++++++++++++++++++++++ docs/apic_example/src/frame_allocator.rs | 52 +++++ docs/apic_example/src/gdt.rs | 62 ++++++ docs/apic_example/src/idt.rs | 74 +++++++ docs/apic_example/src/main.rs | 41 ++++ 9 files changed, 564 insertions(+), 14 deletions(-) create mode 100644 docs/apic_example/Cargo.toml create mode 100644 docs/apic_example/src/apic.rs create mode 100644 docs/apic_example/src/frame_allocator.rs create mode 100644 docs/apic_example/src/gdt.rs create mode 100644 docs/apic_example/src/idt.rs create mode 100644 docs/apic_example/src/main.rs diff --git a/.gitignore b/.gitignore index eccd7b4a..0ec4e612 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target/ **/*.rs.bk +.idea \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 34decae3..e4042d33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,35 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "acpi" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "654f48ab3178632ea535be1765073b990895cb62f70a7e5671975d7150c26d15" +dependencies = [ + "bit_field", + "log", + "rsdp", +] + [[package]] name = "anyhow" version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +[[package]] +name = "apic_example" +version = "0.11.7" +dependencies = [ + "acpi", + "bootloader_api", + "lazy_static", + "log", + "spin", + "x86_64 0.15.1", +] + [[package]] name = "arrayvec" version = "0.5.2" @@ -224,7 +247,7 @@ dependencies = [ "rsdp", "serde-json-core", "usize_conversions", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -242,7 +265,7 @@ dependencies = [ "spinning_top", "uart_16550", "usize_conversions", - "x86_64", + "x86_64 0.14.10", "xmas-elf", ] @@ -256,7 +279,7 @@ dependencies = [ "log", "serde-json-core", "uefi", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -592,6 +615,12 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.147" @@ -1059,7 +1088,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -1068,7 +1097,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -1077,7 +1106,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -1086,7 +1115,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -1095,7 +1124,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -1104,7 +1133,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -1113,7 +1142,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -1122,7 +1151,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -1131,7 +1160,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -1140,7 +1169,7 @@ version = "0.1.0" dependencies = [ "bootloader_api", "uart_16550", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -1171,7 +1200,7 @@ checksum = "b074eb9300ad949edd74c529c0e8d451625af71bb948e6b65fe69f72dc1363d9" dependencies = [ "bitflags 1.3.2", "rustversion", - "x86_64", + "x86_64 0.14.10", ] [[package]] @@ -1382,6 +1411,18 @@ dependencies = [ "volatile", ] +[[package]] +name = "x86_64" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bc79523af8abf92fb1a970c3e086c5a343f6bcc1a0eb890f575cbb3b45743df" +dependencies = [ + "bit_field", + "bitflags 2.3.3", + "rustversion", + "volatile", +] + [[package]] name = "xmas-elf" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index 4ff329fe..c235d430 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ members = [ "tests/test_kernels/min_stack", "tests/test_kernels/lower_memory_free", "tests/test_kernels/write_usable_memory", + "docs/apic_example", ] exclude = ["examples/basic", "examples/test_framework"] diff --git a/docs/apic_example/Cargo.toml b/docs/apic_example/Cargo.toml new file mode 100644 index 00000000..2dc72802 --- /dev/null +++ b/docs/apic_example/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "apic_example" +edition = "2021" +version.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +bootloader_api = { workspace = true } +x86_64 = "=0.15.1" +lazy_static = "=1.5.0" +spin = "=0.9.8" +acpi = "=4.1.1" +log = "=0.4.19" diff --git a/docs/apic_example/src/apic.rs b/docs/apic_example/src/apic.rs new file mode 100644 index 00000000..fc8fc777 --- /dev/null +++ b/docs/apic_example/src/apic.rs @@ -0,0 +1,264 @@ +use crate::idt::{InterruptIndex, IDT}; +use acpi::{AcpiHandler, AcpiTables, PhysicalMapping}; +use core::ptr::NonNull; +use lazy_static::lazy_static; +use spin::Mutex; +use x86_64::structures::paging::{FrameAllocator, Mapper, PhysFrame, Size4KiB}; +use x86_64::{PhysAddr, VirtAddr}; + +lazy_static! { + pub static ref LAPIC_ADDR: Mutex = Mutex::new(LAPICAddress::new()); // Needs to be initialized +} + +// https://wiki.osdev.org/APIC#:~:text=APIC%20(%22Advanced%20Programmable%20Interrupt%20Controller%22)%20is%20the +#[allow(non_camel_case_types)] +#[derive(Debug, Clone, Copy)] +#[repr(isize)] +pub enum APICOffset { + // RESERVED = 0x00 + // RESERVED = 0x10 + IR = 0x20, // ID Register + VR = 0x30, // Version Register + // RESERVED = 0x40 + // RESERVED = 0x50 + // RESERVED = 0x60 + // RESERVED = 0x70 + TPR = 0x80, // Text Priority Register + APR = 0x90, // Arbitration Priority Register + PPR = 0xA0, // Processor Priority Register + EOI = 0xB0, // End of Interrupt + RRD = 0xC0, // Remote Read Register + LDR = 0xD0, // Logical Destination Register + DFR = 0xE0, // DFR + SVR = 0xF0, // Spurious (Interrupt) Vector Register + ISR1 = 0x100, // In-Service Register 1 + ISR2 = 0x110, // In-Service Register 2 + ISR3 = 0x120, // In-Service Register 3 + ISR4 = 0x130, // In-Service Register 4 + ISR5 = 0x140, // In-Service Register 5 + ISR6 = 0x150, // In-Service Register 6 + ISR7 = 0x160, // In-Service Register 7 + ISR8 = 0x170, // In-Service Register 8 + TMR1 = 0x180, // Trigger Mode Register 1 + TMR2 = 0x190, // Trigger Mode Register 2 + TMR3 = 0x1A0, // Trigger Mode Register 3 + TMR4 = 0x1B0, // Trigger Mode Register 4 + TMR5 = 0x1C0, // Trigger Mode Register 5 + TMR6 = 0x1D0, // Trigger Mode Register 6 + TMR7 = 0x1E0, // Trigger Mode Register 7 + TMR8 = 0x1F0, // Trigger Mode Register 8 + IRR1 = 0x200, // Interrupt Request Register 1 + IRR2 = 0x210, // Interrupt Request Register 2 + IRR3 = 0x220, // Interrupt Request Register 3 + IRR4 = 0x230, // Interrupt Request Register 4 + IRR5 = 0x240, // Interrupt Request Register 5 + IRR6 = 0x250, // Interrupt Request Register 6 + IRR7 = 0x260, // Interrupt Request Register 7 + IRR8 = 0x270, // Interrupt Request Register 8 + ESR = 0x280, // Error Status Register + // RESERVED = 0x290 + // RESERVED = 0x2A0 + // RESERVED = 0x2B0 + // RESERVED = 0x2C0 + // RESERVED = 0x2D0 + // RESERVED = 0x2E0 + LVT_CMCI = 0x2F0, // LVT Corrected Machine Check Interrupt (CMCI) Register + ICR1 = 0x300, // Interrupt Command Register 1 + ICR2 = 0x310, // Interrupt Command Register 2 + LVT_T = 0x320, // LVT Timer Register + LVT_TSR = 0x330, // LVT Thermal Sensor Register + LVT_PMCR = 0x340, // LVT Performance Monitoring Counters Register + LVT_LINT0 = 0x350, // LVT LINT0 Register + LVT_LINT1 = 0x360, // LVT LINT1 Register + LVT_E = 0x370, // LVT Error Register + TICR = 0x380, // Initial Count Register (for Timer) + TCCR = 0x390, // Current Count Register (for Timer) + // RESERVED = 0x3A0 + // RESERVED = 0x3B0 + // RESERVED = 0x3C0 + // RESERVED = 0x3D0 + TDCR = 0x3E0, // Divide Configuration Register (for Timer) + // RESERVED = 0x3F0 +} + +pub struct LAPICAddress { + address: *mut u32, +} + +unsafe impl Send for LAPICAddress {} +unsafe impl Sync for LAPICAddress {} + +impl LAPICAddress { + pub fn new() -> Self { + Self { + address: core::ptr::null_mut() + } + } +} + +pub struct AcpiHandlerImpl { + physical_memory_offset: VirtAddr, +} + +impl AcpiHandlerImpl { + pub fn new(physical_memory_offset: VirtAddr) -> Self { + Self { physical_memory_offset } + } +} + +unsafe impl Send for AcpiHandlerImpl {} +unsafe impl Sync for AcpiHandlerImpl {} + +impl Clone for AcpiHandlerImpl { + fn clone(&self) -> Self { + Self { + physical_memory_offset: self.physical_memory_offset, + } + } +} + +impl AcpiHandler for AcpiHandlerImpl { + unsafe fn map_physical_region( + &self, + physical_address: usize, + size: usize, + ) -> PhysicalMapping { + let phys_addr = PhysAddr::new(physical_address as u64); + let virt_addr = self.physical_memory_offset + phys_addr.as_u64(); + + PhysicalMapping::new( + physical_address, + NonNull::new(virt_addr.as_mut_ptr()).expect("Failed to get virtual address"), + size, + size, + self.clone(), + ) + } + + fn unmap_physical_region(_region: &PhysicalMapping) { + // No unmapping necessary as we didn't create any new mappings + } +} + +pub unsafe fn init( + rsdp: usize, physical_memory_offset: VirtAddr, + mapper: &mut impl Mapper, + frame_allocator: &mut impl FrameAllocator, +) { + let handler = AcpiHandlerImpl::new(physical_memory_offset); + let acpi_tables = AcpiTables::from_rsdp(handler, rsdp).expect("Failed to parse ACPI tables"); + let platform_info = acpi_tables.platform_info().expect("Failed to get platform info"); + match platform_info.interrupt_model { + acpi::InterruptModel::Apic(apic) => { + let io_apic_address = apic.io_apics[0].address; + init_io_apic(io_apic_address as usize, mapper, frame_allocator); + + let local_apic_address = apic.local_apic_address; + init_local_apic(local_apic_address as usize, mapper, frame_allocator); + } + _ => { + // Handle other interrupt models if necessary + } + } + + disable_pic(); + + x86_64::instructions::interrupts::enable(); + IDT.load(); +} + +unsafe fn init_local_apic( + local_apic_addr: usize, + mapper: &mut impl Mapper, + frame_allocator: &mut impl FrameAllocator, +) { + let virt_addr = map_apic( + local_apic_addr as u64, + mapper, + frame_allocator, + ); + + let lapic_pointer = virt_addr.as_mut_ptr::(); + LAPIC_ADDR.lock().address = lapic_pointer; + + init_timer(lapic_pointer); + init_keyboard(lapic_pointer); +} + +unsafe fn init_timer(lapic_pointer: *mut u32) { + let svr_register = lapic_pointer.offset(APICOffset::SVR as isize / 4); + svr_register.write_volatile(svr_register.read_volatile() | 0x100); // Set bit 8 + + let lvt_timer_register = lapic_pointer.offset(APICOffset::LVT_LINT1 as isize / 4); + lvt_timer_register.write_volatile(0x20 | (1 << 17)); // Vector 0x20, periodic mode + + let tdcr_register = lapic_pointer.offset(APICOffset::TDCR as isize / 4); + tdcr_register.write_volatile(0x3); + + let timer_initial_count_register = lapic_pointer.offset(APICOffset::TICR as isize / 4); + timer_initial_count_register.write_volatile(0x100000); +} + +unsafe fn init_keyboard(lapic_pointer: *mut u32) { + let lvt_keyboard_register = lapic_pointer.offset(APICOffset::LVT_LINT1 as isize / 4); + lvt_keyboard_register.write_volatile(InterruptIndex::Keyboard as u8 as u32); +} + +unsafe fn init_io_apic( + ioapic_address: usize, + mapper: &mut impl Mapper, + frame_allocator: &mut impl FrameAllocator, +) { + let virt_addr = map_apic( + ioapic_address as u64, + mapper, + frame_allocator, + ); + + let ioapic_pointer = virt_addr.as_mut_ptr::(); + + ioapic_pointer.offset(0).write_volatile(0x12); + ioapic_pointer.offset(4).write_volatile(InterruptIndex::Keyboard as u8 as u32); +} + + +fn map_apic( + physical_address: u64, + mapper: &mut impl Mapper, + frame_allocator: &mut impl FrameAllocator, +) -> VirtAddr { + use x86_64::structures::paging::Page; + use x86_64::structures::paging::PageTableFlags as Flags; + + let phys_addr = PhysAddr::new(physical_address); + let page = Page::containing_address(VirtAddr::new(phys_addr.as_u64())); + let frame = PhysFrame::containing_address(phys_addr); + + let flags = Flags::PRESENT | Flags::WRITABLE | Flags::NO_CACHE; + + unsafe { + mapper + .map_to(page, frame, flags, frame_allocator) + .expect("APIC mapping failed") + .flush(); + } + + page.start_address() +} + +fn disable_pic() { + // Disable any unneeded PIC features, such as timer or keyboard to prevent it from firing interrupts + + use x86_64::instructions::port::Port; + + unsafe { + Port::::new(0xA1).write(0xFF); // PIC2 (Slave PIC) + } +} + +pub fn end_interrupt() { + unsafe { + let lapic_ptr = LAPIC_ADDR.lock().address; + lapic_ptr.offset(APICOffset::EOI as isize / 4).write_volatile(0); + } +} diff --git a/docs/apic_example/src/frame_allocator.rs b/docs/apic_example/src/frame_allocator.rs new file mode 100644 index 00000000..8b17a529 --- /dev/null +++ b/docs/apic_example/src/frame_allocator.rs @@ -0,0 +1,52 @@ +use bootloader_api::info::MemoryRegionKind::Usable; +use bootloader_api::info::MemoryRegions; +use x86_64::registers::control::Cr3; +use x86_64::structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB}; +use x86_64::{PhysAddr, VirtAddr}; + +pub struct BootInfoFrameAllocator { + memory_map: &'static MemoryRegions, + next: usize, +} + +impl BootInfoFrameAllocator { + pub fn new(memory_map: &'static MemoryRegions) -> Self { + BootInfoFrameAllocator { + memory_map, + next: 0, + } + } + pub fn usable_frames(&self) -> impl Iterator { + let regions = self.memory_map.iter(); + + let usable_regions = regions.filter(|region| region.kind == Usable); + let address_ranges = usable_regions.map(|region| region.start..region.end); + let frame_addresses = address_ranges.flat_map(|region| region.step_by(4096)); + + frame_addresses.map(|address| PhysFrame::containing_address(PhysAddr::new(address))) + } +} + +unsafe impl FrameAllocator for BootInfoFrameAllocator { + fn allocate_frame(&mut self) -> Option> { + let frame = self.usable_frames().nth(self.next); + self.next += 1; + frame + } +} + +pub fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> { + let level4_table = active_level4_table(physical_memory_offset); + unsafe { OffsetPageTable::new(level4_table, physical_memory_offset) } +} + +fn active_level4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable { + let (level4_table_frame, _) = Cr3::read(); + + let physical_address = level4_table_frame.start_address(); + let virtual_address = physical_memory_offset + physical_address.as_u64(); + let page_table_pointer: *mut PageTable = virtual_address.as_mut_ptr(); + + unsafe { &mut *page_table_pointer } +} + diff --git a/docs/apic_example/src/gdt.rs b/docs/apic_example/src/gdt.rs new file mode 100644 index 00000000..965ab883 --- /dev/null +++ b/docs/apic_example/src/gdt.rs @@ -0,0 +1,62 @@ +use core::ptr::addr_of; +use lazy_static::lazy_static; +use x86_64::instructions::segmentation::{Segment, CS, DS, ES, FS, GS, SS}; +use x86_64::instructions::tables::load_tss; +use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector}; +use x86_64::structures::tss::TaskStateSegment; +use x86_64::VirtAddr; + +pub const DOUBLE_FAULT_IST_INDEX: u16 = 0; + +lazy_static! { + static ref TSS: TaskStateSegment = { + let mut tss = TaskStateSegment::new(); + tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + + let stack_start = VirtAddr::from_ptr(unsafe { addr_of!(STACK) }); + let stack_end = stack_start + STACK_SIZE as u64; + + stack_end + }; + tss + }; + + static ref GDT: (GlobalDescriptorTable, Selectors) = { + let mut gdt: GlobalDescriptorTable = GlobalDescriptorTable::new(); + + let code_selector = gdt.append(Descriptor::kernel_code_segment()); + let data_selector = gdt.append(Descriptor::kernel_data_segment()); + let tss_selector = gdt.append(Descriptor::tss_segment(&TSS)); + + ( + gdt, + Selectors { + code_selector, + data_selector, + tss_selector, + }, + ) + }; +} + +struct Selectors { + code_selector: SegmentSelector, + data_selector: SegmentSelector, + tss_selector: SegmentSelector, +} + +pub fn init() { + GDT.0.load(); + unsafe { + CS::set_reg(GDT.1.code_selector); + SS::set_reg(GDT.1.data_selector); + DS::set_reg(GDT.1.data_selector); + ES::set_reg(GDT.1.data_selector); + FS::set_reg(GDT.1.data_selector); + GS::set_reg(GDT.1.data_selector); + + load_tss(GDT.1.tss_selector) + } +} diff --git a/docs/apic_example/src/idt.rs b/docs/apic_example/src/idt.rs new file mode 100644 index 00000000..665e8297 --- /dev/null +++ b/docs/apic_example/src/idt.rs @@ -0,0 +1,74 @@ +use lazy_static::lazy_static; +use log::info; +use x86_64::registers::control::Cr2; +use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; +use crate::apic; +use crate::gdt::DOUBLE_FAULT_IST_INDEX; + +pub const PIC_1_OFFSET: u8 = 0x20; +pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; + + +lazy_static! { + pub static ref IDT: InterruptDescriptorTable = { + let mut idt = InterruptDescriptorTable::new(); + + idt.breakpoint.set_handler_fn(handle_breakpoint); + idt.page_fault.set_handler_fn(handle_page_fault); + + idt[InterruptIndex::Timer as u8].set_handler_fn(handle_timer); + idt[InterruptIndex::Keyboard as u8].set_handler_fn(handle_keyboard); + + unsafe { + idt.double_fault + .set_handler_fn(handle_double_fault) + .set_stack_index(DOUBLE_FAULT_IST_INDEX); + } + + idt + }; +} + +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +pub enum InterruptIndex { + Timer = PIC_1_OFFSET, + Keyboard, +} + +pub fn end_interrupt() { + apic::end_interrupt(); +} + +pub extern "x86-interrupt" fn handle_timer(_stack_frame: InterruptStackFrame) { + // Handle logic + + apic::end_interrupt(); +} + +pub extern "x86-interrupt" fn handle_breakpoint(stack_frame: InterruptStackFrame) { + info!("Breakpoint hit:\n{:#?}", stack_frame); +} + +pub extern "x86-interrupt" fn handle_double_fault(stack_frame: InterruptStackFrame, _error_code: u64) -> ! { + info!("\nDouble fault:\n{:#?}", stack_frame); + + loop {} +} + +pub extern "x86-interrupt" fn handle_page_fault(stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode) { + info!("Exception : Page Fault"); + info!("Accessed address : {:?}", Cr2::read()); + info!("ErrorCode : {:?}", error_code); + info!("{:#?}", stack_frame); + + loop {} +} + +pub extern "x86-interrupt" fn handle_keyboard(_stack_frame: InterruptStackFrame) { + // Handle logic + + apic::end_interrupt(); +} + + diff --git a/docs/apic_example/src/main.rs b/docs/apic_example/src/main.rs new file mode 100644 index 00000000..419fc71d --- /dev/null +++ b/docs/apic_example/src/main.rs @@ -0,0 +1,41 @@ +#![feature(abi_x86_interrupt)] +#![no_std] +#![no_main] + +mod frame_allocator; +mod apic; +mod idt; +mod gdt; + +extern crate alloc; + +use bootloader_api::{entry_point, BootInfo}; +use x86_64::structures::paging::OffsetPageTable; +use x86_64::VirtAddr; +use bootloader_api::config::Mapping; +use crate::frame_allocator::BootInfoFrameAllocator; + +pub const CONFIG: bootloader_api::BootloaderConfig = { + let mut config = bootloader_api::BootloaderConfig::new_default(); + config.mappings.physical_memory = Some(Mapping::Dynamic); + config +}; + +entry_point!(kernel_main, config = &CONFIG); + +pub fn kernel_main(boot_info: &'static mut BootInfo) { + let physical_memory_offset = VirtAddr::new( + boot_info + .physical_memory_offset + .take() + .expect("Failed to find physical memory offset"), + ); + let mut mapper: OffsetPageTable<'static> = frame_allocator::init(physical_memory_offset); + let mut frame_allocator = BootInfoFrameAllocator::new(&boot_info.memory_regions); + + let rsdp: Option = boot_info.rsdp_addr.take(); + + unsafe { + apic::init(rsdp.expect("Failed to get RSDP address") as usize, physical_memory_offset, &mut mapper, &mut frame_allocator); + } +} \ No newline at end of file From 6ddeb9204cb3de8b7f1e126551525968238b2dcd Mon Sep 17 00:00:00 2001 From: Voinea Radu Date: Mon, 7 Oct 2024 22:31:12 +0300 Subject: [PATCH 2/5] Did a small refactor on the example code --- docs/apic_example/src/apic.rs | 31 +++++++++++++++---------------- docs/apic_example/src/idt.rs | 4 ++-- docs/apic_example/src/main.rs | 7 +++---- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/docs/apic_example/src/apic.rs b/docs/apic_example/src/apic.rs index fc8fc777..0fe5a8f6 100644 --- a/docs/apic_example/src/apic.rs +++ b/docs/apic_example/src/apic.rs @@ -172,13 +172,13 @@ unsafe fn init_local_apic( mapper: &mut impl Mapper, frame_allocator: &mut impl FrameAllocator, ) { - let virt_addr = map_apic( + let virtual_address = map_apic( local_apic_addr as u64, mapper, frame_allocator, ); - let lapic_pointer = virt_addr.as_mut_ptr::(); + let lapic_pointer = virtual_address.as_mut_ptr::(); LAPIC_ADDR.lock().address = lapic_pointer; init_timer(lapic_pointer); @@ -186,22 +186,22 @@ unsafe fn init_local_apic( } unsafe fn init_timer(lapic_pointer: *mut u32) { - let svr_register = lapic_pointer.offset(APICOffset::SVR as isize / 4); - svr_register.write_volatile(svr_register.read_volatile() | 0x100); // Set bit 8 + let svr = lapic_pointer.offset(APICOffset::SVR as isize / 4); + svr.write_volatile(svr.read_volatile() | 0x100); // Set bit 8 - let lvt_timer_register = lapic_pointer.offset(APICOffset::LVT_LINT1 as isize / 4); - lvt_timer_register.write_volatile(0x20 | (1 << 17)); // Vector 0x20, periodic mode + let lvt_lint1 = lapic_pointer.offset(APICOffset::LVT_LINT1 as isize / 4); + lvt_lint1.write_volatile(0x20 | (1 << 17)); // Vector 0x20, periodic mode - let tdcr_register = lapic_pointer.offset(APICOffset::TDCR as isize / 4); - tdcr_register.write_volatile(0x3); + let tdcr = lapic_pointer.offset(APICOffset::TDCR as isize / 4); + tdcr.write_volatile(0x3); // Divide by 16 mode - let timer_initial_count_register = lapic_pointer.offset(APICOffset::TICR as isize / 4); - timer_initial_count_register.write_volatile(0x100000); + let ticr = lapic_pointer.offset(APICOffset::TICR as isize / 4); + ticr.write_volatile(0x100000); // An arbitrary value for the initial value of the timer } unsafe fn init_keyboard(lapic_pointer: *mut u32) { - let lvt_keyboard_register = lapic_pointer.offset(APICOffset::LVT_LINT1 as isize / 4); - lvt_keyboard_register.write_volatile(InterruptIndex::Keyboard as u8 as u32); + let keyboard_register = lapic_pointer.offset(APICOffset::LVT_LINT1 as isize / 4); + keyboard_register.write_volatile(InterruptIndex::Keyboard as u8 as u32); } unsafe fn init_io_apic( @@ -230,9 +230,9 @@ fn map_apic( use x86_64::structures::paging::Page; use x86_64::structures::paging::PageTableFlags as Flags; - let phys_addr = PhysAddr::new(physical_address); - let page = Page::containing_address(VirtAddr::new(phys_addr.as_u64())); - let frame = PhysFrame::containing_address(phys_addr); + let physical_address = PhysAddr::new(physical_address); + let page = Page::containing_address(VirtAddr::new(physical_address.as_u64())); + let frame = PhysFrame::containing_address(physical_address); let flags = Flags::PRESENT | Flags::WRITABLE | Flags::NO_CACHE; @@ -248,7 +248,6 @@ fn map_apic( fn disable_pic() { // Disable any unneeded PIC features, such as timer or keyboard to prevent it from firing interrupts - use x86_64::instructions::port::Port; unsafe { diff --git a/docs/apic_example/src/idt.rs b/docs/apic_example/src/idt.rs index 665e8297..29885319 100644 --- a/docs/apic_example/src/idt.rs +++ b/docs/apic_example/src/idt.rs @@ -1,9 +1,9 @@ +use crate::apic; +use crate::gdt::DOUBLE_FAULT_IST_INDEX; use lazy_static::lazy_static; use log::info; use x86_64::registers::control::Cr2; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; -use crate::apic; -use crate::gdt::DOUBLE_FAULT_IST_INDEX; pub const PIC_1_OFFSET: u8 = 0x20; pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; diff --git a/docs/apic_example/src/main.rs b/docs/apic_example/src/main.rs index 419fc71d..0038a805 100644 --- a/docs/apic_example/src/main.rs +++ b/docs/apic_example/src/main.rs @@ -2,18 +2,17 @@ #![no_std] #![no_main] +extern crate alloc; mod frame_allocator; mod apic; mod idt; mod gdt; -extern crate alloc; - +use crate::frame_allocator::BootInfoFrameAllocator; +use bootloader_api::config::Mapping; use bootloader_api::{entry_point, BootInfo}; use x86_64::structures::paging::OffsetPageTable; use x86_64::VirtAddr; -use bootloader_api::config::Mapping; -use crate::frame_allocator::BootInfoFrameAllocator; pub const CONFIG: bootloader_api::BootloaderConfig = { let mut config = bootloader_api::BootloaderConfig::new_default(); From 8f2570d1b7986cdc0de841098500a6435afa7dcb Mon Sep 17 00:00:00 2001 From: Voinea Radu Date: Mon, 7 Oct 2024 22:47:44 +0300 Subject: [PATCH 3/5] Added some more explanation on what the purpose of everything is --- docs/apic_example/apic.md | 30 ++++++++++++++++++++++++++++++ docs/apic_example/src/apic.rs | 2 +- docs/migration/v0.9.md | 5 +---- 3 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 docs/apic_example/apic.md diff --git a/docs/apic_example/apic.md b/docs/apic_example/apic.md new file mode 100644 index 00000000..46c98997 --- /dev/null +++ b/docs/apic_example/apic.md @@ -0,0 +1,30 @@ +# How to use the APIC + +## src/main.rs + +In the example provided we will be using a dynamic memory mapping. This is for exemplification only and can be changed +with your own implementation of the memory mapper. + +## src/apic.rs + +Here we create an `AcpiHandlerImpl` that implements the `AcpiHandler` trait from the `apic` crate. +We have also added an enum with all the APIC registers from +the [OS Dev Wiki](https://wiki.osdev.org/APIC) +The main functions of the file are: + +- Init the Local APIC +- Init the IO APIC +- Map the APIC + +## src/frame_allocator.rs + +This implements a basic frame allocator based on the [blog post](https://os.phil-opp.com/heap-allocation/) + +## src/gdt.rs + +Implements a basic Global Descriptor Table based on +the [blog post](https://os.phil-opp.com/double-fault-exceptions/#the-global-descriptor-table/) as well as ensures that +all segment registers are written, including `ss` and `ds`. + +## src/idt.rs +Implements a basic Interrupt Descriptor Table based on the [blog post](https://os.phil-opp.com/hardware-interrupts/) \ No newline at end of file diff --git a/docs/apic_example/src/apic.rs b/docs/apic_example/src/apic.rs index 0fe5a8f6..863b0eb0 100644 --- a/docs/apic_example/src/apic.rs +++ b/docs/apic_example/src/apic.rs @@ -10,7 +10,7 @@ lazy_static! { pub static ref LAPIC_ADDR: Mutex = Mutex::new(LAPICAddress::new()); // Needs to be initialized } -// https://wiki.osdev.org/APIC#:~:text=APIC%20(%22Advanced%20Programmable%20Interrupt%20Controller%22)%20is%20the +// https://wiki.osdev.org/APIC #[allow(non_camel_case_types)] #[derive(Debug, Clone, Copy)] #[repr(isize)] diff --git a/docs/migration/v0.9.md b/docs/migration/v0.9.md index 2770e432..4575738c 100644 --- a/docs/migration/v0.9.md +++ b/docs/migration/v0.9.md @@ -34,10 +34,7 @@ This guide summarizes the steps for migrating from `bootloader v0.9.X` to `bootl ``` See the [`BootloaderConfig`](https://docs.rs/bootloader_api/0.11/bootloader_api/config/struct.BootloaderConfig.html) struct for all configuration options. - The `v0.11` version of the bootloader sets up a pixel-based framebuffer instead of using the VGA text mode. This means that you have to rewrite your screen output code. See the [`common/src/framebuffer.rs`](../../common/src/framebuffer.rs) module for an example implementation based on the [`noto-sans-mono-bitmap`](https://docs.rs/noto-sans-mono-bitmap/latest/noto_sans_mono_bitmap/index.html) and [`log`](https://docs.rs/log/latest) crates. -- If you want to use UEFI booting, you cannot use the [legacy PIC](https://wiki.osdev.org/8259_PIC) for interrupt handling. Instead, you have to set up the [`APIC`](https://wiki.osdev.org/APIC). Unfortunately, we don't have a guide for this yet, but the basic steps are: - - The `boot_info.rsdp_addr` field will tell you the physical address of the [`RSDP`](https://wiki.osdev.org/RSDP) structure, which is part of the [`ACPI`](https://en.wikipedia.org/wiki/ACPI) standard. Note that `ACPI` (_Advanced Configuration and Power Interface_) and `APIC` (_Advanced Programmable Interrupt Controller_) are completely different things that just have confusingly similar acronyms. - - Use the [`acpi`](https://docs.rs/acpi/4.1.1/acpi/index.html) crate and its [`AcpiTables::from_rsdp`](https://docs.rs/acpi/4.1.1/acpi/struct.AcpiTables.html#method.from_rsdp) function to load the ACPI tables. Then use the [`platform_info`](https://docs.rs/acpi/4.1.1/acpi/struct.AcpiTables.html#method.platform_info) method and read the [`interrupt_model`](https://docs.rs/acpi/4.1.1/acpi/platform/struct.PlatformInfo.html#structfield.interrupt_model) field of the returned `PlatformInfo`. This field gives you all the necessary information about the system's interrupt controller. - - Parse and set up the local and IO APIC. We're working on a [crate](https://github.com/rust-osdev/apic) for that, but it's still in a very early state. We would love contributions! Alternatively, there are some other crates on crates.io that might work too. +- If you want to use UEFI booting, you cannot use the [legacy PIC](https://wiki.osdev.org/8259_PIC) for interrupt handling. Instead, you have to set up the [`APIC`](https://wiki.osdev.org/APIC). To do so you can use the provided [example](../apic_example/apic.md) as a starting point. - If you reload the GDT at some point, ensure that all segment registers are written, including `ss` and `ds`. The `v0.9` version of the bootloader used to initialize some of them to 0, but this is no longer the case. If you don't do this, [a general protection fault might happen on `iretq`](https://github.com/rust-osdev/bootloader/issues/196). To build your kernel, run **`cargo build --target x86_64-unknown-none`**. Since the `x86_64-unknown-none` target is a Tier-2 target, there is no need for `bootimage`, `cargo-xbuild`, or `xargo` anymore. Instead, you can run `rustup target add x86_64-unknown-none` to download precompiled versions of the `core` and `alloc` crates. There is no need for custom JSON-based target files anymore. From 9279f36e62c6ccc7639c2c582ca4dd66603b3717 Mon Sep 17 00:00:00 2001 From: Voinea Radu Date: Mon, 7 Oct 2024 23:01:32 +0300 Subject: [PATCH 4/5] Reformatted respecting cargo clippy --- docs/apic_example/src/apic.rs | 107 +++++++++++++++++----------------- docs/apic_example/src/gdt.rs | 8 +-- docs/apic_example/src/idt.rs | 15 +++-- docs/apic_example/src/main.rs | 8 ++- 4 files changed, 71 insertions(+), 67 deletions(-) diff --git a/docs/apic_example/src/apic.rs b/docs/apic_example/src/apic.rs index 863b0eb0..1fa2f7b4 100644 --- a/docs/apic_example/src/apic.rs +++ b/docs/apic_example/src/apic.rs @@ -14,70 +14,71 @@ lazy_static! { #[allow(non_camel_case_types)] #[derive(Debug, Clone, Copy)] #[repr(isize)] +#[allow(dead_code)] pub enum APICOffset { // RESERVED = 0x00 // RESERVED = 0x10 - IR = 0x20, // ID Register - VR = 0x30, // Version Register + Ir = 0x20, // ID Register + Vr = 0x30, // Version Register // RESERVED = 0x40 // RESERVED = 0x50 // RESERVED = 0x60 // RESERVED = 0x70 - TPR = 0x80, // Text Priority Register - APR = 0x90, // Arbitration Priority Register - PPR = 0xA0, // Processor Priority Register - EOI = 0xB0, // End of Interrupt - RRD = 0xC0, // Remote Read Register - LDR = 0xD0, // Logical Destination Register - DFR = 0xE0, // DFR - SVR = 0xF0, // Spurious (Interrupt) Vector Register - ISR1 = 0x100, // In-Service Register 1 - ISR2 = 0x110, // In-Service Register 2 - ISR3 = 0x120, // In-Service Register 3 - ISR4 = 0x130, // In-Service Register 4 - ISR5 = 0x140, // In-Service Register 5 - ISR6 = 0x150, // In-Service Register 6 - ISR7 = 0x160, // In-Service Register 7 - ISR8 = 0x170, // In-Service Register 8 - TMR1 = 0x180, // Trigger Mode Register 1 - TMR2 = 0x190, // Trigger Mode Register 2 - TMR3 = 0x1A0, // Trigger Mode Register 3 - TMR4 = 0x1B0, // Trigger Mode Register 4 - TMR5 = 0x1C0, // Trigger Mode Register 5 - TMR6 = 0x1D0, // Trigger Mode Register 6 - TMR7 = 0x1E0, // Trigger Mode Register 7 - TMR8 = 0x1F0, // Trigger Mode Register 8 - IRR1 = 0x200, // Interrupt Request Register 1 - IRR2 = 0x210, // Interrupt Request Register 2 - IRR3 = 0x220, // Interrupt Request Register 3 - IRR4 = 0x230, // Interrupt Request Register 4 - IRR5 = 0x240, // Interrupt Request Register 5 - IRR6 = 0x250, // Interrupt Request Register 6 - IRR7 = 0x260, // Interrupt Request Register 7 - IRR8 = 0x270, // Interrupt Request Register 8 - ESR = 0x280, // Error Status Register + Tpr = 0x80, // Text Priority Register + Apr = 0x90, // Arbitration Priority Register + Ppr = 0xA0, // Processor Priority Register + Eoi = 0xB0, // End of Interrupt + Rrd = 0xC0, // Remote Read Register + Ldr = 0xD0, // Logical Destination Register + Dfr = 0xE0, // DFR + Svr = 0xF0, // Spurious (Interrupt) Vector Register + Isr1 = 0x100, // In-Service Register 1 + Isr2 = 0x110, // In-Service Register 2 + Isr3 = 0x120, // In-Service Register 3 + Isr4 = 0x130, // In-Service Register 4 + Isr5 = 0x140, // In-Service Register 5 + Isr6 = 0x150, // In-Service Register 6 + Isr7 = 0x160, // In-Service Register 7 + Isr8 = 0x170, // In-Service Register 8 + Tmr1 = 0x180, // Trigger Mode Register 1 + Tmr2 = 0x190, // Trigger Mode Register 2 + Tmr3 = 0x1A0, // Trigger Mode Register 3 + Tmr4 = 0x1B0, // Trigger Mode Register 4 + Tmr5 = 0x1C0, // Trigger Mode Register 5 + Tmr6 = 0x1D0, // Trigger Mode Register 6 + Tmr7 = 0x1E0, // Trigger Mode Register 7 + Tmr8 = 0x1F0, // Trigger Mode Register 8 + Irr1 = 0x200, // Interrupt Request Register 1 + Irr2 = 0x210, // Interrupt Request Register 2 + Irr3 = 0x220, // Interrupt Request Register 3 + Irr4 = 0x230, // Interrupt Request Register 4 + Irr5 = 0x240, // Interrupt Request Register 5 + Irr6 = 0x250, // Interrupt Request Register 6 + Irr7 = 0x260, // Interrupt Request Register 7 + Irr8 = 0x270, // Interrupt Request Register 8 + Esr = 0x280, // Error Status Register // RESERVED = 0x290 // RESERVED = 0x2A0 // RESERVED = 0x2B0 // RESERVED = 0x2C0 // RESERVED = 0x2D0 // RESERVED = 0x2E0 - LVT_CMCI = 0x2F0, // LVT Corrected Machine Check Interrupt (CMCI) Register - ICR1 = 0x300, // Interrupt Command Register 1 - ICR2 = 0x310, // Interrupt Command Register 2 - LVT_T = 0x320, // LVT Timer Register - LVT_TSR = 0x330, // LVT Thermal Sensor Register - LVT_PMCR = 0x340, // LVT Performance Monitoring Counters Register - LVT_LINT0 = 0x350, // LVT LINT0 Register - LVT_LINT1 = 0x360, // LVT LINT1 Register - LVT_E = 0x370, // LVT Error Register - TICR = 0x380, // Initial Count Register (for Timer) - TCCR = 0x390, // Current Count Register (for Timer) + LvtCmci = 0x2F0, // LVT Corrected Machine Check Interrupt (CMCI) Register + Icr1 = 0x300, // Interrupt Command Register 1 + Icr2 = 0x310, // Interrupt Command Register 2 + LvtT = 0x320, // LVT Timer Register + LvtTsr = 0x330, // LVT Thermal Sensor Register + LvtPmcr = 0x340, // LVT Performance Monitoring Counters Register + LvtLint0 = 0x350, // LVT LINT0 Register + LvtLint1 = 0x360, // LVT LINT1 Register + LvtE = 0x370, // LVT Error Register + Ticr = 0x380, // Initial Count Register (for Timer) + Tccr = 0x390, // Current Count Register (for Timer) // RESERVED = 0x3A0 // RESERVED = 0x3B0 // RESERVED = 0x3C0 // RESERVED = 0x3D0 - TDCR = 0x3E0, // Divide Configuration Register (for Timer) + Tdcr = 0x3E0, // Divide Configuration Register (for Timer) // RESERVED = 0x3F0 } @@ -186,21 +187,21 @@ unsafe fn init_local_apic( } unsafe fn init_timer(lapic_pointer: *mut u32) { - let svr = lapic_pointer.offset(APICOffset::SVR as isize / 4); + let svr = lapic_pointer.offset(APICOffset::Svr as isize / 4); svr.write_volatile(svr.read_volatile() | 0x100); // Set bit 8 - let lvt_lint1 = lapic_pointer.offset(APICOffset::LVT_LINT1 as isize / 4); + let lvt_lint1 = lapic_pointer.offset(APICOffset::LvtT as isize / 4); lvt_lint1.write_volatile(0x20 | (1 << 17)); // Vector 0x20, periodic mode - let tdcr = lapic_pointer.offset(APICOffset::TDCR as isize / 4); + let tdcr = lapic_pointer.offset(APICOffset::Tdcr as isize / 4); tdcr.write_volatile(0x3); // Divide by 16 mode - let ticr = lapic_pointer.offset(APICOffset::TICR as isize / 4); + let ticr = lapic_pointer.offset(APICOffset::Ticr as isize / 4); ticr.write_volatile(0x100000); // An arbitrary value for the initial value of the timer } unsafe fn init_keyboard(lapic_pointer: *mut u32) { - let keyboard_register = lapic_pointer.offset(APICOffset::LVT_LINT1 as isize / 4); + let keyboard_register = lapic_pointer.offset(APICOffset::LvtLint1 as isize / 4); keyboard_register.write_volatile(InterruptIndex::Keyboard as u8 as u32); } @@ -258,6 +259,6 @@ fn disable_pic() { pub fn end_interrupt() { unsafe { let lapic_ptr = LAPIC_ADDR.lock().address; - lapic_ptr.offset(APICOffset::EOI as isize / 4).write_volatile(0); + lapic_ptr.offset(APICOffset::Eoi as isize / 4).write_volatile(0); } } diff --git a/docs/apic_example/src/gdt.rs b/docs/apic_example/src/gdt.rs index 965ab883..fe74b016 100644 --- a/docs/apic_example/src/gdt.rs +++ b/docs/apic_example/src/gdt.rs @@ -13,12 +13,10 @@ lazy_static! { let mut tss = TaskStateSegment::new(); tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = { const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + static STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { addr_of!(STACK) }); - let stack_end = stack_start + STACK_SIZE as u64; - - stack_end + let stack_start = VirtAddr::from_ptr( addr_of!(STACK) ); + stack_start + STACK_SIZE as u64 // stack_end }; tss }; diff --git a/docs/apic_example/src/idt.rs b/docs/apic_example/src/idt.rs index 29885319..b935e781 100644 --- a/docs/apic_example/src/idt.rs +++ b/docs/apic_example/src/idt.rs @@ -2,12 +2,11 @@ use crate::apic; use crate::gdt::DOUBLE_FAULT_IST_INDEX; use lazy_static::lazy_static; use log::info; +use x86_64::instructions::hlt; use x86_64::registers::control::Cr2; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; pub const PIC_1_OFFSET: u8 = 0x20; -pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; - lazy_static! { pub static ref IDT: InterruptDescriptorTable = { @@ -36,10 +35,6 @@ pub enum InterruptIndex { Keyboard, } -pub fn end_interrupt() { - apic::end_interrupt(); -} - pub extern "x86-interrupt" fn handle_timer(_stack_frame: InterruptStackFrame) { // Handle logic @@ -53,7 +48,9 @@ pub extern "x86-interrupt" fn handle_breakpoint(stack_frame: InterruptStackFrame pub extern "x86-interrupt" fn handle_double_fault(stack_frame: InterruptStackFrame, _error_code: u64) -> ! { info!("\nDouble fault:\n{:#?}", stack_frame); - loop {} + loop { + hlt() + } } pub extern "x86-interrupt" fn handle_page_fault(stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode) { @@ -62,7 +59,9 @@ pub extern "x86-interrupt" fn handle_page_fault(stack_frame: InterruptStackFrame info!("ErrorCode : {:?}", error_code); info!("{:#?}", stack_frame); - loop {} + loop { + hlt() + } } pub extern "x86-interrupt" fn handle_keyboard(_stack_frame: InterruptStackFrame) { diff --git a/docs/apic_example/src/main.rs b/docs/apic_example/src/main.rs index 0038a805..62f04ac6 100644 --- a/docs/apic_example/src/main.rs +++ b/docs/apic_example/src/main.rs @@ -8,6 +8,7 @@ mod apic; mod idt; mod gdt; +use x86_64::instructions::hlt; use crate::frame_allocator::BootInfoFrameAllocator; use bootloader_api::config::Mapping; use bootloader_api::{entry_point, BootInfo}; @@ -22,7 +23,7 @@ pub const CONFIG: bootloader_api::BootloaderConfig = { entry_point!(kernel_main, config = &CONFIG); -pub fn kernel_main(boot_info: &'static mut BootInfo) { +pub fn kernel_main(boot_info: &'static mut BootInfo) -> ! { let physical_memory_offset = VirtAddr::new( boot_info .physical_memory_offset @@ -34,7 +35,12 @@ pub fn kernel_main(boot_info: &'static mut BootInfo) { let rsdp: Option = boot_info.rsdp_addr.take(); + gdt::init(); unsafe { apic::init(rsdp.expect("Failed to get RSDP address") as usize, physical_memory_offset, &mut mapper, &mut frame_allocator); } + + loop { + hlt() + } } \ No newline at end of file From 09b195ddc3b254b67b18212d6cc0829e49dbd3cf Mon Sep 17 00:00:00 2001 From: Voinea Radu Date: Mon, 7 Oct 2024 23:13:58 +0300 Subject: [PATCH 5/5] Reformatted respecting cargo fmt --all --- docs/apic_example/src/apic.rs | 158 +++++++++++------------ docs/apic_example/src/frame_allocator.rs | 3 +- docs/apic_example/src/idt.rs | 12 +- docs/apic_example/src/main.rs | 15 ++- 4 files changed, 98 insertions(+), 90 deletions(-) diff --git a/docs/apic_example/src/apic.rs b/docs/apic_example/src/apic.rs index 1fa2f7b4..6785ca09 100644 --- a/docs/apic_example/src/apic.rs +++ b/docs/apic_example/src/apic.rs @@ -16,70 +16,70 @@ lazy_static! { #[repr(isize)] #[allow(dead_code)] pub enum APICOffset { - // RESERVED = 0x00 - // RESERVED = 0x10 - Ir = 0x20, // ID Register - Vr = 0x30, // Version Register - // RESERVED = 0x40 - // RESERVED = 0x50 - // RESERVED = 0x60 - // RESERVED = 0x70 - Tpr = 0x80, // Text Priority Register - Apr = 0x90, // Arbitration Priority Register - Ppr = 0xA0, // Processor Priority Register - Eoi = 0xB0, // End of Interrupt - Rrd = 0xC0, // Remote Read Register - Ldr = 0xD0, // Logical Destination Register - Dfr = 0xE0, // DFR - Svr = 0xF0, // Spurious (Interrupt) Vector Register - Isr1 = 0x100, // In-Service Register 1 - Isr2 = 0x110, // In-Service Register 2 - Isr3 = 0x120, // In-Service Register 3 - Isr4 = 0x130, // In-Service Register 4 - Isr5 = 0x140, // In-Service Register 5 - Isr6 = 0x150, // In-Service Register 6 - Isr7 = 0x160, // In-Service Register 7 - Isr8 = 0x170, // In-Service Register 8 - Tmr1 = 0x180, // Trigger Mode Register 1 - Tmr2 = 0x190, // Trigger Mode Register 2 - Tmr3 = 0x1A0, // Trigger Mode Register 3 - Tmr4 = 0x1B0, // Trigger Mode Register 4 - Tmr5 = 0x1C0, // Trigger Mode Register 5 - Tmr6 = 0x1D0, // Trigger Mode Register 6 - Tmr7 = 0x1E0, // Trigger Mode Register 7 - Tmr8 = 0x1F0, // Trigger Mode Register 8 - Irr1 = 0x200, // Interrupt Request Register 1 - Irr2 = 0x210, // Interrupt Request Register 2 - Irr3 = 0x220, // Interrupt Request Register 3 - Irr4 = 0x230, // Interrupt Request Register 4 - Irr5 = 0x240, // Interrupt Request Register 5 - Irr6 = 0x250, // Interrupt Request Register 6 - Irr7 = 0x260, // Interrupt Request Register 7 - Irr8 = 0x270, // Interrupt Request Register 8 - Esr = 0x280, // Error Status Register - // RESERVED = 0x290 - // RESERVED = 0x2A0 - // RESERVED = 0x2B0 - // RESERVED = 0x2C0 - // RESERVED = 0x2D0 - // RESERVED = 0x2E0 - LvtCmci = 0x2F0, // LVT Corrected Machine Check Interrupt (CMCI) Register - Icr1 = 0x300, // Interrupt Command Register 1 - Icr2 = 0x310, // Interrupt Command Register 2 - LvtT = 0x320, // LVT Timer Register - LvtTsr = 0x330, // LVT Thermal Sensor Register - LvtPmcr = 0x340, // LVT Performance Monitoring Counters Register + R0x00 = 0x0, // RESERVED = 0x00 + R0x10 = 0x10, // RESERVED = 0x10 + Ir = 0x20, // ID Register + Vr = 0x30, // Version Register + R0x40 = 0x40, // RESERVED = 0x40 + R0x50 = 0x50, // RESERVED = 0x50 + R0x60 = 0x60, // RESERVED = 0x60 + R0x70 = 0x70, // RESERVED = 0x70 + Tpr = 0x80, // Text Priority Register + Apr = 0x90, // Arbitration Priority Register + Ppr = 0xA0, // Processor Priority Register + Eoi = 0xB0, // End of Interrupt + Rrd = 0xC0, // Remote Read Register + Ldr = 0xD0, // Logical Destination Register + Dfr = 0xE0, // DFR + Svr = 0xF0, // Spurious (Interrupt) Vector Register + Isr1 = 0x100, // In-Service Register 1 + Isr2 = 0x110, // In-Service Register 2 + Isr3 = 0x120, // In-Service Register 3 + Isr4 = 0x130, // In-Service Register 4 + Isr5 = 0x140, // In-Service Register 5 + Isr6 = 0x150, // In-Service Register 6 + Isr7 = 0x160, // In-Service Register 7 + Isr8 = 0x170, // In-Service Register 8 + Tmr1 = 0x180, // Trigger Mode Register 1 + Tmr2 = 0x190, // Trigger Mode Register 2 + Tmr3 = 0x1A0, // Trigger Mode Register 3 + Tmr4 = 0x1B0, // Trigger Mode Register 4 + Tmr5 = 0x1C0, // Trigger Mode Register 5 + Tmr6 = 0x1D0, // Trigger Mode Register 6 + Tmr7 = 0x1E0, // Trigger Mode Register 7 + Tmr8 = 0x1F0, // Trigger Mode Register 8 + Irr1 = 0x200, // Interrupt Request Register 1 + Irr2 = 0x210, // Interrupt Request Register 2 + Irr3 = 0x220, // Interrupt Request Register 3 + Irr4 = 0x230, // Interrupt Request Register 4 + Irr5 = 0x240, // Interrupt Request Register 5 + Irr6 = 0x250, // Interrupt Request Register 6 + Irr7 = 0x260, // Interrupt Request Register 7 + Irr8 = 0x270, // Interrupt Request Register 8 + Esr = 0x280, // Error Status Register + R0x290 = 0x290, // RESERVED = 0x290 + R0x2A0 = 0x2A0, // RESERVED = 0x2A0 + R0x2B0 = 0x2B0, // RESERVED = 0x2B0 + R0x2C0 = 0x2C0, // RESERVED = 0x2C0 + R0x2D0 = 0x2D0, // RESERVED = 0x2D0 + R0x2E0 = 0x2E0, // RESERVED = 0x2E0 + LvtCmci = 0x2F0, // LVT Corrected Machine Check Interrupt (CMCI) Register + Icr1 = 0x300, // Interrupt Command Register 1 + Icr2 = 0x310, // Interrupt Command Register 2 + LvtT = 0x320, // LVT Timer Register + LvtTsr = 0x330, // LVT Thermal Sensor Register + LvtPmcr = 0x340, // LVT Performance Monitoring Counters Register LvtLint0 = 0x350, // LVT LINT0 Register LvtLint1 = 0x360, // LVT LINT1 Register - LvtE = 0x370, // LVT Error Register - Ticr = 0x380, // Initial Count Register (for Timer) - Tccr = 0x390, // Current Count Register (for Timer) - // RESERVED = 0x3A0 - // RESERVED = 0x3B0 - // RESERVED = 0x3C0 - // RESERVED = 0x3D0 - Tdcr = 0x3E0, // Divide Configuration Register (for Timer) - // RESERVED = 0x3F0 + LvtE = 0x370, // LVT Error Register + Ticr = 0x380, // Initial Count Register (for Timer) + Tccr = 0x390, // Current Count Register (for Timer) + R0x3A0 = 0x3A0, // RESERVED = 0x3A0 + R0x3B0 = 0x3B0, // RESERVED = 0x3B0 + R0x3C0 = 0x3C0, // RESERVED = 0x3C0 + R0x3D0 = 0x3D0, // RESERVED = 0x3D0 + Tdcr = 0x3E0, // Divide Configuration Register (for Timer) + R0x3F0 = 0x3F0, // RESERVED = 0x3F0 } pub struct LAPICAddress { @@ -92,7 +92,7 @@ unsafe impl Sync for LAPICAddress {} impl LAPICAddress { pub fn new() -> Self { Self { - address: core::ptr::null_mut() + address: core::ptr::null_mut(), } } } @@ -103,7 +103,9 @@ pub struct AcpiHandlerImpl { impl AcpiHandlerImpl { pub fn new(physical_memory_offset: VirtAddr) -> Self { - Self { physical_memory_offset } + Self { + physical_memory_offset, + } } } @@ -142,13 +144,16 @@ impl AcpiHandler for AcpiHandlerImpl { } pub unsafe fn init( - rsdp: usize, physical_memory_offset: VirtAddr, + rsdp: usize, + physical_memory_offset: VirtAddr, mapper: &mut impl Mapper, frame_allocator: &mut impl FrameAllocator, ) { let handler = AcpiHandlerImpl::new(physical_memory_offset); let acpi_tables = AcpiTables::from_rsdp(handler, rsdp).expect("Failed to parse ACPI tables"); - let platform_info = acpi_tables.platform_info().expect("Failed to get platform info"); + let platform_info = acpi_tables + .platform_info() + .expect("Failed to get platform info"); match platform_info.interrupt_model { acpi::InterruptModel::Apic(apic) => { let io_apic_address = apic.io_apics[0].address; @@ -173,11 +178,7 @@ unsafe fn init_local_apic( mapper: &mut impl Mapper, frame_allocator: &mut impl FrameAllocator, ) { - let virtual_address = map_apic( - local_apic_addr as u64, - mapper, - frame_allocator, - ); + let virtual_address = map_apic(local_apic_addr as u64, mapper, frame_allocator); let lapic_pointer = virtual_address.as_mut_ptr::(); LAPIC_ADDR.lock().address = lapic_pointer; @@ -210,19 +211,16 @@ unsafe fn init_io_apic( mapper: &mut impl Mapper, frame_allocator: &mut impl FrameAllocator, ) { - let virt_addr = map_apic( - ioapic_address as u64, - mapper, - frame_allocator, - ); + let virt_addr = map_apic(ioapic_address as u64, mapper, frame_allocator); let ioapic_pointer = virt_addr.as_mut_ptr::(); ioapic_pointer.offset(0).write_volatile(0x12); - ioapic_pointer.offset(4).write_volatile(InterruptIndex::Keyboard as u8 as u32); + ioapic_pointer + .offset(4) + .write_volatile(InterruptIndex::Keyboard as u8 as u32); } - fn map_apic( physical_address: u64, mapper: &mut impl Mapper, @@ -259,6 +257,8 @@ fn disable_pic() { pub fn end_interrupt() { unsafe { let lapic_ptr = LAPIC_ADDR.lock().address; - lapic_ptr.offset(APICOffset::Eoi as isize / 4).write_volatile(0); + lapic_ptr + .offset(APICOffset::Eoi as isize / 4) + .write_volatile(0); } } diff --git a/docs/apic_example/src/frame_allocator.rs b/docs/apic_example/src/frame_allocator.rs index 8b17a529..2db1d55e 100644 --- a/docs/apic_example/src/frame_allocator.rs +++ b/docs/apic_example/src/frame_allocator.rs @@ -16,7 +16,7 @@ impl BootInfoFrameAllocator { next: 0, } } - pub fn usable_frames(&self) -> impl Iterator { + pub fn usable_frames(&self) -> impl Iterator { let regions = self.memory_map.iter(); let usable_regions = regions.filter(|region| region.kind == Usable); @@ -49,4 +49,3 @@ fn active_level4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTab unsafe { &mut *page_table_pointer } } - diff --git a/docs/apic_example/src/idt.rs b/docs/apic_example/src/idt.rs index b935e781..d5c0f5c2 100644 --- a/docs/apic_example/src/idt.rs +++ b/docs/apic_example/src/idt.rs @@ -45,7 +45,10 @@ pub extern "x86-interrupt" fn handle_breakpoint(stack_frame: InterruptStackFrame info!("Breakpoint hit:\n{:#?}", stack_frame); } -pub extern "x86-interrupt" fn handle_double_fault(stack_frame: InterruptStackFrame, _error_code: u64) -> ! { +pub extern "x86-interrupt" fn handle_double_fault( + stack_frame: InterruptStackFrame, + _error_code: u64, +) -> ! { info!("\nDouble fault:\n{:#?}", stack_frame); loop { @@ -53,7 +56,10 @@ pub extern "x86-interrupt" fn handle_double_fault(stack_frame: InterruptStackFra } } -pub extern "x86-interrupt" fn handle_page_fault(stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode) { +pub extern "x86-interrupt" fn handle_page_fault( + stack_frame: InterruptStackFrame, + error_code: PageFaultErrorCode, +) { info!("Exception : Page Fault"); info!("Accessed address : {:?}", Cr2::read()); info!("ErrorCode : {:?}", error_code); @@ -69,5 +75,3 @@ pub extern "x86-interrupt" fn handle_keyboard(_stack_frame: InterruptStackFrame) apic::end_interrupt(); } - - diff --git a/docs/apic_example/src/main.rs b/docs/apic_example/src/main.rs index 62f04ac6..231d8162 100644 --- a/docs/apic_example/src/main.rs +++ b/docs/apic_example/src/main.rs @@ -3,15 +3,15 @@ #![no_main] extern crate alloc; -mod frame_allocator; mod apic; -mod idt; +mod frame_allocator; mod gdt; +mod idt; -use x86_64::instructions::hlt; use crate::frame_allocator::BootInfoFrameAllocator; use bootloader_api::config::Mapping; use bootloader_api::{entry_point, BootInfo}; +use x86_64::instructions::hlt; use x86_64::structures::paging::OffsetPageTable; use x86_64::VirtAddr; @@ -37,10 +37,15 @@ pub fn kernel_main(boot_info: &'static mut BootInfo) -> ! { gdt::init(); unsafe { - apic::init(rsdp.expect("Failed to get RSDP address") as usize, physical_memory_offset, &mut mapper, &mut frame_allocator); + apic::init( + rsdp.expect("Failed to get RSDP address") as usize, + physical_memory_offset, + &mut mapper, + &mut frame_allocator, + ); } loop { hlt() } -} \ No newline at end of file +}