diff --git a/headers/private/system/safemode_defs.h b/headers/private/system/safemode_defs.h index 41292ddc77..8b92e32a8d 100644 --- a/headers/private/system/safemode_defs.h +++ b/headers/private/system/safemode_defs.h @@ -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" diff --git a/src/system/boot/platform/bios_ia32/long.cpp b/src/system/boot/platform/bios_ia32/long.cpp index c784422d4d..539e91eee1 100644 --- a/src/system/boot/platform/bios_ia32/long.cpp +++ b/src/system/boot/platform/bios_ia32/long.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #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; } diff --git a/src/system/boot/platform/bios_ia32/long_asm.S b/src/system/boot/platform/bios_ia32/long_asm.S index 4556c689fc..c7eec5c85c 100644 --- a/src/system/boot/platform/bios_ia32/long_asm.S +++ b/src/system/boot/platform/bios_ia32/long_asm.S @@ -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): diff --git a/src/system/boot/platform/bios_ia32/smp.cpp b/src/system/boot/platform/bios_ia32/smp.cpp index 277cb6f9f0..0356bb9483 100644 --- a/src/system/boot/platform/bios_ia32/smp.cpp +++ b/src/system/boot/platform/bios_ia32/smp.cpp @@ -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)