From 314189882b96e66d1dc4a192ba154b18d3729f39 Mon Sep 17 00:00:00 2001 From: fekhesk Date: Thu, 27 Oct 2022 21:58:36 -0700 Subject: [PATCH] ITS FUCKING WORKING OH MY GOD --- Cargo.toml | 3 +- serial.log | 50 +++-------------- src/boot/mod.rs | 22 +++++--- src/internals/cpu.rs | 89 ++++++++++++++++++++++------- src/internals/errors.rs | 11 +++- src/main.rs | 114 +++++++++++++++++++++++++++++++------- src/serial/mod.rs | 1 + src/serial/simplifiers.rs | 20 +++++++ 8 files changed, 216 insertions(+), 94 deletions(-) create mode 100644 src/serial/simplifiers.rs diff --git a/Cargo.toml b/Cargo.toml index 15a9816..2885847 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,12 +11,13 @@ rlibc = "1.0" limine = { version = "0.1.9", optional = true } acpi = { version = "4.1.1", optional = true } linked_list_allocator = { version = "0.9.0", optional = true } +pc-keyboard = "0.6.1" [dependencies.lazy_static] version = "1.4.0" features = ["spin_no_std"] [features] -default = ["f_limine", "f_ll_alloc", "f_debug_verbose"] +default = ["f_limine", "f_ll_alloc"]#, "f_debug_verbose"] f_debug_verbose = [] f_limine = ["dep:limine", "dep:acpi"] f_ll_alloc = ["dep:linked_list_allocator"] \ No newline at end of file diff --git a/serial.log b/serial.log index cee038e..d191a2c 100644 --- a/serial.log +++ b/serial.log @@ -12,50 +12,14 @@ debug: IDT loaded welcome to wukkOS! (c) 2022 Real Microsoft, LLC -initialising mapper...[debug] kernel physical address: 0x19b3d000 -[debug] kernel virtual address: 0xffffffff80000000 -[OK] +initialising mapper...[OK] initialising frame allocator...[OK] initialising heap...[OK] testing heap...[OK] checking for apic compatibility...[OK] -initialising apic...[debug] Mapping physical region: 1fb7e014 - 1fb7e038 -[debug] Mapping physical region: 1fb7d0e8 - 1fb7d10c -[WARN] failed to unmap page (this is normal) -[debug] Mapping physical region: 1fb7d0e8 - 1fb7d134 -[debug] Mapping physical region: 1fb7a000 - 1fb7a024 -[WARN] failed to unmap page (this is normal) -[debug] Mapping physical region: 1fb7a000 - 1fb7a114 -[debug] Mapping physical region: 1fb7b000 - 1fb7b024 -[WARN] failed to unmap page (this is normal) -[WARN] failed to unmap page (this is normal) -[debug] Mapping physical region: 1fb79000 - 1fb79024 -[WARN] failed to unmap page (this is normal) -[debug] Mapping physical region: 1fb78000 - 1fb78024 -[WARN] failed to unmap page (this is normal) -[debug] Mapping physical region: 1fb77000 - 1fb77024 -[WARN] failed to unmap page (this is normal) -[debug] Mapping physical region: 1fb76000 - 1fb76024 -[WARN] failed to unmap page (this is normal) -[WARN] failed to unmap page (this is normal) -[WARN] failed to unmap page (this is normal) -[debug] Mapping physical region: 1fb7a000 - 1fb7a074 -[debug] Mapping physical region: 1fb79000 - 1fb79078 -[WARN] failed to unmap page (this is normal) -[WARN] failed to unmap page (this is normal) -[OK] -setting up apic interrupts...[debug] ioapicaddr: 0xfec00000 -[OK] ----KERNEL FUCKY WUKKY UWU--- -double fault! -stack frame: InterruptStackFrame { - instruction_pointer: VirtAddr( - 0xffffffff80004729, - ), - code_segment: 8, - cpu_flags: 0x282, - stack_pointer: VirtAddr( - 0xffff800019b3bd00, - ), - stack_segment: 16, -} +initialising apic...[OK] +setting up apic interrupts...[OK] + +hello world i am typing this using the legacy keyboard driver thingy in the apic from ioapic irq 1! +wukkOS moment, probably gonna swap this out for a real keyboard driver eventually but this is funny so (: +top ten wukkooOS moments \ No newline at end of file diff --git a/src/boot/mod.rs b/src/boot/mod.rs index 8028f98..7a5905d 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -1,8 +1,10 @@ use alloc::sync::Arc; +use alloc::vec::Vec; use core::marker::PhantomData; use core::ptr::NonNull; use acpi::{AcpiHandler, AcpiTables, InterruptModel, PhysicalMapping}; -use limine::{LimineBootInfoRequest, LimineKernelAddressRequest, LimineMemmapRequest, LimineTerminalRequest, LimineTerminalResponse, LimineRsdpRequest}; +use acpi::platform::interrupt::InterruptSourceOverride; +use limine::{LimineBootInfoRequest, LimineKernelAddressRequest, LimineMemmapRequest, LimineTerminalRequest, LimineTerminalResponse, LimineRsdpRequest, LimineSmpRequest}; use crate::{debug, println}; #[cfg(feature = "f_multiboot2")] @@ -17,6 +19,7 @@ pub static TERMINAL_REQUEST: LimineTerminalRequest = LimineTerminalRequest::new( pub static MEM_MAP: LimineMemmapRequest = LimineMemmapRequest::new(0); pub static RSDP_REQUEST: LimineRsdpRequest = LimineRsdpRequest::new(0); pub static KERNEL_ADDRESS: LimineKernelAddressRequest = LimineKernelAddressRequest::new(0); +pub static SMP_REQUEST: LimineSmpRequest = LimineSmpRequest::new(0); #[derive(Clone)] struct Handler; @@ -24,7 +27,7 @@ impl AcpiHandler for Handler { unsafe fn map_physical_region(&self, physical_address: usize, size: usize) -> PhysicalMapping { // todo! check if size is too big // only get lower 32 bits of physical address let physical_address = physical_address as u32; - debug!("Mapping physical region: {:x} - {:x}", physical_address, physical_address + size as u32); + debug!("mapping physical region: {:x} - {:x}", physical_address, physical_address + size as u32); let _ = read_phys_memory32(physical_address as u32) as usize; PhysicalMapping::new( physical_address as usize, @@ -40,8 +43,8 @@ impl AcpiHandler for Handler { let res = unsafe { MEM_MAPPER.lock().as_mut().unwrap().unmap(page) }; // it isn't *that* important if we don't unmap successfully at the moment, so just write a warning if we fail - if res.is_err() { - println!("[WARN] failed to unmap page (this is normal)"); + if let Err(e) = res { + debug!("(THIS IS NORMAL) failed to unmap physical region: {:?}", e); } } } @@ -68,15 +71,18 @@ impl core::fmt::Write for LimineWriter { } } -pub fn get_ioapic_addr() -> u32 { +pub fn get_ioapic_info() -> (u32, Vec) { let rsdp = RSDP_REQUEST.get_response().get().unwrap(); let rsdp_ptr = rsdp.address.get().unwrap() as *const u8; let tables = unsafe { AcpiTables::from_rsdp(Handler, rsdp_ptr as usize).unwrap() }; let platform_info = tables.platform_info().expect("no platform info"); let interrupt_model = platform_info.interrupt_model; - let ioapic_addr = match interrupt_model { - InterruptModel::Apic(apic) => apic.io_apics[0].address, + let apic = match interrupt_model { + InterruptModel::Apic(apic) => apic, _ => panic!("unsupported interrupt model"), }; - ioapic_addr + let ioapic = apic.io_apics.first().expect("no ioapic"); + let address = ioapic.address; + let overrides = apic.interrupt_source_overrides; + (address, overrides) } \ No newline at end of file diff --git a/src/internals/cpu.rs b/src/internals/cpu.rs index 40ff5d2..b7cf438 100644 --- a/src/internals/cpu.rs +++ b/src/internals/cpu.rs @@ -1,15 +1,46 @@ +use alloc::vec::Vec; use core::arch::asm; +use acpi::platform::interrupt::InterruptSourceOverride; +use lazy_static::lazy_static; +use spin::Mutex; use x2apic::ioapic::{IoApic, IrqFlags, IrqMode, RedirectionTableEntry}; -use x2apic::lapic::{LocalApicBuilder, xapic_base}; +use x2apic::lapic::{LocalApic, LocalApicBuilder, xapic_base}; use x86_64::PhysAddr; use x86_64::structures::idt::InterruptStackFrame; use x86_64::structures::paging::PhysFrame; use crate::{debug, print, println}; use crate::memory::{BootInfoFrameAllocator, read_phys_memory32, write_phys_memory32}; use crate::serial::{command, read}; +use crate::serial::simplifiers::handle_scancode; // todo! maybe abstract this into different sections for different parts of cpu func? +pub const APIC_INTERRUPT_OFFSET: usize = 32; + +pub const TIMER_IRQ: usize = 0 + APIC_INTERRUPT_OFFSET; +pub const ERROR_IRQ: usize = 1 + APIC_INTERRUPT_OFFSET; +pub const SPURIOUS_IRQ: usize = 2 + APIC_INTERRUPT_OFFSET; + +pub const IOAPIC_IRQ_OFFSET: usize = 42; +pub const FALLBACK_KEYBOARD_IRQ: usize = 1 + IOAPIC_IRQ_OFFSET; + + +lazy_static!{ + static ref LAPIC: Mutex = { + // we need to get the xapic region + let phys_addr = unsafe { xapic_base() }; + + let mut lapic = LocalApicBuilder::new() + .timer_vector(TIMER_IRQ as usize) + .spurious_vector(SPURIOUS_IRQ as usize) + .error_vector(ERROR_IRQ as usize) + .set_xapic_base(phys_addr) + .build() + .unwrap_or_else(|e| panic!("failed to build local apic: {}", e)); + Mutex::new(lapic) + }; +} + pub fn check_apic_compat() -> bool { unsafe { let mut eax: u32; @@ -23,42 +54,54 @@ pub fn check_apic_compat() -> bool { } } -pub fn enable_apic() { - // we need to get the xapic region - let phys_addr = unsafe { xapic_base() }; - - let mut lapic = LocalApicBuilder::new() - .timer_vector(0x40) - .error_vector(0x41) - .spurious_vector(0x42) - .set_xapic_base(phys_addr) - .build() - .unwrap_or_else(|e| panic!("failed to build local apic: {}", e)); - +pub fn tell_pic8259a_to_f_off() { unsafe { - lapic.enable(); + asm!("cli"); + asm!("out dx, al", in("dx") 0x20, in("al") 0x11i8); + asm!("out dx, al", in("dx") 0xA0, in("al") 0x11i8); + asm!("out dx, al", in("dx") 0x21, in("al") 0x20i8); + asm!("out dx, al", in("dx") 0xA1, in("al") 0x28i8); + asm!("out dx, al", in("dx") 0x21, in("al") 0x04i8); + asm!("out dx, al", in("dx") 0xA1, in("al") 0x02i8); + asm!("out dx, al", in("dx") 0x21, in("al") 0x01i8); + asm!("out dx, al", in("dx") 0xA1, in("al") 0x01i8); + asm!("out dx, al", in("dx") 0x21, in("al") 0x0i8); + asm!("out dx, al", in("dx") 0xA1, in("al") 0x0i8); + asm!("sti"); + } +} + +pub fn enable_apic() { + unsafe { + LAPIC.lock().enable(); } } pub extern "x86-interrupt" fn timer(stack_frame: InterruptStackFrame) { - println!("timer interrupt"); + end_of_interupt(); } pub extern "x86-interrupt" fn error(stack_frame: InterruptStackFrame) { println!("error interrupt"); + end_of_interupt(); } pub extern "x86-interrupt" fn spurious(stack_frame: InterruptStackFrame) { println!("spurious interrupt"); + end_of_interupt(); +} + +fn end_of_interupt() { + unsafe { + LAPIC.lock().end_of_interrupt(); + } } // todo! in the future this will be removed, it is only for testing basic apic functionality pub extern "x86-interrupt" fn keyboard_irq(stack_frame: InterruptStackFrame) { - debug!("keyboard interrupt"); - unsafe { asm!("iretq"); } let scancode = read(0x60); - print!("ksc: {},", scancode); + handle_scancode(scancode); // reset keyboard controller let mut a = read(0x61); @@ -66,21 +109,27 @@ pub extern "x86-interrupt" fn keyboard_irq(stack_frame: InterruptStackFrame) { command(0x61, a); a &= 0x7f; command(0x61, a); + + end_of_interupt(); } // todo! we should abstract this away -pub fn setup_ioapic(ioapicaddr: u32) { +pub fn setup_ioapic(ioapicaddr: u32, isos: Vec) { let mut ioapic = unsafe { IoApic::new(ioapicaddr as u64) }; // setup keyboard interrupt unsafe { + // FIXME! only for testing that this works, abstract ASAP! + let gsi_keyboard = isos.iter().find(|iso| iso.isa_source == 1) + .map(|iso| iso.global_system_interrupt).unwrap_or(1); // init with irq offset - ioapic.init(0x50); + ioapic.init(IOAPIC_IRQ_OFFSET as u8); let mut entry = RedirectionTableEntry::default(); entry.set_mode(IrqMode::Fixed); entry.set_flags(IrqFlags::LEVEL_TRIGGERED | IrqFlags::LOW_ACTIVE | IrqFlags::MASKED); entry.set_dest(0); + entry.set_vector(gsi_keyboard as u8 + IOAPIC_IRQ_OFFSET as u8); ioapic.set_table_entry(1, entry); ioapic.enable_irq(1); diff --git a/src/internals/errors.rs b/src/internals/errors.rs index e42b78f..c7bab66 100644 --- a/src/internals/errors.rs +++ b/src/internals/errors.rs @@ -14,10 +14,11 @@ pub extern "x86-interrupt" fn breakpoint_exception(stack_frame: InterruptStackFr println!("stack frame: {:#?}", stack_frame); } -pub extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, _error_code: u64) -> ! { +pub extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! { println!("---KERNEL FUCKY WUKKY UWU---"); println!("double fault!"); println!("stack frame: {:#?}", stack_frame); + println!("error code: {}", error_code); loop {} } @@ -28,4 +29,12 @@ pub extern "x86-interrupt" fn page_fault(stack_frame: InterruptStackFrame, error println!("error code: {:?}", error_code); println!("stack frame: {:#?}", stack_frame); loop {} +} + +pub fn unhandled(stack_frame: InterruptStackFrame, index: u8, error_code: Option) { + println!("---KERNEL FUCKY WUKKY UWU---"); + println!("unhandled interrupt: {}", index); + println!("error code: {:?}", error_code); + println!("stack frame: {:#?}", stack_frame); + loop {} } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index a6cbe81..6ea16a7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,10 +21,10 @@ use spin::Mutex; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor}; use x86_64::structures::tss::TaskStateSegment; -use x86_64::{PhysAddr, VirtAddr}; +use x86_64::{PhysAddr, set_general_handler, VirtAddr}; use x86_64::registers::segmentation::{CS, Segment, SS}; use x86_64::structures::paging::Translate; -use crate::boot::{get_ioapic_addr, KERNEL_ADDRESS}; +use crate::boot::{get_ioapic_info, KERNEL_ADDRESS}; use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*; use crate::memory::{FRAME_ALLOC, MEM_MAPPER}; use crate::serial::terminal::ST; @@ -45,14 +45,17 @@ lazy_static! { }; static ref IDT: InterruptDescriptorTable = { let mut idt = InterruptDescriptorTable::new(); - idt.breakpoint.set_handler_fn(internals::errors::breakpoint_exception); - idt.double_fault.set_handler_fn(internals::errors::double_fault); - idt.page_fault.set_handler_fn(internals::errors::page_fault); - idt[40].set_handler_fn(internals::cpu::timer); - idt[41].set_handler_fn(internals::cpu::error); - idt[42].set_handler_fn(internals::cpu::spurious); - idt[50].set_handler_fn(internals::cpu::timer); - idt[51].set_handler_fn(internals::cpu::keyboard_irq); + unsafe { + use internals::errors::unhandled; + set_general_handler!(&mut idt, unhandled); + idt.breakpoint.set_handler_fn(internals::errors::breakpoint_exception).set_stack_index(0); + idt.double_fault.set_handler_fn(internals::errors::double_fault).set_stack_index(0); + idt.page_fault.set_handler_fn(internals::errors::page_fault).set_stack_index(0); + idt[internals::cpu::TIMER_IRQ].set_handler_fn(internals::cpu::timer).set_stack_index(1); + idt[internals::cpu::ERROR_IRQ].set_handler_fn(internals::cpu::error).set_stack_index(1); + idt[internals::cpu::SPURIOUS_IRQ].set_handler_fn(internals::cpu::spurious).set_stack_index(1); + idt[internals::cpu::FALLBACK_KEYBOARD_IRQ].set_handler_fn(internals::cpu::keyboard_irq).set_stack_index(1); + } idt }; } @@ -74,7 +77,7 @@ fn panic(info: &PanicInfo) -> ! { println!("no panic payload") }; if let Some(msg) = info.message() { - println!("panic msg: {}", msg.as_str().unwrap_or("no message")) + println!("panic msg: {}", msg) } else { println!("no message"); } @@ -112,13 +115,80 @@ pub extern "C" fn kernel_main() -> ! { static mut tss: TaskStateSegment = TaskStateSegment::new(); { unsafe { - tss.interrupt_stack_table[0] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end - }; + { + tss.interrupt_stack_table[0] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[1] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[2] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[3] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[4] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[5] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.interrupt_stack_table[6] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + } + { + tss.privilege_stack_table[0] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.privilege_stack_table[1] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss.privilege_stack_table[2] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + } // set word at offset 102 to 0x68 and last two bytes of the tss to 0xffff // this is a hack to make the tss valid let tss_ptr = &tss as *const TaskStateSegment as *mut u8; @@ -208,17 +278,19 @@ pub extern "C" fn kernel_main() -> ! { panic!("apic required at the moment"); } print!("initialising apic..."); - let ioapicaddr = get_ioapic_addr(); + //internals::cpu::tell_pic8259a_to_f_off(); + let (addr, isos) = get_ioapic_info(); unsafe { internals::cpu::enable_apic() }; println!("[OK]"); print!("setting up apic interrupts..."); - debug!("ioapicaddr: {:#x}", ioapicaddr); - unsafe { internals::cpu::setup_ioapic(ioapicaddr) }; + debug!("ioapicaddr: {:#x}", addr); + unsafe { internals::cpu::setup_ioapic(addr, isos) }; println!("[OK]"); // enable interrupts //x86_64::instructions::interrupts::enable(); } loop { + x86_64::instructions::hlt(); } } \ No newline at end of file diff --git a/src/serial/mod.rs b/src/serial/mod.rs index ab39655..7d37aab 100644 --- a/src/serial/mod.rs +++ b/src/serial/mod.rs @@ -6,6 +6,7 @@ use core::ops::Deref; pub mod terminal_helpers; pub mod terminal; +pub mod simplifiers; #[derive(Clone, Copy, PartialEq)] pub enum potential_serial_ports { diff --git a/src/serial/simplifiers.rs b/src/serial/simplifiers.rs new file mode 100644 index 0000000..00b32e9 --- /dev/null +++ b/src/serial/simplifiers.rs @@ -0,0 +1,20 @@ +use lazy_static::lazy_static; +use pc_keyboard::{Keyboard, layouts, ScancodeSet1, HandleControl}; +use pc_keyboard::DecodedKey::Unicode; +use spin::Mutex; +use crate::print; + +lazy_static!{ + static ref KBD: Mutex> = Mutex::new(Keyboard::new(HandleControl::MapLettersToUnicode)); +} + +pub fn handle_scancode(scancode: u8) { + let mut kbd = KBD.lock(); + if let Ok(Some(key_event)) = kbd.add_byte(scancode) { + if let Some(key) = kbd.process_keyevent(key_event) { + if let Unicode(c) = key { + print!("{}", c); + } + } + } +} \ No newline at end of file