diff --git a/Architecture/amd64/Bootstrap/MB2.asm b/Architecture/amd64/Bootstrap/MB2.asm new file mode 100644 index 00000000..6b8fd55a --- /dev/null +++ b/Architecture/amd64/Bootstrap/MB2.asm @@ -0,0 +1,70 @@ +; https://wiki.osdev.org/Creating_a_64-bit_kernel +; https://wiki.osdev.org/Entering_Long_Mode_Directly + +KERNEL_VIRTUAL_BASE equ 0xFFFFFFFF80000000 ; 512GB +KERNEL_LMA equ 0x1000000 ; 16MB +KERNEL_STACK_SIZE equ 0x4000 ; 16KB + +extern Multiboot2Entry +extern BootPageTable +extern DetectCPUID +extern Detect64Bit +global MB2_start + +[bits 32] +section .text +MB2_start: + cli + + mov word [0xb8F00], 0x072E ; . + + call DetectCPUID + call Detect64Bit + + mov ecx, cr4 + or ecx, 0x00000010 ; Set PSE in CR4 + mov cr4, ecx + + mov word [0xb8F02], 0x072E ; . + + mov ecx, (BootPageTable - KERNEL_VIRTUAL_BASE) + mov cr3, ecx + + mov ecx, cr0 + or ecx, 0x80000000 ; Set PG in CR0 + mov cr0, ecx + + cli + hlt + + mov word [0xb8F04], 0x072E ; . + + + mov word [0xb8F06], 0x072E ; . + + cli + hlt + + ; lea ecx, [HigherHalfStart] + ; jmp ecx + +[bits 64] +HigherHalfStart: + mov word [0xb8F08], 0x072E ; . + mov dword [BootPageTable], 0 + invlpg [0] + + mov rsp, KernelStack + KERNEL_STACK_SIZE + + push rax ; Multiboot2 Magic + add rbx, KERNEL_VIRTUAL_BASE + push rbx ; Multiboot2 Header + call Multiboot2Entry +Loop: + hlt + jmp Loop + +section .bss +align 16 +KernelStack: + resb KERNEL_STACK_SIZE diff --git a/Architecture/amd64/Bootstrap/MB2Detection.asm b/Architecture/amd64/Bootstrap/MB2Detection.asm new file mode 100644 index 00000000..22ba2959 --- /dev/null +++ b/Architecture/amd64/Bootstrap/MB2Detection.asm @@ -0,0 +1,40 @@ +[bits 32] +global DetectCPUID +DetectCPUID: + pushfd + pop eax + mov ecx, eax + xor eax, 1 << 21 + push eax + popfd + pushfd + pop eax + push ecx + popfd + xor eax, ecx + jz .NoCPUID + ret +.NoCPUID: + mov word [0xb8F00], 0xF00F ; . +.Loop: + cli + hlt + jmp .Loop + +global Detect64Bit +Detect64Bit: + mov eax, 0x80000000 + cpuid + cmp eax, 0x80000001 + jb .NoLongMode + mov eax, 0x80000001 + cpuid + test edx, 1 << 29 + jz .NoLongMode + ret +.NoLongMode: + mov word [0xb8F00], 0xF00A ; . +.Loop: + cli + hlt + jmp .Loop diff --git a/Architecture/amd64/Bootstrap/MB2Header.asm b/Architecture/amd64/Bootstrap/MB2Header.asm new file mode 100644 index 00000000..b05828df --- /dev/null +++ b/Architecture/amd64/Bootstrap/MB2Header.asm @@ -0,0 +1,42 @@ +[bits 32] +section .multiboot2 +align 4096 +HEADER_START: + dd 0xE85250D6 + dd 0 + dd (HEADER_END - HEADER_START) + dd 0x100000000 - (HEADER_END - HEADER_START) - 0 - 0xE85250D6 +align 8 +MB2_INFO_REQUEST_TAG_START: + dw 1 + dw 0 + dd MB2_INFO_REQUEST_TAG_END - MB2_INFO_REQUEST_TAG_START + dd 1 ; Command Line + dd 2 ; Boot Loader Name + dd 3 ; Module + dd 4 ; Basic Memory Information + dd 5 ; BIOS Boot Device + dd 6 ; Memory Map + dd 7 ; VBE + dd 8 ; Framebuffer + dd 9 ; ELF Sections + dd 10 ; APM Table + dd 11 ; EFI 32-bit System Table Pointer + dd 12 ; EFI 64-bit System Table Pointer + ; dd 13 ; SMBIOS + dd 14 ; ACPI Old + dd 15 ; ACPI New + dd 16 ; Network + dd 17 ; EFI Memory Map + dd 18 ; EFI Boot Services Notifier + dd 19 ; EFI 32-bit Image Handle Pointer + dd 20 ; EFI 64-bit Image Handle Pointer + dd 21 ; Load Base Address +MB2_INFO_REQUEST_TAG_END: +align 8 +MB2_TAG_START: + dw 0 + dw 0 + dd MB2_TAG_END - MB2_TAG_START +MB2_TAG_END: +HEADER_END: diff --git a/Architecture/amd64/Bootstrap/MB2PageTable.asm b/Architecture/amd64/Bootstrap/MB2PageTable.asm new file mode 100644 index 00000000..4a66ac4b --- /dev/null +++ b/Architecture/amd64/Bootstrap/MB2PageTable.asm @@ -0,0 +1,14 @@ +%define KERNEL_OFFSET 0xFFFFFFFF80000000 +%define V2P(a) ((a) - KERNEL_OFFSET) + +%define PAGE_PRESENT 0x001 +%define PAGE_WRITE 0x002 +%define PAGE_GLOBAL 0x100 + +%define PAGE_SIZE 0x1000 +%define ENTRIES_PER_PT 512 + +section .data +align PAGE_SIZE +global BootPageTable +BootPageTable: diff --git a/Architecture/amd64/Bootstrap/MB2Switch.asm b/Architecture/amd64/Bootstrap/MB2Switch.asm new file mode 100644 index 00000000..e69de29b diff --git a/Architecture/amd64/Bootstrap/Multiboot2.cpp b/Architecture/amd64/Bootstrap/Multiboot2.cpp new file mode 100644 index 00000000..99ed39a4 --- /dev/null +++ b/Architecture/amd64/Bootstrap/Multiboot2.cpp @@ -0,0 +1,339 @@ +#include + +#include +#include +#include + +#include "../../../kernel.h" + +BootInfo mb2binfo; + +enum VideoType +{ + VIDEO_TYPE_NONE = 0x00, + VIDEO_TYPE_COLOUR = 0x20, + VIDEO_TYPE_MONOCHROME = 0x30, +}; + +uint16_t GetBiosAreaHardware() +{ + const uint16_t *BIOSDataAreaDetectedHardware = (const uint16_t *)0x410; + return *BIOSDataAreaDetectedHardware; +} + +enum VideoType GetVideoType() { return (enum VideoType)(GetBiosAreaHardware() & 0x30); } + +void GetSMBIOS() +{ + unsigned char *SMBIOSAddress = (unsigned char *)0xF0000; + while ((unsigned int)(unsigned long)SMBIOSAddress < 0x100000) + { + if (SMBIOSAddress[0] == '_' && + SMBIOSAddress[1] == 'S' && + SMBIOSAddress[2] == 'M' && + SMBIOSAddress[3] == '_') + { + unsigned char Checksum = 0; + int Length = SMBIOSAddress[5]; + for (int i = 0; i < Length; i++) + Checksum += SMBIOSAddress[i]; + + if (Checksum == 0) + break; + } + SMBIOSAddress += 16; + } + + if ((unsigned int)(unsigned long)SMBIOSAddress == 0x100000) + { + // No SMBIOS found + } +} + +void ProcessMB2(unsigned long Info) +{ + uint8_t *VideoBuffer = (uint8_t *)0xB8F00 + 0xC0000000; + int pos = 0; + auto InfoAddress = Info; + for (auto Tag = (struct multiboot_tag *)((uint8_t *)InfoAddress + 8); + ; + Tag = (struct multiboot_tag *)((multiboot_uint8_t *)Tag + ((Tag->size + 7) & ~7))) + { + VideoBuffer[pos++] = '.'; + VideoBuffer[pos++] = 0x2; + + if (Tag->type == MULTIBOOT_TAG_TYPE_END) + { + debug("End of multiboot2 tags"); + break; + } + + switch (Tag->type) + { + case MULTIBOOT_TAG_TYPE_CMDLINE: + { + strncpy(mb2binfo.Kernel.CommandLine, + ((multiboot_tag_string *)Tag)->string, + strlen(((multiboot_tag_string *)Tag)->string)); + debug("Kernel command line: %s", mb2binfo.Kernel.CommandLine); + break; + } + case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: + { + strncpy(mb2binfo.Bootloader.Name, + ((multiboot_tag_string *)Tag)->string, + strlen(((multiboot_tag_string *)Tag)->string)); + debug("Bootloader name: %s", mb2binfo.Bootloader.Name); + break; + } + case MULTIBOOT_TAG_TYPE_MODULE: + { + multiboot_tag_module *module = (multiboot_tag_module *)Tag; + static int module_count = 0; + mb2binfo.Modules[module_count++].Address = (void *)module->mod_start; + mb2binfo.Modules[module_count++].Size = module->size; + strncpy(mb2binfo.Modules[module_count++].Path, "(null)", 6); + strncpy(mb2binfo.Modules[module_count++].CommandLine, module->cmdline, + strlen(module->cmdline)); + debug("Module: %s", mb2binfo.Modules[module_count++].Path); + break; + } + case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: + { + multiboot_tag_basic_meminfo *meminfo = (multiboot_tag_basic_meminfo *)Tag; + fixme("basic_meminfo->[mem_lower: %#x, mem_upper: %#x]", + meminfo->mem_lower, meminfo->mem_upper); + break; + } + case MULTIBOOT_TAG_TYPE_BOOTDEV: + { + multiboot_tag_bootdev *bootdev = (multiboot_tag_bootdev *)Tag; + fixme("bootdev->[biosdev: %#x, slice: %#x, part: %#x]", + bootdev->biosdev, bootdev->slice, bootdev->part); + break; + } + case MULTIBOOT_TAG_TYPE_MMAP: + { + multiboot_tag_mmap *mmap = (multiboot_tag_mmap *)Tag; + uint32_t EntryCount = mmap->size / sizeof(multiboot_mmap_entry); + mb2binfo.Memory.Entries = EntryCount; + for (uint32_t i = 0; i < EntryCount; i++) + { + if (EntryCount > MAX_MEMORY_ENTRIES) + { + warn("Too many memory entries, skipping the rest..."); + break; + } + multiboot_mmap_entry entry = mmap->entries[i]; + mb2binfo.Memory.Size += entry.len; + switch (entry.type) + { + case MULTIBOOT_MEMORY_AVAILABLE: + mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr; + mb2binfo.Memory.Entry[i].Length = entry.len; + mb2binfo.Memory.Entry[i].Type = Usable; + break; + case MULTIBOOT_MEMORY_RESERVED: + mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr; + mb2binfo.Memory.Entry[i].Length = entry.len; + mb2binfo.Memory.Entry[i].Type = Reserved; + break; + case MULTIBOOT_MEMORY_ACPI_RECLAIMABLE: + mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr; + mb2binfo.Memory.Entry[i].Length = entry.len; + mb2binfo.Memory.Entry[i].Type = ACPIReclaimable; + break; + case MULTIBOOT_MEMORY_NVS: + mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr; + mb2binfo.Memory.Entry[i].Length = entry.len; + mb2binfo.Memory.Entry[i].Type = ACPINVS; + break; + case MULTIBOOT_MEMORY_BADRAM: + mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr; + mb2binfo.Memory.Entry[i].Length = entry.len; + mb2binfo.Memory.Entry[i].Type = BadMemory; + break; + default: + mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr; + mb2binfo.Memory.Entry[i].Length = entry.len; + mb2binfo.Memory.Entry[i].Type = Unknown; + break; + } + debug("Memory entry: [BaseAddress: %#x, Length: %#x, Type: %d]", + mb2binfo.Memory.Entry[i].BaseAddress, + mb2binfo.Memory.Entry[i].Length, + mb2binfo.Memory.Entry[i].Type); + } + break; + } + case MULTIBOOT_TAG_TYPE_VBE: + { + multiboot_tag_vbe *vbe = (multiboot_tag_vbe *)Tag; + fixme("vbe->[vbe_mode: %#x, vbe_interface_seg: %#x, vbe_interface_off: %#x, vbe_interface_len: %#x]", + vbe->vbe_mode, vbe->vbe_interface_seg, vbe->vbe_interface_off, vbe->vbe_interface_len); + break; + } + case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: + { + multiboot_tag_framebuffer *fb = (multiboot_tag_framebuffer *)Tag; + static int fb_count = 0; + mb2binfo.Framebuffer[fb_count].BaseAddress = (void *)fb->common.framebuffer_addr; + mb2binfo.Framebuffer[fb_count].Width = fb->common.framebuffer_width; + mb2binfo.Framebuffer[fb_count].Height = fb->common.framebuffer_height; + mb2binfo.Framebuffer[fb_count].Pitch = fb->common.framebuffer_pitch; + mb2binfo.Framebuffer[fb_count].BitsPerPixel = fb->common.framebuffer_bpp; + mb2binfo.Framebuffer[fb_count].MemoryModel = fb->common.framebuffer_type; + switch (fb->common.framebuffer_type) + { + case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED: + { + fixme("indexed"); + break; + } + case MULTIBOOT_FRAMEBUFFER_TYPE_RGB: + { + mb2binfo.Framebuffer[fb_count].RedMaskSize = fb->framebuffer_red_mask_size; + mb2binfo.Framebuffer[fb_count].RedMaskShift = fb->framebuffer_red_field_position; + mb2binfo.Framebuffer[fb_count].GreenMaskSize = fb->framebuffer_green_mask_size; + mb2binfo.Framebuffer[fb_count].GreenMaskShift = fb->framebuffer_green_field_position; + mb2binfo.Framebuffer[fb_count].BlueMaskSize = fb->framebuffer_blue_mask_size; + mb2binfo.Framebuffer[fb_count].BlueMaskShift = fb->framebuffer_blue_field_position; + break; + } + case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT: + { + fixme("ega_text"); + break; + } + } + debug("Framebuffer %d: %dx%d %d bpp", Tag, fb->common.framebuffer_width, fb->common.framebuffer_height, fb->common.framebuffer_bpp); + debug("More info:\nAddress: %p\nPitch: %lld\nMemoryModel: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d", + fb->common.framebuffer_addr, fb->common.framebuffer_pitch, fb->common.framebuffer_type, + fb->framebuffer_red_mask_size, fb->framebuffer_red_field_position, fb->framebuffer_green_mask_size, + fb->framebuffer_green_field_position, fb->framebuffer_blue_mask_size, fb->framebuffer_blue_field_position); + fb_count++; + break; + } + case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: + { + multiboot_tag_elf_sections *elf = (multiboot_tag_elf_sections *)Tag; + fixme("elf_sections->[num=%d, size=%d, entsize=%d, shndx=%d]", + elf->num, elf->size, elf->entsize, elf->shndx); + break; + } + case MULTIBOOT_TAG_TYPE_APM: + { + multiboot_tag_apm *apm = (multiboot_tag_apm *)Tag; + fixme("apm->[version: %d, cseg: %d, offset: %d, cseg_16: %d, dseg: %d, flags: %d, cseg_len: %d, cseg_16_len: %d, dseg_len: %d]", + apm->version, apm->cseg, apm->offset, apm->cseg_16, apm->dseg, apm->flags, apm->cseg_len, apm->cseg_16_len, apm->dseg_len); + break; + } + case MULTIBOOT_TAG_TYPE_EFI32: + { + multiboot_tag_efi32 *efi32 = (multiboot_tag_efi32 *)Tag; + fixme("efi32->[pointer: %p, size: %d]", efi32->pointer, efi32->size); + break; + } + case MULTIBOOT_TAG_TYPE_EFI64: + { + multiboot_tag_efi64 *efi64 = (multiboot_tag_efi64 *)Tag; + fixme("efi64->[pointer: %p, size: %d]", efi64->pointer, efi64->size); + break; + } + case MULTIBOOT_TAG_TYPE_SMBIOS: + { + multiboot_tag_smbios *smbios = (multiboot_tag_smbios *)Tag; + fixme("smbios->[major: %d, minor: %d]", smbios->major, smbios->minor); + break; + } + case MULTIBOOT_TAG_TYPE_ACPI_OLD: + { + mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_old_acpi *)Tag)->rsdp; + debug("OLD ACPI RSDP: %p", mb2binfo.RSDP); + break; + } + case MULTIBOOT_TAG_TYPE_ACPI_NEW: + { + mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_new_acpi *)Tag)->rsdp; + debug("NEW ACPI RSDP: %p", mb2binfo.RSDP); + break; + } + case MULTIBOOT_TAG_TYPE_NETWORK: + { + multiboot_tag_network *net = (multiboot_tag_network *)Tag; + fixme("network->[dhcpack: %p]", net->dhcpack); + break; + } + case MULTIBOOT_TAG_TYPE_EFI_MMAP: + { + multiboot_tag_efi_mmap *efi_mmap = (multiboot_tag_efi_mmap *)Tag; + fixme("efi_mmap->[descr_size: %d, descr_vers: %d, efi_mmap: %p]", + efi_mmap->descr_size, efi_mmap->descr_vers, efi_mmap->efi_mmap); + break; + } + case MULTIBOOT_TAG_TYPE_EFI_BS: + { + fixme("efi_bs->[%p] (unknown structure)", Tag); + break; + } + case MULTIBOOT_TAG_TYPE_EFI32_IH: + { + multiboot_tag_efi32_ih *efi32_ih = (multiboot_tag_efi32_ih *)Tag; + fixme("efi32_ih->[pointer: %p]", efi32_ih->pointer); + break; + } + case MULTIBOOT_TAG_TYPE_EFI64_IH: + { + multiboot_tag_efi64_ih *efi64_ih = (multiboot_tag_efi64_ih *)Tag; + fixme("efi64_ih->[pointer: %p]", efi64_ih->pointer); + break; + } + case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR: + { + multiboot_tag_load_base_addr *load_base_addr = (multiboot_tag_load_base_addr *)Tag; + mb2binfo.Kernel.PhysicalBase = (void *)load_base_addr->load_base_addr; + mb2binfo.Kernel.VirtualBase = (void *)(load_base_addr->load_base_addr + 0xC0000000); + debug("Kernel base: %p (physical) %p (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase); + break; + } + default: + { + error("Unknown multiboot2 tag type: %d", Tag->type); + break; + } + } + } +} + +EXTERNC void Multiboot2Entry(unsigned long Info, unsigned int Magic) +{ + if (Info == NULL || Magic == NULL) + { + if (Magic == NULL) + error("Multiboot magic is NULL"); + if (Info == NULL) + error("Multiboot info is NULL"); + CPU::Stop(); + } + else if (Magic != MULTIBOOT2_BOOTLOADER_MAGIC) + { + error("Multiboot magic is invalid (%#x != %#x)", Magic, MULTIBOOT2_BOOTLOADER_MAGIC); + CPU::Stop(); + } + + uint64_t div = 1193180 / 1000; + outb(0x43, 0xB6); + outb(0x42, (uint8_t)div); + outb(0x42, (uint8_t)(div >> 8)); + uint8_t tmp = inb(0x61); + if (tmp != (tmp | 3)) + outb(0x61, tmp | 3); + + ProcessMB2(Info); + + tmp = inb(0x61) & 0xFC; + outb(0x61, tmp); + + CPU::Stop(); + Entry(&mb2binfo); +} diff --git a/Architecture/amd64/linker.ld b/Architecture/amd64/linker.ld index 357c4cdc..9407e8ba 100644 --- a/Architecture/amd64/linker.ld +++ b/Architecture/amd64/linker.ld @@ -1,35 +1,45 @@ OUTPUT_FORMAT(elf64-x86-64) OUTPUT_ARCH(i386:x86-64) -ENTRY(_start) +KERNEL_LMA = 16M; +KERNEL_VMA = 0xFFFFFFFF80000000; + +ENTRY(MB2_start) SECTIONS { - . = 0xffffffff80000000; + . = KERNEL_LMA; + + .multiboot2 : + { + *(.multiboot2 .multiboot2.*) + } + + . += KERNEL_VMA; _kernel_start = .; - .text : + .text : AT(ADDR(.text) - KERNEL_VMA) { *(.text .text.*) } _kernel_text_end = ALIGN(CONSTANT(MAXPAGESIZE)); . += CONSTANT(MAXPAGESIZE); - .data : + .data : AT(ADDR(.data) - KERNEL_VMA) { *(.data .data.*) } _kernel_data_end = ALIGN(CONSTANT(MAXPAGESIZE)); . += CONSTANT(MAXPAGESIZE); - .rodata : + .rodata : AT(ADDR(.rodata) - KERNEL_VMA) { *(.rodata .rodata.*) } _kernel_rodata_end = ALIGN(CONSTANT(MAXPAGESIZE)); . += CONSTANT(MAXPAGESIZE); - .init_array : + .init_array : AT(ADDR(.init_array) - KERNEL_VMA) { PROVIDE_HIDDEN(__init_array_start = .); KEEP(*(.init_array .ctors)) @@ -37,7 +47,7 @@ SECTIONS PROVIDE_HIDDEN (__init_array_end = .); } - .fini_array : + .fini_array : AT(ADDR(.fini_array) - KERNEL_VMA) { PROVIDE_HIDDEN(__fini_array_start = .); KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) @@ -46,7 +56,7 @@ SECTIONS } . += CONSTANT(MAXPAGESIZE); - .bss : + .bss : AT(ADDR(.bss) - KERNEL_VMA) { *(COMMON) *(.bss .bss.*)