From 8fcc70bee1078046c404b433ae7a174198b15c48 Mon Sep 17 00:00:00 2001 From: fekhesk Date: Thu, 27 Oct 2022 14:29:40 -0700 Subject: [PATCH 1/5] make it boot on my macbook --- Makefile | 14 ++++++++++---- serial.log | 26 +++----------------------- src/boot/mod.rs | 13 +++++++------ src/lib.rs | 7 ++++--- src/memory/allocator.rs | 7 ++++--- src/memory/mod.rs | 17 +++++++++-------- 6 files changed, 37 insertions(+), 47 deletions(-) diff --git a/Makefile b/Makefile index bd74e82..5a53afc 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,10 @@ iso := build/arch/$(arch)/wukkOS.iso target ?= $(arch)-custom final := build/arch/$(arch)/wukkOS.bin efi_bios := build/arch/$(arch)/OVMF-pure-efi.fd +gcc := x86_64-elf-gcc +ld := x86_64-elf-ld +# set grub-mkrescue to either $GRUB_MKRESCUE or /usr/bin/grub-mkrescue +grub-mkrescue ?= $(shell which grub-mkrescue) linker_script := arch/$(arch)/linker.ld grub_cfg := arch/$(arch)/grub.cfg @@ -11,10 +15,12 @@ assembly_source_files := $(wildcard arch/$(arch)/*.asm) assembly_object_files := $(patsubst arch/$(arch)/%.asm, \ build/arch/$(arch)/%.o, $(assembly_source_files)) -.PHONY: all clean run iso quick_invalidate +.PHONY: all clean run iso quick_invalidate build_no_iso all: $(final) $(iso) +build_no_iso: $(final) + clean: @xargo clean @rm -rf build @@ -36,12 +42,12 @@ $(iso): $(final) $(grub_cfg) @mkdir -p isodir/boot/grub @cp $(final) isodir/boot/wukkOS.bin @cp $(grub_cfg) isodir/boot/grub/grub.cfg - @grub-mkrescue -o $(iso) isodir + @$(grub-mkrescue) -o $(iso) isodir @rm -rf isodir $(final): $(kernel) $(linker_script) $(assembly_object_files) - @ld -n -T $(linker_script) -o $(final) $(assembly_object_files) $(kernel) \ - --gc-sections + @$(ld) -n -T $(linker_script) -o $(final) $(assembly_object_files) $(kernel) \ + --gc-sections -z noexecstack $(kernel): @RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core,alloc --features "f_multiboot2" diff --git a/serial.log b/serial.log index c5b92ba..3b30c1c 100644 --- a/serial.log +++ b/serial.log @@ -1,8 +1,6 @@ -[=3h[=3h[=3h[=3hBdsDxe: loading Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Master,0x0) +[=3hBdsDxe: loading Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Master,0x0) BdsDxe: starting Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Master,0x0) -Welcome to GRUB! - -  Booting `wukkOS basic kernel' + Booting `wukkOS basic kernel' WARNING: no console will be available to OS error: no suitable video mode found. @@ -29,22 +27,4 @@ initialising apic...[debug] read_phys_memory32: addr fee000f0 not mapped [debug] mapped page: Page[4KiB](0xfee00000) [debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfee00000))) [OK] -setting up apic interrupts...[debug] write_phys_memory32: addr fec00000 not mapped -[debug] allocated frame: PhysFrame[4KiB](0x1f000) -[debug] mapped page: Page[4KiB](0xfec00000) -[debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfec00000))) -[OK] -[debug] keyboard interrupt ----KERNEL FUCKY WUKKY UWU--- -double fault! -stack frame: InterruptStackFrame { - instruction_pointer: VirtAddr( - 0x120ef1, - ), - code_segment: 8, - cpu_flags: 0x200002, - stack_pointer: VirtAddr( - 0x140c00, - ), - stack_segment: 16, -} +setting up apic interrupts...[debug] read_phys_memory32: addr 1fb7d000 not mapped diff --git a/src/boot/mod.rs b/src/boot/mod.rs index 3b2bf39..9d65346 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -6,8 +6,9 @@ use crate::{debug, KernelArgs, println}; #[cfg(feature = "f_multiboot2")] use multiboot2::{load, MemoryMapTag, BootInformation}; -use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Translate}; -use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER}; +use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, Translate}; +use x86_64::VirtAddr; +use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize}; pub struct KernelInfo { kernel_start: u64, @@ -27,14 +28,14 @@ impl AcpiHandler for Handler { let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap(); debug!("allocated frame: {:?}", frame); let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE; - let page = x86_64::structures::paging::Page::containing_address(initaladdr); + let page: Page = Page::containing_address(VirtAddr::new(physical_address as u64)); debug!("mapped page: {:?}", page); let map_to_result = unsafe { MEM_MAPPER.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) }; debug!("map_to_result: {:?}", map_to_result); if map_to_result.is_err() { panic!("Failed to map page"); } - let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) }; + let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(VirtAddr::new(physical_address as u64)) }; if let Some(addr) = addr { // physical start, virtual start, region length, mapped length, Self PhysicalMapping::new( @@ -49,7 +50,7 @@ impl AcpiHandler for Handler { fn unmap_physical_region(region: &PhysicalMapping) { // get page - let page = x86_64::structures::paging::Page::containing_address(region.start_address()); + let page: Page = Page::containing_address(VirtAddr::new(region.physical_start() as u64)); // unmap page 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 @@ -108,7 +109,7 @@ impl KernelInfo { let rsdt = rsdp.rsdt_address(); let rsdt = unsafe { acpi::AcpiTables::from_rsdt( - AcpiHandler, 0, + Handler, 0, rsdt) .expect("failed to get acpi tables") }; diff --git a/src/lib.rs b/src/lib.rs index b87a25d..caeb948 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ mod memory; mod macros; lazy_static! { + pub static ref KERN_INFO: Mutex> = Mutex::new(None); static ref GDT: Mutex = { let mut gdt = GlobalDescriptorTable::new(); Mutex::new(gdt) @@ -163,7 +164,7 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { println!(); println!("welcome to wukkOS!"); println!("(c) 2022 Real Microsoft, LLC"); - let kern_info = Mutex::new(KernelInfo::init_from_kernel_args(args)); + KERN_INFO.lock().replace(KernelInfo::init_from_kernel_args(args)); // memory stuff { @@ -171,7 +172,7 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { MEM_MAPPER.lock().replace(unsafe { memory::init(VirtAddr::new(0)) }); println!("[OK]"); print!("initialising frame allocator..."); - FRAME_ALLOC.lock().replace(unsafe { memory::BootInfoFrameAllocator::init(kern_info) }); + FRAME_ALLOC.lock().replace(unsafe { memory::BootInfoFrameAllocator::init() }); println!("[OK]"); print!("initialising heap..."); memory::allocator::init_heap(MEM_MAPPER.lock().as_mut().unwrap(), FRAME_ALLOC.lock().as_mut().unwrap()).expect("heap init failed"); @@ -208,7 +209,7 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { unsafe { internals::cpu::enable_apic() }; println!("[OK]"); print!("setting up apic interrupts..."); - unsafe { internals::cpu::setup_apic_interrupts(kern_info.lock().acpi_get_ioapic_addr()) }; + unsafe { internals::cpu::setup_apic_interrupts(KERN_INFO.lock().as_ref().unwrap().acpi_get_ioapic_addr()) }; println!("[OK]"); // enable interrupts x86_64::instructions::interrupts::enable(); diff --git a/src/memory/allocator.rs b/src/memory/allocator.rs index 229b2a3..7430d06 100644 --- a/src/memory/allocator.rs +++ b/src/memory/allocator.rs @@ -4,6 +4,7 @@ use core::ptr::NonNull; use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB}; use x86_64::structures::paging::mapper::MapToError; use x86_64::VirtAddr; +use crate::memory::PageSize; use super::Locked; pub const HEAP_START: u64 = 0x_4444_4444_0000; @@ -99,9 +100,9 @@ fn list_index(layout: &core::alloc::Layout) -> Option { } pub fn init_heap( - mapper: &mut impl Mapper, - frame_allocator: &mut impl FrameAllocator, -) -> Result<(), MapToError> { + mapper: &mut impl Mapper, + frame_allocator: &mut impl FrameAllocator, +) -> Result<(), MapToError> { let page_range = { let heap_start = VirtAddr::new(HEAP_START as u64); let heap_end = heap_start + HEAP_SIZE - 1u64; diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 1755dec..7bead8e 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -7,10 +7,12 @@ use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, PageTa use x86_64::{PhysAddr, VirtAddr}; lazy_static!{ - pub static ref MEM_MAPPER: Mutex> = Mutex::new(None); + pub static ref MEM_MAPPER: Mutex>> = Mutex::new(None); pub static ref FRAME_ALLOC: Mutex> = Mutex::new(None); } +pub type PageSize = Size4KiB; + pub struct Locked { inner: spin::Mutex, } @@ -48,18 +50,16 @@ unsafe fn active_level_4_table(phys_mem_offset: VirtAddr) -> &'static mut PageTa use multiboot2::{MemoryMapTag, BootInformation}; use spin::Mutex; use crate::boot::KernelInfo; -use crate::{debug, print, println}; +use crate::{debug, KERN_INFO, print, println}; pub struct BootInfoFrameAllocator { - kern_info: Mutex, next: usize, } impl BootInfoFrameAllocator { #[cfg(feature = "f_multiboot2")] - pub unsafe fn init(kern_info: Mutex) -> Self { + pub unsafe fn init() -> Self { Self { - kern_info, next: 0, } } @@ -68,8 +68,9 @@ impl BootInfoFrameAllocator { unsafe impl FrameAllocator for BootInfoFrameAllocator { fn allocate_frame(&mut self) -> Option { #[cfg(feature = "f_multiboot2")] { - let mut kern_lock = self.kern_info.lock(); - let mut usable_frames = kern_lock + let mut kern_lock = KERN_INFO.lock(); + let mut kern_info = kern_lock.as_mut().unwrap(); + let mut usable_frames = kern_info .memory_areas(); let mut usable_frames = usable_frames .map(|area| { @@ -85,7 +86,7 @@ unsafe impl FrameAllocator for BootInfoFrameAllocator { self.next += 1; // ensure unlock - unsafe { self.kern_info.force_unlock() }; + unsafe { KERN_INFO.force_unlock() }; frame } From 600ba7163ac8f040a79f99540f0d79403257079e Mon Sep 17 00:00:00 2001 From: fekhesk Date: Thu, 27 Oct 2022 15:40:21 -0700 Subject: [PATCH 2/5] redoing apic stuff --- .idea/misc.xml | 5 ++ Cargo.toml | 1 + serial.log | 43 +++++++++++-- src/boot/mod.rs | 22 +++---- src/internals/cpu.rs | 149 ++++++++++++++----------------------------- src/lib.rs | 8 +-- 6 files changed, 107 insertions(+), 121 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 6afde3a..85603ba 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,6 +5,11 @@ diff --git a/Cargo.toml b/Cargo.toml index f7dd3b1..a3e9061 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ crate-type = ["staticlib"] [dependencies] spin = "0.9.1" x86_64 = "0.14.10" +x86 = "0.52.0" rlibc = "1.0" multiboot2 = { version = "0.14.0", optional = true } acpi = { version = "4.1.1", optional = true } diff --git a/serial.log b/serial.log index 3b30c1c..38a858c 100644 --- a/serial.log +++ b/serial.log @@ -21,10 +21,43 @@ initialising frame allocator...[OK] initialising heap...[OK] testing heap...[OK] checking for apic compatibility...[OK] -disabling PIC...[OK] -initialising apic...[debug] read_phys_memory32: addr fee000f0 not mapped +initialising apic...[debug] read_phys_memory32: addr fffe0000 not mapped [debug] allocated frame: PhysFrame[4KiB](0x1c000) -[debug] mapped page: Page[4KiB](0xfee00000) -[debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfee00000))) +[debug] mapped page: Page[4KiB](0xfffe0000) +[debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfffe0000))) +[debug] xapic id: 0 +[debug] xapic version: 0 +[OK] +setting up apic interrupts...[debug] acpi tag: RsdpV1Tag { typ: AcpiV1, size: 28, signature: [82, 83, 68, 32, 80, 84, 82, 32], checksum: 172, oem_id: [66, 79, 67, 72, 83, 32], revision: 0, rsdt_address: 532140032 } +[debug] rsdt: 532140032 +[debug] read_phys_memory32: addr 1fb7d000 not mapped +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb7d000 not mapped +[debug] read_phys_memory32: addr 1fb7a000 not mapped +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb7a000 not mapped +[debug] read_phys_memory32: addr 1fb7b000 not mapped +[WARN] failed to unmap page +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb79000 not mapped +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb78000 not mapped +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb77000 not mapped +[WARN] failed to unmap page +[debug] read_phys_memory32: addr 1fb76000 not mapped +[WARN] failed to unmap page +[WARN] failed to unmap page +[debug] loaded rsdt +[debug] read_phys_memory32: addr 1fb7a000 not mapped +[debug] read_phys_memory32: addr 1fb79000 not mapped +[WARN] failed to unmap page +[WARN] failed to unmap page +[debug] ioapic addr: fec00000 +[debug] ioapicaddr: 0xfec00000 +[debug] read_phys_memory32: addr fec00000 not mapped +[debug] allocated frame: PhysFrame[4KiB](0x1f000) +[debug] mapped page: Page[4KiB](0xfec00000) +[debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfec00000))) +[debug] ioapic supported interrupts: 1 [OK] -setting up apic interrupts...[debug] read_phys_memory32: addr 1fb7d000 not mapped diff --git a/src/boot/mod.rs b/src/boot/mod.rs index 9d65346..2ee2989 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -8,7 +8,7 @@ use crate::{debug, KernelArgs, println}; use multiboot2::{load, MemoryMapTag, BootInformation}; use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, Translate}; use x86_64::VirtAddr; -use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize}; +use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize, read_phys_memory32}; pub struct KernelInfo { kernel_start: u64, @@ -24,19 +24,13 @@ impl AcpiHandler for Handler { unsafe fn map_physical_region(&self, physical_address: usize, size: usize) -> PhysicalMapping { // todo! check if size is too big debug!("read_phys_memory32: addr {:x} not mapped", physical_address); - // map the page - let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap(); - debug!("allocated frame: {:?}", frame); - let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE; - let page: Page = Page::containing_address(VirtAddr::new(physical_address as u64)); - debug!("mapped page: {:?}", page); - let map_to_result = unsafe { MEM_MAPPER.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) }; - debug!("map_to_result: {:?}", map_to_result); - if map_to_result.is_err() { - panic!("Failed to map page"); + let mut i = 0; + while i < size { + let _ = read_phys_memory32(physical_address as u32 + i as u32); + i += 4; } let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(VirtAddr::new(physical_address as u64)) }; - if let Some(addr) = addr { + if let Some(addr) = addr.clone() { // physical start, virtual start, region length, mapped length, Self PhysicalMapping::new( physical_address, @@ -104,21 +98,25 @@ impl KernelInfo { #[cfg(feature = "f_multiboot2")] { let acpi_tag = self.boot_info.rsdp_v1_tag().expect("no acpi tag"); + debug!("acpi tag: {:?}", acpi_tag); let rsdp = acpi_tag; let rsdp = unsafe { &*rsdp }; let rsdt = rsdp.rsdt_address(); + debug!("rsdt: {:?}", rsdt); let rsdt = unsafe { acpi::AcpiTables::from_rsdt( Handler, 0, rsdt) .expect("failed to get acpi tables") }; + debug!("loaded rsdt"); let platform_info = rsdt.platform_info().expect("failed to get platform info"); let interrupt_model = platform_info.interrupt_model; if let InterruptModel::Apic(apic) = interrupt_model { let ioapics = apic.io_apics; let ioapic = ioapics.first().expect("no ioapics"); let ioapic_addr = ioapic.address; + debug!("ioapic addr: {:x}", ioapic_addr); ioapic_addr } else { panic!("no ioapic"); diff --git a/src/internals/cpu.rs b/src/internals/cpu.rs index 5ae297c..5d42b2d 100644 --- a/src/internals/cpu.rs +++ b/src/internals/cpu.rs @@ -1,13 +1,23 @@ use core::arch::asm; -use x86_64::{PhysAddr, VirtAddr}; +use x86::apic::{xapic::XAPIC, ioapic::IoApic, ApicControl}; +use x86_64::PhysAddr; use x86_64::structures::idt::InterruptStackFrame; -use x86_64::structures::paging::OffsetPageTable; -use crate::{debug, print, println}; +use x86_64::structures::paging::PhysFrame; +use crate::{debug, KERN_INFO, print, println}; use crate::memory::{BootInfoFrameAllocator, read_phys_memory32, write_phys_memory32}; use crate::serial::{command, read}; // todo! maybe abstract this into different sections for different parts of cpu func? +pub struct WAPICManager { + pub xapic: XAPIC, + pub id: u32, +} + +pub struct WIOAPICManager { + pub ioapic: IoApic, +} + pub fn check_apic_compat() -> bool { unsafe { let mut eax: u32; @@ -21,101 +31,31 @@ pub fn check_apic_compat() -> bool { } } -pub fn set_apic_base(apic: usize) { - const IA32_APIC_BASE_MSR_ENABLE: u32 = 0x800; - let mut edx = 0u32; - let mut eax = (apic & 0xfffff0000) as u32 | IA32_APIC_BASE_MSR_ENABLE; - unsafe { - asm!("wrmsr", - in("ecx") 0x1b, - in("eax") eax, - in("edx") edx, - ); - } -} +pub fn enable_apic() -> WAPICManager { + // we need to get the xapic region + let mut XAPIC_REGION: &'static mut [u32] = unsafe { + // region should be FFFE0000H to FFFE0FFFH + let region_start = 0xFFFE_0000u32; + let region_end = 0xFFFE_0FFFu32; + let region_size = region_end - region_start; + let region_size = region_size as usize; + let region_start = region_start as *mut u32; + // read to make sure it gets mapped + let _ = read_phys_memory32(region_start as u32); + let _ = read_phys_memory32(region_end as u32); + core::slice::from_raw_parts_mut(region_start, region_size) + }; + let mut xapic = unsafe { XAPIC::new(XAPIC_REGION) }; + xapic.attach(); -pub fn get_apic_base() -> usize { - let mut edx = 0u32; - let mut eax = 0u32; - unsafe { - asm!("rdmsr", - in("ecx") 0x1b, - lateout("eax") eax, - lateout("edx") edx, - ); - } - ((edx as usize) << 32) | (eax as usize) -} - -pub fn enable_apic() { - // PIC should be disabled by now - // now enable local apic - // 1. set bit 8 of spurious interrupt vector register - let sivr_addr = 0xfee000f0; - let sivr = read_phys_memory32(sivr_addr); - write_phys_memory32(sivr_addr, sivr | (1 << 8)); -} - -pub fn apic_read_io(ioapicaddr: u32, reg: u32) -> u32 { - write_phys_memory32(ioapicaddr as u32, reg); - read_phys_memory32(ioapicaddr as u32 + 0x10) -} - -pub fn apic_write_io(ioapicaddr: u32, reg: u32, val: u32) { - write_phys_memory32(ioapicaddr as u32, reg); - write_phys_memory32(ioapicaddr as u32 + 0x10, val); -} - -pub fn disable_pic() { - command(0x20, 0x11); - command(0xa0, 0x11); - - command(0x21, 0xe0); - command(0xa1, 0xe8); - - command(0x21, 0x04); - command(0xa1, 0x02); - - command(0x21, 0x01); - command(0xa1, 0x01); - - command(0x21, 0xff); - command(0xa1, 0xff); -} - -pub fn ioapic_set_irq(ioapicaddr: u32, irq: u8, apic_id: u64, vector:u8) { - let lo_index: u32 = (0x10 + irq*2 ) as u32; - let hi_index: u32 = (0x10 + irq*2 + 1) as u32; - - let mut high = apic_read_io(ioapicaddr, hi_index); - // set apic id - high &= !(0xff000000); - high |= (apic_id as u32) << 24; - apic_write_io(ioapicaddr, hi_index, high); - - let mut low = apic_read_io( ioapicaddr, lo_index); - - // unmask - low &= !(1 << 16); - // set to physical delivery - low &= !(1 << 11); - // set to fixed delivery - low &= !(0x700); - // set vector - low &= !(0xff); - low |= vector as u32; - - apic_write_io(ioapicaddr, lo_index, low); -} - -pub fn apic_eoi() { - unsafe { - asm!("mov eax, 0", - "mov ecx, 0xb0", - "wrmsr", - in("ecx") 0x80b, - in("eax") 0, - ); + // get xapic id to ensure it's working + let id = xapic.id(); + debug!("xapic id: {}", id); + debug!("xapic version: {}", xapic.version()); + + WAPICManager { + xapic, + id, } } @@ -136,7 +76,16 @@ pub extern "x86-interrupt" fn keyboard_irq(stack_frame: InterruptStackFrame) { } // todo! we should abstract this away -pub fn setup_apic_interrupts(ioapicaddr: u32) { - // set keyboard irq to interrupt 40 - ioapic_set_irq(ioapicaddr, 1, 0, 40); +pub fn setup_ioapic(ioapicaddr: u32) -> WIOAPICManager { + let mut ioapic = unsafe { IoApic::new(ioapicaddr as usize) }; + let _ = read_phys_memory32(ioapicaddr); + // assert that supported interrupts is greater than 1 + debug!("ioapic supported interrupts: {}", ioapic.supported_interrupts()); + // setup keyboard irq (interrupt 0x40) + ioapic.enable(1, 0x40); + + // return + WIOAPICManager { + ioapic, + } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index caeb948..3a813e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ #![feature(asm_const)] #![feature(const_mut_refs)] #![feature(alloc_error_handler)] +#![feature(const_slice_from_raw_parts_mut)] #![no_std] #![no_main] @@ -202,14 +203,13 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { println!("[FAIL]"); panic!("apic required at the moment"); } - print!("disabling PIC..."); - unsafe { internals::cpu::disable_pic() }; - println!("[OK]"); print!("initialising apic..."); unsafe { internals::cpu::enable_apic() }; println!("[OK]"); print!("setting up apic interrupts..."); - unsafe { internals::cpu::setup_apic_interrupts(KERN_INFO.lock().as_ref().unwrap().acpi_get_ioapic_addr()) }; + let ioapicaddr = KERN_INFO.lock().as_ref().unwrap().acpi_get_ioapic_addr(); + debug!("ioapicaddr: {:#x}", ioapicaddr); + unsafe { internals::cpu::setup_ioapic(ioapicaddr) }; println!("[OK]"); // enable interrupts x86_64::instructions::interrupts::enable(); From 8af40d04143b1dacd3a0eccede55ead6a8b08fc4 Mon Sep 17 00:00:00 2001 From: fekhesk Date: Thu, 27 Oct 2022 18:06:33 -0700 Subject: [PATCH 3/5] some of the stuff now works with limine --- .gitignore | 1 + Cargo.toml | 9 +- Makefile | 32 +++--- arch/x86_64/boot.asm | 161 ------------------------------- arch/x86_64/grub.cfg | 7 -- arch/x86_64/limine.cfg | 5 + arch/x86_64/linker.ld | 58 +++++++---- arch/x86_64/longmodestart.asm | 17 ---- arch/x86_64/multiboot_header.asm | 16 --- byob/.gitignore | 5 + byob/README.md | 9 ++ serial.log | 49 +--------- src/boot/mod.rs | 91 ++++------------- src/internals/cpu.rs | 2 +- src/macros/mod.rs | 10 ++ src/{lib.rs => main.rs} | 24 +++-- src/memory/mod.rs | 23 ++--- x86_64-custom.json | 11 ++- 18 files changed, 140 insertions(+), 390 deletions(-) delete mode 100644 arch/x86_64/boot.asm delete mode 100644 arch/x86_64/grub.cfg create mode 100644 arch/x86_64/limine.cfg delete mode 100644 arch/x86_64/longmodestart.asm delete mode 100644 arch/x86_64/multiboot_header.asm create mode 100644 byob/.gitignore create mode 100644 byob/README.md rename src/{lib.rs => main.rs} (93%) diff --git a/.gitignore b/.gitignore index 17bb528..bb571f8 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ Cargo.lock /boot.o /build/ /OVMF-pure-efi.fd +/isodir \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index a3e9061..06f8013 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,15 +3,12 @@ name = "wukkOS" version = "0.1.0" edition = "2021" -[lib] -crate-type = ["staticlib"] - [dependencies] spin = "0.9.1" x86_64 = "0.14.10" x86 = "0.52.0" rlibc = "1.0" -multiboot2 = { version = "0.14.0", optional = true } +limine = { version = "0.1.9", optional = true } acpi = { version = "4.1.1", optional = true } linked_list_allocator = { version = "0.9.0", optional = true } [dependencies.lazy_static] @@ -19,7 +16,7 @@ version = "1.4.0" features = ["spin_no_std"] [features] -default = ["f_multiboot2", "f_ll_alloc", "f_debug_verbose"] +default = ["f_limine", "f_ll_alloc", "f_debug_verbose"] f_debug_verbose = [] -f_multiboot2 = ["dep:multiboot2", "dep:acpi"] +f_limine = ["dep:limine", "dep:acpi"] f_ll_alloc = ["dep:linked_list_allocator"] \ No newline at end of file diff --git a/Makefile b/Makefile index 5a53afc..6e17c0e 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,14 @@ arch ?= x86_64 -kernel := target/$(arch)-custom/debug/libwukkOS.a +kernel := target/$(arch)-custom/debug/wukkOS iso := build/arch/$(arch)/wukkOS.iso target ?= $(arch)-custom final := build/arch/$(arch)/wukkOS.bin efi_bios := build/arch/$(arch)/OVMF-pure-efi.fd -gcc := x86_64-elf-gcc -ld := x86_64-elf-ld -# set grub-mkrescue to either $GRUB_MKRESCUE or /usr/bin/grub-mkrescue -grub-mkrescue ?= $(shell which grub-mkrescue) +gcc ?= gcc +ld ?= ld linker_script := arch/$(arch)/linker.ld -grub_cfg := arch/$(arch)/grub.cfg +bootloader_cfg := arch/$(arch)/limine.cfg assembly_source_files := $(wildcard arch/$(arch)/*.asm) assembly_object_files := $(patsubst arch/$(arch)/%.asm, \ build/arch/$(arch)/%.o, $(assembly_source_files)) @@ -26,7 +24,7 @@ clean: @rm -rf build run: $(final) $(iso) - @qemu-system-$(arch) -bios $(efi_bios) -cdrom $(iso) \ + @qemu-system-$(arch) -bios $(efi_bios) -cdrom $(iso) -d int -D qemulog.log \ -chardev stdio,id=char0,mux=on,logfile=serial.log,signal=off \ -serial chardev:char0 -mon chardev=char0 -m 512M @@ -39,18 +37,26 @@ iso: $(iso) $(iso): $(final) $(grub_cfg) @cp OVMF-pure-efi.fd build/arch/$(arch)/OVMF-pure-efi.fd # TODO! remove this, it's only for testing and i don't think we can distribute it - @mkdir -p isodir/boot/grub + @mkdir -p isodir/boot @cp $(final) isodir/boot/wukkOS.bin - @cp $(grub_cfg) isodir/boot/grub/grub.cfg - @$(grub-mkrescue) -o $(iso) isodir + @cp $(bootloader_cfg) isodir/boot/limine.cfg + @cp byob/limine.sys byob/limine-cd.bin byob/limine-cd-efi.bin isodir/boot/ + @xorriso -as mkisofs -b boot/limine-cd.bin \ + -no-emul-boot -boot-load-size 4 -boot-info-table \ + --efi-boot boot/limine-cd-efi.bin \ + -efi-boot-part --efi-boot-image --protective-msdos-label \ + isodir -o $(iso) @rm -rf isodir + @byob/limine-deploy $(iso) $(final): $(kernel) $(linker_script) $(assembly_object_files) - @$(ld) -n -T $(linker_script) -o $(final) $(assembly_object_files) $(kernel) \ - --gc-sections -z noexecstack + @mkdir -p $(shell dirname $@) + @cp $(kernel) $(final) + #@$(ld) -n -T $(linker_script) -o $(final) $(kernel) \ + # --gc-sections $(kernel): - @RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core,alloc --features "f_multiboot2" + @RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core,alloc --features "f_limine" build/arch/$(arch)/%.o: arch/$(arch)/%.asm @mkdir -p $(shell dirname $@) diff --git a/arch/x86_64/boot.asm b/arch/x86_64/boot.asm deleted file mode 100644 index bb20481..0000000 --- a/arch/x86_64/boot.asm +++ /dev/null @@ -1,161 +0,0 @@ -global start -extern long_mode_start - -section .text -bits 32 - -;; basic boilerplate stuff from blog_os, expect to be changed - -start: - mov esp, stack_top - mov edi, ebx - - call check_multiboot - call check_cpuid - call check_long_mode - - call setup_page_tables - call enable_paging - - lgdt [gdt64.pointer] - - jmp gdt64.code:long_mode_start - - hlt -check_multiboot: - cmp eax, 0x36d76289 - jne .no_multiboot - ret -.no_multiboot: - mov al, "0" - jmp error -check_cpuid: - ; Check if CPUID is supported by attempting to flip the ID bit (bit 21) - ; in the FLAGS register. If we can flip it, CPUID is available. - - ; Copy FLAGS in to EAX via stack - pushfd - pop eax - - ; Copy to ECX as well for comparing later on - mov ecx, eax - - ; Flip the ID bit - xor eax, 1 << 21 - - ; Copy EAX to FLAGS via the stack - push eax - popfd - - ; Copy FLAGS back to EAX (with the flipped bit if CPUID is supported) - pushfd - pop eax - - ; Restore FLAGS from the old version stored in ECX (i.e. flipping the - ; ID bit back if it was ever flipped). - push ecx - popfd - - ; Compare EAX and ECX. If they are equal then that means the bit - ; wasn't flipped, and CPUID isn't supported. - cmp eax, ecx - je .no_cpuid - ret -.no_cpuid: - mov al, "1" - jmp error -check_long_mode: - ; test if extended processor info in available - mov eax, 0x80000000 ; implicit argument for cpuid - cpuid ; get highest supported argument - cmp eax, 0x80000001 ; it needs to be at least 0x80000001 - jb .no_long_mode ; if it's less, the CPU is too old for long mode - - ; use extended info to test if long mode is available - mov eax, 0x80000001 ; argument for extended processor info - cpuid ; returns various feature bits in ecx and edx - test edx, 1 << 29 ; test if the LM-bit is set in the D-register - jz .no_long_mode ; If it's not set, there is no long mode - ret -.no_long_mode: - mov al, "2" - jmp error -setup_page_tables: - ; map first P4 entry to P3 table - mov eax, p3_table - or eax, 0b11 ; present + writable - mov [p4_table], eax - - ; map first P3 entry to P2 table - mov eax, p2_table - or eax, 0b11 ; present + writable - mov [p3_table], eax - - ; map each P2 entry to a huge 2MiB page - mov ecx, 0 ; counter variable - -.map_p2_table: - ; map ecx-th P2 entry to a huge page that starts at address 2MiB*ecx - mov eax, 0x200000 ; 2MiB - mul ecx ; start address of ecx-th page - or eax, 0b10000011 ; present + writable + huge - mov [p2_table + ecx * 8], eax ; map ecx-th entry - - inc ecx ; increase counter - cmp ecx, 512 ; if counter == 512, the whole P2 table is mapped - jne .map_p2_table ; else map the next entry - - ret - -enable_paging: - ; load P4 to cr3 register (cpu uses this to access the P4 table) - mov eax, p4_table - mov cr3, eax - - ; enable PAE-flag in cr4 (Physical Address Extension) - mov eax, cr4 - or eax, 1 << 5 - mov cr4, eax - - ; set the long mode bit in the EFER MSR (model specific register) - mov ecx, 0xC0000080 - rdmsr - or eax, 1 << 8 - wrmsr - - ; enable paging in the cr0 register - mov eax, cr0 - or eax, 1 << 31 - mov cr0, eax - - ret - -; Prints `ERR: ` and the given error code to screen and hangs. -; parameter: error code (in ascii) in al -error: - mov dword [0xb8000], 0x4f524f45 - mov dword [0xb8004], 0x4f3a4f52 - mov dword [0xb8008], 0x4f204f20 - mov byte [0xb800a], al - hlt - -section .bss -align 4096 -p4_table: - resb 4096 -p3_table: - resb 4096 -p2_table: - resb 4096 -stack_bottom: - resb 4096 * 4 ;; 16 KiB -stack_top: - -section .rodata -gdt64: - dq 0 ; zero entry -.code: equ $ - gdt64 ; new - dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment -.pointer: - dw $ - gdt64 - 1 - dq gdt64 \ No newline at end of file diff --git a/arch/x86_64/grub.cfg b/arch/x86_64/grub.cfg deleted file mode 100644 index a1b062b..0000000 --- a/arch/x86_64/grub.cfg +++ /dev/null @@ -1,7 +0,0 @@ -set timeout=0 -set default=0 - -menuentry "wukkOS basic kernel" { - multiboot2 /boot/wukkOS.bin - boot -} \ No newline at end of file diff --git a/arch/x86_64/limine.cfg b/arch/x86_64/limine.cfg new file mode 100644 index 0000000..2af48f4 --- /dev/null +++ b/arch/x86_64/limine.cfg @@ -0,0 +1,5 @@ +TIMEOUT=0 + +:wukkOS + PROTOCOL=limine + KERNEL_PATH=boot:///boot/wukkOS.bin \ No newline at end of file diff --git a/arch/x86_64/linker.ld b/arch/x86_64/linker.ld index 72e7d29..459344d 100644 --- a/arch/x86_64/linker.ld +++ b/arch/x86_64/linker.ld @@ -1,26 +1,48 @@ -ENTRY(start) +/* Tell the linker that we want an x86_64 ELF64 output file */ +OUTPUT_FORMAT(elf64-x86-64) +OUTPUT_ARCH(i386:x86-64) -SECTIONS { - . = 1M; +/* We want the symbol `x86_64_barebones_main` to be our entry point */ +ENTRY(kernel_main) - .boot : - { - /* ensure that the multiboot header is at the beginning */ - KEEP(*(.multiboot_header)) - } +/* Define the program headers we want so the bootloader gives us the right */ +/* MMU permissions */ +PHDRS +{ + null PT_NULL FLAGS(0) ; /* Null segment */ + text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */ + rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */ + data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */ +} - .text : - { +SECTIONS +{ + /* We wanna be placed in the topmost 2GiB of the address space, for optimisations */ + /* and because that is what the Limine spec mandates. */ + /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ + /* that is the beginning of the region. */ + . = 0xffffffff80000000; + + .text : { *(.text .text.*) - } + } :text - .rodata : - { + /* Move to the next memory page for .rodata */ + . += CONSTANT(MAXPAGESIZE); + + .rodata : { *(.rodata .rodata.*) - } + } :rodata - .data.rel.ro : - { - *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*) - } + /* Move to the next memory page for .data */ + . += CONSTANT(MAXPAGESIZE); + + .data : { + *(.data .data.*) + } :data + + .bss : { + *(COMMON) + *(.bss .bss.*) + } :data } \ No newline at end of file diff --git a/arch/x86_64/longmodestart.asm b/arch/x86_64/longmodestart.asm deleted file mode 100644 index 9c2dc04..0000000 --- a/arch/x86_64/longmodestart.asm +++ /dev/null @@ -1,17 +0,0 @@ -global long_mode_start -extern kernel_main - -section .text -bits 64 -long_mode_start: - mov ax, 0x00 - mov ss, ax - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - extern kernel_main - call kernel_main - - hlt \ No newline at end of file diff --git a/arch/x86_64/multiboot_header.asm b/arch/x86_64/multiboot_header.asm deleted file mode 100644 index e855dfe..0000000 --- a/arch/x86_64/multiboot_header.asm +++ /dev/null @@ -1,16 +0,0 @@ -section .multiboot_header -header_start: - align 4 - ; multiboot 2 magic - dd 0xe85250d6 - dd 0x00000000 - dd header_end - header_start - ; checksum - dd 0x100000000 - (0xe85250d6 + 0x00000000 + (header_end - header_start)) - - ; required end tag - dw 0 ; type - dw 0 ; flags - dd 8 ; size - -header_end: \ No newline at end of file diff --git a/byob/.gitignore b/byob/.gitignore new file mode 100644 index 0000000..c219351 --- /dev/null +++ b/byob/.gitignore @@ -0,0 +1,5 @@ +# limine binaries +limine.sys +limine-cd.bin +limine-cd-efi.bin +limine-deploy \ No newline at end of file diff --git a/byob/README.md b/byob/README.md new file mode 100644 index 0000000..5d33010 --- /dev/null +++ b/byob/README.md @@ -0,0 +1,9 @@ +# bring your own bootloader! +wukkOS is currently reliant on limine, and it is also currently required for you to +provide your own binaries for it. those binaries should be placed in this directory, +and the Makefile will copy them into the iso. +currently the binaries are: +- limine.sys +- limine-cd.bin +- limine-cd-efi.bin +- limine-deploy (should be for your current system) \ No newline at end of file diff --git a/serial.log b/serial.log index 38a858c..9129c8d 100644 --- a/serial.log +++ b/serial.log @@ -1,10 +1,6 @@ -[=3hBdsDxe: loading Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Master,0x0) +[=3h[=3h[=3h[=3hBdsDxe: loading Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Master,0x0) BdsDxe: starting Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Master,0x0) - Booting `wukkOS basic kernel' - - WARNING: no console will be available to OS - error: no suitable video mode found. - using serial port 0 as console +using serial port 0 as console debug: setup GDT debug: GDT loaded debug: CS set @@ -20,44 +16,3 @@ initialising mapper...[OK] initialising frame allocator...[OK] initialising heap...[OK] testing heap...[OK] -checking for apic compatibility...[OK] -initialising apic...[debug] read_phys_memory32: addr fffe0000 not mapped -[debug] allocated frame: PhysFrame[4KiB](0x1c000) -[debug] mapped page: Page[4KiB](0xfffe0000) -[debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfffe0000))) -[debug] xapic id: 0 -[debug] xapic version: 0 -[OK] -setting up apic interrupts...[debug] acpi tag: RsdpV1Tag { typ: AcpiV1, size: 28, signature: [82, 83, 68, 32, 80, 84, 82, 32], checksum: 172, oem_id: [66, 79, 67, 72, 83, 32], revision: 0, rsdt_address: 532140032 } -[debug] rsdt: 532140032 -[debug] read_phys_memory32: addr 1fb7d000 not mapped -[WARN] failed to unmap page -[debug] read_phys_memory32: addr 1fb7d000 not mapped -[debug] read_phys_memory32: addr 1fb7a000 not mapped -[WARN] failed to unmap page -[debug] read_phys_memory32: addr 1fb7a000 not mapped -[debug] read_phys_memory32: addr 1fb7b000 not mapped -[WARN] failed to unmap page -[WARN] failed to unmap page -[debug] read_phys_memory32: addr 1fb79000 not mapped -[WARN] failed to unmap page -[debug] read_phys_memory32: addr 1fb78000 not mapped -[WARN] failed to unmap page -[debug] read_phys_memory32: addr 1fb77000 not mapped -[WARN] failed to unmap page -[debug] read_phys_memory32: addr 1fb76000 not mapped -[WARN] failed to unmap page -[WARN] failed to unmap page -[debug] loaded rsdt -[debug] read_phys_memory32: addr 1fb7a000 not mapped -[debug] read_phys_memory32: addr 1fb79000 not mapped -[WARN] failed to unmap page -[WARN] failed to unmap page -[debug] ioapic addr: fec00000 -[debug] ioapicaddr: 0xfec00000 -[debug] read_phys_memory32: addr fec00000 not mapped -[debug] allocated frame: PhysFrame[4KiB](0x1f000) -[debug] mapped page: Page[4KiB](0xfec00000) -[debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfec00000))) -[debug] ioapic supported interrupts: 1 -[OK] diff --git a/src/boot/mod.rs b/src/boot/mod.rs index 2ee2989..ed79a07 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -2,21 +2,15 @@ use alloc::sync::Arc; use core::marker::PhantomData; use core::ptr::NonNull; use acpi::{AcpiHandler, InterruptModel, PhysicalMapping}; -use crate::{debug, KernelArgs, println}; +use limine::LimineTerminalResponse; +use crate::{debug, println, TERMINAL_REQUEST}; #[cfg(feature = "f_multiboot2")] use multiboot2::{load, MemoryMapTag, BootInformation}; use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, Translate}; use x86_64::VirtAddr; use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize, read_phys_memory32}; - -pub struct KernelInfo { - kernel_start: u64, - kernel_end: u64, - safe_mem_start: u64, - #[cfg(feature = "f_multiboot2")] - boot_info: BootInformation, -} +use crate::serial::terminal::ST; #[derive(Clone)] struct Handler; @@ -54,73 +48,24 @@ impl AcpiHandler for Handler { } } -impl KernelInfo { - pub fn init_from_kernel_args(args: KernelArgs) -> Self { - #[cfg(feature = "f_multiboot2")] - { - let boot_info = unsafe { load(args.multiboot_information_address) }.expect("failed to load multiboot2 information"); - let elf_sections = boot_info.elf_sections_tag().expect("no elf sections tag"); - let kernel_start = elf_sections.sections().map(|s| s.start_address()).min().unwrap(); - let kernel_end = elf_sections.sections().map(|s| s.end_address()).max().unwrap(); - // get end of multiboot for safe memory - let safe_mem_start = boot_info.start_address() + boot_info.total_size(); - let kernel_info = KernelInfo { - kernel_start, - kernel_end, - safe_mem_start: safe_mem_start as u64, - boot_info, - }; - kernel_info - } - } +pub struct LimineWriter; - #[cfg(feature = "f_multiboot2")] - pub fn get_memory_tag(&self) -> &MemoryMapTag { - let mm_tag = self.boot_info.memory_map_tag().expect("no memory map tag").clone(); - mm_tag - } - - #[cfg(feature = "f_multiboot2")] - pub fn memory_areas(&self) -> impl Iterator { - let mm_tag = self.boot_info.memory_map_tag().expect("ERR NO MEM MAP TAG!"); - mm_tag.all_memory_areas() - } - - pub fn is_safe_memory(&self, addr: u64) -> bool { - addr >= self.safe_mem_start && addr >= self.kernel_end - } - - pub fn safe_memory_start(&self) -> u64 { - self.safe_mem_start - } - - pub fn acpi_get_ioapic_addr(&self) -> u32 { - #[cfg(feature = "f_multiboot2")] - { - let acpi_tag = self.boot_info.rsdp_v1_tag().expect("no acpi tag"); - debug!("acpi tag: {:?}", acpi_tag); - let rsdp = acpi_tag; - let rsdp = unsafe { &*rsdp }; - let rsdt = rsdp.rsdt_address(); - debug!("rsdt: {:?}", rsdt); - let rsdt = unsafe { - acpi::AcpiTables::from_rsdt( - Handler, 0, - rsdt) - .expect("failed to get acpi tables") - }; - debug!("loaded rsdt"); - let platform_info = rsdt.platform_info().expect("failed to get platform info"); - let interrupt_model = platform_info.interrupt_model; - if let InterruptModel::Apic(apic) = interrupt_model { - let ioapics = apic.io_apics; - let ioapic = ioapics.first().expect("no ioapics"); - let ioapic_addr = ioapic.address; - debug!("ioapic addr: {:x}", ioapic_addr); - ioapic_addr +impl core::fmt::Write for LimineWriter { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + static mut CACHED: Option<&'static LimineTerminalResponse> = None; + unsafe { + if let Some(writer) = CACHED { + let terminal = &writer.terminals()[0]; + writer.write().unwrap()(terminal, s); } else { - panic!("no ioapic"); + let response = TERMINAL_REQUEST.get_response().get().unwrap(); + let terminal = &response.terminals()[0]; + let writer = response.write().unwrap(); + writer(terminal, s); + + CACHED = Some(response); } } + Ok(()) } } \ No newline at end of file diff --git a/src/internals/cpu.rs b/src/internals/cpu.rs index 5d42b2d..dd5dba1 100644 --- a/src/internals/cpu.rs +++ b/src/internals/cpu.rs @@ -3,7 +3,7 @@ use x86::apic::{xapic::XAPIC, ioapic::IoApic, ApicControl}; use x86_64::PhysAddr; use x86_64::structures::idt::InterruptStackFrame; use x86_64::structures::paging::PhysFrame; -use crate::{debug, KERN_INFO, print, println}; +use crate::{debug, print, println}; use crate::memory::{BootInfoFrameAllocator, read_phys_memory32, write_phys_memory32}; use crate::serial::{command, read}; diff --git a/src/macros/mod.rs b/src/macros/mod.rs index 11c85f3..9314c60 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -1,4 +1,6 @@ use core::fmt; +use limine::LimineTerminalResponse; +use crate::boot::LimineWriter; use crate::serial::terminal::ST; #[macro_export] @@ -21,6 +23,9 @@ macro_rules! debug { pub fn _print(args: fmt::Arguments) { use core::fmt::Write; ST.writer.lock().write_fmt(args).unwrap(); + + let mut limine_writer = LimineWriter; + limine_writer.write_fmt(args).unwrap(); } #[doc(hidden)] @@ -31,5 +36,10 @@ pub fn _debug(args: fmt::Arguments) { ST.log("[debug] "); ST.writer.lock().write_fmt(args).unwrap(); ST.logln(""); + + let mut limine_writer = LimineWriter; + limine_writer.write_str("[debug] ").unwrap(); + limine_writer.write_fmt(args).unwrap(); + limine_writer.write_str("\n").unwrap(); } } \ No newline at end of file diff --git a/src/lib.rs b/src/main.rs similarity index 93% rename from src/lib.rs rename to src/main.rs index 3a813e6..16d049f 100644 --- a/src/lib.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ use alloc::vec; use core::arch::asm; use lazy_static::lazy_static; use core::panic::PanicInfo; -use multiboot2::MemoryAreaType; +use limine::{LimineBootInfoRequest, LimineMemmapRequest, LimineTerminalRequest}; use spin::Mutex; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor}; @@ -24,7 +24,6 @@ use x86_64::structures::tss::TaskStateSegment; use x86_64::{PhysAddr, VirtAddr}; use x86_64::registers::segmentation::{CS, Segment, SS}; use x86_64::structures::paging::Translate; -use crate::boot::KernelInfo; use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*; use crate::memory::{FRAME_ALLOC, MEM_MAPPER}; use crate::serial::terminal::ST; @@ -37,8 +36,12 @@ mod boot; mod memory; mod macros; +static BOOTLOADER_INFO: LimineBootInfoRequest = LimineBootInfoRequest::new(0); +static TERMINAL_REQUEST: LimineTerminalRequest = LimineTerminalRequest::new(0); +static MEM_MAP: LimineMemmapRequest = LimineMemmapRequest::new(0); + lazy_static! { - pub static ref KERN_INFO: Mutex> = Mutex::new(None); + //pub static ref KERN_INFO: Mutex> = Mutex::new(None); static ref GDT: Mutex = { let mut gdt = GlobalDescriptorTable::new(); Mutex::new(gdt) @@ -82,14 +85,10 @@ fn panic(info: &PanicInfo) -> ! { loop {} } -#[repr(C)] -pub struct KernelArgs { - #[cfg(feature = "f_multiboot2")] - multiboot_information_address: usize -} - #[no_mangle] -pub extern fn kernel_main(args: KernelArgs) -> ! { +pub extern "C" fn kernel_main() -> ! { + debug!("entry point"); + // initialise serial let mut serial_ports = serial::init_serial(); let mut console_port = None; @@ -165,7 +164,6 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { println!(); println!("welcome to wukkOS!"); println!("(c) 2022 Real Microsoft, LLC"); - KERN_INFO.lock().replace(KernelInfo::init_from_kernel_args(args)); // memory stuff { @@ -194,7 +192,7 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { } // apic stuff - { + /*{ print!("checking for apic compatibility..."); let apic_compatible = unsafe { internals::cpu::check_apic_compat() }; if apic_compatible { @@ -213,7 +211,7 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { println!("[OK]"); // enable interrupts x86_64::instructions::interrupts::enable(); - } + }*/ loop { } diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 7bead8e..70c9ca5 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -46,18 +46,14 @@ unsafe fn active_level_4_table(phys_mem_offset: VirtAddr) -> &'static mut PageTa unsafe { &mut *page_table_ptr } // unsafe } -#[cfg(feature = "f_multiboot2")] -use multiboot2::{MemoryMapTag, BootInformation}; use spin::Mutex; -use crate::boot::KernelInfo; -use crate::{debug, KERN_INFO, print, println}; +use crate::{debug, MEM_MAP, print, println}; pub struct BootInfoFrameAllocator { next: usize, } impl BootInfoFrameAllocator { - #[cfg(feature = "f_multiboot2")] pub unsafe fn init() -> Self { Self { next: 0, @@ -67,15 +63,13 @@ impl BootInfoFrameAllocator { unsafe impl FrameAllocator for BootInfoFrameAllocator { fn allocate_frame(&mut self) -> Option { - #[cfg(feature = "f_multiboot2")] { - let mut kern_lock = KERN_INFO.lock(); - let mut kern_info = kern_lock.as_mut().unwrap(); - let mut usable_frames = kern_info - .memory_areas(); - let mut usable_frames = usable_frames + #[cfg(feature = "f_limine")] { + let mmap = MEM_MAP.get_response().get().expect("failed to get memory map") + .memmap(); + let mut usable_frames = mmap.iter() .map(|area| { - let frame_addr = area.start_address(); - let frame_end = area.end_address(); + let frame_addr = area.base; + let frame_end = area.base + area.len; let frame_size = frame_end - frame_addr; let num_frames = frame_size / 4096; let start_frame = PhysFrame::containing_address(PhysAddr::new(frame_addr)); @@ -85,9 +79,6 @@ unsafe impl FrameAllocator for BootInfoFrameAllocator { let frame = usable_frames.nth(self.next).clone(); self.next += 1; - // ensure unlock - unsafe { KERN_INFO.force_unlock() }; - frame } } diff --git a/x86_64-custom.json b/x86_64-custom.json index 346fefd..33ca2b2 100644 --- a/x86_64-custom.json +++ b/x86_64-custom.json @@ -9,7 +9,14 @@ "executables": true, "linker-flavor": "ld.lld", "linker": "rust-lld", - "panic-strategy": "abort", "disable-redzone": true, - "features": "-mmx,-sse,+soft-float" + "panic-strategy": "abort", + "features": "-mmx,-sse,+soft-float", + "code-model": "kernel", + "pre-link-args": { + "ld.lld": [ + "--gc-sections", + "--script=arch/x86_64/linker.ld" + ] + } } \ No newline at end of file From d11d5ddd9750a11899e931f42ffce3622e86cb4c Mon Sep 17 00:00:00 2001 From: fekhesk Date: Thu, 27 Oct 2022 20:08:32 -0700 Subject: [PATCH 4/5] wtf double fault ): --- Cargo.toml | 2 +- serial.log | 45 +++++++++++++++++++++++- src/boot/mod.rs | 59 ++++++++++++++++++------------- src/internals/cpu.rs | 84 +++++++++++++++++++++----------------------- src/main.rs | 24 ++++++++----- src/memory/mod.rs | 9 +++-- 6 files changed, 143 insertions(+), 80 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 06f8013..15a9816 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] spin = "0.9.1" x86_64 = "0.14.10" -x86 = "0.52.0" +x2apic = "0.4.1" rlibc = "1.0" limine = { version = "0.1.9", optional = true } acpi = { version = "4.1.1", optional = true } diff --git a/serial.log b/serial.log index 9129c8d..cee038e 100644 --- a/serial.log +++ b/serial.log @@ -12,7 +12,50 @@ debug: IDT loaded welcome to wukkOS! (c) 2022 Real Microsoft, LLC -initialising mapper...[OK] +initialising mapper...[debug] kernel physical address: 0x19b3d000 +[debug] kernel virtual address: 0xffffffff80000000 +[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, +} diff --git a/src/boot/mod.rs b/src/boot/mod.rs index ed79a07..8028f98 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -1,39 +1,36 @@ use alloc::sync::Arc; use core::marker::PhantomData; use core::ptr::NonNull; -use acpi::{AcpiHandler, InterruptModel, PhysicalMapping}; -use limine::LimineTerminalResponse; -use crate::{debug, println, TERMINAL_REQUEST}; +use acpi::{AcpiHandler, AcpiTables, InterruptModel, PhysicalMapping}; +use limine::{LimineBootInfoRequest, LimineKernelAddressRequest, LimineMemmapRequest, LimineTerminalRequest, LimineTerminalResponse, LimineRsdpRequest}; +use crate::{debug, println}; #[cfg(feature = "f_multiboot2")] use multiboot2::{load, MemoryMapTag, BootInformation}; use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, Translate}; use x86_64::VirtAddr; -use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize, read_phys_memory32}; +use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize, read_phys_memory32, VIRT_MEM_OFFSET}; use crate::serial::terminal::ST; +pub static BOOTLOADER_INFO: LimineBootInfoRequest = LimineBootInfoRequest::new(0); +pub static TERMINAL_REQUEST: LimineTerminalRequest = LimineTerminalRequest::new(0); +pub static MEM_MAP: LimineMemmapRequest = LimineMemmapRequest::new(0); +pub static RSDP_REQUEST: LimineRsdpRequest = LimineRsdpRequest::new(0); +pub static KERNEL_ADDRESS: LimineKernelAddressRequest = LimineKernelAddressRequest::new(0); + #[derive(Clone)] struct Handler; impl AcpiHandler for Handler { - unsafe fn map_physical_region(&self, physical_address: usize, size: usize) -> PhysicalMapping { - // todo! check if size is too big - debug!("read_phys_memory32: addr {:x} not mapped", physical_address); - let mut i = 0; - while i < size { - let _ = read_phys_memory32(physical_address as u32 + i as u32); - i += 4; - } - let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(VirtAddr::new(physical_address as u64)) }; - if let Some(addr) = addr.clone() { - // physical start, virtual start, region length, mapped length, Self - PhysicalMapping::new( - physical_address, - NonNull::new_unchecked(addr.as_u64() as *mut T), - size, size, - Self) - } else { - panic!("Failed to map page"); - } + 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); + let _ = read_phys_memory32(physical_address as u32) as usize; + PhysicalMapping::new( + physical_address as usize, + NonNull::new_unchecked(physical_address as *mut T), + size, size, + Self) } fn unmap_physical_region(region: &PhysicalMapping) { @@ -42,8 +39,9 @@ impl AcpiHandler for Handler { // unmap page 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"); + println!("[WARN] failed to unmap page (this is normal)"); } } } @@ -68,4 +66,17 @@ impl core::fmt::Write for LimineWriter { } Ok(()) } +} + +pub fn get_ioapic_addr() -> u32 { + 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, + _ => panic!("unsupported interrupt model"), + }; + ioapic_addr } \ No newline at end of file diff --git a/src/internals/cpu.rs b/src/internals/cpu.rs index dd5dba1..40ff5d2 100644 --- a/src/internals/cpu.rs +++ b/src/internals/cpu.rs @@ -1,5 +1,6 @@ use core::arch::asm; -use x86::apic::{xapic::XAPIC, ioapic::IoApic, ApicControl}; +use x2apic::ioapic::{IoApic, IrqFlags, IrqMode, RedirectionTableEntry}; +use x2apic::lapic::{LocalApicBuilder, xapic_base}; use x86_64::PhysAddr; use x86_64::structures::idt::InterruptStackFrame; use x86_64::structures::paging::PhysFrame; @@ -9,15 +10,6 @@ use crate::serial::{command, read}; // todo! maybe abstract this into different sections for different parts of cpu func? -pub struct WAPICManager { - pub xapic: XAPIC, - pub id: u32, -} - -pub struct WIOAPICManager { - pub ioapic: IoApic, -} - pub fn check_apic_compat() -> bool { unsafe { let mut eax: u32; @@ -31,34 +23,35 @@ pub fn check_apic_compat() -> bool { } } -pub fn enable_apic() -> WAPICManager { +pub fn enable_apic() { // we need to get the xapic region - let mut XAPIC_REGION: &'static mut [u32] = unsafe { - // region should be FFFE0000H to FFFE0FFFH - let region_start = 0xFFFE_0000u32; - let region_end = 0xFFFE_0FFFu32; - let region_size = region_end - region_start; - let region_size = region_size as usize; - let region_start = region_start as *mut u32; - // read to make sure it gets mapped - let _ = read_phys_memory32(region_start as u32); - let _ = read_phys_memory32(region_end as u32); - core::slice::from_raw_parts_mut(region_start, region_size) - }; - let mut xapic = unsafe { XAPIC::new(XAPIC_REGION) }; - xapic.attach(); + let phys_addr = unsafe { xapic_base() }; - // get xapic id to ensure it's working - let id = xapic.id(); - debug!("xapic id: {}", id); - debug!("xapic version: {}", xapic.version()); - - WAPICManager { - xapic, - id, + 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)); + + unsafe { + lapic.enable(); } } +pub extern "x86-interrupt" fn timer(stack_frame: InterruptStackFrame) { + println!("timer interrupt"); +} + +pub extern "x86-interrupt" fn error(stack_frame: InterruptStackFrame) { + println!("error interrupt"); +} + +pub extern "x86-interrupt" fn spurious(stack_frame: InterruptStackFrame) { + println!("spurious 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"); @@ -76,16 +69,21 @@ pub extern "x86-interrupt" fn keyboard_irq(stack_frame: InterruptStackFrame) { } // todo! we should abstract this away -pub fn setup_ioapic(ioapicaddr: u32) -> WIOAPICManager { - let mut ioapic = unsafe { IoApic::new(ioapicaddr as usize) }; - let _ = read_phys_memory32(ioapicaddr); - // assert that supported interrupts is greater than 1 - debug!("ioapic supported interrupts: {}", ioapic.supported_interrupts()); - // setup keyboard irq (interrupt 0x40) - ioapic.enable(1, 0x40); +pub fn setup_ioapic(ioapicaddr: u32) { + let mut ioapic = unsafe { + IoApic::new(ioapicaddr as u64) + }; + // setup keyboard interrupt + unsafe { + // init with irq offset + ioapic.init(0x50); + 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); + ioapic.set_table_entry(1, entry); - // return - WIOAPICManager { - ioapic, + ioapic.enable_irq(1); } + } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 16d049f..a6cbe81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,7 @@ use x86_64::structures::tss::TaskStateSegment; use x86_64::{PhysAddr, 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::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*; use crate::memory::{FRAME_ALLOC, MEM_MAPPER}; use crate::serial::terminal::ST; @@ -36,10 +37,6 @@ mod boot; mod memory; mod macros; -static BOOTLOADER_INFO: LimineBootInfoRequest = LimineBootInfoRequest::new(0); -static TERMINAL_REQUEST: LimineTerminalRequest = LimineTerminalRequest::new(0); -static MEM_MAP: LimineMemmapRequest = LimineMemmapRequest::new(0); - lazy_static! { //pub static ref KERN_INFO: Mutex> = Mutex::new(None); static ref GDT: Mutex = { @@ -51,7 +48,11 @@ lazy_static! { 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::keyboard_irq); + 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); idt }; } @@ -168,6 +169,11 @@ pub extern "C" fn kernel_main() -> ! { // memory stuff { print!("initialising mapper..."); + let kernel_physical_address = KERNEL_ADDRESS.get_response().get().unwrap().physical_base; + let kernel_virtual_address = KERNEL_ADDRESS.get_response().get().unwrap().virtual_base; + debug!("kernel physical address: {:#x}", kernel_physical_address); + debug!("kernel virtual address: {:#x}", kernel_virtual_address); + let offset = (kernel_virtual_address as i64) as usize;// - kernel_physical_address as i64) as usize; MEM_MAPPER.lock().replace(unsafe { memory::init(VirtAddr::new(0)) }); println!("[OK]"); print!("initialising frame allocator..."); @@ -192,7 +198,7 @@ pub extern "C" fn kernel_main() -> ! { } // apic stuff - /*{ + { print!("checking for apic compatibility..."); let apic_compatible = unsafe { internals::cpu::check_apic_compat() }; if apic_compatible { @@ -202,16 +208,16 @@ pub extern "C" fn kernel_main() -> ! { panic!("apic required at the moment"); } print!("initialising apic..."); + let ioapicaddr = get_ioapic_addr(); unsafe { internals::cpu::enable_apic() }; println!("[OK]"); print!("setting up apic interrupts..."); - let ioapicaddr = KERN_INFO.lock().as_ref().unwrap().acpi_get_ioapic_addr(); debug!("ioapicaddr: {:#x}", ioapicaddr); unsafe { internals::cpu::setup_ioapic(ioapicaddr) }; println!("[OK]"); // enable interrupts - x86_64::instructions::interrupts::enable(); - }*/ + //x86_64::instructions::interrupts::enable(); + } loop { } diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 70c9ca5..053eaf5 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -3,7 +3,8 @@ pub mod allocator; use alloc::boxed::Box; use alloc::sync::Arc; use lazy_static::lazy_static; -use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, PageTable, PhysFrame, Size4KiB, Translate}; +use limine::LimineMemoryMapEntryType; +use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PageTableFlags, PhysFrame, Size4KiB, Translate}; use x86_64::{PhysAddr, VirtAddr}; lazy_static!{ @@ -11,6 +12,8 @@ lazy_static!{ pub static ref FRAME_ALLOC: Mutex> = Mutex::new(None); } +pub const VIRT_MEM_OFFSET: u64 = 0xffffffff80000000; + pub type PageSize = Size4KiB; pub struct Locked { @@ -47,7 +50,8 @@ unsafe fn active_level_4_table(phys_mem_offset: VirtAddr) -> &'static mut PageTa } use spin::Mutex; -use crate::{debug, MEM_MAP, print, println}; +use crate::{debug, print, println}; +use crate::boot::{KERNEL_ADDRESS, MEM_MAP}; pub struct BootInfoFrameAllocator { next: usize, @@ -67,6 +71,7 @@ unsafe impl FrameAllocator for BootInfoFrameAllocator { let mmap = MEM_MAP.get_response().get().expect("failed to get memory map") .memmap(); let mut usable_frames = mmap.iter() + .filter(|entry| entry.typ == LimineMemoryMapEntryType::Usable) .map(|area| { let frame_addr = area.base; let frame_end = area.base + area.len; From 314189882b96e66d1dc4a192ba154b18d3729f39 Mon Sep 17 00:00:00 2001 From: fekhesk Date: Thu, 27 Oct 2022 21:58:36 -0700 Subject: [PATCH 5/5] 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