Kernel Loader: Difference between revisions
(6 intermediate revisions by one other user not shown) | |||
Line 183: | Line 183: | ||
// Maps .rodata as R-- | // Maps .rodata as R-- | ||
attribute = 0x60000000000788; | attribute = 0x60000000000788; | ||
// 9.0.0+ | |||
{ | |||
// On 9.0.0+, .rodata is initially RW- to facilitate .rel.ro. | |||
attribute = 0x60000000000708; | |||
} | |||
ttbr1_page_table.Map(final_virtual_kernel_base + ro_offset, ro_end_offset - ro_offset, kernel_base + ro_offset, &attribute, &g_InitialPageAllocator); | ttbr1_page_table.Map(final_virtual_kernel_base + ro_offset, ro_end_offset - ro_offset, kernel_base + ro_offset, &attribute, &g_InitialPageAllocator); | ||
Line 197: | Line 204: | ||
// Applies all R_AARCH64_RELATIVE relocations. | // Applies all R_AARCH64_RELATIVE relocations. | ||
KernelLdr_ApplyRelocations(final_kernel_virtual_base, final_kernel_virtual_base + dynamic_offset); | KernelLdr_ApplyRelocations(final_kernel_virtual_base, final_kernel_virtual_base + dynamic_offset); | ||
// 9.0.0+: Reprotects .rodata as R--. | |||
ttbr1_page_table.ReprotectToReadOnly(final_virtual_kernel_base + ro_offset, ro_end_offset - ro_offset); | |||
// This is standard libc init_array code, but called for the kernel's binary instead of kernelldr's. | // This is standard libc init_array code, but called for the kernel's binary instead of kernelldr's. | ||
Line 248: | Line 258: | ||
// Check what CPU we're running on to configure CPUECTLR, CPUACTLR appropriately. | // Check what CPU we're running on to configure CPUECTLR, CPUACTLR appropriately. | ||
manufacture_id = MIDR_EL1; | manufacture_id = MIDR_EL1; | ||
implementer = manufacturer_id >> 24) & 0xFF; | |||
// 9.0.0+: Save X19-X30 + SP, save context struct in TPIDR_EL1. | |||
KernelLdr_SaveRegistersToTpidrEl1(); | |||
if (implementer == 0x41) { | if (implementer == 0x41) { | ||
// Implementer ID is 0x41 (ARM Limited). | // Implementer ID is 0x41 (ARM Limited). | ||
Line 257: | Line 271: | ||
// Architecture is 0xD07 (Cortex-A57). | // Architecture is 0xD07 (Cortex-A57). | ||
cpuactlr_value = 0x1000000; // Non-cacheable load forwarding enabled | cpuactlr_value = 0x1000000; // Non-cacheable load forwarding enabled | ||
cpuectlr_value = 0x1B00000040; // | cpuectlr_value = 0x1B00000040; // Enable the processor to receive instruction cache and TLB maintenance operations broadcast from other processors in the cluster; set the L2 load/store data prefetch distance to 8 requests; set the L2 instruction fetch prefetch distance to 3 requests. | ||
if (hw_variant == 0 || (hw_variant == 1 && hw_revision <= 1)) { | if (hw_variant == 0 || (hw_variant == 1 && hw_revision <= 1)) { | ||
// If supported, disable load-pass DMB. | // If supported, disable load-pass DMB. | ||
cpuactlr_value |= 0x800000000000000; | cpuactlr_value |= 0x800000000000000; | ||
} | |||
CPUACTLR_EL1 = cpuactlr_value; | |||
if (CPUECTLR_EL1 != cpuectlr_value) { | |||
CPUECTLR_EL1 = cpuectlr_value; | |||
} | |||
} else if (architecture == 0xD03) { // 9.0.0+ | |||
// Architecture is 0xD03 (Cortex-A53). | |||
cpuactlr_value = 0x90CA000; // Set L1 data prefetch control to allow 5 outstanding prefetches; enable device split throttle; set the number of independent data prefetch streams to 2; disable transient and no-read-allocate hints for loads; set write streaming no-allocate threshold so the 128th consecutive streaming cache line does not allocate in the L1 or L2 cache. | |||
cpuectlr_value = 0x40; // Enable hardware management of data coherency with other cores in the cluster. | |||
if (hw_variant != 0 || (hw_variant == 0 && hw_revision > 2)) { | |||
// If supported, enable data cache clean as data cache clean/invalidate. | |||
cpuactlr_value |= 0x100000000000; | |||
} | } | ||
CPUACTLR_EL1 = cpuactlr_value; | CPUACTLR_EL1 = cpuactlr_value; | ||
Line 268: | Line 294: | ||
} | } | ||
} | } | ||
// 9.0.0+: Verify that TPIDR_EL1 is still set. | |||
KernelLdr_VerifyTpidrEl1(); | |||
</pre> | </pre> | ||
Line 384: | Line 414: | ||
Standard ARM cache clean code, uses LoUIS from CLIDR_EL1. | Standard ARM cache clean code, uses LoUIS from CLIDR_EL1. | ||
== KernelLdr_ExceptionTable == | |||
Standard aarch64 exception table, only function that doesn't infinite loop is synchronous exception from same EL (synch_spx_exception) | |||
synch_spx_exception does the following: | |||
* Moves TPIDR_EL1 into X0 | |||
* Infinite loops if it is 0/NULL. | |||
* Restores X19-X30 + SP from the memory pointed to by TPIDR_EL1. | |||
* Returns to the saved LR stored in the context save struct. | |||
== KernelLdr_SaveRegistersToTpidrEl1 == | |||
This saves X19-X30 + SP to an input pointer, and moves the pointer into TPIDR_EL1. | |||
== KernelLdr_VerifyTpidrEl1 == | |||
This just verifies that TPIDR_EL1 is equal to an input argument, and clears it. | |||
<pre> | |||
// 9.0.0+ | |||
if (TPIDR_EL1 != input_arg) { | |||
while (1) { /* Infinite loop panic */ } | |||
} | |||
TPIDR_EL1 = 0 | |||
</pre> | |||
== KInitialPageAllocator::KInitialPageAllocator == | == KInitialPageAllocator::KInitialPageAllocator == | ||
Line 454: | Line 510: | ||
This is just standard aarch64 page table code. Walks the page table, verifying that all entries it would map for size + range are free. | This is just standard aarch64 page table code. Walks the page table, verifying that all entries it would map for size + range are free. | ||
== KInitialPageTable::ReprotectToReadOnly == | |||
This is just standard aarch64 page table code. Walks the page table, reprotects the read-write pages in the specified region as read-only. | |||
This is probably a compiler-optimized version of a function that does an arbitrary reprotection. | |||
== KInitialPageTable::GetL1Table == | == KInitialPageTable::GetL1Table == |