From 9efb41e05f4ca77c49b69e8593429d4bf094ab05 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 13 Apr 2024 13:33:45 -0400 Subject: [PATCH 01/20] UEFI-only - Update build script - Remove MBR and multiboot files - Update uefi.asm to stay in 64-bit mode - Update pure64.asm to remove 32-bit code --- build.sh | 6 +- src/boot/mbr.asm | 267 ---------------------------------------- src/boot/multiboot.asm | 110 ----------------- src/boot/multiboot2.asm | 55 --------- src/boot/pxestart.asm | 233 ----------------------------------- src/boot/uefi.asm | 109 ++++------------ src/init/acpi.asm | 7 +- src/pure64.asm | 137 ++++----------------- 8 files changed, 50 insertions(+), 874 deletions(-) delete mode 100644 src/boot/mbr.asm delete mode 100644 src/boot/multiboot.asm delete mode 100644 src/boot/multiboot2.asm delete mode 100644 src/boot/pxestart.asm diff --git a/build.sh b/build.sh index 8606352..4db2e06 100755 --- a/build.sh +++ b/build.sh @@ -8,10 +8,6 @@ nasm pure64.asm -o ../bin/pure64.sys -l ../bin/pure64-debug.txt cd boot -nasm mbr.asm -o ../../bin/mbr.sys -nasm pxestart.asm -o ../../bin/pxestart.sys -nasm multiboot.asm -o ../../bin/multiboot.sys -nasm multiboot2.asm -o ../../bin/multiboot2.sys -nasm uefi.asm -o ../../bin/uefi.sys +nasm uefi.asm -o ../../bin/uefi.sys -l ../../bin/uefi-debug.txt cd ../.. diff --git a/src/boot/mbr.asm b/src/boot/mbr.asm deleted file mode 100644 index 03e7ba1..0000000 --- a/src/boot/mbr.asm +++ /dev/null @@ -1,267 +0,0 @@ -; ============================================================================= -; Pure64 MBR -- a 64-bit OS/software loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2024 Return Infinity -- see LICENSE.TXT -; -; This Master Boot Record will load Pure64 from a pre-defined location on the -; hard drive without making use of the file system. -; -; In this code we are expecting a BMFS-formatted drive. With BMFS the Pure64 -; binary is required to start at sector 16 (8192 bytes from the start). A small -; check is made to make sure Pure64 was loaded by comparing a signature. -; ============================================================================= - -; Default location of the second stage boot loader. This loads -; 32 KiB from sector 16 into memory at 0x8000 -%define DAP_SECTORS 64 -%define DAP_STARTSECTOR 16 -%define DAP_ADDRESS 0x8000 -%define DAP_SEGMENT 0x0000 - - -BITS 16 -org 0x7C00 - -entry: - cli ; Disable interrupts - cld ; Clear direction flag - xor eax, eax - mov ss, ax - mov es, ax - mov ds, ax - mov sp, 0x7C00 - sti ; Enable interrupts - - mov [DriveNumber], dl ; BIOS passes drive number in DL - - mov ah, 0 - mov al, 11100011b ; 9600bps, no parity, 1 stop bit, 8 data bits - mov dx, 0 ; Serial port 0 - int 0x14 ; Configure serial port - -; Get the BIOS E820 Memory Map -; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map -; inputs: es:di -> destination buffer for 24 byte entries -; outputs: bp = entry count, trashes all registers except esi -do_e820: - mov edi, 0x00006000 ; location that memory map will be stored to - xor ebx, ebx ; ebx must be 0 to start - xor bp, bp ; keep an entry count in bp - mov edx, 0x0534D4150 ; Place "SMAP" into edx - mov eax, 0xe820 - mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry - mov ecx, 24 ; ask for 24 bytes - int 0x15 - jc nomemmap ; carry set on first call means "unsupported function" - mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register? - cmp eax, edx ; on success, eax must have been reset to "SMAP" - jne nomemmap - test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) - je nomemmap - jmp jmpin -e820lp: - mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call - mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry - mov ecx, 24 ; ask for 24 bytes again - int 0x15 - jc memmapend ; carry set means "end of list already reached" - mov edx, 0x0534D4150 ; repair potentially trashed register -jmpin: - jcxz skipent ; skip any 0 length entries - cmp cl, 20 ; got a 24 byte ACPI 3.X response? - jbe notext - test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? - je skipent -notext: - mov ecx, [es:di + 8] ; get lower dword of memory region length - test ecx, ecx ; is the qword == 0? - jne goodent - mov ecx, [es:di + 12] ; get upper dword of memory region length - jecxz skipent ; if length qword is 0, skip entry -goodent: - inc bp ; got a good entry: ++count, move to next storage spot - add di, 32 -skipent: - test ebx, ebx ; if ebx resets to 0, list is complete - jne e820lp -nomemmap: -; mov byte [cfg_e820], 0 ; No memory map function -memmapend: - xor eax, eax ; Create a blank record for termination (32 bytes) - mov ecx, 8 - rep stosd - -; Enable the A20 gate -set_A20: - in al, 0x64 - test al, 0x02 - jnz set_A20 - mov al, 0xD1 - out 0x64, al -check_A20: - in al, 0x64 - test al, 0x02 - jnz check_A20 - mov al, 0xDF - out 0x60, al - - mov si, msg_Load - call print_string_16 - - mov cx, 0x4000 - 1 ; Start looking from here -VBESearch: - inc cx - cmp cx, 0x5000 - je halt - mov edi, VBEModeInfoBlock ; VBE data will be stored at this address - mov ax, 0x4F01 ; GET SuperVGA MODE INFORMATION - http://www.ctyme.com/intr/rb-0274.htm - - mov bx, cx ; Mode is saved to BX for the set command later - int 0x10 - cmp ax, 0x004F ; Return value in AX should equal 0x004F if command supported and successful - jne VBESearch ; Try next mode - cmp byte [VBEModeInfoBlock.BitsPerPixel], 32 ; Desired bit depth - jne VBESearch ; If not equal, try next mode - cmp word [VBEModeInfoBlock.XResolution], 800 ; Desired XRes here - jne VBESearch - cmp word [VBEModeInfoBlock.YResolution], 600 ; Desired YRes here - jne VBESearch - - or bx, 0x4000 ; Use linear/flat frame buffer model (set bit 14) - mov ax, 0x4F02 ; SET SuperVGA VIDEO MODE - http://www.ctyme.com/intr/rb-0275.htm - int 0x10 - cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and successful - jne halt - - ; Read the 2nd stage boot loader into memory. - mov ah, 0x42 ; Extended Read - mov dl, [DriveNumber] ; http://www.ctyme.com/intr/rb-0708.htm - mov si, DAP - int 0x13 - jc read_fail - - ; Verify that the 2nd stage boot loader was read. - mov ax, [0x8006] - cmp ax, 0x3436 ; Match against the Pure64 binary - jne sig_fail - - mov si, msg_OK - call print_string_16 - - ; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. - cli ; No more interrupts - lgdt [cs:GDTR32] ; Load GDT register - mov eax, cr0 - or al, 0x01 ; Set protected mode bit - mov cr0, eax - jmp 8:0x8000 ; Jump to 32-bit protected mode - -read_fail: - mov si, msg_ReadFail - call print_string_16 - jmp halt -sig_fail: - mov si, msg_SigFail - call print_string_16 -halt: - hlt - jmp halt -;------------------------------------------------------------------------------ - - -;------------------------------------------------------------------------------ -; 16-bit function to output a string to the serial port -; IN: SI - Address of start of string -print_string_16: ; Output string in SI to screen - pusha - mov dx, 0 ; Port 0 -.repeat: - mov ah, 0x01 ; Serial - Write character to port - lodsb ; Get char from string - cmp al, 0 - je .done ; If char is zero, end of string - int 0x14 ; Output the character - jmp short .repeat -.done: - popa - ret -;------------------------------------------------------------------------------ - -align 16 -GDTR32: ; Global Descriptors Table Register -dw gdt32_end - gdt32 - 1 ; limit of GDT (size minus one) -dq gdt32 ; linear address of GDT - -align 16 -gdt32: -dw 0x0000, 0x0000, 0x0000, 0x0000 ; Null descriptor -dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; 32-bit code descriptor -dw 0xFFFF, 0x0000, 0x9200, 0x00CF ; 32-bit data descriptor -gdt32_end: - -msg_Load db 10, "MBR ", 0 -msg_OK db "OK", 0 -msg_SigFail db "- Bad Sig!", 0 -msg_ReadFail db "Failed to read drive!", 0 - -times 446-$+$$ db 0 - -; False partition table entry required by some BIOS vendors. -db 0x80, 0x00, 0x01, 0x00, 0xEB, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF -DriveNumber db 0x00 - -times 476-$+$$ db 0 - -align 4 - -DAP: - db 0x10 - db 0x00 - dw DAP_SECTORS - dw DAP_ADDRESS - dw DAP_SEGMENT - dq DAP_STARTSECTOR - -times 510-$+$$ db 0 - -sign dw 0xAA55 - -VBEModeInfoBlock: equ 0x5F00 -; VESA -; Mandatory information for all VBE revisions -VBEModeInfoBlock.ModeAttributes equ VBEModeInfoBlock + 0 ; DW - mode attributes -VBEModeInfoBlock.WinAAttributes equ VBEModeInfoBlock + 2 ; DB - window A attributes -VBEModeInfoBlock.WinBAttributes equ VBEModeInfoBlock + 3 ; DB - window B attributes -VBEModeInfoBlock.WinGranularity equ VBEModeInfoBlock + 4 ; DW - window granularity in KB -VBEModeInfoBlock.WinSize equ VBEModeInfoBlock + 6 ; DW - window size in KB -VBEModeInfoBlock.WinASegment equ VBEModeInfoBlock + 8 ; DW - window A start segment -VBEModeInfoBlock.WinBSegment equ VBEModeInfoBlock + 10 ; DW - window B start segment -VBEModeInfoBlock.WinFuncPtr equ VBEModeInfoBlock + 12 ; DD - real mode pointer to window function -VBEModeInfoBlock.BytesPerScanLine equ VBEModeInfoBlock + 16 ; DW - bytes per scan line -; Mandatory information for VBE 1.2 and above -VBEModeInfoBlock.XResolution equ VBEModeInfoBlock + 18 ; DW - horizontal resolution in pixels or characters -VBEModeInfoBlock.YResolution equ VBEModeInfoBlock + 20 ; DW - vertical resolution in pixels or characters -VBEModeInfoBlock.XCharSize equ VBEModeInfoBlock + 22 ; DB - character cell width in pixels -VBEModeInfoBlock.YCharSize equ VBEModeInfoBlock + 23 ; DB - character cell height in pixels -VBEModeInfoBlock.NumberOfPlanes equ VBEModeInfoBlock + 24 ; DB - number of memory planes -VBEModeInfoBlock.BitsPerPixel equ VBEModeInfoBlock + 25 ; DB - bits per pixel -VBEModeInfoBlock.NumberOfBanks equ VBEModeInfoBlock + 26 ; DB - number of banks -VBEModeInfoBlock.MemoryModel equ VBEModeInfoBlock + 27 ; DB - memory model type -VBEModeInfoBlock.BankSize equ VBEModeInfoBlock + 28 ; DB - bank size in KB -VBEModeInfoBlock.NumberOfImagePages equ VBEModeInfoBlock + 29 ; DB - number of image pages -VBEModeInfoBlock.Reserved equ VBEModeInfoBlock + 30 ; DB - reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) -; Direct Color fields (required for direct/6 and YUV/7 memory models) -VBEModeInfoBlock.RedMaskSize equ VBEModeInfoBlock + 31 ; DB - size of direct color red mask in bits -VBEModeInfoBlock.RedFieldPosition equ VBEModeInfoBlock + 32 ; DB - bit position of lsb of red mask -VBEModeInfoBlock.GreenMaskSize equ VBEModeInfoBlock + 33 ; DB - size of direct color green mask in bits -VBEModeInfoBlock.GreenFieldPosition equ VBEModeInfoBlock + 34 ; DB - bit position of lsb of green mask -VBEModeInfoBlock.BlueMaskSize equ VBEModeInfoBlock + 35 ; DB - size of direct color blue mask in bits -VBEModeInfoBlock.BlueFieldPosition equ VBEModeInfoBlock + 36 ; DB - bit position of lsb of blue mask -VBEModeInfoBlock.RsvdMaskSize equ VBEModeInfoBlock + 37 ; DB - size of direct color reserved mask in bits -VBEModeInfoBlock.RsvdFieldPosition equ VBEModeInfoBlock + 38 ; DB - bit position of lsb of reserved mask -VBEModeInfoBlock.DirectColorModeInfo equ VBEModeInfoBlock + 39 ; DB - direct color mode attributes -; Mandatory information for VBE 2.0 and above -VBEModeInfoBlock.PhysBasePtr equ VBEModeInfoBlock + 40 ; DD - physical address for flat memory frame buffer -VBEModeInfoBlock.Reserved1 equ VBEModeInfoBlock + 44 ; DD - Reserved - always set to 0 -VBEModeInfoBlock.Reserved2 equ VBEModeInfoBlock + 48 ; DD - Reserved - always set to 0 - -; EOF diff --git a/src/boot/multiboot.asm b/src/boot/multiboot.asm deleted file mode 100644 index 33e7199..0000000 --- a/src/boot/multiboot.asm +++ /dev/null @@ -1,110 +0,0 @@ -; ============================================================================= -; Pure64 Multiboot -- a 64-bit OS/software loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2024 Return Infinity -- see LICENSE.TXT -; -; http://stackoverflow.com/questions/33488194/creating-a-simple-multiboot-kernel-loaded-with-grub2 -; https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#OS-image-format -; ============================================================================= - - -[BITS 32] -[global _start] -[ORG 0x100000] ;If using '-f bin' we need to specify the - ;origin point for our code with ORG directive - ;multiboot loaders load us at physical - ;address 0x100000 - -FLAG_ALIGN equ 1<<0 ; align loaded modules on page boundaries -FLAG_MEMINFO equ 1<<1 ; provide memory map -FLAG_VIDEO equ 1<<2 ; set video mode -FLAG_AOUT_KLUDGE equ 1<<16 - ;FLAGS[16] indicates to GRUB we are not - ;an ELF executable and the fields - ;header address, load address, load end address; - ;bss end address and entry address will be available - ;in Multiboot header - -MAGIC equ 0x1BADB002 - ;magic number GRUB searches for in the first 8k - ;of the kernel file GRUB is told to load - -FLAGS equ FLAG_ALIGN | FLAG_MEMINFO | FLAG_VIDEO | FLAG_AOUT_KLUDGE -CHECKSUM equ -(MAGIC + FLAGS) - -mode_type equ 0 ; Linear -width equ 1024 -height equ 768 -depth equ 24 - -_start: ; We need some code before the multiboot header - xor eax, eax ; Clear eax and ebx in the event - xor ebx, ebx ; we are not loaded by GRUB. - jmp multiboot_entry ; Jump over the multiboot header - align 4 ; Multiboot header must be 32-bit aligned - -multiboot_header: - dd MAGIC ; magic - dd FLAGS ; flags - dd CHECKSUM ; checksum - dd multiboot_header ; header address - dd _start ; load address of code entry point - dd 0x00 ; load end address : not necessary - dd 0x00 ; bss end address : not necessary - dd multiboot_entry ; entry address GRUB will start at - dd mode_type - dd width - dd height - dd depth - -align 16 - -multiboot_entry: - push 0 - popf - cld ; Clear direction flag - -; Copy memory map - mov esi, ebx ; GRUB stores the Multiboot info table at the address in EBX - mov edi, 0x6000 ; We want the memory map stored here - add esi, 44 ; Memory map address at this offset in the Mutliboot table - lodsd ; Grab the memory map size in bytes - mov ecx, eax - lodsd ; Grab the memory map address - mov esi, eax - -memmap_entry: - lodsd ; Size of entry - cmp eax, 0 - je memmap_end - movsd ; base_addr_low - movsd ; base_addr_high - movsd ; length_low - movsd ; length_high - movsd ; type - xor eax, eax - stosd ; padding - stosd - stosd - jmp memmap_entry - -memmap_end: - xor eax, eax - mov ecx, 8 - rep stosd - -; Copy loader and kernel to expected location - mov esi, multiboot_end - mov edi, 0x00008000 - mov ecx, 8192 ; Copy 32K - rep movsd ; Copy loader to expected address - - cli - - jmp 0x00008000 - -times 512-$+$$ db 0 ; Padding - -multiboot_end: - -; ============================================================================= -; EOF diff --git a/src/boot/multiboot2.asm b/src/boot/multiboot2.asm deleted file mode 100644 index bee725b..0000000 --- a/src/boot/multiboot2.asm +++ /dev/null @@ -1,55 +0,0 @@ -; ============================================================================= -; Pure64 Multiboot 2 -- a 64-bit OS/software loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2024 Return Infinity -- see LICENSE.TXT -; -; http://nongnu.askapache.com/grub/phcoder/multiboot.pdf -; ============================================================================= - - -[BITS 32] -[global _start] -[ORG 0x100000] ;If using '-f bin' we need to specify the - ;origin point for our code with ORG directive - ;multiboot loaders load us at physical - ;address 0x100000 - -MAGIC equ 0xE85250D6 -ARCHITECHTURE equ 0 -HEADER_LENGTH equ multiboot_header_end - multiboot_header_start -CHECKSUM equ 0x100000000 - (MAGIC + ARCHITECHTURE + HEADER_LENGTH) - -_start: ; We need some code before the multiboot header - xor eax, eax ; Clear eax and ebx in the event - xor ebx, ebx ; we are not loaded by GRUB. - jmp multiboot_entry ; Jump over the multiboot header - align 8 ; Multiboot 2 header must be 64-bit aligned - -multiboot_header_start: - dd MAGIC - dd ARCHITECHTURE - dd HEADER_LENGTH - dd CHECKSUM -entry_address_tag_start: - dw 3 - dw 0 - dd entry_address_tag_end - entry_address_tag_start - dq multiboot_entry -entry_address_tag_end: -framebuffer_tag_start: - dw 5 - dw 0 - dd framebuffer_tag_end - framebuffer_tag_start - dd 800 - dd 600 - dd 32 -framebuffer_tag_end: - dw 0 ; End type - dw 0 - dd 8 -multiboot_header_end: - -multiboot_entry: - cmp eax, 0x36D76289 ; Magic value - jne error -error: - jmp $ diff --git a/src/boot/pxestart.asm b/src/boot/pxestart.asm deleted file mode 100644 index 67667ae..0000000 --- a/src/boot/pxestart.asm +++ /dev/null @@ -1,233 +0,0 @@ -; ============================================================================= -; Pure64 PXE Start -- a 64-bit OS/software loader written in Assembly for x86-64 systems -; Copyright (C) 2008-2024 Return Infinity -- see LICENSE.TXT -; -; This is a stub file for loading Pure64 and a kernel/software package via PXE. -; -; Windows - copy /b pxestart.bin + pure64.sys + kernel64.sys pxeboot.bin -; Unix - cat pxestart.bin pure64.sys kernel64.sys > pxeboot.bin -; -; Max size of the resulting pxeboot.bin is 33792 bytes. 1K for the PXE loader -; stub and up to 32KiB for the code/data. PXE loads the file to address -; 0x00007C00 (Just like a boot sector). -; -; File Sizes -; pxestart.bin 1024 bytes -; pure64.sys 4096 bytes -; kernel64.sys 16384 bytes (or so) -; ============================================================================= - - -BITS 16 -org 0x7C00 - -start: - cli ; Disable interrupts - cld ; Clear direction flag - xor eax, eax - mov ss, ax - mov es, ax - mov ds, ax - mov sp, 0x7C00 - sti ; Enable interrupts - - mov ah, 0 - mov al, 11100011b ; 9600bps, no parity, 1 stop bit, 8 data bits - mov dx, 0 ; Serial port 0 - int 0x14 ; Configure serial port - -; Get the BIOS E820 Memory Map -; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map -; inputs: es:di -> destination buffer for 24 byte entries -; outputs: bp = entry count, trashes all registers except esi -do_e820: - mov edi, 0x00006000 ; location that memory map will be stored to - xor ebx, ebx ; ebx must be 0 to start - xor bp, bp ; keep an entry count in bp - mov edx, 0x0534D4150 ; Place "SMAP" into edx - mov eax, 0xe820 - mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry - mov ecx, 24 ; ask for 24 bytes - int 0x15 - jc nomemmap ; carry set on first call means "unsupported function" - mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register? - cmp eax, edx ; on success, eax must have been reset to "SMAP" - jne nomemmap - test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) - je nomemmap - jmp jmpin -e820lp: - mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call - mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry - mov ecx, 24 ; ask for 24 bytes again - int 0x15 - jc memmapend ; carry set means "end of list already reached" - mov edx, 0x0534D4150 ; repair potentially trashed register -jmpin: - jcxz skipent ; skip any 0 length entries - cmp cl, 20 ; got a 24 byte ACPI 3.X response? - jbe notext - test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? - je skipent -notext: - mov ecx, [es:di + 8] ; get lower dword of memory region length - test ecx, ecx ; is the qword == 0? - jne goodent - mov ecx, [es:di + 12] ; get upper dword of memory region length - jecxz skipent ; if length qword is 0, skip entry -goodent: - inc bp ; got a good entry: ++count, move to next storage spot - add di, 32 -skipent: - test ebx, ebx ; if ebx resets to 0, list is complete - jne e820lp -nomemmap: -; mov byte [cfg_e820], 0 ; No memory map function -memmapend: - xor eax, eax ; Create a blank record for termination (32 bytes) - mov ecx, 8 - rep stosd - -; Enable the A20 gate -set_A20: - in al, 0x64 - test al, 0x02 - jnz set_A20 - mov al, 0xD1 - out 0x64, al -check_A20: - in al, 0x64 - test al, 0x02 - jnz check_A20 - mov al, 0xDF - out 0x60, al - - mov si, msg_Load ; Print message - call print_string_16 - - mov edi, VBEModeInfoBlock ; VBE data will be stored at this address - mov ax, 0x4F01 ; GET SuperVGA MODE INFORMATION - http://www.ctyme.com/intr/rb-0274.htm - ; CX queries the mode, it should be in the form 0x41XX as bit 14 is set for LFB and bit 8 is set for VESA mode - ; 0x4112 is 640x480x24bit, 0x4129 should be 32bit - ; 0x4115 is 800x600x24bit, 0x412E should be 32bit - ; 0x4118 is 1024x768x24bit, 0x4138 should be 32bit - ; 0x411B is 1280x1024x24bit, 0x413D should be 32bit - mov cx, 0x4118 ; Put your desired mode here - mov bx, cx ; Mode is saved to BX for the set command later - int 0x10 - - cmp ax, 0x004F ; Return value in AX should equal 0x004F if command supported and successful - jne halt - cmp byte [VBEModeInfoBlock.BitsPerPixel], 24 ; Make sure this matches the number of bits for the mode! - jne halt ; If set bit mode was unsuccessful then bail out - or bx, 0x4000 ; Use linear/flat frame buffer model (set bit 14) - mov ax, 0x4F02 ; SET SuperVGA VIDEO MODE - http://www.ctyme.com/intr/rb-0275.htm - int 0x10 - cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and successful - jne halt - - mov ax, [0x8006] - cmp ax, 0x3436 ; Match against the Pure64 binary - jne sig_fail - - mov si, msg_OK - call print_string_16 - -; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. - cli ; No more interrupts - lgdt [cs:GDTR32] ; Load GDT register - mov eax, cr0 - or al, 0x01 ; Set protected mode bit - mov cr0, eax - jmp 8:0x8000 ; Jump to 32-bit protected mode - -sig_fail: - mov si, msg_SigFail - call print_string_16 -halt: - hlt - jmp halt -;------------------------------------------------------------------------------ - - -;------------------------------------------------------------------------------ -; 16-bit function to output a string to the serial port -; IN: SI - Address of start of string -print_string_16: ; Output string in SI to screen - pusha - mov dx, 0 ; Port 0 -.repeat: - mov ah, 0x01 ; Serial - Write character to port - lodsb ; Get char from string - cmp al, 0 - je .done ; If char is zero, end of string - int 0x14 ; Output the character - jmp short .repeat -.done: - popa - ret -;------------------------------------------------------------------------------ - - -align 16 -GDTR32: ; Global Descriptors Table Register -dw gdt32_end - gdt32 - 1 ; limit of GDT (size minus one) -dq gdt32 ; linear address of GDT - -align 16 -gdt32: -dw 0x0000, 0x0000, 0x0000, 0x0000 ; Null desciptor -dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; 32-bit code descriptor -dw 0xFFFF, 0x0000, 0x9200, 0x00CF ; 32-bit data descriptor -gdt32_end: - -msg_Load db "PXE ", 0 -msg_OK db "OK", 0 -msg_SigFail db "- Bad Sig!", 0 - -times 510-$+$$ db 0 ; Pad out for a normal boot sector - -sign dw 0xAA55 ; BIOS boot sector signature - -times 1024-$+$$ db 0 ; Padding so that Pure64 will be aligned at 0x8000 - -VBEModeInfoBlock: equ 0x5F00 -; VESA -; Mandatory information for all VBE revisions -VBEModeInfoBlock.ModeAttributes equ VBEModeInfoBlock + 0 ; DW - mode attributes -VBEModeInfoBlock.WinAAttributes equ VBEModeInfoBlock + 2 ; DB - window A attributes -VBEModeInfoBlock.WinBAttributes equ VBEModeInfoBlock + 3 ; DB - window B attributes -VBEModeInfoBlock.WinGranularity equ VBEModeInfoBlock + 4 ; DW - window granularity in KB -VBEModeInfoBlock.WinSize equ VBEModeInfoBlock + 6 ; DW - window size in KB -VBEModeInfoBlock.WinASegment equ VBEModeInfoBlock + 8 ; DW - window A start segment -VBEModeInfoBlock.WinBSegment equ VBEModeInfoBlock + 10 ; DW - window B start segment -VBEModeInfoBlock.WinFuncPtr equ VBEModeInfoBlock + 12 ; DD - real mode pointer to window function -VBEModeInfoBlock.BytesPerScanLine equ VBEModeInfoBlock + 16 ; DW - bytes per scan line -; Mandatory information for VBE 1.2 and above -VBEModeInfoBlock.XResolution equ VBEModeInfoBlock + 18 ; DW - horizontal resolution in pixels or characters -VBEModeInfoBlock.YResolution equ VBEModeInfoBlock + 20 ; DW - vertical resolution in pixels or characters -VBEModeInfoBlock.XCharSize equ VBEModeInfoBlock + 22 ; DB - character cell width in pixels -VBEModeInfoBlock.YCharSize equ VBEModeInfoBlock + 23 ; DB - character cell height in pixels -VBEModeInfoBlock.NumberOfPlanes equ VBEModeInfoBlock + 24 ; DB - number of memory planes -VBEModeInfoBlock.BitsPerPixel equ VBEModeInfoBlock + 25 ; DB - bits per pixel -VBEModeInfoBlock.NumberOfBanks equ VBEModeInfoBlock + 26 ; DB - number of banks -VBEModeInfoBlock.MemoryModel equ VBEModeInfoBlock + 27 ; DB - memory model type -VBEModeInfoBlock.BankSize equ VBEModeInfoBlock + 28 ; DB - bank size in KB -VBEModeInfoBlock.NumberOfImagePages equ VBEModeInfoBlock + 29 ; DB - number of image pages -VBEModeInfoBlock.Reserved equ VBEModeInfoBlock + 30 ; DB - reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) -; Direct Color fields (required for direct/6 and YUV/7 memory models) -VBEModeInfoBlock.RedMaskSize equ VBEModeInfoBlock + 31 ; DB - size of direct color red mask in bits -VBEModeInfoBlock.RedFieldPosition equ VBEModeInfoBlock + 32 ; DB - bit position of lsb of red mask -VBEModeInfoBlock.GreenMaskSize equ VBEModeInfoBlock + 33 ; DB - size of direct color green mask in bits -VBEModeInfoBlock.GreenFieldPosition equ VBEModeInfoBlock + 34 ; DB - bit position of lsb of green mask -VBEModeInfoBlock.BlueMaskSize equ VBEModeInfoBlock + 35 ; DB - size of direct color blue mask in bits -VBEModeInfoBlock.BlueFieldPosition equ VBEModeInfoBlock + 36 ; DB - bit position of lsb of blue mask -VBEModeInfoBlock.RsvdMaskSize equ VBEModeInfoBlock + 37 ; DB - size of direct color reserved mask in bits -VBEModeInfoBlock.RsvdFieldPosition equ VBEModeInfoBlock + 38 ; DB - bit position of lsb of reserved mask -VBEModeInfoBlock.DirectColorModeInfo equ VBEModeInfoBlock + 39 ; DB - direct color mode attributes -; Mandatory information for VBE 2.0 and above -VBEModeInfoBlock.PhysBasePtr equ VBEModeInfoBlock + 40 ; DD - physical address for flat memory frame buffer -VBEModeInfoBlock.Reserved1 equ VBEModeInfoBlock + 44 ; DD - Reserved - always set to 0 -VBEModeInfoBlock.Reserved2 equ VBEModeInfoBlock + 48 ; DD - Reserved - always set to 0 - -; EOF diff --git a/src/boot/uefi.asm b/src/boot/uefi.asm index 9804d61..e9ccc6f 100644 --- a/src/boot/uefi.asm +++ b/src/boot/uefi.asm @@ -12,8 +12,8 @@ ; ============================================================================= ; Set the desired screen resolution values below -Horizontal_Resolution equ 640 -Vertical_Resolution equ 480 +Horizontal_Resolution equ 800 +Vertical_Resolution equ 600 BITS 64 ORG 0x00400000 @@ -126,7 +126,7 @@ EntryPoint: ; Set screen colour attributes mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This - mov rdx, 0x7F ; IN UINTN Attribute Light grey background, white foreground + mov rdx, 0x07 ; IN UINTN Attribute Light black background, grey foreground call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_SET_ATTRIBUTE] ; Clear screen @@ -185,7 +185,7 @@ next_video_mode: mov rdx, [vid_max] cmp rax, rdx je skip_set_video ; If we have reached the max then bail out - + vid_query: ; Query a video mode mov rcx, [VIDEO] ; IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This @@ -243,10 +243,6 @@ skip_set_video: cmp ax, 0x3436 ; Match against the Pure64 binary jne sig_fail - ; Signal to Pure64 that it was booted via UEFI - mov al, 'U' - mov [0x8005], al - ; Save video values to the area of memory where Pure64 expects them mov rdi, 0x00005C00 + 40 ; VBEModeInfoBlock.PhysBasePtr mov rax, [FB] @@ -300,62 +296,26 @@ get_memmap: ; Stop interrupts cli - ; Build a 32-bit memory table for 4GiB of identity mapped memory - mov rdi, 0x200000 - mov rax, 0x00000083 - mov rcx, 1024 -nextpage: - stosd - add rax, 0x400000 - dec rcx - cmp rcx, 0 - jne nextpage - - ; Load the custom GDT - lgdt [gdtr] - - ; Switch to compatibility mode - mov rax, SYS32_CODE_SEL ; Compatibility mode - push rax - lea rax, [compatmode] - push rax - retfq - -BITS 32 -compatmode: - ; Set the segment registers - mov eax, SYS32_DATA_SEL - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - ; Deactivate IA-32e mode by clearing CR0.PG - mov eax, cr0 - btc eax, 31 ; Clear PG (Bit 31) - mov cr0, eax - - ; Load CR3 - mov eax, 0x00200000 ; Address of memory map - mov cr3, eax - - ; Disable IA-32e mode by setting IA32_EFER.LME = 0 - mov ecx, 0xC0000080 ; EFER MSR number - rdmsr ; Read EFER - and eax, 0xFFFFFEFF ; Clear LME (Bit 8) - wrmsr ; Write EFER - - mov eax, 0x00000010 ; Set PSE (Bit 4) - mov cr4, eax - - ; Enable legacy paged-protected mode by setting CR0.PG - mov eax, 0x00000001 ; Set PM (Bit 0) - mov cr0, eax - - jmp SYS32_CODE_SEL:0x8000 ; 32-bit jump to set CS + ; Clear registers + xor eax, eax ; aka r0 + xor ecx, ecx ; aka r1 + xor edx, edx ; aka r2 + xor ebx, ebx ; aka r3 + mov rsp, 0x8000 ; aka r4 + xor ebp, ebp ; aka r5 + xor esi, esi ; aka r6 + xor edi, edi ; aka r7 + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + jmp 0x8000 -BITS 64 exitfailure: mov rdi, [FB] mov eax, 0x00FF0000 ; Red @@ -417,26 +377,7 @@ db 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a hextable: db '0123456789ABCDEF' msg_error: dw u('Error'), 0 msg_SigFail: dw u('Bad Sig!'), 0 -msg_OK: dw u('OK'), 0 - -align 16 -gdtr: ; Global Descriptors Table Register -dw gdt_end - gdt - 1 ; limit of GDT (size minus one) -dq gdt ; linear address of GDT - -align 16 -gdt: -SYS64_NULL_SEL equ $-gdt ; Null Segment -dq 0x0000000000000000 -SYS32_CODE_SEL equ $-gdt ; 32-bit code descriptor -dq 0x00CF9A000000FFFF ; 55 Granularity 4KiB, 54 Size 32bit, 47 Present, 44 Code/Data, 43 Executable, 41 Readable -SYS32_DATA_SEL equ $-gdt ; 32-bit data descriptor -dq 0x00CF92000000FFFF ; 55 Granularity 4KiB, 54 Size 32bit, 47 Present, 44 Code/Data, 41 Writeable -SYS64_CODE_SEL equ $-gdt ; 64-bit code segment, read/execute, nonconforming -dq 0x00209A0000000000 ; 53 Long mode code, 47 Present, 44 Code/Data, 43 Executable, 41 Readable -SYS64_DATA_SEL equ $-gdt ; 64-bit data segment, read/write, expand down -dq 0x0000920000000000 ; 47 Present, 44 Code/Data, 41 Writable -gdt_end: +msg_OK: dw u('UEFI OK'), 0 align 4096 PAYLOAD: @@ -462,7 +403,7 @@ EFI_NO_MEDIA equ 12 EFI_MEDIA_CHANGED equ 13 EFI_NOT_FOUND equ 14 -EFI_SYSTEM_TABLE_CONOUT equ 64 +EFI_SYSTEM_TABLE_CONOUT equ 64 EFI_SYSTEM_TABLE_RUNTIMESERVICES equ 88 EFI_SYSTEM_TABLE_BOOTSERVICES equ 96 EFI_SYSTEM_TABLE_NUMBEROFENTRIES equ 104 diff --git a/src/init/acpi.asm b/src/init/acpi.asm index 4a3403f..e672092 100644 --- a/src/init/acpi.asm +++ b/src/init/acpi.asm @@ -7,11 +7,8 @@ init_acpi: - mov al, [p_BootMode] - cmp al, 'U' - je foundACPIfromUEFI - mov esi, 0x000E0000 ; Start looking for the Root System Description Pointer Structure - mov rbx, 'RSD PTR ' ; This in the Signature for the ACPI Structure Table (0x2052545020445352) + jmp foundACPIfromUEFI + searchingforACPI: lodsq ; Load a quad word from RSI and store in RAX, then increment RSI by 8 cmp rax, rbx diff --git a/src/pure64.asm b/src/pure64.asm index 2b2492c..e259921 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -17,12 +17,12 @@ ; ============================================================================= -BITS 32 +BITS 64 ORG 0x00008000 PURE64SIZE equ 4096 ; Pad Pure64 to this length start: - jmp start32 ; This command will be overwritten with 'NOP's before the AP's are started + jmp start64 ; This command will be overwritten with 'NOP's before the AP's are started nop db 0x36, 0x34 ; '64' marker @@ -47,30 +47,16 @@ BITS 16 %include "init/smp_ap.asm" ; AP's will start execution at 0x8000 and fall through to this code ; ============================================================================= -; 32-bit mode -BITS 32 -start32: - mov eax, 16 ; Set the correct segment registers - mov ds, ax - mov es, ax - mov ss, ax - mov fs, ax - mov gs, ax +; 64-bit mode +BITS 64 +start64: + mov esp, 0x8000 ; Set a known free location for the stack mov edi, 0x5000 ; Clear the info map and system variable memory xor eax, eax mov ecx, 960 ; 3840 bytes (Range is 0x5000 - 0x5EFF) rep stosd ; Don't overwrite the VBE data at 0x5F00 - xor eax, eax ; Clear all registers - xor ebx, ebx - xor ecx, ecx - xor edx, edx - xor esi, esi - xor edi, edi - xor ebp, ebp - mov esp, 0x8000 ; Set a known free location for the stack - ; Set up RTC ; Port 0x70 is RTC Address, and 0x71 is RTC Data ; http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt @@ -149,7 +135,7 @@ rtc_poll: mov esi, gdt64 mov edi, 0x00001000 ; GDT address mov ecx, (gdt64_end - gdt64) - rep movsb ; Move it to final pos. + rep movsb ; Copy it to final location ; Create the Page Map Level 4 Entries (PML4E) ; PML4 is stored at 0x0000000000002000, create the first entry there @@ -178,10 +164,10 @@ rtc_poll: mov eax, 0x00010007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of first low PD (4KiB aligned) create_pdpte_low: stosd - push eax + push rax xor eax, eax stosd - pop eax + pop rax add eax, 0x00001000 ; 4KiB later (512 records x 8 bytes) dec ecx cmp ecx, 0 @@ -192,51 +178,21 @@ create_pdpte_low: ; A single PDE is 8 bytes in length mov edi, 0x00010000 ; Location of first PDE mov eax, 0x0000008F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), and 7 (PS) set - xor ecx, ecx + mov ecx, 2048 ; Create 2048 2 MiB page maps. pde_low: ; Create a 2 MiB page stosd - push eax + push rax xor eax, eax stosd - pop eax + pop rax add eax, 0x00200000 ; Increment by 2MiB - inc ecx - cmp ecx, 2048 - jne pde_low ; Create 2048 2 MiB page maps. + dec ecx + cmp ecx, 0 + jne pde_low ; Load the GDT lgdt [GDTR64] -; Enable extended properties - mov eax, cr4 - or eax, 0x0000000B0 ; PGE (Bit 7), PAE (Bit 5), and PSE (Bit 4) - mov cr4, eax - -; Point cr3 at PML4 - mov eax, 0x00002008 ; Write-thru enabled (Bit 3) - mov cr3, eax - -; Enable long mode and SYSCALL/SYSRET - mov ecx, 0xC0000080 ; EFER MSR number - rdmsr ; Read EFER - or eax, 0x00000101 ; LME (Bit 8) - wrmsr ; Write EFER - -; Enable paging to activate long mode - mov eax, cr0 - or eax, 0x80000000 ; PG (Bit 31) - mov cr0, eax - - jmp SYS64_CODE_SEL:start64 ; Jump to 64-bit mode - - -align 16 - -; ============================================================================= -; 64-bit mode -BITS 64 - -start64: xor eax, eax ; aka r0 xor ebx, ebx ; aka r3 xor ecx, ecx ; aka r1 @@ -254,76 +210,27 @@ start64: xor r14, r14 xor r15, r15 - mov ds, ax ; Clear the legacy segment registers + mov ax, 0x10 ; TODO Is this needed? + mov ds, ax mov es, ax mov ss, ax mov fs, ax mov gs, ax - mov rax, clearcs64 ; Do a proper 64-bit jump. Should not be needed as the ... - jmp rax ; jmp SYS64_CODE_SEL:start64 would have sent us ... - nop ; out of compatibility mode and into 64-bit mode + ; Set CS with a far return + push SYS64_CODE_SEL + push clearcs64 + retfq clearcs64: - xor eax, eax lgdt [GDTR64] ; Reload the GDT -; Save the Boot Mode (it will be 'U' if started via UEFI) - mov al, [0x8005] - mov [p_BootMode], al ; Save the byte as a Boot Mode flag - ; Patch Pure64 AP code ; The AP's will be told to start execution at 0x8000 mov edi, start ; We need to remove the BSP Jump call to get the AP's mov eax, 0x90909090 ; to fall through to the AP Init code stosd stosd ; Write 8 bytes in total to overwrite the 'far jump' and marker - mov al, [p_BootMode] - cmp al, 'U' - je uefi_memmap -; Process the E820 memory map to find all possible 2MiB pages that are free to use -; Build a map at 0x400000 - xor ecx, ecx - xor ebx, ebx ; Counter for pages found - mov esi, 0x00006000 ; E820 Map location -nextentry: - add esi, 16 ; Skip ESI to type marker - mov eax, [esi] ; Load the 32-bit type marker - cmp eax, 0 ; End of the list? - je end820 - cmp eax, 1 ; Is it marked as free? - je processfree - add esi, 16 ; Skip ESI to start of next entry - jmp nextentry - -processfree: - sub esi, 16 - mov rax, [rsi] ; Physical start address - add esi, 8 - mov rcx, [rsi] ; Physical length - add esi, 24 - shr rcx, 21 ; Convert bytes to # of 2 MiB pages - cmp rcx, 0 ; Do we have at least 1 page? - je nextentry - shl rax, 1 - mov edx, 0x1FFFFF - not rdx ; Clear bits 20 - 0 - and rax, rdx - ; At this point RAX points to the start and RCX has the # of pages - shr rax, 21 ; page # to start on - mov rdi, 0x400000 ; 4 MiB into physical memory - add rdi, rax - mov al, 1 - add ebx, ecx - rep stosb - jmp nextentry - -end820: - shl ebx, 1 - mov dword [p_mem_amount], ebx - shr ebx, 1 - jmp memmap_end - uefi_memmap: ; TODO fix this as it is a terrible hack mov rdi, 0x400000 mov al, 1 @@ -375,7 +282,7 @@ pd_high_entry: pd_high_done: -; Build a temporary IDT +; Build the IDT xor edi, edi ; create the 64-bit IDT (at linear address 0x0000000000000000) mov rcx, 32 From ed2373125dbf347447b1bc264ccf3ab5ae5902d8 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 13 Apr 2024 13:59:43 -0400 Subject: [PATCH 02/20] Fix for CR3 not being set to the new PML4 --- src/init/smp_ap.asm | 7 +------ src/pure64.asm | 9 +++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/init/smp_ap.asm b/src/init/smp_ap.asm index 0e8f60a..b204b04 100644 --- a/src/init/smp_ap.asm +++ b/src/init/smp_ap.asm @@ -110,18 +110,13 @@ startap64: xor r14, r14 xor r15, r15 + mov ax, 0x10 ; TODO Is this needed? mov ds, ax ; Clear the legacy segment registers mov es, ax mov ss, ax mov fs, ax mov gs, ax - mov rax, clearcs64_ap - jmp rax - nop -clearcs64_ap: - xor eax, eax - ; Reset the stack. Each CPU gets a 1024-byte unique stack location mov rsi, [p_LocalAPICAddress] ; We would call p_smp_get_id here but the stack is not ... add rsi, 0x20 ; ... yet defined. It is safer to find the value directly. diff --git a/src/pure64.asm b/src/pure64.asm index e259921..cd63968 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -193,6 +193,15 @@ pde_low: ; Create a 2 MiB page ; Load the GDT lgdt [GDTR64] +; Enable extended properties +; mov eax, cr4 +; or eax, 0x0000000B0 ; PGE (Bit 7), PAE (Bit 5), and PSE (Bit 4) +; mov cr4, eax + +; Point cr3 at PML4 + mov rax, 0x00002008 ; Write-thru enabled (Bit 3) + mov cr3, rax + xor eax, eax ; aka r0 xor ebx, ebx ; aka r3 xor ecx, ecx ; aka r1 From 416622cbde38d04660b23f31482bd3301b745a14 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 13 Apr 2024 15:21:52 -0400 Subject: [PATCH 03/20] Remove legacy VBE data --- src/boot/uefi.asm | 16 ++++++++++------ src/init/acpi.asm | 4 ++++ src/pure64.asm | 13 +++++++++---- src/sysvar.asm | 39 --------------------------------------- 4 files changed, 23 insertions(+), 49 deletions(-) diff --git a/src/boot/uefi.asm b/src/boot/uefi.asm index e9ccc6f..cde34ed 100644 --- a/src/boot/uefi.asm +++ b/src/boot/uefi.asm @@ -244,17 +244,15 @@ skip_set_video: jne sig_fail ; Save video values to the area of memory where Pure64 expects them - mov rdi, 0x00005C00 + 40 ; VBEModeInfoBlock.PhysBasePtr + mov rdi, 0x00005F00 mov rax, [FB] - stosd - mov rdi, 0x00005C00 + 18 ; VBEModeInfoBlock.XResolution & .YResolution + stosq + mov rax, [FBS] + stosq mov rax, [HR] stosw mov rax, [VR] stosw - mov rdi, 0x00005C00 + 25 ; VBEModeInfoBlock.BitsPerPixel - mov rax, 32 - stosb mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This lea rdx, [msg_OK] ; IN CHAR16 *String @@ -314,6 +312,12 @@ get_memmap: xor r14, r14 xor r15, r15 + mov rdi, [FB] + mov eax, 0x00101010 ; 0x00RRGGBB + mov rcx, [FBS] + shr rcx, 2 ; Quick divide by 4 (32-bit colour) + rep stosd + jmp 0x8000 exitfailure: diff --git a/src/init/acpi.asm b/src/init/acpi.asm index e672092..160908f 100644 --- a/src/init/acpi.asm +++ b/src/init/acpi.asm @@ -133,6 +133,10 @@ init_smp_acpi_done: noACPI: novalidacpi: + mov rdi, [0x00005F00 + 40] + mov eax, 0x00FF0000 ; 0x00RRGGBB + mov ecx, 800 * 600 + rep stosd jmp $ diff --git a/src/pure64.asm b/src/pure64.asm index cd63968..dab2397 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -392,6 +392,11 @@ clearmapnext: and cl, 1 mov byte [p_x2APIC], cl + mov rdi, [0x00005F00 + 40] + mov eax, 0x00202020 ; 0x00RRGGBB + mov ecx, 800 * 600 + rep stosd + call init_acpi ; Find and process the ACPI tables call init_cpu ; Configure the BSP CPU @@ -444,11 +449,11 @@ clearmapnext: stosq mov di, 0x5080 - mov eax, [VBEModeInfoBlock.PhysBasePtr] ; Base address of video memory (if graphics mode is set) - stosd - mov eax, [VBEModeInfoBlock.XResolution] ; X and Y resolution (16-bits each) + mov eax, [0x00005F00] ; Base address of video memory + stosd ; TODO QWORD + mov eax, [0x00005F00 + 0x10] ; X and Y resolution (16-bits each) stosd - mov al, [VBEModeInfoBlock.BitsPerPixel] ; Color depth + mov al, 32 ; Color depth stosb mov di, 0x5090 diff --git a/src/sysvar.asm b/src/sysvar.asm index 4c5f380..9582efb 100644 --- a/src/sysvar.asm +++ b/src/sysvar.asm @@ -57,7 +57,6 @@ dq 0x00CF92000000FFFF ; 32-bit data descriptor ; 55 Granularity 4KiB, 54 Size 32bit, 47 Present, 44 Code/Data, 41 Writeable gdt32_end: -; ----------------------------------------------------------------------------- align 16 GDTR64: ; Global Descriptors Table Register dw gdt64_end - gdt64 - 1 ; limit of GDT (size minus one) @@ -75,45 +74,7 @@ gdt64_end: IDTR64: ; Interrupt Descriptor Table Register dw 256*16-1 ; limit of IDT (size minus one) (4096 bytes - 1) dq 0x0000000000000000 ; linear address of IDT -; ----------------------------------------------------------------------------- -; VESA -; Mandatory information for all VBE revisions -VBEModeInfoBlock.ModeAttributes equ VBEModeInfoBlock + 0 ; DW - mode attributes -VBEModeInfoBlock.WinAAttributes equ VBEModeInfoBlock + 2 ; DB - window A attributes -VBEModeInfoBlock.WinBAttributes equ VBEModeInfoBlock + 3 ; DB - window B attributes -VBEModeInfoBlock.WinGranularity equ VBEModeInfoBlock + 4 ; DW - window granularity in KB -VBEModeInfoBlock.WinSize equ VBEModeInfoBlock + 6 ; DW - window size in KB -VBEModeInfoBlock.WinASegment equ VBEModeInfoBlock + 8 ; DW - window A start segment -VBEModeInfoBlock.WinBSegment equ VBEModeInfoBlock + 10 ; DW - window B start segment -VBEModeInfoBlock.WinFuncPtr equ VBEModeInfoBlock + 12 ; DD - real mode pointer to window function -VBEModeInfoBlock.BytesPerScanLine equ VBEModeInfoBlock + 16 ; DW - bytes per scan line -; Mandatory information for VBE 1.2 and above -VBEModeInfoBlock.XResolution equ VBEModeInfoBlock + 18 ; DW - horizontal resolution in pixels or characters -VBEModeInfoBlock.YResolution equ VBEModeInfoBlock + 20 ; DW - vertical resolution in pixels or characters -VBEModeInfoBlock.XCharSize equ VBEModeInfoBlock + 22 ; DB - character cell width in pixels -VBEModeInfoBlock.YCharSize equ VBEModeInfoBlock + 23 ; DB - character cell height in pixels -VBEModeInfoBlock.NumberOfPlanes equ VBEModeInfoBlock + 24 ; DB - number of memory planes -VBEModeInfoBlock.BitsPerPixel equ VBEModeInfoBlock + 25 ; DB - bits per pixel -VBEModeInfoBlock.NumberOfBanks equ VBEModeInfoBlock + 26 ; DB - number of banks -VBEModeInfoBlock.MemoryModel equ VBEModeInfoBlock + 27 ; DB - memory model type -VBEModeInfoBlock.BankSize equ VBEModeInfoBlock + 28 ; DB - bank size in KB -VBEModeInfoBlock.NumberOfImagePages equ VBEModeInfoBlock + 29 ; DB - number of image pages -VBEModeInfoBlock.Reserved equ VBEModeInfoBlock + 30 ; DB - reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) -; Direct Color fields (required for direct/6 and YUV/7 memory models) -VBEModeInfoBlock.RedMaskSize equ VBEModeInfoBlock + 31 ; DB - size of direct color red mask in bits -VBEModeInfoBlock.RedFieldPosition equ VBEModeInfoBlock + 32 ; DB - bit position of lsb of red mask -VBEModeInfoBlock.GreenMaskSize equ VBEModeInfoBlock + 33 ; DB - size of direct color green mask in bits -VBEModeInfoBlock.GreenFieldPosition equ VBEModeInfoBlock + 34 ; DB - bit position of lsb of green mask -VBEModeInfoBlock.BlueMaskSize equ VBEModeInfoBlock + 35 ; DB - size of direct color blue mask in bits -VBEModeInfoBlock.BlueFieldPosition equ VBEModeInfoBlock + 36 ; DB - bit position of lsb of blue mask -VBEModeInfoBlock.RsvdMaskSize equ VBEModeInfoBlock + 37 ; DB - size of direct color reserved mask in bits -VBEModeInfoBlock.RsvdFieldPosition equ VBEModeInfoBlock + 38 ; DB - bit position of lsb of reserved mask -VBEModeInfoBlock.DirectColorModeInfo equ VBEModeInfoBlock + 39 ; DB - direct color mode attributes -; Mandatory information for VBE 2.0 and above -VBEModeInfoBlock.PhysBasePtr equ VBEModeInfoBlock + 40 ; DD - physical address for flat memory frame buffer -VBEModeInfoBlock.Reserved1 equ VBEModeInfoBlock + 44 ; DD - Reserved - always set to 0 -VBEModeInfoBlock.Reserved2 equ VBEModeInfoBlock + 48 ; DD - Reserved - always set to 0 ; ============================================================================= ; EOF From e524837c655002540104a1cfb94e461e95e3e5e2 Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 14 Apr 2024 09:53:08 -0400 Subject: [PATCH 04/20] Pull proper values for frame buffer. --- src/pure64.asm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pure64.asm b/src/pure64.asm index dab2397..4262a90 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -392,9 +392,10 @@ clearmapnext: and cl, 1 mov byte [p_x2APIC], cl - mov rdi, [0x00005F00 + 40] + mov rdi, [0x00005F00] ; Frame buffer base + mov rcx, [0x00005F08] ; Frame buffer size + shr rcx, 2 ; Quick divide by 4 mov eax, 0x00202020 ; 0x00RRGGBB - mov ecx, 800 * 600 rep stosd call init_acpi ; Find and process the ACPI tables From 3fc4a76c1853416944d24e7e4fb0fc140b4e797c Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 14 Apr 2024 17:01:41 -0400 Subject: [PATCH 05/20] Cleanup --- docs/README.md | 15 +++--- src/boot/uefi.asm | 48 ++++++++++-------- src/pure64.asm | 127 +++++++++++++++++++++++++++++----------------- src/sysvar.asm | 4 +- 4 files changed, 119 insertions(+), 75 deletions(-) diff --git a/docs/README.md b/docs/README.md index 7c9d716..7cd788f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -231,13 +231,14 @@ MPS INTI flags: Trigger Mode2201 Edge-triggered, 11 Level-triggered -A copy of the E820 System Memory Map is stored at memory address `0x0000000000006000`. Each E820 record is 32 bytes in length and the memory map is terminated by a blank record. +A copy of the UEFI System Memory Map is stored at memory address `0x0000000000006000`. Each UEFI record is 48 bytes in length and the memory map is terminated by a blank record. - - - - - + + + + + +
VariableVariable SizeDescription
Starting Address64-bitThe starting address for this record
Length64-bitThe length of memory for this record
Memory Type32-bitType 1 is usable memory, Type 2 is not usable
Extended Attributes32-bitACPI 3.0 Extended Attributes bitfield
Padding64-bitPadding for 32-byte alignment
Type64-bitThe type of the memory region
Physical Start64-bitPhysical Address - 4K aligned
Virtual Start64-bitVirtual Address - 4K aligned
NumberOfPages64-bitThe number of 4K pages in this section
Attribute64-bitSee document linked below
Padding64-bitPadding
-For more information on the E820 Memory Map: OSDev wiki on E820 +For more information on the UEFI Memory Map: UEFI Specs diff --git a/src/boot/uefi.asm b/src/boot/uefi.asm index cde34ed..0e3fe32 100644 --- a/src/boot/uefi.asm +++ b/src/boot/uefi.asm @@ -126,13 +126,18 @@ EntryPoint: ; Set screen colour attributes mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This - mov rdx, 0x07 ; IN UINTN Attribute Light black background, grey foreground + mov rdx, 0x07 ; IN UINTN Attribute - Black background, grey foreground call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_SET_ATTRIBUTE] ; Clear screen mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_CLEAR_SCREEN] + ; Output 'UEFI ' + mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + lea rdx, [msg_uefi] ; IN CHAR16 *String + call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING] + ; Find the address of the ACPI data from the UEFI configuration table mov rax, [EFI_SYSTEM_TABLE] mov rcx, [rax + EFI_SYSTEM_TABLE_NUMBEROFENTRIES] @@ -246,19 +251,20 @@ skip_set_video: ; Save video values to the area of memory where Pure64 expects them mov rdi, 0x00005F00 mov rax, [FB] - stosq + stosq ; 64-bit Frame Buffer Base mov rax, [FBS] - stosq + stosq ; 64-bit Frame Buffer Size in bytes mov rax, [HR] - stosw + stosw ; 16-bit Screen X mov rax, [VR] - stosw + stosw ; 16-bit Screen Y + ; Output 'OK' as we are about to leave UEFI mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This lea rdx, [msg_OK] ; IN CHAR16 *String call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING] - ; Get Memory Map + ; Get Memory Map from UEFI and save it to 0x6000 get_memmap: lea rcx, [memmapsize] ; IN OUT UINTN *MemoryMapSize lea rdx, 0x6000 ; OUT EFI_MEMORY_DESCRIPTOR *MemoryMap @@ -279,7 +285,7 @@ get_memmap: ; 0 UINT32 - Type ; 8 EFI_PHYSICAL_ADDRESS - PhysicalStart ; 16 EFI_VIRTUAL_ADDRESS - VirtualStart - ; 24 UINT64 - NumberOfPages + ; 24 UINT64 - NumberOfPages - This is a number of 4K pages (must be a non-zero value) ; 32 UINT64 - Attribute ; 40 UINT64 - Blank @@ -295,14 +301,14 @@ get_memmap: cli ; Clear registers - xor eax, eax ; aka r0 - xor ecx, ecx ; aka r1 - xor edx, edx ; aka r2 - xor ebx, ebx ; aka r3 - mov rsp, 0x8000 ; aka r4 - xor ebp, ebp ; aka r5 - xor esi, esi ; aka r6 - xor edi, edi ; aka r7 + xor eax, eax + xor ecx, ecx + xor edx, edx + xor ebx, ebx + mov rsp, 0x8000 + xor ebp, ebp + xor esi, esi + xor edi, edi xor r8, r8 xor r9, r9 xor r10, r10 @@ -312,8 +318,9 @@ get_memmap: xor r14, r14 xor r15, r15 + ; Set screen to green before jumping to Pure64 mov rdi, [FB] - mov eax, 0x00101010 ; 0x00RRGGBB + mov eax, 0x0000FF00 ; 0x00RRGGBB mov rcx, [FBS] shr rcx, 2 ; Quick divide by 4 (32-bit colour) rep stosd @@ -321,12 +328,12 @@ get_memmap: jmp 0x8000 exitfailure: + ; Set screen to red on exit failure mov rdi, [FB] - mov eax, 0x00FF0000 ; Red + mov eax, 0x00FF0000 ; 0x00RRGGBB mov rcx, [FBS] shr rcx, 2 ; Quick divide by 4 (32-bit colour) rep stosd - jmp halt error: mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This lea rdx, [msg_error] ; IN CHAR16 *String @@ -378,10 +385,11 @@ dd 0x9042a9de dw 0x23dc, 0x4a38 db 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a -hextable: db '0123456789ABCDEF' +msg_uefi: dw u('UEFI '), 0 +msg_OK: dw u('OK'), 0 msg_error: dw u('Error'), 0 msg_SigFail: dw u('Bad Sig!'), 0 -msg_OK: dw u('UEFI OK'), 0 + align 4096 PAYLOAD: diff --git a/src/pure64.asm b/src/pure64.asm index 4262a90..241a090 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -100,25 +100,34 @@ rtc_poll: out 0x21, al out 0xA1, al -; Configure serial port @ 0x03F8 +; Configure serial port @ 0x03F8 as 115200 8N1 mov dx, 0x03F8 + 1 ; Interrupt Enable mov al, 0x00 ; Disable all interrupts out dx, al mov dx, 0x03F8 + 3 ; Line Control - mov al, 80 + mov al, 80 ; Enable DLAB out dx, al - mov dx, 0x03F8 + 0 ; Divisor Latch - mov ax, 1 ; 1 = 115200 baud - out dx, ax - mov dx, 0x03F8 + 3 ; Line Control - mov al, 3 ; 8 bits, no parity, one stop bit + mov dx, 0x03F8 + 0 ; Divisor Latch Low + mov al, 1 ; 1 = 115200 baud out dx, al - mov dx, 0x03F8 + 4 ; Modem Control - mov al, 3 + mov dx, 0x03F8 + 1 ; Divisor Latch High + mov al, 0 + out dx, al + mov dx, 0x03F8 + 3 ; Line Control + mov al, 3 ; 8 data bits (0-1 set), one stop bit (2 set), no parity (3-5 clear), DLB (7 clear) out dx, al + mov dx, 0x03F8 + 2 ; Interrupt Identification and FIFO Control mov al, 0xC7 ; Enable FIFO, clear them, with 14-byte threshold - mov dx, 0x03F8 + 2 out dx, al + mov dx, 0x03F8 + 4 ; Modem Control + mov al, 0 ; No flow control, no interrupts + out dx, al + + mov rsi, message_pure64 ; Location of message + call debug_msg + +; mov al, 'a' ; Newline +; call debug_msg_char ; Clear out the first 20KiB of memory. This will store the 64-bit IDT, GDT, PML4, PDP Low, and PDP High mov ecx, 5120 @@ -142,17 +151,13 @@ rtc_poll: ; A single PML4 entry can map 512GiB with 2MiB pages ; A single PML4 entry is 8 bytes in length cld - mov edi, 0x00002000 ; Create a PML4 entry for the first 4GiB of RAM + mov edi, 0x00002000 ; Create a PML4 entry for physical memory mov eax, 0x00003007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of low PDP (4KiB aligned) - stosd - xor eax, eax - stosd + stosq mov edi, 0x00002800 ; Create a PML4 entry for higher half (starting at 0xFFFF800000000000) mov eax, 0x00004007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of high PDP (4KiB aligned) - stosd - xor eax, eax - stosd + stosq ; Create the Page-Directory-Pointer-Table Entries (PDPTE) ; PDPTE is stored at 0x0000000000003000, create the first entry there @@ -163,12 +168,8 @@ rtc_poll: mov edi, 0x00003000 ; location of low PDPE mov eax, 0x00010007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of first low PD (4KiB aligned) create_pdpte_low: - stosd - push rax - xor eax, eax - stosd - pop rax - add eax, 0x00001000 ; 4KiB later (512 records x 8 bytes) + stosq + add rax, 0x00001000 ; 4KiB later (512 records x 8 bytes) dec ecx cmp ecx, 0 jne create_pdpte_low @@ -180,12 +181,8 @@ create_pdpte_low: mov eax, 0x0000008F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), and 7 (PS) set mov ecx, 2048 ; Create 2048 2 MiB page maps. pde_low: ; Create a 2 MiB page - stosd - push rax - xor eax, eax - stosd - pop rax - add eax, 0x00200000 ; Increment by 2MiB + stosq + add rax, 0x00200000 ; Increment by 2MiB dec ecx cmp ecx, 0 jne pde_low @@ -468,23 +465,8 @@ clearmapnext: rep movsq ; Copy 8 bytes at a time ; Output message via serial port - cld ; Clear the direction flag.. we want to increment through the string - mov dx, 0x03F8 ; Address of first serial port - mov rsi, message ; Location of message - mov cx, 11 ; Length of message -serial_nextchar: - jrcxz serial_done ; If RCX is 0 then the function is complete - add dx, 5 ; Offset to Line Status Register - in al, dx - sub dx, 5 ; Back to to base - and al, 0x20 - cmp al, 0 - je serial_nextchar - dec cx - lodsb ; Get char from string and store in AL - out dx, al ; Send the char to the serial port - jmp serial_nextchar -serial_done: + mov rsi, message_ok ; Location of message + call debug_msg ; Clear all registers (skip the stack pointer) xor eax, eax ; These 32-bit calls also clear the upper bits of the 64-bit registers @@ -512,6 +494,59 @@ serial_done: %include "interrupt.asm" %include "sysvar.asm" + +; ----------------------------------------------------------------------------- +; debug_msg_char - Send a single char via the serial port +; IN: AL = Byte to send +debug_msg_char: + pushf + push rdx + push rax ; Save the byte + mov dx, 0x03F8 ; Address of first serial port +debug_msg_char_wait: + add dx, 5 ; Offset to Line Status Register + in al, dx + sub dx, 5 ; Back to to base + and al, 0x20 + cmp al, 0 + je debug_msg_char_wait + pop rax ; Restore the byte + out dx, al ; Send the char to the serial port +debug_msg_char_done: + pop rdx + popf + ret +; ----------------------------------------------------------------------------- + +; ----------------------------------------------------------------------------- +; debug_msg_char - Send a message via the serial port +; IN: RSI = Location of message +debug_msg: + pushf + push rdx + push rax + cld ; Clear the direction flag.. we want to increment through the string + mov dx, 0x03F8 ; Address of first serial port +debug_msg_next: + add dx, 5 ; Offset to Line Status Register + in al, dx + sub dx, 5 ; Back to to base + and al, 0x20 + cmp al, 0 + je debug_msg_next + lodsb ; Get char from string and store in AL + cmp al, 0 + je debug_msg_done + out dx, al ; Send the char to the serial port + jmp debug_msg_next +debug_msg_done: + pop rax + pop rdx + popf + ret +; ----------------------------------------------------------------------------- + + EOF: db 0xDE, 0xAD, 0xC0, 0xDE diff --git a/src/sysvar.asm b/src/sysvar.asm index 9582efb..1a868ab 100644 --- a/src/sysvar.asm +++ b/src/sysvar.asm @@ -6,13 +6,13 @@ ; ============================================================================= -message: db 10, 'Pure64 OK', 10 +message_pure64: db 10, 'Pure64 ', 0 +message_ok: db 'OK', 10, 0 ;CONFIG cfg_smpinit: db 1 ; By default SMP is enabled. Set to 0 to disable. ; Memory locations -E820Map: equ 0x0000000000004000 InfoMap: equ 0x0000000000005000 IM_PCIE: equ 0x0000000000005400 ; 16 bytes per entry IM_IOAPICAddress: equ 0x0000000000005600 ; 16 bytes per entry From 78a5f5ae860e8d6ed451c4070eb84f10b6c23565 Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 14 Apr 2024 20:03:01 -0400 Subject: [PATCH 06/20] Map 64MB to higher half for now. --- src/pure64.asm | 84 ++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 44 deletions(-) diff --git a/src/pure64.asm b/src/pure64.asm index 241a090..e48e847 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -150,16 +150,14 @@ rtc_poll: ; PML4 is stored at 0x0000000000002000, create the first entry there ; A single PML4 entry can map 512GiB with 2MiB pages ; A single PML4 entry is 8 bytes in length - cld mov edi, 0x00002000 ; Create a PML4 entry for physical memory mov eax, 0x00003007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of low PDP (4KiB aligned) stosq - mov edi, 0x00002800 ; Create a PML4 entry for higher half (starting at 0xFFFF800000000000) mov eax, 0x00004007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of high PDP (4KiB aligned) stosq -; Create the Page-Directory-Pointer-Table Entries (PDPTE) +; Create the Low Page-Directory-Pointer-Table Entries (PDPTE) ; PDPTE is stored at 0x0000000000003000, create the first entry there ; A single PDPTE can map 1GiB with 2MiB pages ; A single PDPTE is 8 bytes in length @@ -174,13 +172,13 @@ create_pdpte_low: cmp ecx, 0 jne create_pdpte_low -; Create the low Page-Directory Entries (PDE). +; Create the Low Page-Directory Entries (PDE) ; A single PDE can map 2MiB of RAM ; A single PDE is 8 bytes in length mov edi, 0x00010000 ; Location of first PDE mov eax, 0x0000008F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), and 7 (PS) set - mov ecx, 2048 ; Create 2048 2 MiB page maps. -pde_low: ; Create a 2 MiB page + mov ecx, 2048 ; Create 2048 2MiB page maps +pde_low: ; Create a 2MiB page stosq add rax, 0x00200000 ; Increment by 2MiB dec ecx @@ -237,18 +235,30 @@ clearcs64: stosd stosd ; Write 8 bytes in total to overwrite the 'far jump' and marker -uefi_memmap: ; TODO fix this as it is a terrible hack - mov rdi, 0x400000 - mov al, 1 - mov rcx, 32 - rep stosb - mov ebx, 64 - mov dword [p_mem_amount], ebx -memmap_end: - -; Create the high memory map - mov rcx, rbx - shr rcx, 9 ; TODO - This isn't the exact math but good enough +; Parse the Memory Map at 0x6000 +;uefi_memmap: +; xor ebx, ebx ; Running counter of 4K pages +; mov esi, 0x6018 +;uefi_memmap_next: +; mov rax, [rsi] +; cmp rax, 0 +; je uefi_memmap_end +; add rbx, rax +; add esi, 48 +; jmp uefi_memmap_next +;uefi_memmap_end: +; mov dword [p_mem_amount], ebx + +; FIXME - Don't hardcode the RAM to 64MiB + mov eax, 64 + mov dword [p_mem_amount], eax + +; Create the High Page-Directory-Pointer-Table Entries (PDPTE) +; High PDPTE is stored at 0x0000000000004000, create the first entry there +; A single PDPTE can map 1GiB with 2MiB pages +; A single PDPTE is 8 bytes in length +; 1 entry is created to map the first 1GiB of physical RAM to 0xFFFF800000000000 +; FIXME - Create more than just one PDPE depending on the amount of RAM in the system add rcx, 1 ; number of PDPE's to make.. each PDPE maps 1GB of physical memory mov edi, 0x00004000 ; location of high PDPE mov eax, 0x00020007 ; location of first high PD. Bits (0) P, 1 (R/W), and 2 (U/S) set @@ -259,34 +269,20 @@ create_pdpe_high: cmp ecx, 0 jne create_pdpe_high -; Create the high PD entries -; EBX contains the number of pages that should exist in the map, once they are all found bail out - xor ecx, ecx - xor eax, eax - xor edx, edx - mov edi, 0x00020000 ; Location of high PD entries - mov esi, 0x00400000 ; Location of free pages map - -pd_high: - cmp rdx, rbx ; Compare mapped pages to max pages - je pd_high_done - lodsb - cmp al, 1 - je pd_high_entry - add rcx, 1 - jmp pd_high - -pd_high_entry: +; Create the High Page-Directory Entries (PDE). +; A single PDE can map 2MiB of RAM +; A single PDE is 8 bytes in length +; FIXME - Map more than 64MiB depending on the amount of RAM in the system + mov edi, 0x00020000 ; Location of first PDE mov eax, 0x0000008F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), and 7 (PS) set - shl rcx, 21 - add rax, rcx - shr rcx, 21 + add rax, 0x00400000 ; Start at 4MiB in + mov ecx, 32 ; Create 32 2MiB page maps +pde_high: ; Create a 2MiB page stosq - add rcx, 1 - add rdx, 1 ; We have mapped a valid page - jmp pd_high - -pd_high_done: + add rax, 0x00200000 ; Increment by 2MiB + dec ecx + cmp ecx, 0 + jne pde_high ; Build the IDT xor edi, edi ; create the 64-bit IDT (at linear address 0x0000000000000000) From cfd5afd4ecc19e62f200616e7cbd5ab8a2407663 Mon Sep 17 00:00:00 2001 From: Ian Date: Mon, 15 Apr 2024 19:40:00 -0400 Subject: [PATCH 07/20] Cleanup and reorg --- src/boot/uefi.asm | 73 ++++++++++++++++++++++++++--------------------- src/pure64.asm | 48 ++++++++++++++++++++++--------- 2 files changed, 76 insertions(+), 45 deletions(-) diff --git a/src/boot/uefi.asm b/src/boot/uefi.asm index 0e3fe32..fc1b0c0 100644 --- a/src/boot/uefi.asm +++ b/src/boot/uefi.asm @@ -129,7 +129,7 @@ EntryPoint: mov rdx, 0x07 ; IN UINTN Attribute - Black background, grey foreground call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_SET_ATTRIBUTE] - ; Clear screen + ; Clear screen (This also sets the cursor position to 0,0) mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_CLEAR_SCREEN] @@ -248,39 +248,25 @@ skip_set_video: cmp ax, 0x3436 ; Match against the Pure64 binary jne sig_fail - ; Save video values to the area of memory where Pure64 expects them - mov rdi, 0x00005F00 - mov rax, [FB] - stosq ; 64-bit Frame Buffer Base - mov rax, [FBS] - stosq ; 64-bit Frame Buffer Size in bytes - mov rax, [HR] - stosw ; 16-bit Screen X - mov rax, [VR] - stosw ; 16-bit Screen Y - +get_memmap: ; Output 'OK' as we are about to leave UEFI mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This lea rdx, [msg_OK] ; IN CHAR16 *String call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING] - ; Get Memory Map from UEFI and save it to 0x6000 -get_memmap: + ; Get Memory Map from UEFI and save it [memmap] lea rcx, [memmapsize] ; IN OUT UINTN *MemoryMapSize - lea rdx, 0x6000 ; OUT EFI_MEMORY_DESCRIPTOR *MemoryMap + mov rdx, [memmap] ; OUT EFI_MEMORY_DESCRIPTOR *MemoryMap lea r8, [memmapkey] ; OUT UINTN *MapKey lea r9, [memmapdescsize] ; OUT UINTN *DescriptorSize lea r10, [memmapdescver] ; OUT UINT32 *DescriptorVersion - sub rsp, 32 ; Shadow space - push r10 + mov [rsp+32], r10 mov rax, [BS] call [rax + EFI_BOOT_SERVICES_GETMEMORYMAP] - pop r10 - add rsp, 32 - cmp al, 5 ; EFI_BUFFER_TOO_SMALL + cmp al, EFI_BUFFER_TOO_SMALL je get_memmap ; Attempt again as the memmapsize was updated by EFI cmp rax, EFI_SUCCESS - jne error + jne exitfailure ; Output at 0x6000 is as follows: ; 0 UINT32 - Type ; 8 EFI_PHYSICAL_ADDRESS - PhysicalStart @@ -289,17 +275,46 @@ get_memmap: ; 32 UINT64 - Attribute ; 40 UINT64 - Blank - ; Exit Boot services as EFI is no longer needed + ; Exit Boot services as UEFI is no longer needed mov rcx, [EFI_IMAGE_HANDLE] ; IN EFI_HANDLE ImageHandle mov rdx, [memmapkey] ; IN UINTN MapKey mov rax, [BS] call [rax + EFI_BOOT_SERVICES_EXITBOOTSERVICES] cmp rax, EFI_SUCCESS - jne exitfailure + jne get_memmap ; If it failed, get the memory map and try to exit again ; Stop interrupts cli + ; Save video values to the area of memory where Pure64 expects them + mov rdi, 0x00005F00 + mov rax, [FB] + stosq ; 64-bit Frame Buffer Base + mov rax, [FBS] + stosq ; 64-bit Frame Buffer Size in bytes + mov rax, [HR] + stosw ; 16-bit Screen X + mov rax, [VR] + stosw ; 16-bit Screen Y + xor eax, eax + stosd + mov rax, [memmap] + stosq + mov rax, [memmapsize] + stosq + mov rax, [memmapkey] + stosq + mov rax, [memmapdescsize] + stosq + mov rax, [memmapdescver] + + ; Set screen to green before jumping to Pure64 + mov rdi, [FB] + mov eax, 0x0000FF00 ; 0x00RRGGBB + mov rcx, [FBS] + shr rcx, 2 ; Quick divide by 4 (32-bit colour) + rep stosd + ; Clear registers xor eax, eax xor ecx, ecx @@ -318,13 +333,6 @@ get_memmap: xor r14, r14 xor r15, r15 - ; Set screen to green before jumping to Pure64 - mov rdi, [FB] - mov eax, 0x0000FF00 ; 0x00RRGGBB - mov rcx, [FBS] - shr rcx, 2 ; Quick divide by 4 (32-bit colour) - rep stosd - jmp 0x8000 exitfailure: @@ -366,7 +374,8 @@ FB: dq 0 ; Frame buffer base address FBS: dq 0 ; Frame buffer size HR: dq 0 ; Horizontal Resolution VR: dq 0 ; Vertical Resolution -memmapsize: dq 8192 +memmap: dq 0x200000 ; Store the Memory Map from UEFI here +memmapsize: dq 32768 ; Max size we are expecting memmapkey: dq 0 memmapdescsize: dq 0 memmapdescver: dq 0 @@ -386,7 +395,7 @@ dw 0x23dc, 0x4a38 db 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a msg_uefi: dw u('UEFI '), 0 -msg_OK: dw u('OK'), 0 +msg_OK: dw u('OK '), 0 msg_error: dw u('Error'), 0 msg_SigFail: dw u('Bad Sig!'), 0 diff --git a/src/pure64.asm b/src/pure64.asm index e48e847..685afa5 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -185,6 +185,13 @@ pde_low: ; Create a 2MiB page cmp ecx, 0 jne pde_low + ; Debug - Set screen to blue prior to loading GDT and PML4 + mov rdi, [0x00005F00] ; Frame buffer base + mov rcx, [0x00005F08] ; Frame buffer size + shr rcx, 2 ; Quick divide by 4 + mov eax, 0x002020F0 ; 0x00RRGGBB + rep stosd + ; Load the GDT lgdt [GDTR64] @@ -229,25 +236,40 @@ clearcs64: lgdt [GDTR64] ; Reload the GDT + ; Debug - Set screen to purple after loading GDT and PML4 + mov rdi, [0x00005F00] ; Frame buffer base + mov rcx, [0x00005F08] ; Frame buffer size + shr rcx, 2 ; Quick divide by 4 + mov eax, 0x00F020F0 ; 0x00RRGGBB + rep stosd + + ; Patch Pure64 AP code ; The AP's will be told to start execution at 0x8000 mov edi, start ; We need to remove the BSP Jump call to get the AP's mov eax, 0x90909090 ; to fall through to the AP Init code stosd stosd ; Write 8 bytes in total to overwrite the 'far jump' and marker -; Parse the Memory Map at 0x6000 -;uefi_memmap: -; xor ebx, ebx ; Running counter of 4K pages -; mov esi, 0x6018 -;uefi_memmap_next: -; mov rax, [rsi] -; cmp rax, 0 -; je uefi_memmap_end -; add rbx, rax -; add esi, 48 -; jmp uefi_memmap_next -;uefi_memmap_end: -; mov dword [p_mem_amount], ebx +; Parse the Memory Map at 0x200000 +uefi_memmap: + xor ebx, ebx ; Running counter of 4K pages + mov esi, 0x200000 +uefi_memmap_next: + mov rax, [rsi] + cmp rax, 7 + je uefi_memmap_conventional + cmp rax, 0 + je uefi_memmap_end +uefi_memmap_skip: + add esi, 48 + jmp uefi_memmap_next +uefi_memmap_conventional: + mov rax, [rsi + 24] + add rbx, rax + jmp uefi_memmap_skip +uefi_memmap_end: + shr rbx, 8 + mov dword [p_mem_amount], ebx ; FIXME - Don't hardcode the RAM to 64MiB mov eax, 64 From a95048ba51f086def2a01a2ca2518ab18070608e Mon Sep 17 00:00:00 2001 From: Ian Date: Mon, 15 Apr 2024 20:32:46 -0400 Subject: [PATCH 08/20] Add comments --- docs/README.md | 28 ++++++++++++++-------------- src/boot/uefi.asm | 15 ++++++++------- src/pure64.asm | 13 +++++++++---- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/docs/README.md b/docs/README.md index 7cd788f..7e7a2ac 100644 --- a/docs/README.md +++ b/docs/README.md @@ -73,19 +73,19 @@ OUTPUT_ARCH("i386:x86-64") SECTIONS { - . = 0x100000; - .text : { - *(.text) - } - .data : { - *(.data) - } - .rodata : { - *(.rodata) - } - .bss : { - *(.bss) - } + . = 0x100000; + .text : { + *(.text) + } + .data : { + *(.data) + } + .rodata : { + *(.rodata) + } + .bss : { + *(.bss) + } } ``` @@ -108,7 +108,7 @@ extern int main(void); void _start(void) { - main(); + main(); } ``` This file would **always** have to be linked in front of everything else. For the above example that would mean the linker command above would have to become: diff --git a/src/boot/uefi.asm b/src/boot/uefi.asm index fc1b0c0..25d62f8 100644 --- a/src/boot/uefi.asm +++ b/src/boot/uefi.asm @@ -286,7 +286,7 @@ get_memmap: ; Stop interrupts cli - ; Save video values to the area of memory where Pure64 expects them + ; Save UEFI values to the area of memory where Pure64 expects them mov rdi, 0x00005F00 mov rax, [FB] stosq ; 64-bit Frame Buffer Base @@ -297,16 +297,17 @@ get_memmap: mov rax, [VR] stosw ; 16-bit Screen Y xor eax, eax - stosd + stosd ; Padding mov rax, [memmap] - stosq + stosq ; Memory Map Base mov rax, [memmapsize] - stosq + stosq ; Size of Memory Map in bytes mov rax, [memmapkey] - stosq + stosq ; The key used to exit Boot Services mov rax, [memmapdescsize] - stosq + stosq ; EFI_MEMORY_DESCRIPTOR size in bytes mov rax, [memmapdescver] + stosq ; EFI_MEMORY_DESCRIPTOR version ; Set screen to green before jumping to Pure64 mov rdi, [FB] @@ -375,7 +376,7 @@ FBS: dq 0 ; Frame buffer size HR: dq 0 ; Horizontal Resolution VR: dq 0 ; Vertical Resolution memmap: dq 0x200000 ; Store the Memory Map from UEFI here -memmapsize: dq 32768 ; Max size we are expecting +memmapsize: dq 32768 ; Max size we are expecting in bytes memmapkey: dq 0 memmapdescsize: dq 0 memmapdescver: dq 0 diff --git a/src/pure64.asm b/src/pure64.asm index 685afa5..c79d497 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -55,7 +55,7 @@ start64: mov edi, 0x5000 ; Clear the info map and system variable memory xor eax, eax mov ecx, 960 ; 3840 bytes (Range is 0x5000 - 0x5EFF) - rep stosd ; Don't overwrite the VBE data at 0x5F00 + rep stosd ; Don't overwrite the UEFI data at 0x5F00 ; Set up RTC ; Port 0x70 is RTC Address, and 0x71 is RTC Data @@ -243,7 +243,6 @@ clearcs64: mov eax, 0x00F020F0 ; 0x00RRGGBB rep stosd - ; Patch Pure64 AP code ; The AP's will be told to start execution at 0x8000 mov edi, start ; We need to remove the BSP Jump call to get the AP's mov eax, 0x90909090 ; to fall through to the AP Init code @@ -464,9 +463,14 @@ clearmapnext: mov rax, [p_LocalAPICAddress] stosq + ; TODO - Copy the data we received from GOP + ; FB + ; FBS + ; X + ; Y mov di, 0x5080 mov eax, [0x00005F00] ; Base address of video memory - stosd ; TODO QWORD + stosd mov eax, [0x00005F00 + 0x10] ; X and Y resolution (16-bits each) stosd mov al, 32 ; Color depth @@ -502,7 +506,7 @@ clearmapnext: xor r13, r13 xor r14, r14 xor r15, r15 - jmp 0x00100000 + jmp 0x00100000 ; Done with Pure64, jump to the kernel %include "init/acpi.asm" @@ -536,6 +540,7 @@ debug_msg_char_done: ret ; ----------------------------------------------------------------------------- + ; ----------------------------------------------------------------------------- ; debug_msg_char - Send a message via the serial port ; IN: RSI = Location of message From 46c531d21743449c5080b61fb2bb5fc207317939 Mon Sep 17 00:00:00 2001 From: Ian Date: Tue, 16 Apr 2024 16:10:01 -0400 Subject: [PATCH 09/20] Add printhex function for debugging if needed --- src/boot/uefi.asm | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/boot/uefi.asm b/src/boot/uefi.asm index 25d62f8..ae1c649 100644 --- a/src/boot/uefi.asm +++ b/src/boot/uefi.asm @@ -248,6 +248,9 @@ skip_set_video: cmp ax, 0x3436 ; Match against the Pure64 binary jne sig_fail +; mov rbx, [FB] ; Display the framebuffer address +; call printhex + get_memmap: ; Output 'OK' as we are about to leave UEFI mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This @@ -356,6 +359,39 @@ halt: hlt jmp halt +; ----------------------------------------------------------------------------- +; printhex - Display a 64-bit value in hex +; IN: RBX = Value +printhex: + mov rbp, 16 ; Stack msialigned by 8 at function entry + push rax + push rcx + push rdx ; 3 pushes also align stack on 16 byte boundary + ; (8+3*8)=32, 32 evenly divisible by 16 + sub rsp, 32 ; Allocate 32 bytes of shadow space +printhex_loop: + rol rbx, 4 + mov rax, rbx + and rax, 0Fh + lea rcx, [Hex] + mov rax, [rax + rcx] + mov byte [Num], al + lea rdx, [Num] + mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING] + dec rbp + jnz printhex_loop + lea rdx, [NL] + mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING] + + add rsp, 32 + pop rdx + pop rcx + pop rax + ret +; ----------------------------------------------------------------------------- + align 2048 CODE_END: @@ -399,6 +435,9 @@ msg_uefi: dw u('UEFI '), 0 msg_OK: dw u('OK '), 0 msg_error: dw u('Error'), 0 msg_SigFail: dw u('Bad Sig!'), 0 +Hex: db '0123456789ABCDEF' +Num: dw 0, 0 +NL: dw 13, 10, 0 align 4096 From 0b23826ef6c3b94e09435d3fa0c6e334cb96e412 Mon Sep 17 00:00:00 2001 From: Ian Date: Tue, 16 Apr 2024 21:58:00 -0400 Subject: [PATCH 10/20] Initial support for 1GiB pages --- src/boot/uefi.asm | 2 +- src/pure64.asm | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/boot/uefi.asm b/src/boot/uefi.asm index ae1c649..ce21e43 100644 --- a/src/boot/uefi.asm +++ b/src/boot/uefi.asm @@ -363,7 +363,7 @@ halt: ; printhex - Display a 64-bit value in hex ; IN: RBX = Value printhex: - mov rbp, 16 ; Stack msialigned by 8 at function entry + mov rbp, 16 ; Counter push rax push rcx push rdx ; 3 pushes also align stack on 16 byte boundary diff --git a/src/pure64.asm b/src/pure64.asm index c79d497..d63bb0b 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -151,12 +151,19 @@ rtc_poll: ; A single PML4 entry can map 512GiB with 2MiB pages ; A single PML4 entry is 8 bytes in length mov edi, 0x00002000 ; Create a PML4 entry for physical memory - mov eax, 0x00003007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of low PDP (4KiB aligned) + mov eax, 0x0000300F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), location of low PDP (4KiB aligned) stosq mov edi, 0x00002800 ; Create a PML4 entry for higher half (starting at 0xFFFF800000000000) - mov eax, 0x00004007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of high PDP (4KiB aligned) + mov eax, 0x0000400F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), location of high PDP (4KiB aligned) stosq +; Check to see if the system supports 1 GiB pages +; If it does we will use that for identity mapping the lower memory + mov eax, 0x80000001 + cpuid + bt edx, 26 ; Page1GB + jc pdpte_1GB + ; Create the Low Page-Directory-Pointer-Table Entries (PDPTE) ; PDPTE is stored at 0x0000000000003000, create the first entry there ; A single PDPTE can map 1GiB with 2MiB pages @@ -164,13 +171,12 @@ rtc_poll: ; 4 entries are created to map the first 4GiB of RAM mov ecx, 4 ; number of PDPE's to make.. each PDPE maps 1GiB of physical memory mov edi, 0x00003000 ; location of low PDPE - mov eax, 0x00010007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of first low PD (4KiB aligned) -create_pdpte_low: + mov eax, 0x0001000F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), location of first low PD (4KiB aligned) +pdpte_low: stosq add rax, 0x00001000 ; 4KiB later (512 records x 8 bytes) dec ecx - cmp ecx, 0 - jne create_pdpte_low + jnz pdpte_low ; Create the Low Page-Directory Entries (PDE) ; A single PDE can map 2MiB of RAM @@ -182,9 +188,25 @@ pde_low: ; Create a 2MiB page stosq add rax, 0x00200000 ; Increment by 2MiB dec ecx - cmp ecx, 0 - jne pde_low + jnz pde_low + jmp skip1GB + +; Create the Low Page-Directory-Pointer Table Entries (PDPTE) +; PDPTE is stored at 0x0000000000003000, create the first entry there +; A single PDPTE can map 1GiB +; A single PDPTE is 8 bytes in length +; 512 entries are created to map the first 512GiB of RAM +pdpte_1GB: + mov ecx, 512 ; number of PDPE's to make.. each PDPE maps 1GiB of physical memory + mov edi, 0x00003000 ; location of low PDPE + mov eax, 0x0000008F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), 7 (PS) +pdpte_low_1GB: ; Create a 1GiB page + stosq + add rax, 0x40000000 ; Increment by 1GiB + dec ecx + jnz pdpte_low_1GB +skip1GB: ; Debug - Set screen to blue prior to loading GDT and PML4 mov rdi, [0x00005F00] ; Frame buffer base mov rcx, [0x00005F08] ; Frame buffer size From f702128cb48aaccfe450eb8d731bbb6f6a58adfb Mon Sep 17 00:00:00 2001 From: Ian Date: Wed, 17 Apr 2024 12:31:09 -0400 Subject: [PATCH 11/20] =?UTF-8?q?Don=E2=80=99t=20set=20PWT=20in=20page=20t?= =?UTF-8?q?able=20entries.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pure64.asm | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pure64.asm b/src/pure64.asm index d63bb0b..16e41fe 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -148,13 +148,13 @@ rtc_poll: ; Create the Page Map Level 4 Entries (PML4E) ; PML4 is stored at 0x0000000000002000, create the first entry there -; A single PML4 entry can map 512GiB with 2MiB pages +; A single PML4 entry can map 512GiB ; A single PML4 entry is 8 bytes in length mov edi, 0x00002000 ; Create a PML4 entry for physical memory - mov eax, 0x0000300F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), location of low PDP (4KiB aligned) + mov eax, 0x00003007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of low PDP (4KiB aligned) stosq mov edi, 0x00002800 ; Create a PML4 entry for higher half (starting at 0xFFFF800000000000) - mov eax, 0x0000400F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), location of high PDP (4KiB aligned) + mov eax, 0x00004007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of high PDP (4KiB aligned) stosq ; Check to see if the system supports 1 GiB pages @@ -166,12 +166,12 @@ rtc_poll: ; Create the Low Page-Directory-Pointer-Table Entries (PDPTE) ; PDPTE is stored at 0x0000000000003000, create the first entry there -; A single PDPTE can map 1GiB with 2MiB pages +; A single PDPTE can map 1GiB ; A single PDPTE is 8 bytes in length ; 4 entries are created to map the first 4GiB of RAM mov ecx, 4 ; number of PDPE's to make.. each PDPE maps 1GiB of physical memory mov edi, 0x00003000 ; location of low PDPE - mov eax, 0x0001000F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), location of first low PD (4KiB aligned) + mov eax, 0x00010007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of first low PD (4KiB aligned) pdpte_low: stosq add rax, 0x00001000 ; 4KiB later (512 records x 8 bytes) @@ -182,7 +182,7 @@ pdpte_low: ; A single PDE can map 2MiB of RAM ; A single PDE is 8 bytes in length mov edi, 0x00010000 ; Location of first PDE - mov eax, 0x0000008F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), and 7 (PS) set + mov eax, 0x00000087 ; Bits 0 (P), 1 (R/W), 2 (U/S), and 7 (PS) set mov ecx, 2048 ; Create 2048 2MiB page maps pde_low: ; Create a 2MiB page stosq @@ -199,7 +199,7 @@ pde_low: ; Create a 2MiB page pdpte_1GB: mov ecx, 512 ; number of PDPE's to make.. each PDPE maps 1GiB of physical memory mov edi, 0x00003000 ; location of low PDPE - mov eax, 0x0000008F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), 7 (PS) + mov eax, 0x00000087 ; Bits 0 (P), 1 (R/W), 2 (U/S), 7 (PS) pdpte_low_1GB: ; Create a 1GiB page stosq add rax, 0x40000000 ; Increment by 1GiB @@ -431,7 +431,7 @@ clearmapnext: mov rdi, [0x00005F00] ; Frame buffer base mov rcx, [0x00005F08] ; Frame buffer size shr rcx, 2 ; Quick divide by 4 - mov eax, 0x00202020 ; 0x00RRGGBB + mov eax, 0x00206020 ; 0x00RRGGBB rep stosd call init_acpi ; Find and process the ACPI tables From 426eaaa6cf0665461d4f518e0fe00f29ab5b3538 Mon Sep 17 00:00:00 2001 From: Ian Date: Wed, 17 Apr 2024 12:43:07 -0400 Subject: [PATCH 12/20] Add some output to the exception handler. --- src/interrupt.asm | 11 ++++++++++- src/sysvar.asm | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/interrupt.asm b/src/interrupt.asm index 6ad9de4..9b50c8e 100644 --- a/src/interrupt.asm +++ b/src/interrupt.asm @@ -174,8 +174,17 @@ exception_gate_19: jmp exception_gate_main exception_gate_main: + ; Output message via serial port + mov rsi, message_error ; Location of message + call debug_msg + ; Set screen to Red + mov rdi, [0x00005F00] ; Frame buffer base + mov rcx, [0x00005F08] ; Frame buffer size + shr rcx, 2 ; Quick divide by 4 + mov eax, 0x00FF0000 ; 0x00RRGGBB + rep stosd exception_gate_main_hang: - nop + hlt jmp exception_gate_main_hang ; Hang. User must reset machine at this point ; ----------------------------------------------------------------------------- diff --git a/src/sysvar.asm b/src/sysvar.asm index 1a868ab..9df8b75 100644 --- a/src/sysvar.asm +++ b/src/sysvar.asm @@ -8,6 +8,7 @@ message_pure64: db 10, 'Pure64 ', 0 message_ok: db 'OK', 10, 0 +message_error: db 'Error', 10, 0 ;CONFIG cfg_smpinit: db 1 ; By default SMP is enabled. Set to 0 to disable. From 81d28c12fc725fcbe111d08cd4a3362664d7993e Mon Sep 17 00:00:00 2001 From: Ian Date: Fri, 19 Apr 2024 14:22:56 -0400 Subject: [PATCH 13/20] Align comments Add boot method marker --- src/boot/uefi.asm | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/boot/uefi.asm b/src/boot/uefi.asm index ce21e43..fa030c3 100644 --- a/src/boot/uefi.asm +++ b/src/boot/uefi.asm @@ -311,6 +311,9 @@ get_memmap: stosq ; EFI_MEMORY_DESCRIPTOR size in bytes mov rax, [memmapdescver] stosq ; EFI_MEMORY_DESCRIPTOR version + mov rdi, 0x00005FFF + mov al, 'U' + stosb ; 'U' as we booted via UEFI ; Set screen to green before jumping to Pure64 mov rdi, [FB] @@ -363,12 +366,12 @@ halt: ; printhex - Display a 64-bit value in hex ; IN: RBX = Value printhex: - mov rbp, 16 ; Counter + mov rbp, 16 ; Counter push rax push rcx - push rdx ; 3 pushes also align stack on 16 byte boundary - ; (8+3*8)=32, 32 evenly divisible by 16 - sub rsp, 32 ; Allocate 32 bytes of shadow space + push rdx ; 3 pushes also align stack on 16 byte boundary + ; (8+3*8)=32, 32 evenly divisible by 16 + sub rsp, 32 ; Allocate 32 bytes of shadow space printhex_loop: rol rbx, 4 mov rax, rbx @@ -381,7 +384,7 @@ printhex_loop: call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING] dec rbp jnz printhex_loop - lea rdx, [NL] + lea rdx, [newline] mov rcx, [OUTPUT] ; IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING] @@ -398,21 +401,21 @@ CODE_END: ; Data begins here DATA: -EFI_IMAGE_HANDLE: dq 0 ; EFI gives this in RCX -EFI_SYSTEM_TABLE: dq 0 ; And this in RDX -EFI_RETURN: dq 0 ; And this in RSP -BS: dq 0 ; Boot services -RTS: dq 0 ; Runtime services -CONFIG: dq 0 ; Config Table address -ACPI: dq 0 ; ACPI table address -OUTPUT: dq 0 ; Output services -VIDEO: dq 0 ; Video services -FB: dq 0 ; Frame buffer base address -FBS: dq 0 ; Frame buffer size -HR: dq 0 ; Horizontal Resolution -VR: dq 0 ; Vertical Resolution -memmap: dq 0x200000 ; Store the Memory Map from UEFI here -memmapsize: dq 32768 ; Max size we are expecting in bytes +EFI_IMAGE_HANDLE: dq 0 ; EFI gives this in RCX +EFI_SYSTEM_TABLE: dq 0 ; And this in RDX +EFI_RETURN: dq 0 ; And this in RSP +BS: dq 0 ; Boot services +RTS: dq 0 ; Runtime services +CONFIG: dq 0 ; Config Table address +ACPI: dq 0 ; ACPI table address +OUTPUT: dq 0 ; Output services +VIDEO: dq 0 ; Video services +FB: dq 0 ; Frame buffer base address +FBS: dq 0 ; Frame buffer size +HR: dq 0 ; Horizontal Resolution +VR: dq 0 ; Vertical Resolution +memmap: dq 0x200000 ; Store the Memory Map from UEFI here +memmapsize: dq 32768 ; Max size we are expecting in bytes memmapkey: dq 0 memmapdescsize: dq 0 memmapdescver: dq 0 @@ -437,13 +440,13 @@ msg_error: dw u('Error'), 0 msg_SigFail: dw u('Bad Sig!'), 0 Hex: db '0123456789ABCDEF' Num: dw 0, 0 -NL: dw 13, 10, 0 +newline: dw 13, 10, 0 align 4096 PAYLOAD: -align 65536 ; Pad out to 64K +align 65536 ; Pad out to 64K DATA_END: END: From 7161db44c9b59e0b7b3f550613b1215455251941 Mon Sep 17 00:00:00 2001 From: Ian Date: Fri, 19 Apr 2024 15:32:05 -0400 Subject: [PATCH 14/20] Add back BIOS MBR for hybrid loader --- src/boot/bios.asm | 268 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 src/boot/bios.asm diff --git a/src/boot/bios.asm b/src/boot/bios.asm new file mode 100644 index 0000000..6cbae10 --- /dev/null +++ b/src/boot/bios.asm @@ -0,0 +1,268 @@ +; ============================================================================= +; Pure64 MBR -- a 64-bit OS/software loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2024 Return Infinity -- see LICENSE.TXT +; +; This Master Boot Record will load Pure64 from a pre-defined location on the +; hard drive without making use of the file system. +; +; In this code we are expecting a BMFS-formatted drive. With BMFS the Pure64 +; binary is required to start at sector 16 (8192 bytes from the start). A small +; check is made to make sure Pure64 was loaded by comparing a signature. +; ============================================================================= + +; Default location of the second stage boot loader. This loads +; 32 KiB from sector 16 into memory at 0x8000 +%define DAP_SECTORS 64 +%define DAP_STARTSECTOR 262114+16 +%define DAP_ADDRESS 0x8000 +%define DAP_SEGMENT 0x0000 + + +BITS 16 +org 0x7C00 + +entry: + cli ; Disable interrupts + cld ; Clear direction flag + xor eax, eax + mov ss, ax + mov es, ax + mov ds, ax + mov sp, 0x7C00 + sti ; Enable interrupts + + mov [DriveNumber], dl ; BIOS passes drive number in DL + + mov ah, 0 + mov al, 11100011b ; 9600bps, no parity, 1 stop bit, 8 data bits + mov dx, 0 ; Serial port 0 + int 0x14 ; Configure serial port + +; Get the BIOS E820 Memory Map +; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map +; inputs: es:di -> destination buffer for 24 byte entries +; outputs: bp = entry count, trashes all registers except esi +do_e820: + mov edi, 0x00006000 ; location that memory map will be stored to + xor ebx, ebx ; ebx must be 0 to start + xor bp, bp ; keep an entry count in bp + mov edx, 0x0534D4150 ; Place "SMAP" into edx + mov eax, 0xe820 + mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry + mov ecx, 24 ; ask for 24 bytes + int 0x15 + jc nomemmap ; carry set on first call means "unsupported function" + mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register? + cmp eax, edx ; on success, eax must have been reset to "SMAP" + jne nomemmap + test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) + je nomemmap + jmp jmpin +e820lp: + mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call + mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry + mov ecx, 24 ; ask for 24 bytes again + int 0x15 + jc memmapend ; carry set means "end of list already reached" + mov edx, 0x0534D4150 ; repair potentially trashed register +jmpin: + jcxz skipent ; skip any 0 length entries + cmp cl, 20 ; got a 24 byte ACPI 3.X response? + jbe notext + test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? + je skipent +notext: + mov ecx, [es:di + 8] ; get lower dword of memory region length + test ecx, ecx ; is the qword == 0? + jne goodent + mov ecx, [es:di + 12] ; get upper dword of memory region length + jecxz skipent ; if length qword is 0, skip entry +goodent: + inc bp ; got a good entry: ++count, move to next storage spot + add di, 32 +skipent: + test ebx, ebx ; if ebx resets to 0, list is complete + jne e820lp +nomemmap: +; mov byte [cfg_e820], 0 ; No memory map function +memmapend: + xor eax, eax ; Create a blank record for termination (32 bytes) + mov ecx, 8 + rep stosd + +; Enable the A20 gate +set_A20: + in al, 0x64 + test al, 0x02 + jnz set_A20 + mov al, 0xD1 + out 0x64, al +check_A20: + in al, 0x64 + test al, 0x02 + jnz check_A20 + mov al, 0xDF + out 0x60, al + + mov si, msg_Load + call print_string_16 + + mov cx, 0x4000 - 1 ; Start looking from here +VBESearch: + inc cx + cmp cx, 0x5000 + je halt + mov edi, VBEModeInfoBlock ; VBE data will be stored at this address + mov ax, 0x4F01 ; GET SuperVGA MODE INFORMATION - http://www.ctyme.com/intr/rb-0274.htm + + mov bx, cx ; Mode is saved to BX for the set command later + int 0x10 + cmp ax, 0x004F ; Return value in AX should equal 0x004F if command supported and successful + jne VBESearch ; Try next mode + cmp byte [VBEModeInfoBlock.BitsPerPixel], 32 ; Desired bit depth + jne VBESearch ; If not equal, try next mode + cmp word [VBEModeInfoBlock.XResolution], 800 ; Desired XRes here + jne VBESearch + cmp word [VBEModeInfoBlock.YResolution], 600 ; Desired YRes here + jne VBESearch + + or bx, 0x4000 ; Use linear/flat frame buffer model (set bit 14) + mov ax, 0x4F02 ; SET SuperVGA VIDEO MODE - http://www.ctyme.com/intr/rb-0275.htm + int 0x10 + cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and successful + jne halt + + ; Read the 2nd stage boot loader into memory. + mov ah, 0x42 ; Extended Read + mov dl, [DriveNumber] ; http://www.ctyme.com/intr/rb-0708.htm + mov si, DAP + int 0x13 + jc read_fail + + ; Verify that the 2nd stage boot loader was read. + mov ax, [0x8006] + cmp ax, 0x3436 ; Match against the Pure64 binary + jne sig_fail + + mov al, 'B' ; 'B' as we booted via BIOS + mov [0x5FFF], al + + mov si, msg_OK + call print_string_16 + + ; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. + cli ; No more interrupts + lgdt [cs:GDTR32] ; Load GDT register + mov eax, cr0 + or al, 0x01 ; Set protected mode bit + mov cr0, eax + jmp 8:0x8000 ; Jump to 32-bit protected mode + +read_fail: + mov si, msg_ReadFail + call print_string_16 + jmp halt +sig_fail: + mov si, msg_SigFail + call print_string_16 +halt: + hlt + jmp halt +;------------------------------------------------------------------------------ + + +;------------------------------------------------------------------------------ +; 16-bit function to output a string to the serial port +; IN: SI - Address of start of string +print_string_16: ; Output string in SI to screen + pusha + mov dx, 0 ; Port 0 +.repeat: + mov ah, 0x01 ; Serial - Write character to port + lodsb ; Get char from string + cmp al, 0 + je .done ; If char is zero, end of string + int 0x14 ; Output the character + jmp short .repeat +.done: + popa + ret +;------------------------------------------------------------------------------ + +align 16 +GDTR32: ; Global Descriptors Table Register +dw gdt32_end - gdt32 - 1 ; limit of GDT (size minus one) +dq gdt32 ; linear address of GDT + +align 16 +gdt32: +dw 0x0000, 0x0000, 0x0000, 0x0000 ; Null descriptor +dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; 32-bit code descriptor +dw 0xFFFF, 0x0000, 0x9200, 0x00CF ; 32-bit data descriptor +gdt32_end: + +align 4 + +DAP: +db 0x10 +db 0x00 +dw DAP_SECTORS +dw DAP_ADDRESS +dw DAP_SEGMENT +dq DAP_STARTSECTOR + +msg_Load db 10, "MBR ", 0 +msg_OK db "OK", 0 +msg_SigFail db "- Bad Sig!", 0 +msg_ReadFail db "Failed to read!", 0 + +times 446-$+$$ db 0 + +; False partition table entry required by some BIOS vendors. +db 0x80, 0x00, 0x01, 0x00, 0xEB, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF +DriveNumber db 0x00 + +times 510-$+$$ db 0 + +sign dw 0xAA55 + +VBEModeInfoBlock: equ 0x5F00 +; VESA +; Mandatory information for all VBE revisions +VBEModeInfoBlock.ModeAttributes equ VBEModeInfoBlock + 0 ; DW - mode attributes +VBEModeInfoBlock.WinAAttributes equ VBEModeInfoBlock + 2 ; DB - window A attributes +VBEModeInfoBlock.WinBAttributes equ VBEModeInfoBlock + 3 ; DB - window B attributes +VBEModeInfoBlock.WinGranularity equ VBEModeInfoBlock + 4 ; DW - window granularity in KB +VBEModeInfoBlock.WinSize equ VBEModeInfoBlock + 6 ; DW - window size in KB +VBEModeInfoBlock.WinASegment equ VBEModeInfoBlock + 8 ; DW - window A start segment +VBEModeInfoBlock.WinBSegment equ VBEModeInfoBlock + 10 ; DW - window B start segment +VBEModeInfoBlock.WinFuncPtr equ VBEModeInfoBlock + 12 ; DD - real mode pointer to window function +VBEModeInfoBlock.BytesPerScanLine equ VBEModeInfoBlock + 16 ; DW - bytes per scan line +; Mandatory information for VBE 1.2 and above +VBEModeInfoBlock.XResolution equ VBEModeInfoBlock + 18 ; DW - horizontal resolution in pixels or characters +VBEModeInfoBlock.YResolution equ VBEModeInfoBlock + 20 ; DW - vertical resolution in pixels or characters +VBEModeInfoBlock.XCharSize equ VBEModeInfoBlock + 22 ; DB - character cell width in pixels +VBEModeInfoBlock.YCharSize equ VBEModeInfoBlock + 23 ; DB - character cell height in pixels +VBEModeInfoBlock.NumberOfPlanes equ VBEModeInfoBlock + 24 ; DB - number of memory planes +VBEModeInfoBlock.BitsPerPixel equ VBEModeInfoBlock + 25 ; DB - bits per pixel +VBEModeInfoBlock.NumberOfBanks equ VBEModeInfoBlock + 26 ; DB - number of banks +VBEModeInfoBlock.MemoryModel equ VBEModeInfoBlock + 27 ; DB - memory model type +VBEModeInfoBlock.BankSize equ VBEModeInfoBlock + 28 ; DB - bank size in KB +VBEModeInfoBlock.NumberOfImagePages equ VBEModeInfoBlock + 29 ; DB - number of image pages +VBEModeInfoBlock.Reserved equ VBEModeInfoBlock + 30 ; DB - reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) +; Direct Color fields (required for direct/6 and YUV/7 memory models) +VBEModeInfoBlock.RedMaskSize equ VBEModeInfoBlock + 31 ; DB - size of direct color red mask in bits +VBEModeInfoBlock.RedFieldPosition equ VBEModeInfoBlock + 32 ; DB - bit position of lsb of red mask +VBEModeInfoBlock.GreenMaskSize equ VBEModeInfoBlock + 33 ; DB - size of direct color green mask in bits +VBEModeInfoBlock.GreenFieldPosition equ VBEModeInfoBlock + 34 ; DB - bit position of lsb of green mask +VBEModeInfoBlock.BlueMaskSize equ VBEModeInfoBlock + 35 ; DB - size of direct color blue mask in bits +VBEModeInfoBlock.BlueFieldPosition equ VBEModeInfoBlock + 36 ; DB - bit position of lsb of blue mask +VBEModeInfoBlock.RsvdMaskSize equ VBEModeInfoBlock + 37 ; DB - size of direct color reserved mask in bits +VBEModeInfoBlock.RsvdFieldPosition equ VBEModeInfoBlock + 38 ; DB - bit position of lsb of reserved mask +VBEModeInfoBlock.DirectColorModeInfo equ VBEModeInfoBlock + 39 ; DB - direct color mode attributes +; Mandatory information for VBE 2.0 and above +VBEModeInfoBlock.PhysBasePtr equ VBEModeInfoBlock + 40 ; DD - physical address for flat memory frame buffer +VBEModeInfoBlock.Reserved1 equ VBEModeInfoBlock + 44 ; DD - Reserved - always set to 0 +VBEModeInfoBlock.Reserved2 equ VBEModeInfoBlock + 48 ; DD - Reserved - always set to 0 + +; EOF From ebd166f1d1dac1663c772e06ccecc80aef132c02 Mon Sep 17 00:00:00 2001 From: Ian Date: Fri, 19 Apr 2024 15:32:18 -0400 Subject: [PATCH 15/20] update build --- build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build.sh b/build.sh index 4db2e06..5f643b9 100755 --- a/build.sh +++ b/build.sh @@ -8,6 +8,7 @@ nasm pure64.asm -o ../bin/pure64.sys -l ../bin/pure64-debug.txt cd boot +nasm bios.asm -o ../../bin/bios.sys -l ../../bin/bios-debug.txt nasm uefi.asm -o ../../bin/uefi.sys -l ../../bin/uefi-debug.txt cd ../.. From e4139fac2e41f102c713ed664cefe97527f4a034 Mon Sep 17 00:00:00 2001 From: Ian Date: Fri, 19 Apr 2024 18:48:24 -0400 Subject: [PATCH 16/20] Start on hybrid Pure64 --- src/pure64.asm | 107 ++++++++++++++++++++++++++++++++++++++++++++++++- src/sysvar.asm | 5 +++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/src/pure64.asm b/src/pure64.asm index 16e41fe..e1778ec 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -22,7 +22,7 @@ ORG 0x00008000 PURE64SIZE equ 4096 ; Pad Pure64 to this length start: - jmp start64 ; This command will be overwritten with 'NOP's before the AP's are started + jmp bootmode ; This command will be overwritten with 'NOP's before the AP's are started nop db 0x36, 0x34 ; '64' marker @@ -46,6 +46,111 @@ BITS 16 %include "init/smp_ap.asm" ; AP's will start execution at 0x8000 and fall through to this code +; ============================================================================= +; This is 32-bit code so it's important that the encoding of the first few instructions also +; work in 64-bit mode. If a 'U' is stored at 0x5FFF then we know it was a UEFI boot and can +; immediately proceed to start64. Otherwise we need to set up a minimal 64-bit environment. +BITS 32 +bootmode: + mov esi, 0x5FFF + lodsb + cmp al, 'U' + je start64 + + mov eax, 16 ; Set the correct segment registers + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + xor eax, eax ; Clear all registers + xor ebx, ebx + xor ecx, ecx + xor edx, edx + xor esi, esi + xor edi, edi + xor ebp, ebp + mov esp, 0x8000 ; Set a known free location for the stack + +; ; Clear memory for the Page Descriptor Entries (0x10000 - 0x5FFFF) +; mov edi, 0x00210000 +; mov ecx, 81920 +; rep stosd ; Write 320KiB + +; Create the Page Map Level 4 Entries (PML4E) +; PML4 is stored at 0x0000000000002000, create the first entry there +; A single PML4 entry can map 512GiB with 2MiB pages +; A single PML4 entry is 8 bytes in length + cld + mov edi, 0x00202000 ; Create a PML4 entry for the first 4GiB of RAM + mov eax, 0x00203007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of low PDP (4KiB aligned) + stosd + xor eax, eax + stosd + +; Create the Page-Directory-Pointer-Table Entries (PDPTE) +; PDPTE is stored at 0x0000000000003000, create the first entry there +; A single PDPTE can map 1GiB with 2MiB pages +; A single PDPTE is 8 bytes in length +; 4 entries are created to map the first 4GiB of RAM + mov ecx, 4 ; number of PDPE's to make.. each PDPE maps 1GiB of physical memory + mov edi, 0x00203000 ; location of low PDPE + mov eax, 0x00410007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of first low PD (4KiB aligned) +pdpte_low_32: + stosd + push eax + xor eax, eax + stosd + pop eax + add eax, 0x00001000 ; 4KiB later (512 records x 8 bytes) + dec ecx + cmp ecx, 0 + jne pdpte_low_32 + +; Create the low Page-Directory Entries (PDE). +; A single PDE can map 2MiB of RAM +; A single PDE is 8 bytes in length + mov edi, 0x00210000 ; Location of first PDE + mov eax, 0x0000008F ; Bits 0 (P), 1 (R/W), 2 (U/S), 3 (PWT), and 7 (PS) set + xor ecx, ecx +pde_low_32: ; Create a 2 MiB page + stosd + push eax + xor eax, eax + stosd + pop eax + add eax, 0x00200000 ; Increment by 2MiB + inc ecx + cmp ecx, 2048 + jne pde_low_32 ; Create 2048 2 MiB page maps. + +; Load the GDT + lgdt [tGDTR64] + +; Enable extended properties + mov eax, cr4 + or eax, 0x0000000B0 ; PGE (Bit 7), PAE (Bit 5), and PSE (Bit 4) + mov cr4, eax + +; Point cr3 at PML4 + mov eax, 0x00202008 ; Write-thru enabled (Bit 3) + mov cr3, eax + +; Enable long mode and SYSCALL/SYSRET + mov ecx, 0xC0000080 ; EFER MSR number + rdmsr ; Read EFER + or eax, 0x00000101 ; LME (Bit 8) + wrmsr ; Write EFER + +; Enable paging to activate long mode + mov eax, cr0 + or eax, 0x80000000 ; PG (Bit 31) + mov cr0, eax + + jmp SYS64_CODE_SEL:start64 ; Jump to 64-bit mode + + ; ============================================================================= ; 64-bit mode BITS 64 diff --git a/src/sysvar.asm b/src/sysvar.asm index 9df8b75..287291a 100644 --- a/src/sysvar.asm +++ b/src/sysvar.asm @@ -58,6 +58,11 @@ dq 0x00CF92000000FFFF ; 32-bit data descriptor ; 55 Granularity 4KiB, 54 Size 32bit, 47 Present, 44 Code/Data, 41 Writeable gdt32_end: +align 16 +tGDTR64: ; Global Descriptors Table Register +dw gdt64_end - gdt64 - 1 ; limit of GDT (size minus one) +dq gdt64 ; linear address of GDT + align 16 GDTR64: ; Global Descriptors Table Register dw gdt64_end - gdt64 - 1 ; limit of GDT (size minus one) From c92cc6ffc30d2d5a6874fe4b9d92a082be354ec2 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 20 Apr 2024 14:18:04 -0400 Subject: [PATCH 17/20] Cleanup --- src/boot/bios.asm | 11 +++++++---- src/boot/uefi.asm | 13 +++++++++---- src/pure64.asm | 41 +++++++++++++++++++++++++++-------------- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/boot/bios.asm b/src/boot/bios.asm index 6cbae10..90f31a9 100644 --- a/src/boot/bios.asm +++ b/src/boot/bios.asm @@ -13,10 +13,13 @@ ; Default location of the second stage boot loader. This loads ; 32 KiB from sector 16 into memory at 0x8000 %define DAP_SECTORS 64 -%define DAP_STARTSECTOR 262114+16 +%define DAP_STARTSECTOR 262160 %define DAP_ADDRESS 0x8000 %define DAP_SEGMENT 0x0000 +; Set the desired screen resolution values below +Horizontal_Resolution equ 800 +Vertical_Resolution equ 600 BITS 16 org 0x7C00 @@ -121,9 +124,9 @@ VBESearch: jne VBESearch ; Try next mode cmp byte [VBEModeInfoBlock.BitsPerPixel], 32 ; Desired bit depth jne VBESearch ; If not equal, try next mode - cmp word [VBEModeInfoBlock.XResolution], 800 ; Desired XRes here + cmp word [VBEModeInfoBlock.XResolution], Horizontal_Resolution ; Desired XRes here jne VBESearch - cmp word [VBEModeInfoBlock.YResolution], 600 ; Desired YRes here + cmp word [VBEModeInfoBlock.YResolution], Vertical_Resolution ; Desired YRes here jne VBESearch or bx, 0x4000 ; Use linear/flat frame buffer model (set bit 14) @@ -145,7 +148,7 @@ VBESearch: jne sig_fail mov al, 'B' ; 'B' as we booted via BIOS - mov [0x5FFF], al + mov [0x5FFF], al ; Store the boot marker mov si, msg_OK call print_string_16 diff --git a/src/boot/uefi.asm b/src/boot/uefi.asm index fa030c3..b7a46c9 100644 --- a/src/boot/uefi.asm +++ b/src/boot/uefi.asm @@ -169,7 +169,7 @@ nextentry: jne error ; Parse the graphics information - ; Mode Structure + ; EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE Structure ; 0 UINT32 - MaxMode ; 4 UINT32 - Mode ; 8 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION - *Info; @@ -180,7 +180,9 @@ nextentry: add rax, EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE mov rax, [rax] ; RAX holds the address of the Mode structure mov eax, [rax] ; RAX holds UINT32 MaxMode - mov [vid_max], rax + mov ebx, [rax+4] ; RBX holds UINT32 Mode (The current mode) + mov [vid_max], rax ; The maximum video modes we can check + mov [vid_orig], rbx ; The mode currently used by UEFI jmp vid_query next_video_mode: @@ -216,6 +218,8 @@ vid_query: mov rcx, [VIDEO] ; IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This mov rdx, [vid_current] ; IN UINT32 ModeNumber call [rcx + EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE] + cmp rax, EFI_SUCCESS + jne next_video_mode skip_set_video: ; Gather video mode details @@ -312,8 +316,8 @@ get_memmap: mov rax, [memmapdescver] stosq ; EFI_MEMORY_DESCRIPTOR version mov rdi, 0x00005FFF - mov al, 'U' - stosb ; 'U' as we booted via UEFI + mov al, 'U' ; 'U' as we booted via UEFI + stosb ; Store the boor marker ; Set screen to green before jumping to Pure64 mov rdi, [FB] @@ -419,6 +423,7 @@ memmapsize: dq 32768 ; Max size we are expecting in bytes memmapkey: dq 0 memmapdescsize: dq 0 memmapdescver: dq 0 +vid_orig: dq 0 vid_current: dq 0 vid_max: dq 0 vid_size: dq 0 diff --git a/src/pure64.asm b/src/pure64.asm index e1778ec..a51de43 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -53,9 +53,9 @@ BITS 16 BITS 32 bootmode: mov esi, 0x5FFF - lodsb - cmp al, 'U' - je start64 + lodsb ; Load the boot marker + cmp al, 'U' ; If it is 'U' then we booted via UEFI and are already in 64-bit mode for the BSP + je start64 ; Jump to the 64-bit code, otherwise fall through to 32-bit init mov eax, 16 ; Set the correct segment registers mov ds, ax @@ -73,13 +73,26 @@ bootmode: xor ebp, ebp mov esp, 0x8000 ; Set a known free location for the stack -; ; Clear memory for the Page Descriptor Entries (0x10000 - 0x5FFFF) -; mov edi, 0x00210000 -; mov ecx, 81920 -; rep stosd ; Write 320KiB + ; Save the frame buffer address, + mov esi, 0x5F00 + mov eax, [0x5F00 + 40] + stosd ; 64-bit Frame Buffer Base (low) + xor eax, eax + stosd ; 64-bit Frame Buffer Base (high) + stosd ; 64-bit Frame Buffer Size in bytes (low) + stosd ; 64-bit Frame Buffer Size in bytes (high) + mov eax, [0x5F00 + 18] + stosw ; 16-bit Screen X + mov eax, [0x5F00 + 20] + stosw ; 16-bit Screen y + + ; Clear memory for the Page Descriptor Entries (0x10000 - 0x5FFFF) + mov edi, 0x00210000 + mov ecx, 81920 + rep stosd ; Write 320KiB -; Create the Page Map Level 4 Entries (PML4E) -; PML4 is stored at 0x0000000000002000, create the first entry there +; Create the temporary Page Map Level 4 Entries (PML4E) +; PML4 is stored at 0x0000000000202000, create the first entry there ; A single PML4 entry can map 512GiB with 2MiB pages ; A single PML4 entry is 8 bytes in length cld @@ -89,14 +102,14 @@ bootmode: xor eax, eax stosd -; Create the Page-Directory-Pointer-Table Entries (PDPTE) -; PDPTE is stored at 0x0000000000003000, create the first entry there +; Create the temporary Page-Directory-Pointer-Table Entries (PDPTE) +; PDPTE is stored at 0x0000000000203000, create the first entry there ; A single PDPTE can map 1GiB with 2MiB pages ; A single PDPTE is 8 bytes in length ; 4 entries are created to map the first 4GiB of RAM mov ecx, 4 ; number of PDPE's to make.. each PDPE maps 1GiB of physical memory mov edi, 0x00203000 ; location of low PDPE - mov eax, 0x00410007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of first low PD (4KiB aligned) + mov eax, 0x00210007 ; Bits 0 (P), 1 (R/W), 2 (U/S), location of first low PD (4KiB aligned) pdpte_low_32: stosd push eax @@ -108,7 +121,7 @@ pdpte_low_32: cmp ecx, 0 jne pdpte_low_32 -; Create the low Page-Directory Entries (PDE). +; Create the temporary low Page-Directory Entries (PDE). ; A single PDE can map 2MiB of RAM ; A single PDE is 8 bytes in length mov edi, 0x00210000 ; Location of first PDE @@ -160,7 +173,7 @@ start64: mov edi, 0x5000 ; Clear the info map and system variable memory xor eax, eax mov ecx, 960 ; 3840 bytes (Range is 0x5000 - 0x5EFF) - rep stosd ; Don't overwrite the UEFI data at 0x5F00 + rep stosd ; Don't overwrite the UEFI/BIOS data at 0x5F00 ; Set up RTC ; Port 0x70 is RTC Address, and 0x71 is RTC Data From b1fff96a405dd6deacad4a401c87a09b5acc8618 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 20 Apr 2024 20:20:51 -0400 Subject: [PATCH 18/20] Fixes for hybrid mode --- src/init/acpi.asm | 7 +++++-- src/pure64.asm | 20 ++++++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/init/acpi.asm b/src/init/acpi.asm index 160908f..eaaa276 100644 --- a/src/init/acpi.asm +++ b/src/init/acpi.asm @@ -7,8 +7,11 @@ init_acpi: - jmp foundACPIfromUEFI - + mov al, [p_BootMode] + cmp al, 'U' + je foundACPIfromUEFI + mov esi, 0x000E0000 ; Start looking for the Root System Description Pointer Structure + mov rbx, 'RSD PTR ' ; This in the Signature for the ACPI Structure Table (0x2052545020445352) searchingforACPI: lodsq ; Load a quad word from RSI and store in RAX, then increment RSI by 8 cmp rax, rbx diff --git a/src/pure64.asm b/src/pure64.asm index a51de43..03594ed 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -73,17 +73,26 @@ bootmode: xor ebp, ebp mov esp, 0x8000 ; Set a known free location for the stack - ; Save the frame buffer address, - mov esi, 0x5F00 + ; Save the frame buffer address, size (after its calculated), and the screen x,y + mov bx, [0x5F00 + 20] + push ebx + mov ax, [0x5F00 + 18] + push eax + mul ebx + mov ecx, eax + shl ecx, 2 ; Quick multiply by 4 + mov edi, 0x5F00 mov eax, [0x5F00 + 40] stosd ; 64-bit Frame Buffer Base (low) xor eax, eax stosd ; 64-bit Frame Buffer Base (high) + mov eax, ecx stosd ; 64-bit Frame Buffer Size in bytes (low) + xor eax, eax stosd ; 64-bit Frame Buffer Size in bytes (high) - mov eax, [0x5F00 + 18] + pop eax stosw ; 16-bit Screen X - mov eax, [0x5F00 + 20] + pop eax stosw ; 16-bit Screen y ; Clear memory for the Page Descriptor Entries (0x10000 - 0x5FFFF) @@ -175,6 +184,9 @@ start64: mov ecx, 960 ; 3840 bytes (Range is 0x5000 - 0x5EFF) rep stosd ; Don't overwrite the UEFI/BIOS data at 0x5F00 + mov al, [0x5FFF] + mov [p_BootMode], al + ; Set up RTC ; Port 0x70 is RTC Address, and 0x71 is RTC Data ; http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt From 0d4df906ded9739200eefb4d65e5b0337b068f74 Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 21 Apr 2024 11:10:41 -0400 Subject: [PATCH 19/20] Fix FAT32 MBR - Add BPB and EBPB - Remove test output and serial code setup - Change boot mode to be passed in BL --- src/boot/bios.asm | 109 +++++++++++++++++++++++++++++----------------- src/boot/uefi.asm | 5 +-- src/pure64.asm | 9 ++-- 3 files changed, 76 insertions(+), 47 deletions(-) diff --git a/src/boot/bios.asm b/src/boot/bios.asm index 90f31a9..f358437 100644 --- a/src/boot/bios.asm +++ b/src/boot/bios.asm @@ -25,6 +25,41 @@ BITS 16 org 0x7C00 entry: + jmp bootcode + nop + +; BPB (BIOS Parameter Block) +dq 0 ; OEM identifier +dw 0 ; Bytes per sector +db 0 ; Sectors per cluster +dw 0 ; Reserved sectors +db 0 ; Number of FATs +dw 0 ; Number of root directory entries +dw 0 ; The total sectors in the logical volume +db 0 ; Media descriptor type +dw 0 ; Number of sectors per FAT +dw 0 ; Number of sectors per track +dw 0 ; Number of heads or sides on the storage media +dd 0 ; Number of hidden sectors +dd 0 ; Large sector count + +; EBPB (Extended Boot Record) +dd 0 ; Sectors per FAT +dw 0 ; Flags +dw 0 ; FAT version number +dd 0 ; The cluster number of the root directory +dw 0 ; The sector number of the FSInfo structure +dw 0 ; The sector number of the backup boot sector +dq 0 ; Reserved +dd 0 ; Reserved +db 0 ; Drive number +db 0 ; Flags in Windows NT +db 0 ; Signature +dd 0 ; Volume ID 'Serial' number +times 11 db 0 ; Volume label string +dq 0 ; System identifier string. Always "FAT32 " + +bootcode: cli ; Disable interrupts cld ; Clear direction flag xor eax, eax @@ -36,11 +71,6 @@ entry: mov [DriveNumber], dl ; BIOS passes drive number in DL - mov ah, 0 - mov al, 11100011b ; 9600bps, no parity, 1 stop bit, 8 data bits - mov dx, 0 ; Serial port 0 - int 0x14 ; Configure serial port - ; Get the BIOS E820 Memory Map ; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map ; inputs: es:di -> destination buffer for 24 byte entries @@ -107,8 +137,8 @@ check_A20: mov al, 0xDF out 0x60, al - mov si, msg_Load - call print_string_16 +; mov si, msg_Load +; call print_string_16 mov cx, 0x4000 - 1 ; Start looking from here VBESearch: @@ -143,15 +173,15 @@ VBESearch: jc read_fail ; Verify that the 2nd stage boot loader was read. - mov ax, [0x8006] - cmp ax, 0x3436 ; Match against the Pure64 binary - jne sig_fail +; mov ax, [0x8006] +; cmp ax, 0x3436 ; Match against the Pure64 binary +; jne sig_fail - mov al, 'B' ; 'B' as we booted via BIOS - mov [0x5FFF], al ; Store the boot marker + mov bl, 'B' ; 'B' as we booted via BIOS +; mov [0x5FFF], al ; Store the boot marker - mov si, msg_OK - call print_string_16 +; mov si, msg_OK +; call print_string_16 ; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. cli ; No more interrupts @@ -162,12 +192,12 @@ VBESearch: jmp 8:0x8000 ; Jump to 32-bit protected mode read_fail: - mov si, msg_ReadFail - call print_string_16 - jmp halt +; mov si, msg_ReadFail +; call print_string_16 +; jmp halt sig_fail: - mov si, msg_SigFail - call print_string_16 +; mov si, msg_SigFail +; call print_string_16 halt: hlt jmp halt @@ -177,19 +207,19 @@ halt: ;------------------------------------------------------------------------------ ; 16-bit function to output a string to the serial port ; IN: SI - Address of start of string -print_string_16: ; Output string in SI to screen - pusha - mov dx, 0 ; Port 0 -.repeat: - mov ah, 0x01 ; Serial - Write character to port - lodsb ; Get char from string - cmp al, 0 - je .done ; If char is zero, end of string - int 0x14 ; Output the character - jmp short .repeat -.done: - popa - ret +;print_string_16: ; Output string in SI to screen +; pusha +; mov dx, 0 ; Port 0 +;.repeat: +; mov ah, 0x01 ; Serial - Write character to port +; lodsb ; Get char from string +; cmp al, 0 +; je .done ; If char is zero, end of string +; int 0x14 ; Output the character +; jmp short .repeat +;.done: +; popa +; ret ;------------------------------------------------------------------------------ align 16 @@ -214,19 +244,20 @@ dw DAP_ADDRESS dw DAP_SEGMENT dq DAP_STARTSECTOR -msg_Load db 10, "MBR ", 0 -msg_OK db "OK", 0 -msg_SigFail db "- Bad Sig!", 0 -msg_ReadFail db "Failed to read!", 0 +DriveNumber db 0x00 + +;msg_Load db 10, "MBR ", 0 +;msg_OK db "OK", 0 +;msg_SigFail db "- Bad Sig!", 0 +;msg_ReadFail db "Failed to read!", 0 times 446-$+$$ db 0 -; False partition table entry required by some BIOS vendors. -db 0x80, 0x00, 0x01, 0x00, 0xEB, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF -DriveNumber db 0x00 +; Partition entries (4x 16-bytes) times 510-$+$$ db 0 +; Boot signature sign dw 0xAA55 VBEModeInfoBlock: equ 0x5F00 diff --git a/src/boot/uefi.asm b/src/boot/uefi.asm index b7a46c9..2d1a9b8 100644 --- a/src/boot/uefi.asm +++ b/src/boot/uefi.asm @@ -252,6 +252,7 @@ skip_set_video: cmp ax, 0x3436 ; Match against the Pure64 binary jne sig_fail +; Debug ; mov rbx, [FB] ; Display the framebuffer address ; call printhex @@ -315,9 +316,6 @@ get_memmap: stosq ; EFI_MEMORY_DESCRIPTOR size in bytes mov rax, [memmapdescver] stosq ; EFI_MEMORY_DESCRIPTOR version - mov rdi, 0x00005FFF - mov al, 'U' ; 'U' as we booted via UEFI - stosb ; Store the boor marker ; Set screen to green before jumping to Pure64 mov rdi, [FB] @@ -344,6 +342,7 @@ get_memmap: xor r14, r14 xor r15, r15 + mov bl, 'U' jmp 0x8000 exitfailure: diff --git a/src/pure64.asm b/src/pure64.asm index 03594ed..dc6db6b 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -52,9 +52,7 @@ BITS 16 ; immediately proceed to start64. Otherwise we need to set up a minimal 64-bit environment. BITS 32 bootmode: - mov esi, 0x5FFF - lodsb ; Load the boot marker - cmp al, 'U' ; If it is 'U' then we booted via UEFI and are already in 64-bit mode for the BSP + cmp bl, 'U' ; If it is 'U' then we booted via UEFI and are already in 64-bit mode for the BSP je start64 ; Jump to the 64-bit code, otherwise fall through to 32-bit init mov eax, 16 ; Set the correct segment registers @@ -165,6 +163,8 @@ pde_low_32: ; Create a 2 MiB page or eax, 0x00000101 ; LME (Bit 8) wrmsr ; Write EFER + mov bl, 'B' + ; Enable paging to activate long mode mov eax, cr0 or eax, 0x80000000 ; PG (Bit 31) @@ -184,8 +184,7 @@ start64: mov ecx, 960 ; 3840 bytes (Range is 0x5000 - 0x5EFF) rep stosd ; Don't overwrite the UEFI/BIOS data at 0x5F00 - mov al, [0x5FFF] - mov [p_BootMode], al + mov [p_BootMode], bl ; Set up RTC ; Port 0x70 is RTC Address, and 0x71 is RTC Data From 93d4d09ee239964873f8ce4499c2249b438c29ad Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 21 Apr 2024 11:33:06 -0400 Subject: [PATCH 20/20] Add bios-pxe.asm --- src/boot/bios-pxe.asm | 238 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 src/boot/bios-pxe.asm diff --git a/src/boot/bios-pxe.asm b/src/boot/bios-pxe.asm new file mode 100644 index 0000000..e655a63 --- /dev/null +++ b/src/boot/bios-pxe.asm @@ -0,0 +1,238 @@ +; ============================================================================= +; Pure64 PXE Start -- a 64-bit OS/software loader written in Assembly for x86-64 systems +; Copyright (C) 2008-2024 Return Infinity -- see LICENSE.TXT +; +; This is a stub file for loading Pure64 and a kernel/software package via PXE. +; +; Windows - copy /b pxestart.bin + pure64.sys + kernel64.sys pxeboot.bin +; Unix - cat pxestart.bin pure64.sys kernel64.sys > pxeboot.bin +; +; Max size of the resulting pxeboot.bin is 33792 bytes. 1K for the PXE loader +; stub and up to 32KiB for the code/data. PXE loads the file to address +; 0x00007C00 (Just like a boot sector). +; +; File Sizes +; pxestart.bin 1024 bytes +; pure64.sys 4096 bytes +; kernel64.sys 16384 bytes (or so) +; ============================================================================= + +; Set the desired screen resolution values below +Horizontal_Resolution equ 800 +Vertical_Resolution equ 600 + +BITS 16 +org 0x7C00 + +start: + cli ; Disable interrupts + cld ; Clear direction flag + xor eax, eax + mov ss, ax + mov es, ax + mov ds, ax + mov sp, 0x7C00 + sti ; Enable interrupts + +; mov ah, 0 +; mov al, 11100011b ; 9600bps, no parity, 1 stop bit, 8 data bits +; mov dx, 0 ; Serial port 0 +; int 0x14 ; Configure serial port + +; Get the BIOS E820 Memory Map +; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map +; inputs: es:di -> destination buffer for 24 byte entries +; outputs: bp = entry count, trashes all registers except esi +do_e820: + mov edi, 0x00006000 ; location that memory map will be stored to + xor ebx, ebx ; ebx must be 0 to start + xor bp, bp ; keep an entry count in bp + mov edx, 0x0534D4150 ; Place "SMAP" into edx + mov eax, 0xe820 + mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry + mov ecx, 24 ; ask for 24 bytes + int 0x15 + jc nomemmap ; carry set on first call means "unsupported function" + mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register? + cmp eax, edx ; on success, eax must have been reset to "SMAP" + jne nomemmap + test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) + je nomemmap + jmp jmpin +e820lp: + mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call + mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry + mov ecx, 24 ; ask for 24 bytes again + int 0x15 + jc memmapend ; carry set means "end of list already reached" + mov edx, 0x0534D4150 ; repair potentially trashed register +jmpin: + jcxz skipent ; skip any 0 length entries + cmp cl, 20 ; got a 24 byte ACPI 3.X response? + jbe notext + test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? + je skipent +notext: + mov ecx, [es:di + 8] ; get lower dword of memory region length + test ecx, ecx ; is the qword == 0? + jne goodent + mov ecx, [es:di + 12] ; get upper dword of memory region length + jecxz skipent ; if length qword is 0, skip entry +goodent: + inc bp ; got a good entry: ++count, move to next storage spot + add di, 32 +skipent: + test ebx, ebx ; if ebx resets to 0, list is complete + jne e820lp +nomemmap: +; mov byte [cfg_e820], 0 ; No memory map function +memmapend: + xor eax, eax ; Create a blank record for termination (32 bytes) + mov ecx, 8 + rep stosd + +; Enable the A20 gate +set_A20: + in al, 0x64 + test al, 0x02 + jnz set_A20 + mov al, 0xD1 + out 0x64, al +check_A20: + in al, 0x64 + test al, 0x02 + jnz check_A20 + mov al, 0xDF + out 0x60, al + + mov si, msg_Load ; Print message + call print_string_16 + + mov edi, VBEModeInfoBlock ; VBE data will be stored at this address + mov ax, 0x4F01 ; GET SuperVGA MODE INFORMATION - http://www.ctyme.com/intr/rb-0274.htm + ; CX queries the mode, it should be in the form 0x41XX as bit 14 is set for LFB and bit 8 is set for VESA mode + ; 0x4112 is 640x480x24bit, 0x4129 should be 32bit + ; 0x4115 is 800x600x24bit, 0x412E should be 32bit + ; 0x4118 is 1024x768x24bit, 0x4138 should be 32bit + ; 0x411B is 1280x1024x24bit, 0x413D should be 32bit + mov cx, 0x4118 ; Put your desired mode here + mov bx, cx ; Mode is saved to BX for the set command later + int 0x10 + + cmp ax, 0x004F ; Return value in AX should equal 0x004F if command supported and successful + jne halt + cmp byte [VBEModeInfoBlock.BitsPerPixel], 24 ; Make sure this matches the number of bits for the mode! + jne halt ; If set bit mode was unsuccessful then bail out + or bx, 0x4000 ; Use linear/flat frame buffer model (set bit 14) + mov ax, 0x4F02 ; SET SuperVGA VIDEO MODE - http://www.ctyme.com/intr/rb-0275.htm + int 0x10 + cmp ax, 0x004F ; Return value in AX should equal 0x004F if supported and successful + jne halt + + mov ax, [0x8006] + cmp ax, 0x3436 ; Match against the Pure64 binary + jne sig_fail + + mov si, msg_OK + call print_string_16 + + mov bl, 'B' ; 'B' as we booted via BIOS + +; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode. + cli ; No more interrupts + lgdt [cs:GDTR32] ; Load GDT register + mov eax, cr0 + or al, 0x01 ; Set protected mode bit + mov cr0, eax + jmp 8:0x8000 ; Jump to 32-bit protected mode + +sig_fail: + mov si, msg_SigFail + call print_string_16 +halt: + hlt + jmp halt +;------------------------------------------------------------------------------ + + +;------------------------------------------------------------------------------ +; 16-bit function to output a string to the serial port +; IN: SI - Address of start of string +print_string_16: ; Output string in SI to screen + pusha + mov dx, 0 ; Port 0 +.repeat: + mov ah, 0x01 ; Serial - Write character to port + lodsb ; Get char from string + cmp al, 0 + je .done ; If char is zero, end of string + int 0x14 ; Output the character + jmp short .repeat +.done: + popa + ret +;------------------------------------------------------------------------------ + + +align 16 +GDTR32: ; Global Descriptors Table Register +dw gdt32_end - gdt32 - 1 ; limit of GDT (size minus one) +dq gdt32 ; linear address of GDT + +align 16 +gdt32: +dw 0x0000, 0x0000, 0x0000, 0x0000 ; Null desciptor +dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; 32-bit code descriptor +dw 0xFFFF, 0x0000, 0x9200, 0x00CF ; 32-bit data descriptor +gdt32_end: + +msg_Load db "PXE ", 0 +msg_OK db "OK", 0 +msg_SigFail db "- Bad Sig!", 0 + +times 510-$+$$ db 0 ; Pad out for a normal boot sector + +sign dw 0xAA55 ; BIOS boot sector signature + +times 1024-$+$$ db 0 ; Padding so that Pure64 will be aligned at 0x8000 + +VBEModeInfoBlock: equ 0x5F00 +; VESA +; Mandatory information for all VBE revisions +VBEModeInfoBlock.ModeAttributes equ VBEModeInfoBlock + 0 ; DW - mode attributes +VBEModeInfoBlock.WinAAttributes equ VBEModeInfoBlock + 2 ; DB - window A attributes +VBEModeInfoBlock.WinBAttributes equ VBEModeInfoBlock + 3 ; DB - window B attributes +VBEModeInfoBlock.WinGranularity equ VBEModeInfoBlock + 4 ; DW - window granularity in KB +VBEModeInfoBlock.WinSize equ VBEModeInfoBlock + 6 ; DW - window size in KB +VBEModeInfoBlock.WinASegment equ VBEModeInfoBlock + 8 ; DW - window A start segment +VBEModeInfoBlock.WinBSegment equ VBEModeInfoBlock + 10 ; DW - window B start segment +VBEModeInfoBlock.WinFuncPtr equ VBEModeInfoBlock + 12 ; DD - real mode pointer to window function +VBEModeInfoBlock.BytesPerScanLine equ VBEModeInfoBlock + 16 ; DW - bytes per scan line +; Mandatory information for VBE 1.2 and above +VBEModeInfoBlock.XResolution equ VBEModeInfoBlock + 18 ; DW - horizontal resolution in pixels or characters +VBEModeInfoBlock.YResolution equ VBEModeInfoBlock + 20 ; DW - vertical resolution in pixels or characters +VBEModeInfoBlock.XCharSize equ VBEModeInfoBlock + 22 ; DB - character cell width in pixels +VBEModeInfoBlock.YCharSize equ VBEModeInfoBlock + 23 ; DB - character cell height in pixels +VBEModeInfoBlock.NumberOfPlanes equ VBEModeInfoBlock + 24 ; DB - number of memory planes +VBEModeInfoBlock.BitsPerPixel equ VBEModeInfoBlock + 25 ; DB - bits per pixel +VBEModeInfoBlock.NumberOfBanks equ VBEModeInfoBlock + 26 ; DB - number of banks +VBEModeInfoBlock.MemoryModel equ VBEModeInfoBlock + 27 ; DB - memory model type +VBEModeInfoBlock.BankSize equ VBEModeInfoBlock + 28 ; DB - bank size in KB +VBEModeInfoBlock.NumberOfImagePages equ VBEModeInfoBlock + 29 ; DB - number of image pages +VBEModeInfoBlock.Reserved equ VBEModeInfoBlock + 30 ; DB - reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) +; Direct Color fields (required for direct/6 and YUV/7 memory models) +VBEModeInfoBlock.RedMaskSize equ VBEModeInfoBlock + 31 ; DB - size of direct color red mask in bits +VBEModeInfoBlock.RedFieldPosition equ VBEModeInfoBlock + 32 ; DB - bit position of lsb of red mask +VBEModeInfoBlock.GreenMaskSize equ VBEModeInfoBlock + 33 ; DB - size of direct color green mask in bits +VBEModeInfoBlock.GreenFieldPosition equ VBEModeInfoBlock + 34 ; DB - bit position of lsb of green mask +VBEModeInfoBlock.BlueMaskSize equ VBEModeInfoBlock + 35 ; DB - size of direct color blue mask in bits +VBEModeInfoBlock.BlueFieldPosition equ VBEModeInfoBlock + 36 ; DB - bit position of lsb of blue mask +VBEModeInfoBlock.RsvdMaskSize equ VBEModeInfoBlock + 37 ; DB - size of direct color reserved mask in bits +VBEModeInfoBlock.RsvdFieldPosition equ VBEModeInfoBlock + 38 ; DB - bit position of lsb of reserved mask +VBEModeInfoBlock.DirectColorModeInfo equ VBEModeInfoBlock + 39 ; DB - direct color mode attributes +; Mandatory information for VBE 2.0 and above +VBEModeInfoBlock.PhysBasePtr equ VBEModeInfoBlock + 40 ; DD - physical address for flat memory frame buffer +VBEModeInfoBlock.Reserved1 equ VBEModeInfoBlock + 44 ; DD - Reserved - always set to 0 +VBEModeInfoBlock.Reserved2 equ VBEModeInfoBlock + 48 ; DD - Reserved - always set to 0 + +; EOF \ No newline at end of file