Skip to contentSkip to conversation

ARM64: 3 Level page support

PATCH In review Pratyush Anand 3 participants 8 messages Dec 5, 2015 – Dec 10, 2015

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover ARM64: 3 Level page support

Hi Atsushi,

ARM64 was supporting only two level page support. These patches add support for 3 level page table as well.

~Pratyush

Pratyush Anand (3):
ARM64: Refactor code to support multiple page level
arm64: Decide VA Bits on the basis of _stext symbol value
arm64: Fix KVBASE

Sameer Goel (1):
arm64: Fix for ARM64 3 level translation tables

 arch/arm64.c   | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 makedumpfile.h |  29 +++-------------
 2 files changed, 98 insertions(+), 34 deletions(-)
Signature · 7 lines
2.5.0


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
#1 lore raw

PATCH 1/4 ARM64: Refactor code to support multiple page level

This patch refactor existing code, so that multiple page level can be supported. No functional change. Platform dependent values like page table level, page shift and VA bits are still hard coded as 2, 16 and 42, to support 2 level 64K pages.

---
 arch/arm64.c   | 44 +++++++++++++++++++++++++++++++++++++++++---
 makedumpfile.h | 26 ++++----------------------
 2 files changed, 45 insertions(+), 25 deletions(-)
arch/arm64.c +41 -3
index 06daf646e35d..643c21f8feb1 100644
@@ -23,7 +23,6 @@
 #include "../makedumpfile.h"
 #include "../print_info.h"
 
-#if CONFIG_ARM64_PGTABLE_LEVELS == 2
 typedef struct {
 	unsigned long pgd;
 } pgd_t;
@@ -45,8 +44,6 @@ typedef struct {
 #define PUD_SHIFT		PGDIR_SHIFT
 #define PUD_SIZE		(1UL << PUD_SHIFT)
 
-#endif
-
 typedef struct {
 	unsigned long pte;
 } pte_t;
@@ -96,6 +93,41 @@ typedef struct {
 #define MODULES_END			PAGE_OFFSET
 #define MODULES_VADDR			(MODULES_END - 0x4000000)
 
+static int pgtable_level;
+static int va_bits;
+static int page_shift;
+
+int
+get_pgtable_level_arm64(void)
+{
+	return pgtable_level;
+}
+
+int
+get_va_bits_arm64(void)
+{
+	return va_bits;
+}
+
+int
+get_page_shift_arm64(void)
+{
+	return page_shift;
+}
+
+static int calculate_plat_config(void)
+{
+	/*
+	 * TODO: Keep it fixed for page level 2, size 64K and VA bits as
+	 * 42, as of now. Will calculate them from symbol address values
+	 * latter.
+	 */
+	pgtable_level = 2;
+	va_bits = 42;
+	page_shift = 16;
+
+	return TRUE;
+}
 
 static int
 is_vtop_from_page_table_arm64(unsigned long vaddr)
@@ -114,6 +146,12 @@ get_phys_base_arm64(void)
 	unsigned long phys_base = ULONG_MAX;
 	unsigned long long phys_start;
 	int i;
+
+	if (!calculate_plat_config()) {
+		ERRMSG("Can't determine platform config values\n");
+		return FALSE;
+	}
+
 	/*
 	 * We resolve phys_base from PT_LOAD segments. LMA contains physical
 	 * address of the segment, and we use the lowest start as
makedumpfile.h +4 -22
index e333ae8a37a2..abe6a9897095 100644
@@ -503,28 +503,10 @@ do { \
 #define PMASK			(0x7ffffffffffff000UL)
 
 #ifdef __aarch64__
-#define CONFIG_ARM64_PGTABLE_LEVELS	2
-#define CONFIG_ARM64_VA_BITS		42
-#define CONFIG_ARM64_64K_PAGES		1
-
-/* Currently we only suport following defines based on above
- * config definitions.
- * TODOs: We need to find a way to get above defines dynamically and
- * then to support following definitions based on that
- */
-
-#if CONFIG_ARM64_PGTABLE_LEVELS == 2
-#define ARM64_PGTABLE_LEVELS	2
-#endif
-
-#if CONFIG_ARM64_VA_BITS == 42
-#define VA_BITS			42
-#endif
-
-#ifdef CONFIG_ARM64_64K_PAGES
-#define PAGE_SHIFT		16
-#endif
-
+int get_va_bits_arm64(void);
+#define ARM64_PGTABLE_LEVELS	get_pgtable_level_arm64()
+#define VA_BITS			get_va_bits_arm64()
+#define PAGE_SHIFT		get_page_shift_arm64()
 #define KVBASE_MASK		(0xffffffffffffffffUL << (VA_BITS - 1))
 #define KVBASE			(SYMBOL(_stext) & KVBASE_MASK)
 #endif /* aarch64 */
Signature · 7 lines
2.5.0


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
#2 lore raw

PATCH 2/4 arm64: Decide VA Bits on the basis of _stext symbol value

In reply to Pratyush Anand

Currently we assume that there are only two possible configuration supported by kernel.
1) Page Table Level:2, Page Size 64K and VA Bits 42
1) Page Table Level:3, Page Size 4K and VA Bits 39
Ideally, we should have some mechanism to decide these from kernel symbols, but we have limited symbols in vmcore, and we can not do much. So until some one comes with a better way, we use _stext symbol value for VA bits determination.
We also assume that when VA Bits are 39, Page table level will be 3 and Page size will be 4K, while when VA Bits are 42, Page table level will be 2 an Page size will be 64K.

