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:
Jérôme Duval
2020-12-28 18:21:11 +00:00
parent 58353b3809
commit 1f8a8d2b48
4 changed files with 69 additions and 26 deletions
+1
View File
@@ -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"
+34 -13
View File
@@ -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;
}
+11 -4
View File
@@ -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):
+23 -9
View File
@@ -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)