diff options
| author | Christoffer Dall <c.dall@virtualopensystems.com> | 2013-01-20 18:43:10 -0500 |
|---|---|---|
| committer | Christoffer Dall <c.dall@virtualopensystems.com> | 2013-01-23 13:29:09 -0500 |
| commit | 9e9a367c29cebd25a356d53414612e115efdadcf (patch) | |
| tree | cca8b98c33597179e5cbc50118b1cf86e6299ed0 | |
| parent | cc577c26e2e9740b046591a72e77213c556bff19 (diff) | |
ARM: Section based HYP idmap
Add a method (hyp_idmap_setup) to populate a hyp pgd with an
identity mapping of the code contained in the .hyp.idmap.text
section.
Offer a method to drop this identity mapping through
hyp_idmap_teardown.
Make all the above depend on CONFIG_ARM_VIRT_EXT and CONFIG_ARM_LPAE.
Reviewed-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
| -rw-r--r-- | arch/arm/include/asm/idmap.h | 1 | ||||
| -rw-r--r-- | arch/arm/include/asm/pgtable-3level-hwdef.h | 1 | ||||
| -rw-r--r-- | arch/arm/kernel/vmlinux.lds.S | 6 | ||||
| -rw-r--r-- | arch/arm/mm/idmap.c | 55 |
4 files changed, 51 insertions, 12 deletions
diff --git a/arch/arm/include/asm/idmap.h b/arch/arm/include/asm/idmap.h index bf863edb517d..1a66f907e5cc 100644 --- a/arch/arm/include/asm/idmap.h +++ b/arch/arm/include/asm/idmap.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #define __idmap __section(.idmap.text) noinline notrace | 8 | #define __idmap __section(.idmap.text) noinline notrace |
| 9 | 9 | ||
| 10 | extern pgd_t *idmap_pgd; | 10 | extern pgd_t *idmap_pgd; |
| 11 | extern pgd_t *hyp_pgd; | ||
| 11 | 12 | ||
| 12 | void setup_mm_for_reboot(void); | 13 | void setup_mm_for_reboot(void); |
| 13 | 14 | ||
diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h index d7952824c5c4..a2d404ed1ade 100644 --- a/arch/arm/include/asm/pgtable-3level-hwdef.h +++ b/arch/arm/include/asm/pgtable-3level-hwdef.h | |||
| @@ -44,6 +44,7 @@ | |||
| 44 | #define PMD_SECT_XN (_AT(pmdval_t, 1) << 54) | 44 | #define PMD_SECT_XN (_AT(pmdval_t, 1) << 54) |
| 45 | #define PMD_SECT_AP_WRITE (_AT(pmdval_t, 0)) | 45 | #define PMD_SECT_AP_WRITE (_AT(pmdval_t, 0)) |
| 46 | #define PMD_SECT_AP_READ (_AT(pmdval_t, 0)) | 46 | #define PMD_SECT_AP_READ (_AT(pmdval_t, 0)) |
| 47 | #define PMD_SECT_AP1 (_AT(pmdval_t, 1) << 6) | ||
| 47 | #define PMD_SECT_TEX(x) (_AT(pmdval_t, 0)) | 48 | #define PMD_SECT_TEX(x) (_AT(pmdval_t, 0)) |
| 48 | 49 | ||
| 49 | /* | 50 | /* |
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 11c1785bf63e..b571484e9f03 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S | |||
| @@ -19,7 +19,11 @@ | |||
| 19 | ALIGN_FUNCTION(); \ | 19 | ALIGN_FUNCTION(); \ |
| 20 | VMLINUX_SYMBOL(__idmap_text_start) = .; \ | 20 | VMLINUX_SYMBOL(__idmap_text_start) = .; \ |
| 21 | *(.idmap.text) \ | 21 | *(.idmap.text) \ |
| 22 | VMLINUX_SYMBOL(__idmap_text_end) = .; | 22 | VMLINUX_SYMBOL(__idmap_text_end) = .; \ |
| 23 | ALIGN_FUNCTION(); \ | ||
| 24 | VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ | ||
| 25 | *(.hyp.idmap.text) \ | ||
| 26 | VMLINUX_SYMBOL(__hyp_idmap_text_end) = .; | ||
| 23 | 27 | ||
| 24 | #ifdef CONFIG_HOTPLUG_CPU | 28 | #ifdef CONFIG_HOTPLUG_CPU |
| 25 | #define ARM_CPU_DISCARD(x) | 29 | #define ARM_CPU_DISCARD(x) |
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c index 99db769307ec..2dffc010cc41 100644 --- a/arch/arm/mm/idmap.c +++ b/arch/arm/mm/idmap.c | |||
| @@ -1,4 +1,6 @@ | |||
| 1 | #include <linux/module.h> | ||
| 1 | #include <linux/kernel.h> | 2 | #include <linux/kernel.h> |
| 3 | #include <linux/slab.h> | ||
| 2 | 4 | ||
| 3 | #include <asm/cputype.h> | 5 | #include <asm/cputype.h> |
| 4 | #include <asm/idmap.h> | 6 | #include <asm/idmap.h> |
| @@ -6,6 +8,7 @@ | |||
| 6 | #include <asm/pgtable.h> | 8 | #include <asm/pgtable.h> |
| 7 | #include <asm/sections.h> | 9 | #include <asm/sections.h> |
| 8 | #include <asm/system_info.h> | 10 | #include <asm/system_info.h> |
| 11 | #include <asm/virt.h> | ||
| 9 | 12 | ||
| 10 | pgd_t *idmap_pgd; | 13 | pgd_t *idmap_pgd; |
| 11 | 14 | ||
| @@ -59,11 +62,17 @@ static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end, | |||
| 59 | } while (pud++, addr = next, addr != end); | 62 | } while (pud++, addr = next, addr != end); |
| 60 | } | 63 | } |
| 61 | 64 | ||
| 62 | static void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end) | 65 | static void identity_mapping_add(pgd_t *pgd, const char *text_start, |
| 66 | const char *text_end, unsigned long prot) | ||
| 63 | { | 67 | { |
| 64 | unsigned long prot, next; | 68 | unsigned long addr, end; |
| 69 | unsigned long next; | ||
| 70 | |||
| 71 | addr = virt_to_phys(text_start); | ||
| 72 | end = virt_to_phys(text_end); | ||
| 73 | |||
| 74 | prot |= PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF; | ||
| 65 | 75 | ||
| 66 | prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF; | ||
| 67 | if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale()) | 76 | if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale()) |
| 68 | prot |= PMD_BIT4; | 77 | prot |= PMD_BIT4; |
| 69 | 78 | ||
| @@ -74,28 +83,52 @@ static void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long e | |||
| 74 | } while (pgd++, addr = next, addr != end); | 83 | } while (pgd++, addr = next, addr != end); |
| 75 | } | 84 | } |
| 76 | 85 | ||
| 86 | #if defined(CONFIG_ARM_VIRT_EXT) && defined(CONFIG_ARM_LPAE) | ||
| 87 | pgd_t *hyp_pgd; | ||
| 88 | |||
| 89 | extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[]; | ||
| 90 | |||
| 91 | static int __init init_static_idmap_hyp(void) | ||
| 92 | { | ||
| 93 | hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); | ||
| 94 | if (!hyp_pgd) | ||
| 95 | return -ENOMEM; | ||
| 96 | |||
| 97 | pr_info("Setting up static HYP identity map for 0x%p - 0x%p\n", | ||
| 98 | __hyp_idmap_text_start, __hyp_idmap_text_end); | ||
| 99 | identity_mapping_add(hyp_pgd, __hyp_idmap_text_start, | ||
| 100 | __hyp_idmap_text_end, PMD_SECT_AP1); | ||
| 101 | |||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | #else | ||
| 105 | static int __init init_static_idmap_hyp(void) | ||
| 106 | { | ||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | #endif | ||
| 110 | |||
| 77 | extern char __idmap_text_start[], __idmap_text_end[]; | 111 | extern char __idmap_text_start[], __idmap_text_end[]; |
| 78 | 112 | ||
| 79 | static int __init init_static_idmap(void) | 113 | static int __init init_static_idmap(void) |
| 80 | { | 114 | { |
| 81 | phys_addr_t idmap_start, idmap_end; | 115 | int ret; |
| 82 | 116 | ||
| 83 | idmap_pgd = pgd_alloc(&init_mm); | 117 | idmap_pgd = pgd_alloc(&init_mm); |
| 84 | if (!idmap_pgd) | 118 | if (!idmap_pgd) |
| 85 | return -ENOMEM; | 119 | return -ENOMEM; |
| 86 | 120 | ||
| 87 | /* Add an identity mapping for the physical address of the section. */ | 121 | pr_info("Setting up static identity map for 0x%p - 0x%p\n", |
| 88 | idmap_start = virt_to_phys((void *)__idmap_text_start); | 122 | __idmap_text_start, __idmap_text_end); |
| 89 | idmap_end = virt_to_phys((void *)__idmap_text_end); | 123 | identity_mapping_add(idmap_pgd, __idmap_text_start, |
| 124 | __idmap_text_end, 0); | ||
| 90 | 125 | ||
| 91 | pr_info("Setting up static identity map for 0x%llx - 0x%llx\n", | 126 | ret = init_static_idmap_hyp(); |
| 92 | (long long)idmap_start, (long long)idmap_end); | ||
| 93 | identity_mapping_add(idmap_pgd, idmap_start, idmap_end); | ||
| 94 | 127 | ||
| 95 | /* Flush L1 for the hardware to see this page table content */ | 128 | /* Flush L1 for the hardware to see this page table content */ |
| 96 | flush_cache_louis(); | 129 | flush_cache_louis(); |
| 97 | 130 | ||
| 98 | return 0; | 131 | return ret; |
| 99 | } | 132 | } |
| 100 | early_initcall(init_static_idmap); | 133 | early_initcall(init_static_idmap); |
| 101 | 134 | ||