---
 arch/arm64.c | 34 +++++++++++++++++++++++++++-------
 1 file changed, 27 insertions(+), 7 deletions(-)
arch/arm64.c +27 -7
index 643c21f8feb1..4d50012529c3 100644
@@ -115,16 +115,36 @@ get_page_shift_arm64(void)
 	return page_shift;
 }
 
+#define PAGE_OFFSET_39 (0xffffffffffffffffUL << 39)
+#define PAGE_OFFSET_42 (0xffffffffffffffffUL << 42)
 static int calculate_plat_config(void)
 {
-	/*
-	 * TODO: Keep it fixed for page level 2, size 64K and VA bits as
-	 * 42, as of now. Will calculate them from symbol address values
-	 * latter.
+	unsigned long long stext;
+
+	/* Currently we assume that there are only two possible
+	 * configuration supported by kernel.
+	 * 1) Page Table Level:2, Page Size 64K and VA Bits 42
+	 * 1) Page Table Level:3, Page Size 4K and VA Bits 39
+	 * Ideally, we should have some mechanism to decide these values
+	 * from kernel symbols, but we have limited symbols in vmcore,
+	 * and we can not do much. So until some one comes with a better
+	 * way, we use following.
 	 */
-	pgtable_level = 2;
-	va_bits = 42;
-	page_shift = 16;
+	stext = SYMBOL(_stext);
+
+	/* condition for minimum VA bits must be checked first and so on */
+	if ((stext & PAGE_OFFSET_39) == PAGE_OFFSET_39) {
+		pgtable_level = 3;
+		va_bits = 39;
+		page_shift = 12;
+	} else if ((stext & PAGE_OFFSET_42) == PAGE_OFFSET_42) {
+		pgtable_level = 2;
+		va_bits = 42;
+		page_shift = 16;
+	} else {
+		ERRMSG("Kernel Configuration not supported\n");
+		return FALSE;
+	}
 
 	return TRUE;
 }
Signature · 7 lines
2.5.0


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
#3 lore raw

PATCH 3/4 arm64: Fix KVBASE

In reply to Pratyush Anand

KVBASE should be VMALLOC_START. So fix it.

---
 arch/arm64.c   | 3 ++-
 makedumpfile.h | 3 +--
 2 files changed, 3 insertions(+), 3 deletions(-)
