Map the kernel to -2GB in virtual memory in the initial page tables.
.code64
_start:
+ # At this point we expect to have a valid page table identity mapping (at least) the lowest 1G
+ # of physical memory; that means that the first PML4 entry must point to a valid PDP, and the
+ # first entry of that PDP must point to a valid PD.
+ # Our goal is to map the first (physical) gigabyte to -2 GB in virtual address space; thus, we
+ # need to make the last entry of the PML4 (covering the last 256T) point to a PDP, and the
+ # second-to-last entry in that PDP point to the same PD as the PD in the lower half.
+ #
+ # We can reuse the existing data structures to achieve that goal. By pointing the last entry
+ # of PML4 to the same PD as the first entry, and setting the second-to-last entry of that PD
+ # to be the same as the first, we get our desired effect of mapping physical address 0x0 to
+ # virtual address 0xFFFFFFFF80000000. As a side effect, this will map physical address 0x0 to
+ # virtual address 0x0000007F80000000 (510*1G) as well, but that's fine. We'll be rewriting
+ # the page tables soon after jumping to the kernel anyway.
+ #
+ # Note: don't touch %rsi, as that contains the address of the zero page.
+
+ # Map the last entry of PML4 to the same location as the first.
+ movq %cr3, %rbx # rbx = cr3
+ movq (%rbx), %rax # rax = *rbx
+ movq %rax, 4088(%rbx) # rbx[511] = rax
+
+ # Map the last entry of PDP to the same location as the first.
+ movabsq $0x000FFFFFFFFFF000, %rax # rax = $const
+ andq (%rbx), %rax # rax = *rbx & rax (mask out all but the address)
+ movq (%rax), %rdx # rdx = *rax
+ movq %rdx, 4080(%rax) # rax[510] = rdx
+
+ # Finally, trigger a full TLB flush by overwriting CR3, even if it is the same value.
+ movq %rbx, %cr3
+
mov $stack_start, %rsp
- # Push 8 bytes to fix stack alignment issue. Because we enter rust64_start
- # with a jmp rather than a call the function prologue means that the stack
- # is no loger 16-byte aligned.
+ # Push 8 bytes to fix stack alignment issue. Because we enter rust64_start with a jmp rather
+ # than a call the function prologue means that the stack is no longer 16-byte aligned.
push $0
jmp rust64_start
