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 @@
[2J[01;01H[=3h[2J[01;01H[2J[01;01H[=3h[2J[01;01H[2J[01;01H[=3h[2J[01;01H[2J[01;01H[=3h[2J[01;01HBdsDxe: 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)
-[2J[01;01H[01;01Husing serial port 0 as console
+[0m[30m[47mWelcome to GRUB!
+
+
[0m[37m[40m[0m[30m[40m[2J[01;01H[0m[37m[40m 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