The new paging more is extension of IA32e mode with more additional page
table level.
It brings support of 57-bit vitrual address space (128PB) and 52-bit
physical address space (4PB).
The structure of new page table level is identical to pml4.
The feature is enumerated with CPUID.(EAX=07H, ECX=0):ECX[bit 16].
CR4.LA57[bit 12] need to be set when pageing enables to activate 5-level
paging mode.
Signed-off-by: Kirill A. Shutemov
Cc: qemu-devel@nongnu.org
---
target-i386/arch_memory_mapping.c | 42 --
target-i386/cpu.c | 16 ++--
target-i386/cpu.h | 2 +
target-i386/helper.c | 54 ++--
target-i386/monitor.c | 167 --
target-i386/translate.c | 2 +
6 files changed, 238 insertions(+), 45 deletions(-)
diff --git a/target-i386/arch_memory_mapping.c
b/target-i386/arch_memory_mapping.c
index 88f341e1bbd0..826aee597b13 100644
--- a/target-i386/arch_memory_mapping.c
+++ b/target-i386/arch_memory_mapping.c
@@ -220,7 +220,8 @@ static void walk_pdpe(MemoryMappingList *list, AddressSpace
*as,
/* IA-32e Paging */
static void walk_pml4e(MemoryMappingList *list, AddressSpace *as,
- hwaddr pml4e_start_addr, int32_t a20_mask)
+ hwaddr pml4e_start_addr, int32_t a20_mask,
+ target_ulong start_line_addr)
{
hwaddr pml4e_addr, pdpe_start_addr;
uint64_t pml4e;
@@ -236,11 +237,34 @@ static void walk_pml4e(MemoryMappingList *list,
AddressSpace *as,
continue;
}
-line_addr = ((i & 0x1ffULL) << 39) | (0xULL << 48);
+line_addr = start_line_addr | ((i & 0x1ffULL) << 39);
pdpe_start_addr = (pml4e & PLM4_ADDR_MASK) & a20_mask;
walk_pdpe(list, as, pdpe_start_addr, a20_mask, line_addr);
}
}
+
+static void walk_pml5e(MemoryMappingList *list, AddressSpace *as,
+ hwaddr pml5e_start_addr, int32_t a20_mask)
+{
+hwaddr pml5e_addr, pml4e_start_addr;
+uint64_t pml5e;
+target_ulong line_addr;
+int i;
+
+for (i = 0; i < 512; i++) {
+pml5e_addr = (pml5e_start_addr + i * 8) & a20_mask;
+pml5e = address_space_ldq(as, pml5e_addr, MEMTXATTRS_UNSPECIFIED,
+ NULL);
+if (!(pml5e & PG_PRESENT_MASK)) {
+/* not present */
+continue;
+}
+
+line_addr = (0x7fULL << 57) | ((i & 0x1ffULL) << 48);
+pml4e_start_addr = (pml5e & PLM4_ADDR_MASK) & a20_mask;
+walk_pml4e(list, as, pml4e_start_addr, a20_mask, line_addr);
+}
+}
#endif
void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list,
@@ -257,10 +281,18 @@ void x86_cpu_get_memory_mapping(CPUState *cs,
MemoryMappingList *list,
if (env->cr[4] & CR4_PAE_MASK) {
#ifdef TARGET_X86_64
if (env->hflags & HF_LMA_MASK) {
-hwaddr pml4e_addr;
+if (env->cr[4] & CR4_LA57_MASK) {
+hwaddr pml5e_addr;
+
+pml5e_addr = (env->cr[3] & PLM4_ADDR_MASK) & env->a20_mask;
+walk_pml5e(list, cs->as, pml5e_addr, env->a20_mask);
+} else {
+hwaddr pml4e_addr;
-pml4e_addr = (env->cr[3] & PLM4_ADDR_MASK) & env->a20_mask;
-walk_pml4e(list, cs->as, pml4e_addr, env->a20_mask);
+pml4e_addr = (env->cr[3] & PLM4_ADDR_MASK) & env->a20_mask;
+walk_pml4e(list, cs->as, pml4e_addr, env->a20_mask,
+0xULL << 48);
+}
} else
#endif
{
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index de1f30eeda63..a4b9832b5916 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -238,7 +238,8 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t
vendor1,
CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2,
CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
CPUID_7_0_EBX_RDSEED */
-#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_OSPKE)
+#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_OSPKE | \
+ CPUID_7_0_ECX_LA57)
#define TCG_7_0_EDX_FEATURES 0
#define TCG_APM_FEATURES 0
#define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT
@@ -435,7 +436,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
"ospke", NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
-NULL, NULL, NULL, NULL,
+"la57", NULL, NULL, NULL,
NULL, NULL, "rdpid", NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
@@ -2742,10 +2743,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index,
uint32_t count,
case 0x8008:
/* virtual & phys address size in low 2 bytes. */
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
-/* 64 bit processor, 48 bits virtual, configurable
-