boot/bios_ia32: basic support la57 aka 5-level paging for x86_64 kernels
la57 kernel support is required. we simply add a 5th level and enable the cr4 feature. the safemode option "256tb_memory_limit" is named after the 4gb one, but the current support is limited to 512GB as before (this can be later extended). Change-Id: I922774473c4a6112a0e4ff74162285ad58aa53af Reviewed-on: https://review.haiku-os.org/c/haiku/+/3552 Reviewed-by: Adrien Destugues <[email protected]> Reviewed-by: Axel Dörfler <[email protected]>
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#define B_SAFEMODE_DISABLE_HYPER_THREADING "disable_hyperthreading"
|
||||
#define B_SAFEMODE_FAIL_SAFE_VIDEO_MODE "fail_safe_video_mode"
|
||||
#define B_SAFEMODE_4_GB_MEMORY_LIMIT "4gb_memory_limit"
|
||||
#define B_SAFEMODE_256_TB_MEMORY_LIMIT "256tb_memory_limit"
|
||||
|
||||
#if DEBUG_SPINLOCK_LATENCIES
|
||||
# define B_SAFEMODE_DISABLE_LATENCY_CHECK "disable_latency_check"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <boot/stage2.h>
|
||||
#include <boot/stdio.h>
|
||||
#include <kernel.h>
|
||||
#include <safemode.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "mmu.h"
|
||||
@@ -35,7 +36,8 @@ static const uint64 kPageMappingFlags = 0x103;
|
||||
extern "C" void long_enter_kernel(int currentCPU, uint64 stackTop);
|
||||
|
||||
extern uint64 gLongGDT;
|
||||
extern uint32 gLongPhysicalPML4;
|
||||
extern uint32 gLongPhysicalPMLTop;
|
||||
extern bool gLongLA57;
|
||||
extern uint64 gLongKernelEntry;
|
||||
|
||||
|
||||
@@ -88,16 +90,11 @@ long_gdt_init()
|
||||
static void
|
||||
long_mmu_init()
|
||||
{
|
||||
uint64* pml4;
|
||||
uint64* pdpt;
|
||||
uint64* pageDir;
|
||||
uint64* pageTable;
|
||||
addr_t physicalAddress;
|
||||
|
||||
// Allocate the top level PML4.
|
||||
pml4 = (uint64*)mmu_allocate_page(&gKernelArgs.arch_args.phys_pgdir);
|
||||
memset(pml4, 0, B_PAGE_SIZE);
|
||||
gKernelArgs.arch_args.vir_pgdir = fix_address((uint64)(addr_t)pml4);
|
||||
uint64* pmlTop;
|
||||
// Allocate the top level PMLTop.
|
||||
pmlTop = (uint64*)mmu_allocate_page(&gKernelArgs.arch_args.phys_pgdir);
|
||||
memset(pmlTop, 0, B_PAGE_SIZE);
|
||||
gKernelArgs.arch_args.vir_pgdir = fix_address((uint64)(addr_t)pmlTop);
|
||||
|
||||
// Store the virtual memory usage information.
|
||||
gKernelArgs.virtual_allocated_range[0].start = KERNEL_LOAD_BASE_64_BIT;
|
||||
@@ -127,6 +124,29 @@ long_mmu_init()
|
||||
if (maxAddress / 0x40000000 > 512)
|
||||
panic("Can't currently support more than 512GB of RAM!");
|
||||
|
||||
uint64* pml4 = pmlTop;
|
||||
addr_t physicalAddress;
|
||||
cpuid_info info;
|
||||
if (get_current_cpuid(&info, 7, 0) == B_OK
|
||||
&& (info.regs.ecx & IA32_FEATURE_LA57) != 0) {
|
||||
|
||||
if (get_safemode_boolean(B_SAFEMODE_256_TB_MEMORY_LIMIT, false)) {
|
||||
// LA57 has been disabled!
|
||||
dprintf("la57 disabled per safemode setting\n");
|
||||
} else {
|
||||
dprintf("la57 enabled\n");
|
||||
gLongLA57 = true;
|
||||
pml4 = (uint64*)mmu_allocate_page(&physicalAddress);
|
||||
memset(pml4, 0, B_PAGE_SIZE);
|
||||
pmlTop[511] = physicalAddress | kTableMappingFlags;
|
||||
pmlTop[0] = physicalAddress | kTableMappingFlags;
|
||||
}
|
||||
}
|
||||
|
||||
uint64* pdpt;
|
||||
uint64* pageDir;
|
||||
uint64* pageTable;
|
||||
|
||||
// Create page tables for the physical map area. Also map this PDPT
|
||||
// temporarily at the bottom of the address space so that we are identity
|
||||
// mapped.
|
||||
@@ -151,7 +171,6 @@ long_mmu_init()
|
||||
mmu_free(pdpt, B_PAGE_SIZE);
|
||||
|
||||
// Allocate tables for the kernel mappings.
|
||||
|
||||
pdpt = (uint64*)mmu_allocate_page(&physicalAddress);
|
||||
memset(pdpt, 0, B_PAGE_SIZE);
|
||||
pml4[511] = physicalAddress | kTableMappingFlags;
|
||||
@@ -186,6 +205,8 @@ long_mmu_init()
|
||||
mmu_free(pageTable, B_PAGE_SIZE);
|
||||
mmu_free(pageDir, B_PAGE_SIZE);
|
||||
mmu_free(pdpt, B_PAGE_SIZE);
|
||||
if (pml4 != pmlTop)
|
||||
mmu_free(pml4, B_PAGE_SIZE);
|
||||
|
||||
// Sort the address ranges.
|
||||
sort_address_ranges(gKernelArgs.physical_memory_range,
|
||||
@@ -216,7 +237,7 @@ long_mmu_init()
|
||||
gKernelArgs.virtual_allocated_range[i].size);
|
||||
}
|
||||
|
||||
gLongPhysicalPML4 = gKernelArgs.arch_args.phys_pgdir;
|
||||
gLongPhysicalPMLTop = gKernelArgs.arch_args.phys_pgdir;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@ FUNCTION(long_enter_kernel):
|
||||
movl 8(%esp), %edi
|
||||
movl 12(%esp), %esi
|
||||
|
||||
movl gLongLA57, %ecx
|
||||
shl $12, %ecx
|
||||
|
||||
// Currently running with 32-bit paging tables at an identity mapped
|
||||
// address. To switch to 64-bit paging we must first disable 32-bit paging,
|
||||
// otherwise loading the new CR3 will fault.
|
||||
@@ -34,13 +37,14 @@ FUNCTION(long_enter_kernel):
|
||||
andl $~(1 << 31), %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
// Enable PAE and PGE
|
||||
// Enable PAE and PGE, and optionally LA57
|
||||
movl %cr4, %eax
|
||||
orl $(1 << 5) | (1 << 7), %eax
|
||||
orl %ecx, %eax
|
||||
movl %eax, %cr4
|
||||
|
||||
// Point CR3 to the kernel's PML4.
|
||||
movl gLongPhysicalPML4, %eax
|
||||
// Point CR3 to the kernel's PMLTop.
|
||||
movl gLongPhysicalPMLTop, %eax
|
||||
movl %eax, %cr3
|
||||
|
||||
// Enable long mode by setting EFER.LME.
|
||||
@@ -97,7 +101,10 @@ long_gdtr:
|
||||
SYMBOL(gLongGDT):
|
||||
.long 0
|
||||
|
||||
SYMBOL(gLongPhysicalPML4):
|
||||
SYMBOL(gLongPhysicalPMLTop):
|
||||
.long 0
|
||||
|
||||
SYMBOL(gLongLA57):
|
||||
.long 0
|
||||
|
||||
SYMBOL(gLongKernelEntry):
|
||||
|
||||
@@ -589,16 +589,30 @@ smp_add_safemode_menus(Menu *menu)
|
||||
item->SetHelpText("Disables using X2APIC.");
|
||||
}
|
||||
|
||||
if (get_current_cpuid(&info, 7, 0) == B_OK
|
||||
&& (info.regs.ebx & (IA32_FEATURE_SMEP
|
||||
| IA32_FEATURE_SMAP)) != 0) {
|
||||
menu->AddItem(item = new(nothrow) MenuItem(
|
||||
"Disable SMEP and SMAP"));
|
||||
item->SetType(MENU_ITEM_MARKABLE);
|
||||
item->SetData(B_SAFEMODE_DISABLE_SMEP_SMAP);
|
||||
item->SetHelpText("Disables using SMEP and SMAP.");
|
||||
}
|
||||
get_current_cpuid(&info, 0, 0);
|
||||
uint32 maxBasicLeaf = info.eax_0.max_eax;
|
||||
if (maxBasicLeaf >= 7) {
|
||||
if (get_current_cpuid(&info, 7, 0) == B_OK
|
||||
&& (info.regs.ebx & (IA32_FEATURE_SMEP
|
||||
| IA32_FEATURE_SMAP)) != 0) {
|
||||
menu->AddItem(item = new(nothrow) MenuItem(
|
||||
"Disable SMEP and SMAP"));
|
||||
item->SetType(MENU_ITEM_MARKABLE);
|
||||
item->SetData(B_SAFEMODE_DISABLE_SMEP_SMAP);
|
||||
item->SetHelpText("Disables using SMEP and SMAP.");
|
||||
}
|
||||
|
||||
if (get_current_cpuid(&info, 7, 0) == B_OK
|
||||
&& (info.regs.ecx & IA32_FEATURE_LA57) != 0) {
|
||||
menu->AddItem(item = new(nothrow) MenuItem(
|
||||
"Ignore memory beyond 256 TiB"));
|
||||
item->SetType(MENU_ITEM_MARKABLE);
|
||||
item->SetData(B_SAFEMODE_256_TB_MEMORY_LIMIT);
|
||||
item->SetHelpText("Ignores all memory beyond the 256 TiB "
|
||||
"address limit, overriding the setting in the kernel "
|
||||
"settings file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gKernelArgs.num_cpus < 2)
|
||||
|
||||
Reference in New Issue
Block a user