arch/arm64.c +2 -1
index 4d50012529c3..a94a4ba16dd5 100644
@@ -199,7 +199,8 @@ get_machdep_info_arm64(void)
 {
 	info->max_physmem_bits = PHYS_MASK_SHIFT;
 	info->section_size_bits = SECTIONS_SIZE_BITS;
-	info->page_offset = KVBASE;
+	info->page_offset = SYMBOL(_stext)
+		& (0xffffffffffffffffUL << (VA_BITS - 1));
 	info->vmalloc_start = 0xffffffffffffffffUL << VA_BITS;
 	info->vmalloc_end = PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - 0x10000;
 	info->vmemmap_start = VMALLOC_END + 0x10000;
makedumpfile.h +1 -2
index abe6a9897095..c42fc8142663 100644
@@ -507,8 +507,7 @@ int get_va_bits_arm64(void);
 #define ARM64_PGTABLE_LEVELS	get_pgtable_level_arm64()
 #define VA_BITS			get_va_bits_arm64()
 #define PAGE_SHIFT		get_page_shift_arm64()
-#define KVBASE_MASK		(0xffffffffffffffffUL << (VA_BITS - 1))
-#define KVBASE			(SYMBOL(_stext) & KVBASE_MASK)
+#define KVBASE			VMALLOC_START
 #endif /* aarch64 */
 
 #ifdef __arm__
Signature · 7 lines
2.5.0


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
#4 lore raw

Re: [PATCH 3/4] arm64: Fix KVBASE

arch/arm64.c get_machdep_info_arm64(void) · line 203

Quoted 1 line · Pratyush Anand
arch/arm64.c +1 -0
+		& (0xffffffffffffffffUL << (VA_BITS - 1));

Shouldn't this be ULL instead of just UL?

Signature · 8 lines
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, hosted by The Linux Foundation.

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
#5 lore raw

Re: [PATCH 3/4] arm64: Fix KVBASE

Hi Timur,

Thanks for your review.

Quoted 4 lines · Timur Tabi

arch/arm64.c get_machdep_info_arm64(void) · line 203

Quoted 1 line · Pratyush Anand
arch/arm64.c +1 -0
+		& (0xffffffffffffffffUL << (VA_BITS - 1));

Shouldn't this be ULL instead of just UL?

I think on 64 bit platform, unsigned long is always 64 bit (with gcc). More over, info->page_offset is unsigned long. So, I think using UL would be in sync, no?

~Pratyush

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#6 lore raw

PATCH 4/4 arm64: Fix for ARM64 3 level translation tables

In reply to Pratyush Anand

From: Sameer Goel <[email protected]>

Add the implementation for PMD translation in case of 3 level page tables. Assign the kernel page size based on the page structure read from the kernel ELF file.

---
 arch/arm64.c | 36 ++++++++++++++++++++++++++++++------
 1 file changed, 30 insertions(+), 6 deletions(-)
arch/arm64.c +30 -6
index a94a4ba16dd5..ab20389fa673 100644
@@ -36,7 +36,7 @@ typedef struct {
 } pmd_t;
 
 #define pud_offset(pgd, vaddr) 	((pud_t *)pgd)
-#define pmd_offset(pud, vaddr) 	((pmd_t *)pud)
+
 #define pgd_val(x)		((x).pgd)
 #define pud_val(x)		(pgd_val((x).pgd))
 #define pmd_val(x)		(pud_val((x).pud))
@@ -68,6 +68,11 @@ typedef struct {
 */
 #define PHYS_MASK_SHIFT		48
 #define PHYS_MASK		((1UL << PHYS_MASK_SHIFT) - 1)
+/*
+ * Remove the highest order bits that are not a part of the
+ * physical address in a section
+ */
+#define PMD_SECTION_MASK        ((1UL << 40) - 1)
 
 #define PMD_TYPE_MASK		3
 #define PMD_TYPE_SECT		1
@@ -83,10 +88,18 @@ typedef struct {
 #define pmd_page_vaddr(pmd)		(__va(pmd_val(pmd) & PHYS_MASK & (int32_t)PAGE_MASK))
 #define pte_offset(dir, vaddr) 		((pte_t*)pmd_page_vaddr((*dir)) + pte_index(vaddr))
 
+
+#define pmd_offset_pgtbl_lvl_2(pud, vaddr) ((pmd_t *)pud)
+
+#define pmd_index(vaddr)		(((vaddr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
+#define pud_page_vaddr(pud)		(__va(pud_val(pud) & PHYS_MASK & (int32_t)PAGE_MASK))
+#define pmd_offset_pgtbl_lvl_3(pud, vaddr) ((pmd_t *)pud_page_vaddr((*pud)) + pmd_index(vaddr))
+
 /* kernel struct page size can be kernel version dependent, currently
  * keep it constant.
  */
-#define KERN_STRUCT_PAGE_SIZE		64
+#define KERN_STRUCT_PAGE_SIZE		get_structure_size("page", DWARF_INFO_GET_STRUCT_SIZE)
+
 #define ALIGN(x, a) 			(((x) + (a) - 1) & ~((a) - 1))
 #define PFN_DOWN(x)			((x) >> PAGE_SHIFT)
 #define VMEMMAP_SIZE			ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * KERN_STRUCT_PAGE_SIZE, PUD_SIZE)
@@ -97,6 +110,15 @@ static int pgtable_level;
 static int va_bits;
 static int page_shift;
 
+pmd_t *
+pmd_offset(pud_t *pud, unsigned long vaddr)
+{
+	if (pgtable_level == 2) {
+		return pmd_offset_pgtbl_lvl_2(pud, vaddr);
+	} else {
+		return pmd_offset_pgtbl_lvl_3(pud, vaddr);
+	}
+}
 int
 get_pgtable_level_arm64(void)
 {
@@ -256,7 +278,7 @@ vtop_arm64(unsigned long vaddr)
 {
 	unsigned long long paddr = NOT_PADDR;
 	pgd_t	*pgda, pgdv;
-	pud_t	*puda;
+	pud_t	*puda, pudv;
 	pmd_t	*pmda, pmdv;
 	pte_t 	*ptea, ptev;
 
@@ -271,8 +293,9 @@ vtop_arm64(unsigned long vaddr)
 		return NOT_PADDR;
 	}
 
-	puda = pud_offset(pgda, vaddr);
-	pmda = pmd_offset(puda, vaddr);
+	pudv.pgd = pgdv;
+
+	pmda = pmd_offset(&pudv, vaddr);
 	if (!readmem(VADDR, (unsigned long long)pmda, &pmdv, sizeof(pmdv))) {
 		ERRMSG("Can't read pmd\n");
 		return NOT_PADDR;
@@ -298,7 +321,8 @@ vtop_arm64(unsigned long vaddr)
 		break;
 	case PMD_TYPE_SECT:
 		/* 1GB section */
-		paddr = (pmd_val(pmdv) & PMD_MASK) + (vaddr & (PMD_SIZE - 1));
+		paddr = (pmd_val(pmdv) & (PMD_MASK & PMD_SECTION_MASK))
+					+ (vaddr & (PMD_SIZE - 1));
 		break;
 	}
 
Signature · 7 lines
2.5.0


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
#7 lore raw
In reply to Pratyush Anand

Hello Pratyush,

Quoted 6 lines

Hi Atsushi,

ARM64 was supporting only two level page support. These patches add support for 3 level page table as well.

~Pratyush

Thanks for your work, I'll merge these patches into v1.6.0.

Regards,
Atsushi Kumagai

Quoted 12 lines

Pratyush Anand (3):
ARM64: Refactor code to support multiple page level
arm64: Decide VA Bits on the basis of _stext symbol value
arm64: Fix KVBASE

Sameer Goel (1):
arm64: Fix for ARM64 3 level translation tables

arch/arm64.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++------
makedumpfile.h | 29 +++-------------

2 files changed, 98 insertions(+), 34 deletions(-)
Quoted 8 lines

--
2.5.0

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec