I've cut out a great deal of my code which performs the checks for long mode, and ended up with a set of 3 files which I've included below. As you can probably tell, I create a new section at the 1 MiB mark which contains the long mode and kernel bootstrap; everything else gets linked at 0xFFFF800000100000, which my code will probably jump to (assuming I've not messed up with the paging structures; it's a little difficult for me to verify in Bochs at the moment)
LinkScript.ld:
Code: Select all
OUTPUT_FORMAT(elf64-x86-64)
ENTRY(asmEntry)
LINEAR_ADDRESS = 0x100000;
VIRTUAL_ADDRESS = 0xFFFF800000000000;
SECTIONS
{
. = LINEAR_ADDRESS;
textStart = .;
.pmode ALIGN(0x1000) :
{
*(.multiboot*)
*(.pmode.gdt*)
*(.pmode.text*)
}
. += VIRTUAL_ADDRESS;
.text ALIGN(0x1000) : AT(ADDR(.text) - VIRTUAL_ADDRESS)
{
*(.text)
*(.rodata*)
}
textEnd = .;
dataStart = .;
.data ALIGN(0x1000) : AT(ADDR(.data) - VIRTUAL_ADDRESS)
{
constructorStart = .;
*(.ctor*)
constructorEnd = .;
*(.data)
}
dataEnd = .;
bssStart = .;
.bss ALIGN(0x1000) : AT(ADDR(.bss) - VIRTUAL_ADDRESS)
{
startBss = .;
*(COMMON)
*(.bss)
endBss = .;
}
bssEnd = .;
/DISCARD/ :
{
*(.eh_frame)
}
end = .;
}
Code: Select all
GLOBAL asmEntry
EXTERN textStart
EXTERN bssStart
EXTERN bssEnd
EXTERN HigherHalfEntry
%include "Multitasking/Paging.s"
; Basic GrUB information
ModuleAlign equ 1
MemoryMap equ 2
AOUTKludge equ (1 << 16)
Flags equ ModuleAlign | MemoryMap | AOUTKludge
Magic equ 0x1BADB002
Checksum equ -(Magic + Flags)
[BITS 32]
section .multiboot
align 0x4
MultibootHeader:
dd Magic
dd Flags
dd Checksum
dd (MultibootHeader) ; header_addr
dd (textStart) ; load_addr
dd (bssStart - VirtualAddressBase) ; load_end_addr
dd (bssEnd - VirtualAddressBase) ; bss_end_addr
dd (asmEntry) ; entry_addr
section .pmode.gdt
align 0x8
gdt:
dq 0x0000000000000000 ; Standard NULL entry
dq 0x00AF9A000000FFFF ; 64-bit kernel code
dq 0x00AF93000000FFFF ; 64-bit kernel data
gdtEnd:
align 0x8
gdtPtr:
dw gdtEnd - gdt - 1
dq gdt
section .pmode.text
; GrUB will jump here, so it needs to be 32-bit code
asmEntry:
; First, make certain that an interrupt won't arrive and mess up the boot code
cli
mov ecx, cr0
and ecx, 0x7FFFFFFF
mov cr0, ecx
; Enable bit 5 (PAE) in CR4
mov ecx, cr4
bts ecx, 5
mov cr4, ecx
; Switch on long mode in the necessary MSR
mov ecx, 0xC0000080
rdmsr
bts eax, 8
wrmsr
xchg bx, bx
mov ecx, (pml4Base - VirtualAddressBase) ; Load ECX with the physical address of the boot page directory
mov cr3, ecx
mov ecx, cr0
bts ecx, 31
mov cr0, ecx
lgdt [gdtPtr]
; After this jump, the CPU is in long mode
jmp 0x8:(HigherHalfEntry - VirtualAddressBase)
Code: Select all
%ifndef Paging_S
%define Paging_S
; This file just contains the basic structures necessary to get the higher half operating
; It also stores the first page directory entries (including recursive page mapping)
VirtualAddressBase equ 0xFFFF800000000000
VirtualAddressBasePML4 equ (VirtualAddressBase >> 40) & 0x1FF
VirtualAddressBasePDPT equ (VirtualAddressBase >> 31) & 0x1FF
VirtualAddressBasePageDirectory equ (VirtualAddressBase >> 22) & 0x1FF
VirtualAddressBasePageTable equ (VirtualAddressBase >> 13) & 0x1FF
section .data
; All this just creates a simple mapping for the bootstrap code
; pageTable gets reused so that it can create another mapping later
align 0x1000
; Using this page table allows me to map any virtual address to 0
; 512 entries in the page table, resulting in each page table representing 2 MiB
pageTable:
%assign i 0
%rep 512
dq i | 11b
%assign i i+0x1000
%endrep
align 0x1000
pageDirectory:
dq pageTable - VirtualAddressBase + 11b
%rep 511
dq 0
%endrep
; 512 entries in the PDPT
align 0x1000
pdpt:
dq pageDirectory - VirtualAddressBase + 11b
%assign i 0
%rep 511
dq 0
%endrep
align 0x1000
higherHalfPageDirectory:
times (VirtualAddressBasePageTable) dq 0
dq (pageTable - VirtualAddressBase + 11b)
times (512 - VirtualAddressBasePageTable - 1) dq 0
; 512 entries in the PDPT
align 0x1000
higherHalfPDPT:
times (VirtualAddressBasePageDirectory) dq 0
dq (higherHalfPageDirectory - VirtualAddressBase + 11b)
times (512 - VirtualAddressBasePageDirectory) dq 0
; There are 512 entries in the PML4
align 0x1000
pml4Base:
dq pdpt - VirtualAddressBase + 11b
times 254 dq 0
dq (higherHalfPDPT - VirtualAddressBase + 11b)
times 255 dq 0
dq pdpt - VirtualAddressBase + 11b
%endif