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_DISABLE_HYPER_THREADING "disable_hyperthreading"
|
||||||
#define B_SAFEMODE_FAIL_SAFE_VIDEO_MODE "fail_safe_video_mode"
|
#define B_SAFEMODE_FAIL_SAFE_VIDEO_MODE "fail_safe_video_mode"
|
||||||
#define B_SAFEMODE_4_GB_MEMORY_LIMIT "4gb_memory_limit"
|
#define B_SAFEMODE_4_GB_MEMORY_LIMIT "4gb_memory_limit"
|
||||||
|
#define B_SAFEMODE_256_TB_MEMORY_LIMIT "256tb_memory_limit"
|
||||||
|
|
||||||
#if DEBUG_SPINLOCK_LATENCIES
|
#if DEBUG_SPINLOCK_LATENCIES
|
||||||
# define B_SAFEMODE_DISABLE_LATENCY_CHECK "disable_latency_check"
|
# define B_SAFEMODE_DISABLE_LATENCY_CHECK "disable_latency_check"
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <boot/stage2.h>
|
#include <boot/stage2.h>
|
||||||
#include <boot/stdio.h>
|
#include <boot/stdio.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
|
#include <safemode.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
@@ -35,7 +36,8 @@ static const uint64 kPageMappingFlags = 0x103;
|
|||||||
extern "C" void long_enter_kernel(int currentCPU, uint64 stackTop);
|
extern "C" void long_enter_kernel(int currentCPU, uint64 stackTop);
|
||||||
|
|
||||||
extern uint64 gLongGDT;
|
extern uint64 gLongGDT;
|
||||||
extern uint32 gLongPhysicalPML4;
|
extern uint32 gLongPhysicalPMLTop;
|
||||||
|
extern bool gLongLA57;
|
||||||
extern uint64 gLongKernelEntry;
|
extern uint64 gLongKernelEntry;
|
||||||
|
|
||||||
|
|
||||||
@@ -88,16 +90,11 @@ long_gdt_init()
|
|||||||
static void
|
static void
|
||||||
long_mmu_init()
|
long_mmu_init()
|
||||||
{
|
{
|
||||||
uint64* pml4;
|
uint64* pmlTop;
|
||||||
uint64* pdpt;
|
// Allocate the top level PMLTop.
|
||||||
uint64* pageDir;
|
pmlTop = (uint64*)mmu_allocate_page(&gKernelArgs.arch_args.phys_pgdir);
|
||||||
uint64* pageTable;
|
memset(pmlTop, 0, B_PAGE_SIZE);
|
||||||
addr_t physicalAddress;
|
gKernelArgs.arch_args.vir_pgdir = fix_address((uint64)(addr_t)pmlTop);
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Store the virtual memory usage information.
|
// Store the virtual memory usage information.
|
||||||
gKernelArgs.virtual_allocated_range[0].start = KERNEL_LOAD_BASE_64_BIT;
|
gKernelArgs.virtual_allocated_range[0].start = KERNEL_LOAD_BASE_64_BIT;
|
||||||
@@ -127,6 +124,29 @@ long_mmu_init()
|
|||||||
if (maxAddress / 0x40000000 > 512)
|
if (maxAddress / 0x40000000 > 512)
|
||||||
panic("Can't currently support more than 512GB of RAM!");
|
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
|
// 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
|
// temporarily at the bottom of the address space so that we are identity
|
||||||
// mapped.
|
// mapped.
|
||||||
@@ -151,7 +171,6 @@ long_mmu_init()
|
|||||||
mmu_free(pdpt, B_PAGE_SIZE);
|
mmu_free(pdpt, B_PAGE_SIZE);
|
||||||
|
|
||||||
// Allocate tables for the kernel mappings.
|
// Allocate tables for the kernel mappings.
|
||||||
|
|
||||||
pdpt = (uint64*)mmu_allocate_page(&physicalAddress);
|
pdpt = (uint64*)mmu_allocate_page(&physicalAddress);
|
||||||
memset(pdpt, 0, B_PAGE_SIZE);
|
memset(pdpt, 0, B_PAGE_SIZE);
|
||||||
pml4[511] = physicalAddress | kTableMappingFlags;
|
pml4[511] = physicalAddress | kTableMappingFlags;
|
||||||
@@ -186,6 +205,8 @@ long_mmu_init()
|
|||||||
mmu_free(pageTable, B_PAGE_SIZE);
|
mmu_free(pageTable, B_PAGE_SIZE);
|
||||||
mmu_free(pageDir, B_PAGE_SIZE);
|
mmu_free(pageDir, B_PAGE_SIZE);
|
||||||
mmu_free(pdpt, B_PAGE_SIZE);
|
mmu_free(pdpt, B_PAGE_SIZE);
|
||||||
|
if (pml4 != pmlTop)
|
||||||
|
mmu_free(pml4, B_PAGE_SIZE);
|
||||||
|
|
||||||
// Sort the address ranges.
|
// Sort the address ranges.
|
||||||
sort_address_ranges(gKernelArgs.physical_memory_range,
|
sort_address_ranges(gKernelArgs.physical_memory_range,
|
||||||
@@ -216,7 +237,7 @@ long_mmu_init()
|
|||||||
gKernelArgs.virtual_allocated_range[i].size);
|
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 8(%esp), %edi
|
||||||
movl 12(%esp), %esi
|
movl 12(%esp), %esi
|
||||||
|
|
||||||
|
movl gLongLA57, %ecx
|
||||||
|
shl $12, %ecx
|
||||||
|
|
||||||
// Currently running with 32-bit paging tables at an identity mapped
|
// 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,
|
// address. To switch to 64-bit paging we must first disable 32-bit paging,
|
||||||
// otherwise loading the new CR3 will fault.
|
// otherwise loading the new CR3 will fault.
|
||||||
@@ -34,13 +37,14 @@ FUNCTION(long_enter_kernel):
|
|||||||
andl $~(1 << 31), %eax
|
andl $~(1 << 31), %eax
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
|
|
||||||
// Enable PAE and PGE
|
// Enable PAE and PGE, and optionally LA57
|
||||||
movl %cr4, %eax
|
movl %cr4, %eax
|
||||||
orl $(1 << 5) | (1 << 7), %eax
|
orl $(1 << 5) | (1 << 7), %eax
|
||||||
|
orl %ecx, %eax
|
||||||
movl %eax, %cr4
|
movl %eax, %cr4
|
||||||
|
|
||||||
// Point CR3 to the kernel's PML4.
|
// Point CR3 to the kernel's PMLTop.
|
||||||
movl gLongPhysicalPML4, %eax
|
movl gLongPhysicalPMLTop, %eax
|
||||||
movl %eax, %cr3
|
movl %eax, %cr3
|
||||||
|
|
||||||
// Enable long mode by setting EFER.LME.
|
// Enable long mode by setting EFER.LME.
|
||||||
@@ -97,7 +101,10 @@ long_gdtr:
|
|||||||
SYMBOL(gLongGDT):
|
SYMBOL(gLongGDT):
|
||||||
.long 0
|
.long 0
|
||||||
|
|
||||||
SYMBOL(gLongPhysicalPML4):
|
SYMBOL(gLongPhysicalPMLTop):
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
SYMBOL(gLongLA57):
|
||||||
.long 0
|
.long 0
|
||||||
|
|
||||||
SYMBOL(gLongKernelEntry):
|
SYMBOL(gLongKernelEntry):
|
||||||
|
|||||||
@@ -589,16 +589,30 @@ smp_add_safemode_menus(Menu *menu)
|
|||||||
item->SetHelpText("Disables using X2APIC.");
|
item->SetHelpText("Disables using X2APIC.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_current_cpuid(&info, 7, 0) == B_OK
|
get_current_cpuid(&info, 0, 0);
|
||||||
&& (info.regs.ebx & (IA32_FEATURE_SMEP
|
uint32 maxBasicLeaf = info.eax_0.max_eax;
|
||||||
| IA32_FEATURE_SMAP)) != 0) {
|
if (maxBasicLeaf >= 7) {
|
||||||
menu->AddItem(item = new(nothrow) MenuItem(
|
if (get_current_cpuid(&info, 7, 0) == B_OK
|
||||||
"Disable SMEP and SMAP"));
|
&& (info.regs.ebx & (IA32_FEATURE_SMEP
|
||||||
item->SetType(MENU_ITEM_MARKABLE);
|
| IA32_FEATURE_SMAP)) != 0) {
|
||||||
item->SetData(B_SAFEMODE_DISABLE_SMEP_SMAP);
|
menu->AddItem(item = new(nothrow) MenuItem(
|
||||||
item->SetHelpText("Disables using SMEP and SMAP.");
|
"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)
|
if (gKernelArgs.num_cpus < 2)
|
||||||
|
|||||||
Reference in New Issue
Block a user