diff --git a/.gitignore b/.gitignore index bb571f8..17bb528 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,3 @@ Cargo.lock /boot.o /build/ /OVMF-pure-efi.fd -/isodir \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 85603ba..6afde3a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,11 +5,6 @@ diff --git a/Cargo.toml b/Cargo.toml index 2885847..f7dd3b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,21 +3,22 @@ name = "wukkOS" version = "0.1.0" edition = "2021" +[lib] +crate-type = ["staticlib"] + [dependencies] spin = "0.9.1" x86_64 = "0.14.10" -x2apic = "0.4.1" rlibc = "1.0" -limine = { version = "0.1.9", optional = true } +multiboot2 = { version = "0.14.0", 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_multiboot2", "f_ll_alloc", "f_debug_verbose"] f_debug_verbose = [] -f_limine = ["dep:limine", "dep:acpi"] +f_multiboot2 = ["dep:multiboot2", "dep:acpi"] f_ll_alloc = ["dep:linked_list_allocator"] \ No newline at end of file diff --git a/Makefile b/Makefile index 6e17c0e..bd74e82 100644 --- a/Makefile +++ b/Makefile @@ -1,30 +1,26 @@ arch ?= x86_64 -kernel := target/$(arch)-custom/debug/wukkOS +kernel := target/$(arch)-custom/debug/libwukkOS.a 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 ?= gcc -ld ?= ld linker_script := arch/$(arch)/linker.ld -bootloader_cfg := arch/$(arch)/limine.cfg +grub_cfg := arch/$(arch)/grub.cfg 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 build_no_iso +.PHONY: all clean run iso quick_invalidate all: $(final) $(iso) -build_no_iso: $(final) - clean: @xargo clean @rm -rf build run: $(final) $(iso) - @qemu-system-$(arch) -bios $(efi_bios) -cdrom $(iso) -d int -D qemulog.log \ + @qemu-system-$(arch) -bios $(efi_bios) -cdrom $(iso) \ -chardev stdio,id=char0,mux=on,logfile=serial.log,signal=off \ -serial chardev:char0 -mon chardev=char0 -m 512M @@ -37,26 +33,18 @@ 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 + @mkdir -p isodir/boot/grub @cp $(final) isodir/boot/wukkOS.bin - @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) + @cp $(grub_cfg) isodir/boot/grub/grub.cfg + @grub-mkrescue -o $(iso) isodir @rm -rf isodir - @byob/limine-deploy $(iso) $(final): $(kernel) $(linker_script) $(assembly_object_files) - @mkdir -p $(shell dirname $@) - @cp $(kernel) $(final) - #@$(ld) -n -T $(linker_script) -o $(final) $(kernel) \ - # --gc-sections + @ld -n -T $(linker_script) -o $(final) $(assembly_object_files) $(kernel) \ + --gc-sections $(kernel): - @RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core,alloc --features "f_limine" + @RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core,alloc --features "f_multiboot2" 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 new file mode 100644 index 0000000..bb20481 --- /dev/null +++ b/arch/x86_64/boot.asm @@ -0,0 +1,161 @@ +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 new file mode 100644 index 0000000..a1b062b --- /dev/null +++ b/arch/x86_64/grub.cfg @@ -0,0 +1,7 @@ +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 deleted file mode 100644 index 2af48f4..0000000 --- a/arch/x86_64/limine.cfg +++ /dev/null @@ -1,5 +0,0 @@ -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 459344d..72e7d29 100644 --- a/arch/x86_64/linker.ld +++ b/arch/x86_64/linker.ld @@ -1,48 +1,26 @@ -/* Tell the linker that we want an x86_64 ELF64 output file */ -OUTPUT_FORMAT(elf64-x86-64) -OUTPUT_ARCH(i386:x86-64) +ENTRY(start) -/* We want the symbol `x86_64_barebones_main` to be our entry point */ -ENTRY(kernel_main) +SECTIONS { + . = 1M; -/* 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 */ -} + .boot : + { + /* ensure that the multiboot header is at the beginning */ + KEEP(*(.multiboot_header)) + } -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.*) - } :text + } - /* Move to the next memory page for .rodata */ - . += CONSTANT(MAXPAGESIZE); - - .rodata : { + .rodata : + { *(.rodata .rodata.*) - } :rodata + } - /* Move to the next memory page for .data */ - . += CONSTANT(MAXPAGESIZE); - - .data : { - *(.data .data.*) - } :data - - .bss : { - *(COMMON) - *(.bss .bss.*) - } :data + .data.rel.ro : + { + *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*) + } } \ No newline at end of file diff --git a/arch/x86_64/longmodestart.asm b/arch/x86_64/longmodestart.asm new file mode 100644 index 0000000..9c2dc04 --- /dev/null +++ b/arch/x86_64/longmodestart.asm @@ -0,0 +1,17 @@ +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 new file mode 100644 index 0000000..e855dfe --- /dev/null +++ b/arch/x86_64/multiboot_header.asm @@ -0,0 +1,16 @@ +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 deleted file mode 100644 index c219351..0000000 --- a/byob/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# 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 deleted file mode 100644 index 5d33010..0000000 --- a/byob/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# 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 d191a2c..c5b92ba 100644 --- a/serial.log +++ b/serial.log @@ -1,6 +1,12 @@ [=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) -using serial port 0 as console +Welcome to GRUB! + +  Booting `wukkOS basic kernel' + + WARNING: no console will be available to OS + error: no suitable video mode found. + using serial port 0 as console debug: setup GDT debug: GDT loaded debug: CS set @@ -17,9 +23,28 @@ initialising frame allocator...[OK] initialising heap...[OK] testing heap...[OK] checking for apic compatibility...[OK] -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 +disabling PIC...[OK] +initialising apic...[debug] read_phys_memory32: addr fee000f0 not mapped +[debug] allocated frame: PhysFrame[4KiB](0x1c000) +[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, +} diff --git a/src/boot/mod.rs b/src/boot/mod.rs index 7a5905d..3b2bf39 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -1,88 +1,127 @@ use alloc::sync::Arc; -use alloc::vec::Vec; use core::marker::PhantomData; use core::ptr::NonNull; -use acpi::{AcpiHandler, AcpiTables, InterruptModel, PhysicalMapping}; -use acpi::platform::interrupt::InterruptSourceOverride; -use limine::{LimineBootInfoRequest, LimineKernelAddressRequest, LimineMemmapRequest, LimineTerminalRequest, LimineTerminalResponse, LimineRsdpRequest, LimineSmpRequest}; -use crate::{debug, println}; +use acpi::{AcpiHandler, InterruptModel, PhysicalMapping}; +use crate::{debug, KernelArgs, 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, VIRT_MEM_OFFSET}; -use crate::serial::terminal::ST; +use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Translate}; +use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER}; -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); -pub static SMP_REQUEST: LimineSmpRequest = LimineSmpRequest::new(0); +pub struct KernelInfo { + kernel_start: u64, + kernel_end: u64, + safe_mem_start: u64, + #[cfg(feature = "f_multiboot2")] + boot_info: BootInformation, +} #[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 - // 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) + 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 = x86_64::structures::paging::Page::containing_address(initaladdr); + 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) }; + if let Some(addr) = addr { + // 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"); + } } fn unmap_physical_region(region: &PhysicalMapping) { // get page - let page: Page = Page::containing_address(VirtAddr::new(region.physical_start() as u64)); + let page = x86_64::structures::paging::Page::containing_address(region.start_address()); // 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 let Err(e) = res { - debug!("(THIS IS NORMAL) failed to unmap physical region: {:?}", e); + if res.is_err() { + println!("[WARN] failed to unmap page"); } } } -pub struct LimineWriter; +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 + } + } -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); + #[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"); + let rsdp = acpi_tag; + let rsdp = unsafe { &*rsdp }; + let rsdt = rsdp.rsdt_address(); + let rsdt = unsafe { + acpi::AcpiTables::from_rsdt( + AcpiHandler, 0, + rsdt) + .expect("failed to get acpi tables") + }; + 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; + ioapic_addr } else { - let response = TERMINAL_REQUEST.get_response().get().unwrap(); - let terminal = &response.terminals()[0]; - let writer = response.write().unwrap(); - writer(terminal, s); - - CACHED = Some(response); + panic!("no ioapic"); } } - Ok(()) } -} - -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 apic = match interrupt_model { - InterruptModel::Apic(apic) => apic, - _ => panic!("unsupported interrupt model"), - }; - 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 b7cf438..5ae297c 100644 --- a/src/internals/cpu.rs +++ b/src/internals/cpu.rs @@ -1,46 +1,13 @@ -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::{LocalApic, LocalApicBuilder, xapic_base}; -use x86_64::PhysAddr; +use x86_64::{PhysAddr, VirtAddr}; use x86_64::structures::idt::InterruptStackFrame; -use x86_64::structures::paging::PhysFrame; +use x86_64::structures::paging::OffsetPageTable; 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; @@ -54,54 +21,111 @@ pub fn check_apic_compat() -> bool { } } -pub fn tell_pic8259a_to_f_off() { +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!("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"); + asm!("wrmsr", + in("ecx") 0x1b, + in("eax") eax, + in("edx") edx, + ); } } +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 { - LAPIC.lock().enable(); - } -} - -pub extern "x86-interrupt" fn timer(stack_frame: InterruptStackFrame) { - 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(); + asm!("mov eax, 0", + "mov ecx, 0xb0", + "wrmsr", + in("ecx") 0x80b, + in("eax") 0, + ); } } // 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); - handle_scancode(scancode); + print!("ksc: {},", scancode); // reset keyboard controller let mut a = read(0x61); @@ -109,30 +133,10 @@ 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, 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(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); - } - +pub fn setup_apic_interrupts(ioapicaddr: u32) { + // set keyboard irq to interrupt 40 + ioapic_set_irq(ioapicaddr, 1, 0, 40); } \ No newline at end of file diff --git a/src/internals/errors.rs b/src/internals/errors.rs index c7bab66..e42b78f 100644 --- a/src/internals/errors.rs +++ b/src/internals/errors.rs @@ -14,11 +14,10 @@ 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 {} } @@ -29,12 +28,4 @@ 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/lib.rs b/src/lib.rs new file mode 100644 index 0000000..b87a25d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,219 @@ +#![feature(abi_x86_interrupt)] +#![feature(default_alloc_error_handler)] +#![feature(panic_info_message)] +#![feature(asm_const)] +#![feature(const_mut_refs)] +#![feature(alloc_error_handler)] +#![no_std] +#![no_main] + +extern crate rlibc; +extern crate alloc; + +use alloc::rc::Rc; +use alloc::vec; +use core::arch::asm; +use lazy_static::lazy_static; +use core::panic::PanicInfo; +use multiboot2::MemoryAreaType; +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::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; + +mod font; +mod serial; +mod internals; +mod security; +mod boot; +mod memory; +mod macros; + +lazy_static! { + static ref GDT: Mutex = { + let mut gdt = GlobalDescriptorTable::new(); + Mutex::new(gdt) + }; + 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::keyboard_irq); + idt + }; +} + + +const RAINBOW : [Colour; 6] = [Colour{r:255,g:0,b:0}, Colour{r:255,g:127,b:0}, Colour{r:255,g:255,b:0}, Colour{r:0,g:255,b:0}, Colour{r:0,g:255,b:255}, Colour{r:0,g:0,b:255}]; + +#[alloc_error_handler] +fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! { + panic!("allocation error: {:?}", layout) +} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + println!("---KERNEL FUCKY WUKKY UWU (panic)---"); + if let Some(s) = info.payload().downcast_ref::<&str>() { + println!("panic payload: {s:?}") + } else { + println!("no panic payload") + }; + if let Some(msg) = info.message() { + println!("panic msg: {}", msg.as_str().unwrap_or("no message")) + } else { + println!("no message"); + } + if let Some(location) = info.location() { + println!("location: file {} line {}", location.file(), location.line()); + } else { + println!("no location"); + }; + loop {} +} + +#[repr(C)] +pub struct KernelArgs { + #[cfg(feature = "f_multiboot2")] + multiboot_information_address: usize +} + +#[no_mangle] +pub extern fn kernel_main(args: KernelArgs) -> ! { + // initialise serial + let mut serial_ports = serial::init_serial(); + let mut console_port = None; + for (i, enabled) in serial_ports.ports_enabled.iter().enumerate() { + if *enabled { + console_port = Some(i); + } + } + + if let Some(i) = console_port { + let port = &serial_ports.ports[i]; + ST.init_from_port(*port); + println!("using serial port {} as console", i); + } + + // temporarily disable interrupts + x86_64::instructions::interrupts::disable(); + println!("debug: setup GDT"); + // load TSS + 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 + }; + // 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; + unsafe { + *tss_ptr.add(102) = 0x68; + *tss_ptr.add(104) = 0xff; + *tss_ptr.add(105) = 0xff; + } + } + let kcs = GDT.lock().add_entry(Descriptor::kernel_code_segment()); + let kds = GDT.lock().add_entry(Descriptor::kernel_data_segment()); + let tsss = unsafe { GDT.lock().add_entry(Descriptor::tss_segment(&tss)) }; + // load GDT + unsafe { + GDT.lock().load_unsafe(); + } + println!("debug: GDT loaded"); + // set code segment to kernel code segment + unsafe { + CS::set_reg(kcs); + } + println!("debug: CS set"); + // set data segment to kernel data segment + unsafe { + SS::set_reg(kds); + } + println!("debug: SS set"); + // load TSS + unsafe { + x86_64::instructions::tables::load_tss(tsss); + } + println!("debug: TSS loaded"); + + // load IDT + IDT.load(); + println!("debug: IDT loaded"); + // enable interrupts + x86_64::instructions::interrupts::enable(); + } + + + println!(); + println!(); + println!(); + println!("welcome to wukkOS!"); + println!("(c) 2022 Real Microsoft, LLC"); + let kern_info = Mutex::new(KernelInfo::init_from_kernel_args(args)); + + // memory stuff + { + print!("initialising mapper..."); + 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) }); + 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"); + println!("[OK]"); + + print!("testing heap..."); + let reference_counted = Rc::new(vec![1, 2, 3]); + let cloned = reference_counted.clone(); + let test_1 = Rc::strong_count(&reference_counted) == 2; + drop(cloned); + let test_2 = Rc::strong_count(&reference_counted) == 1; + if test_1 && test_2 { + println!("[OK]"); + } else { + println!("[FAIL]"); + } + drop(reference_counted); + } + + // apic stuff + { + print!("checking for apic compatibility..."); + let apic_compatible = unsafe { internals::cpu::check_apic_compat() }; + if apic_compatible { + println!("[OK]"); + } else { + 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().acpi_get_ioapic_addr()) }; + println!("[OK]"); + // enable interrupts + x86_64::instructions::interrupts::enable(); + } + + loop { + } +} \ No newline at end of file diff --git a/src/macros/mod.rs b/src/macros/mod.rs index 9314c60..11c85f3 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -1,6 +1,4 @@ use core::fmt; -use limine::LimineTerminalResponse; -use crate::boot::LimineWriter; use crate::serial::terminal::ST; #[macro_export] @@ -23,9 +21,6 @@ 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)] @@ -36,10 +31,5 @@ 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/main.rs b/src/main.rs deleted file mode 100644 index 6ea16a7..0000000 --- a/src/main.rs +++ /dev/null @@ -1,296 +0,0 @@ -#![feature(abi_x86_interrupt)] -#![feature(default_alloc_error_handler)] -#![feature(panic_info_message)] -#![feature(asm_const)] -#![feature(const_mut_refs)] -#![feature(alloc_error_handler)] -#![feature(const_slice_from_raw_parts_mut)] -#![no_std] -#![no_main] - -extern crate rlibc; -extern crate alloc; - -use alloc::rc::Rc; -use alloc::vec; -use core::arch::asm; -use lazy_static::lazy_static; -use core::panic::PanicInfo; -use limine::{LimineBootInfoRequest, LimineMemmapRequest, LimineTerminalRequest}; -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, set_general_handler, VirtAddr}; -use x86_64::registers::segmentation::{CS, Segment, SS}; -use x86_64::structures::paging::Translate; -use crate::boot::{get_ioapic_info, KERNEL_ADDRESS}; -use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*; -use crate::memory::{FRAME_ALLOC, MEM_MAPPER}; -use crate::serial::terminal::ST; - -mod font; -mod serial; -mod internals; -mod security; -mod boot; -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) - }; - static ref IDT: InterruptDescriptorTable = { - let mut idt = InterruptDescriptorTable::new(); - 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 - }; -} - - -const RAINBOW : [Colour; 6] = [Colour{r:255,g:0,b:0}, Colour{r:255,g:127,b:0}, Colour{r:255,g:255,b:0}, Colour{r:0,g:255,b:0}, Colour{r:0,g:255,b:255}, Colour{r:0,g:0,b:255}]; - -#[alloc_error_handler] -fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! { - panic!("allocation error: {:?}", layout) -} - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - println!("---KERNEL FUCKY WUKKY UWU (panic)---"); - if let Some(s) = info.payload().downcast_ref::<&str>() { - println!("panic payload: {s:?}") - } else { - println!("no panic payload") - }; - if let Some(msg) = info.message() { - println!("panic msg: {}", msg) - } else { - println!("no message"); - } - if let Some(location) = info.location() { - println!("location: file {} line {}", location.file(), location.line()); - } else { - println!("no location"); - }; - loop {} -} - -#[no_mangle] -pub extern "C" fn kernel_main() -> ! { - debug!("entry point"); - - // initialise serial - let mut serial_ports = serial::init_serial(); - let mut console_port = None; - for (i, enabled) in serial_ports.ports_enabled.iter().enumerate() { - if *enabled { - console_port = Some(i); - } - } - - if let Some(i) = console_port { - let port = &serial_ports.ports[i]; - ST.init_from_port(*port); - println!("using serial port {} as console", i); - } - - // temporarily disable interrupts - x86_64::instructions::interrupts::disable(); - println!("debug: setup GDT"); - // load TSS - 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[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; - unsafe { - *tss_ptr.add(102) = 0x68; - *tss_ptr.add(104) = 0xff; - *tss_ptr.add(105) = 0xff; - } - } - let kcs = GDT.lock().add_entry(Descriptor::kernel_code_segment()); - let kds = GDT.lock().add_entry(Descriptor::kernel_data_segment()); - let tsss = unsafe { GDT.lock().add_entry(Descriptor::tss_segment(&tss)) }; - // load GDT - unsafe { - GDT.lock().load_unsafe(); - } - println!("debug: GDT loaded"); - // set code segment to kernel code segment - unsafe { - CS::set_reg(kcs); - } - println!("debug: CS set"); - // set data segment to kernel data segment - unsafe { - SS::set_reg(kds); - } - println!("debug: SS set"); - // load TSS - unsafe { - x86_64::instructions::tables::load_tss(tsss); - } - println!("debug: TSS loaded"); - - // load IDT - IDT.load(); - println!("debug: IDT loaded"); - // enable interrupts - x86_64::instructions::interrupts::enable(); - } - - - println!(); - println!(); - println!(); - println!("welcome to wukkOS!"); - println!("(c) 2022 Real Microsoft, LLC"); - - // 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..."); - 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"); - println!("[OK]"); - - print!("testing heap..."); - let reference_counted = Rc::new(vec![1, 2, 3]); - let cloned = reference_counted.clone(); - let test_1 = Rc::strong_count(&reference_counted) == 2; - drop(cloned); - let test_2 = Rc::strong_count(&reference_counted) == 1; - if test_1 && test_2 { - println!("[OK]"); - } else { - println!("[FAIL]"); - } - drop(reference_counted); - } - - // apic stuff - { - print!("checking for apic compatibility..."); - let apic_compatible = unsafe { internals::cpu::check_apic_compat() }; - if apic_compatible { - println!("[OK]"); - } else { - println!("[FAIL]"); - panic!("apic required at the moment"); - } - print!("initialising apic..."); - //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}", 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/memory/allocator.rs b/src/memory/allocator.rs index 7430d06..229b2a3 100644 --- a/src/memory/allocator.rs +++ b/src/memory/allocator.rs @@ -4,7 +4,6 @@ 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; @@ -100,9 +99,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 053eaf5..1755dec 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -3,19 +3,14 @@ pub mod allocator; use alloc::boxed::Box; use alloc::sync::Arc; use lazy_static::lazy_static; -use limine::LimineMemoryMapEntryType; -use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PageTableFlags, PhysFrame, Size4KiB, Translate}; +use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, PageTable, PhysFrame, Size4KiB, Translate}; 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 const VIRT_MEM_OFFSET: u64 = 0xffffffff80000000; - -pub type PageSize = Size4KiB; - pub struct Locked { inner: spin::Mutex, } @@ -49,17 +44,22 @@ 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, print, println}; -use crate::boot::{KERNEL_ADDRESS, MEM_MAP}; pub struct BootInfoFrameAllocator { + kern_info: Mutex, next: usize, } impl BootInfoFrameAllocator { - pub unsafe fn init() -> Self { + #[cfg(feature = "f_multiboot2")] + pub unsafe fn init(kern_info: Mutex) -> Self { Self { + kern_info, next: 0, } } @@ -67,14 +67,14 @@ impl BootInfoFrameAllocator { unsafe impl FrameAllocator for BootInfoFrameAllocator { fn allocate_frame(&mut self) -> Option { - #[cfg(feature = "f_limine")] { - 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) + #[cfg(feature = "f_multiboot2")] { + let mut kern_lock = self.kern_info.lock(); + let mut usable_frames = kern_lock + .memory_areas(); + let mut usable_frames = usable_frames .map(|area| { - let frame_addr = area.base; - let frame_end = area.base + area.len; + let frame_addr = area.start_address(); + let frame_end = area.end_address(); let frame_size = frame_end - frame_addr; let num_frames = frame_size / 4096; let start_frame = PhysFrame::containing_address(PhysAddr::new(frame_addr)); @@ -84,6 +84,9 @@ unsafe impl FrameAllocator for BootInfoFrameAllocator { let frame = usable_frames.nth(self.next).clone(); self.next += 1; + // ensure unlock + unsafe { self.kern_info.force_unlock() }; + frame } } diff --git a/src/serial/mod.rs b/src/serial/mod.rs index 7d37aab..ab39655 100644 --- a/src/serial/mod.rs +++ b/src/serial/mod.rs @@ -6,7 +6,6 @@ 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 deleted file mode 100644 index 00b32e9..0000000 --- a/src/serial/simplifiers.rs +++ /dev/null @@ -1,20 +0,0 @@ -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 diff --git a/x86_64-custom.json b/x86_64-custom.json index 33ca2b2..346fefd 100644 --- a/x86_64-custom.json +++ b/x86_64-custom.json @@ -9,14 +9,7 @@ "executables": true, "linker-flavor": "ld.lld", "linker": "rust-lld", - "disable-redzone": true, "panic-strategy": "abort", - "features": "-mmx,-sse,+soft-float", - "code-model": "kernel", - "pre-link-args": { - "ld.lld": [ - "--gc-sections", - "--script=arch/x86_64/linker.ld" - ] - } + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float" } \ No newline at end of file