Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/amd64/mpboot.S
Show First 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | protmode: | ||||
mov $bootdata-gdt, %eax | mov $bootdata-gdt, %eax | ||||
mov %ax, %ds | mov %ax, %ds | ||||
/* | /* | ||||
* Turn on the PAE bit and optionally the LA57 bit for when paging | * Turn on the PAE bit and optionally the LA57 bit for when paging | ||||
* is later enabled. | * is later enabled. | ||||
*/ | */ | ||||
mov %cr4, %eax | mov %cr4, %eax | ||||
orl $CR4_PAE, %eax | orl $(CR4_PAE | CR4_PGE), %eax | ||||
markj: Why does PGE now need to be set here? In particular, the load_cr4() in init_secondary_tail()… | |||||
Done Inline ActionsBecause I am switching to the kernel page table which in some configurations have PG_G bit set in PTEs. If not enabled there, CPU reacts with #gp when paging is enabled. I removed reload of %cr4 for PGE from the amd64-specific block in init_secondary_tail(). There is no need to flush TLB, we are already on the right page table. kib: Because I am switching to the kernel page table which in some configurations have PG_G bit set… | |||||
cmpb $0, mptramp_la57-mptramp_start(%ebx) | cmpb $0, mptramp_la57-mptramp_start(%ebx) | ||||
je 1f | je 1f | ||||
orl $CR4_LA57, %eax | orl $CR4_LA57, %eax | ||||
1: mov %eax, %cr4 | 1: mov %eax, %cr4 | ||||
/* | /* | ||||
* If the BSP reported NXE support, enable EFER.NXE for all APs | |||||
* prior to loading %cr3. This avoids page faults if the AP | |||||
* encounters memory marked with the NX bit prior to detecting and | |||||
* enabling NXE support. | |||||
*/ | |||||
cmpb $0,mptramp_nx-mptramp_start(%ebx) | |||||
je 2f | |||||
movl $MSR_EFER, %ecx | |||||
rdmsr | |||||
orl $EFER_NXE, %eax | |||||
wrmsr | |||||
2: | |||||
/* | |||||
* Enable EFER.LME so that we get long mode when all the prereqs are | * Enable EFER.LME so that we get long mode when all the prereqs are | ||||
* in place. In this case, it turns on when CR0_PG is finally enabled. | * in place. In this case, it turns on when CR0_PG is finally enabled. | ||||
* Pick up a few other EFER bits that we'll use need we're here. | * Pick up a few other EFER bits that we'll use need we're here. | ||||
*/ | */ | ||||
movl $MSR_EFER, %ecx | movl $MSR_EFER, %ecx | ||||
rdmsr | rdmsr | ||||
orl $EFER_LME | EFER_SCE, %eax | orl $EFER_LME | EFER_SCE, %eax | ||||
wrmsr | wrmsr | ||||
/* | /* | ||||
* Point to the embedded page tables for startup. Note that this | * Load kernel page table pointer into %cr3. | ||||
* only gets accessed after we're actually in 64 bit mode, however | * %ebx is still our relocation base. | ||||
* we can only set the bottom 32 bits of %cr3 in this state. This | * | ||||
* means we are required to use a temporary page table that is below | * Note that this only gets accessed after we're actually in 64 bit | ||||
* the 4GB limit. %ebx is still our relocation base. We could just | * mode, however we can only set the bottom 32 bits of %cr3 in this | ||||
* subtract 3 * PAGE_SIZE, but that would be too easy. | * state. This means we depend on the kernel page table being | ||||
* allocated from the low 4G. | |||||
*/ | */ | ||||
leal mptramp_pagetables-mptramp_start(%ebx),%eax | leal mptramp_pagetables-mptramp_start(%ebx),%eax | ||||
movl (%eax), %eax | movl (%eax), %eax | ||||
mov %eax, %cr3 | mov %eax, %cr3 | ||||
/* | /* | ||||
* Finally, switch to long bit mode by enabling paging. We have | * Finally, switch to long bit mode by enabling paging. We have | ||||
* to be very careful here because all the segmentation disappears | * to be very careful here because all the segmentation disappears | ||||
Show All 21 Lines | |||||
jmp_64: | jmp_64: | ||||
.byte 0xea /* opcode for far jump */ | .byte 0xea /* opcode for far jump */ | ||||
.long tramp_64-mptramp_start /* offset in segment */ | .long tramp_64-mptramp_start /* offset in segment */ | ||||
.word kernelcode-gdt /* index in gdt for 64 bit code */ | .word kernelcode-gdt /* index in gdt for 64 bit code */ | ||||
/* | /* | ||||
* Yeehar! We're running in 64 bit mode! We can mostly ignore our | * Yeehar! We're running in 64 bit mode! We can mostly ignore our | ||||
* segment registers, and get on with it. | * segment registers, and get on with it. | ||||
* Note that we are running at the correct virtual address, but with | * We are running at the correct virtual address space. | ||||
* a 1:1 1GB mirrored mapping over entire address space. We had better | * Note that the jmp is relative and that we've been relocated, | ||||
* switch to a real %cr3 promptly so that we can get to the direct map | |||||
* space. Remember that jmp is relative and that we've been relocated, | |||||
* so use an indirect jump. | * so use an indirect jump. | ||||
*/ | */ | ||||
.code64 | .code64 | ||||
tramp_64: | tramp_64: | ||||
movabsq $entry_64,%rax /* 64 bit immediate load */ | movabsq $entry_64,%rax /* 64 bit immediate load */ | ||||
jmp *%rax | jmp *%rax | ||||
.p2align 4,0 | .p2align 4,0 | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
mptramp_pagetables: | mptramp_pagetables: | ||||
.long 0 | .long 0 | ||||
/* 5-level paging ? */ | /* 5-level paging ? */ | ||||
.globl mptramp_la57 | .globl mptramp_la57 | ||||
mptramp_la57: | mptramp_la57: | ||||
.long 0 | .long 0 | ||||
.globl mptramp_nx | |||||
mptramp_nx: | |||||
.long 0 | |||||
/* | /* | ||||
* The pseudo descriptor for lgdt to use. | * The pseudo descriptor for lgdt to use. | ||||
*/ | */ | ||||
lgdt_desc: | lgdt_desc: | ||||
.word gdtend-gdt /* Length */ | .word gdtend-gdt /* Length */ | ||||
.long gdt-mptramp_start /* Offset plus %ds << 4 */ | .long gdt-mptramp_start /* Offset plus %ds << 4 */ | ||||
mptramp_end: | mptramp_end: | ||||
/* | /* | ||||
* The size of the trampoline code that needs to be relocated | * The size of the trampoline code that needs to be relocated | ||||
* below the 1MiB boundary. | * below the 1MiB boundary. | ||||
*/ | */ | ||||
.globl bootMP_size | .globl bootMP_size | ||||
bootMP_size: | bootMP_size: | ||||
.long mptramp_end - mptramp_start | .long mptramp_end - mptramp_start | ||||
/* | /* | ||||
* From here on down is executed in the kernel .text section. | * From here on down is executed in the kernel .text section. | ||||
*/ | */ | ||||
.text | .text | ||||
.code64 | .code64 | ||||
.p2align 4,0 | .p2align 4,0 | ||||
entry_64: | entry_64: | ||||
/* | |||||
* If the BSP reported NXE support, enable EFER.NXE for all APs | |||||
* prior to loading %cr3. This avoids page faults if the AP | |||||
* encounters memory marked with the NX bit prior to detecting and | |||||
* enabling NXE support. | |||||
*/ | |||||
movq pg_nx, %rbx | |||||
testq %rbx, %rbx | |||||
je 1f | |||||
movl $MSR_EFER, %ecx | |||||
rdmsr | |||||
orl $EFER_NXE, %eax | |||||
wrmsr | |||||
1: | |||||
/* | |||||
* Load a real %cr3 that has all the direct map stuff and switches | |||||
* off the 1GB replicated mirror. Load a stack pointer and jump | |||||
* into AP startup code in C. | |||||
*/ | |||||
cmpl $0, la57 | |||||
jne 2f | |||||
movq KPML4phys, %rax | |||||
jmp 3f | |||||
2: movq KPML5phys, %rax | |||||
3: movq %rax, %cr3 | |||||
movq bootSTK, %rsp | movq bootSTK, %rsp | ||||
jmp init_secondary | jmp init_secondary |
Why does PGE now need to be set here? In particular, the load_cr4() in init_secondary_tail() which sets CR4_PGE no longer flushes the TLB, I believe.