Message ID | 20130108183848.46302.77369.stgit@ubuntu (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Tue, Jan 08, 2013 at 01:38:48PM -0500, Christoffer Dall wrote: > 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. > > Cc: 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> > --- > arch/arm/include/asm/idmap.h | 1 + > arch/arm/include/asm/pgtable-3level-hwdef.h | 1 + > arch/arm/kernel/vmlinux.lds.S | 6 +++ > arch/arm/mm/idmap.c | 54 ++++++++++++++++++++++----- > 4 files changed, 50 insertions(+), 12 deletions(-) > > diff --git a/arch/arm/include/asm/idmap.h b/arch/arm/include/asm/idmap.h > index bf863ed..1a66f907 100644 > --- a/arch/arm/include/asm/idmap.h > +++ b/arch/arm/include/asm/idmap.h > @@ -8,6 +8,7 @@ > #define __idmap __section(.idmap.text) noinline notrace > > extern pgd_t *idmap_pgd; > +extern pgd_t *hyp_pgd; > > void setup_mm_for_reboot(void); > > diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h > index d795282..a2d404e 100644 > --- a/arch/arm/include/asm/pgtable-3level-hwdef.h > +++ b/arch/arm/include/asm/pgtable-3level-hwdef.h > @@ -44,6 +44,7 @@ > #define PMD_SECT_XN (_AT(pmdval_t, 1) << 54) > #define PMD_SECT_AP_WRITE (_AT(pmdval_t, 0)) > #define PMD_SECT_AP_READ (_AT(pmdval_t, 0)) > +#define PMD_SECT_AP1 (_AT(pmdval_t, 1) << 6) > #define PMD_SECT_TEX(x) (_AT(pmdval_t, 0)) > > /* > diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S > index 11c1785..b571484 100644 > --- a/arch/arm/kernel/vmlinux.lds.S > +++ b/arch/arm/kernel/vmlinux.lds.S > @@ -19,7 +19,11 @@ > ALIGN_FUNCTION(); \ > VMLINUX_SYMBOL(__idmap_text_start) = .; \ > *(.idmap.text) \ > - VMLINUX_SYMBOL(__idmap_text_end) = .; > + VMLINUX_SYMBOL(__idmap_text_end) = .; \ > + ALIGN_FUNCTION(); \ > + VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ > + *(.hyp.idmap.text) \ > + VMLINUX_SYMBOL(__hyp_idmap_text_end) = .; > > #ifdef CONFIG_HOTPLUG_CPU > #define ARM_CPU_DISCARD(x) > diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c > index 99db769..d9213a5 100644 > --- a/arch/arm/mm/idmap.c > +++ b/arch/arm/mm/idmap.c > @@ -1,4 +1,6 @@ > +#include <linux/module.h> > #include <linux/kernel.h> > +#include <linux/slab.h> > > #include <asm/cputype.h> > #include <asm/idmap.h> > @@ -6,6 +8,7 @@ > #include <asm/pgtable.h> > #include <asm/sections.h> > #include <asm/system_info.h> > +#include <asm/virt.h> > > pgd_t *idmap_pgd; > > @@ -59,11 +62,20 @@ static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end, > } while (pud++, addr = next, addr != end); > } > > -static void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end) > +static void identity_mapping_add(pgd_t *pgd, const char *text_start, > + const char *text_end, unsigned long prot) > { > - unsigned long prot, next; > + unsigned long addr, end; > + unsigned long next; > + > + addr = virt_to_phys(text_start); > + end = virt_to_phys(text_end); How does this work with phys addresses greater than 32bit (with LPAE)? This was the same before the patch too, but I am still curious. Since __virt_to_phys() returns unsigned long kernel cannot be put in high memory, right? > + > + pr_info("Setting up static %sidentity map for 0x%llx - 0x%llx\n", > + prot ? "HYP " : "", > + (long long)addr, (long long)end); > + prot |= PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF; > > - prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF; > if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale()) > prot |= PMD_BIT4; > > @@ -74,28 +86,48 @@ static void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long e > } while (pgd++, addr = next, addr != end); > } > > +#ifdef CONFIG_ARM_VIRT_EXT > +pgd_t *hyp_pgd; > + > +extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[]; > + > +static int __init init_static_idmap_hyp(void) > +{ > + hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); > + if (!hyp_pgd) > + return -ENOMEM; > + > + identity_mapping_add(hyp_pgd, __hyp_idmap_text_start, > + __hyp_idmap_text_end, PMD_SECT_AP1); > + > + return 0; > +} > +#else > +static int __init init_static_idmap_hyp(void) > +{ > + return 0; > +} > +#endif > + > extern char __idmap_text_start[], __idmap_text_end[]; > > static int __init init_static_idmap(void) > { > - phys_addr_t idmap_start, idmap_end; > + int ret; > > idmap_pgd = pgd_alloc(&init_mm); > if (!idmap_pgd) > return -ENOMEM; > > - /* Add an identity mapping for the physical address of the section. */ > - idmap_start = virt_to_phys((void *)__idmap_text_start); > - idmap_end = virt_to_phys((void *)__idmap_text_end); > + identity_mapping_add(idmap_pgd, __idmap_text_start, > + __idmap_text_end, 0); > > - pr_info("Setting up static identity map for 0x%llx - 0x%llx\n", > - (long long)idmap_start, (long long)idmap_end); > - identity_mapping_add(idmap_pgd, idmap_start, idmap_end); > + ret = init_static_idmap_hyp(); > > /* Flush L1 for the hardware to see this page table content */ > flush_cache_louis(); > > - return 0; > + return ret; > } > early_initcall(init_static_idmap); > > > -- > To unsubscribe from this list: send the line "unsubscribe kvm" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Gleb.
On Mon, Jan 14, 2013 at 10:27:21AM +0000, Gleb Natapov wrote: > On Tue, Jan 08, 2013 at 01:38:48PM -0500, Christoffer Dall wrote: > > 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. > > > > Cc: 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> > > --- > > arch/arm/include/asm/idmap.h | 1 + > > arch/arm/include/asm/pgtable-3level-hwdef.h | 1 + > > arch/arm/kernel/vmlinux.lds.S | 6 +++ > > arch/arm/mm/idmap.c | 54 ++++++++++++++++++++++----- > > 4 files changed, 50 insertions(+), 12 deletions(-) [...] > > -static void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end) > > +static void identity_mapping_add(pgd_t *pgd, const char *text_start, > > + const char *text_end, unsigned long prot) > > { > > - unsigned long prot, next; > > + unsigned long addr, end; > > + unsigned long next; > > + > > + addr = virt_to_phys(text_start); > > + end = virt_to_phys(text_end); > How does this work with phys addresses greater than 32bit (with > LPAE)? This was the same before the patch too, but I am still > curious. Since __virt_to_phys() returns unsigned long kernel cannot be > put in high memory, right? Well, AArch32 (arch/arm/) only supports 32-bit virtual addresses by virtue of the fact that our registers are only 32 bits wide, so we can't identity-map physical addresses above the 4GB boundary. You may want to look at the keystone patches from TI for insight about kernels at high (>32-bit) addresses, although I've not seen any activity around that for some time now (which is a pity, because the code-patching stuff was in a good shape). Will
On Mon, Jan 14, 2013 at 10:49:53AM +0000, Will Deacon wrote: > On Mon, Jan 14, 2013 at 10:27:21AM +0000, Gleb Natapov wrote: > > On Tue, Jan 08, 2013 at 01:38:48PM -0500, Christoffer Dall wrote: > > > 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. > > > > > > Cc: 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> > > > --- > > > arch/arm/include/asm/idmap.h | 1 + > > > arch/arm/include/asm/pgtable-3level-hwdef.h | 1 + > > > arch/arm/kernel/vmlinux.lds.S | 6 +++ > > > arch/arm/mm/idmap.c | 54 ++++++++++++++++++++++----- > > > 4 files changed, 50 insertions(+), 12 deletions(-) > > [...] > > > > -static void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end) > > > +static void identity_mapping_add(pgd_t *pgd, const char *text_start, > > > + const char *text_end, unsigned long prot) > > > { > > > - unsigned long prot, next; > > > + unsigned long addr, end; > > > + unsigned long next; > > > + > > > + addr = virt_to_phys(text_start); > > > + end = virt_to_phys(text_end); > > How does this work with phys addresses greater than 32bit (with > > LPAE)? This was the same before the patch too, but I am still > > curious. Since __virt_to_phys() returns unsigned long kernel cannot be > > put in high memory, right? > > Well, AArch32 (arch/arm/) only supports 32-bit virtual addresses by virtue > of the fact that our registers are only 32 bits wide, so we can't > identity-map physical addresses above the 4GB boundary. > Ah, of course. This is ident map so by definition it cannot map phys addresses above 4G. And since __virt_to_phys() suppose to work only on ident map it's OK to returns unsigned long. > You may want to look at the keystone patches from TI for insight about > kernels at high (>32-bit) addresses, although I've not seen any activity > around that for some time now (which is a pity, because the code-patching > stuff was in a good shape). > > Will -- Gleb.
On Mon, Jan 14, 2013 at 01:07:56PM +0200, Gleb Natapov wrote: > Ah, of course. This is ident map so by definition it cannot map phys > addresses above 4G. And since __virt_to_phys() suppose to work only on > ident map it's OK to returns unsigned long. Let's get this right... the lack of correct definition in these comments needs correction. Firstly, __virt_to_phys() is an ARM-arch private function. Only ARM-arch private code should be using it - it must not be used outside that context. Secondly, it's "public" counterpart, virt_to_phys(), and itself are valid _only_ for what we call the "kernel direct map", which are the addresses corresponding with the lowmem pages mapped from PAGE_OFFSET up to the _start_ of vmalloc space. No other mapping is valid for this. That means that addresses in the identity mapping, if the identity mapping is outside of the range {PAGE_OFFSET..vmalloc start}, are _not_ valid for virt_to_phys(). The same is true of their counterparts, __phys_to_virt() and phys_to_virt(). These are _only_ valid for physical addresses corresponding to the pages mapped in as "lowmem" and they will return addresses for that mapping of the pages. Both these functions are invalid when used on highmem pages. *virt_to_phys() is invalid when used on pointers returned from ioremap(), vmalloc(), vmap(), dma_alloc_coherent(), and any other interface which remaps memory.
On Tue, Jan 08, 2013 at 01:38:48PM -0500, Christoffer Dall wrote: > + pr_info("Setting up static %sidentity map for 0x%llx - 0x%llx\n", > + prot ? "HYP " : "", > + (long long)addr, (long long)end); There's no point using 0x%llx and casting to 64-bit longs if the arguments are always going to be 32-bit.
diff --git a/arch/arm/include/asm/idmap.h b/arch/arm/include/asm/idmap.h index bf863ed..1a66f907 100644 --- a/arch/arm/include/asm/idmap.h +++ b/arch/arm/include/asm/idmap.h @@ -8,6 +8,7 @@ #define __idmap __section(.idmap.text) noinline notrace extern pgd_t *idmap_pgd; +extern pgd_t *hyp_pgd; void setup_mm_for_reboot(void); diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h index d795282..a2d404e 100644 --- a/arch/arm/include/asm/pgtable-3level-hwdef.h +++ b/arch/arm/include/asm/pgtable-3level-hwdef.h @@ -44,6 +44,7 @@ #define PMD_SECT_XN (_AT(pmdval_t, 1) << 54) #define PMD_SECT_AP_WRITE (_AT(pmdval_t, 0)) #define PMD_SECT_AP_READ (_AT(pmdval_t, 0)) +#define PMD_SECT_AP1 (_AT(pmdval_t, 1) << 6) #define PMD_SECT_TEX(x) (_AT(pmdval_t, 0)) /* diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 11c1785..b571484 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -19,7 +19,11 @@ ALIGN_FUNCTION(); \ VMLINUX_SYMBOL(__idmap_text_start) = .; \ *(.idmap.text) \ - VMLINUX_SYMBOL(__idmap_text_end) = .; + VMLINUX_SYMBOL(__idmap_text_end) = .; \ + ALIGN_FUNCTION(); \ + VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ + *(.hyp.idmap.text) \ + VMLINUX_SYMBOL(__hyp_idmap_text_end) = .; #ifdef CONFIG_HOTPLUG_CPU #define ARM_CPU_DISCARD(x) diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c index 99db769..d9213a5 100644 --- a/arch/arm/mm/idmap.c +++ b/arch/arm/mm/idmap.c @@ -1,4 +1,6 @@ +#include <linux/module.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <asm/cputype.h> #include <asm/idmap.h> @@ -6,6 +8,7 @@ #include <asm/pgtable.h> #include <asm/sections.h> #include <asm/system_info.h> +#include <asm/virt.h> pgd_t *idmap_pgd; @@ -59,11 +62,20 @@ static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end, } while (pud++, addr = next, addr != end); } -static void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end) +static void identity_mapping_add(pgd_t *pgd, const char *text_start, + const char *text_end, unsigned long prot) { - unsigned long prot, next; + unsigned long addr, end; + unsigned long next; + + addr = virt_to_phys(text_start); + end = virt_to_phys(text_end); + + pr_info("Setting up static %sidentity map for 0x%llx - 0x%llx\n", + prot ? "HYP " : "", + (long long)addr, (long long)end); + prot |= PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF; - prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF; if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale()) prot |= PMD_BIT4; @@ -74,28 +86,48 @@ static void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long e } while (pgd++, addr = next, addr != end); } +#ifdef CONFIG_ARM_VIRT_EXT +pgd_t *hyp_pgd; + +extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[]; + +static int __init init_static_idmap_hyp(void) +{ + hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); + if (!hyp_pgd) + return -ENOMEM; + + identity_mapping_add(hyp_pgd, __hyp_idmap_text_start, + __hyp_idmap_text_end, PMD_SECT_AP1); + + return 0; +} +#else +static int __init init_static_idmap_hyp(void) +{ + return 0; +} +#endif + extern char __idmap_text_start[], __idmap_text_end[]; static int __init init_static_idmap(void) { - phys_addr_t idmap_start, idmap_end; + int ret; idmap_pgd = pgd_alloc(&init_mm); if (!idmap_pgd) return -ENOMEM; - /* Add an identity mapping for the physical address of the section. */ - idmap_start = virt_to_phys((void *)__idmap_text_start); - idmap_end = virt_to_phys((void *)__idmap_text_end); + identity_mapping_add(idmap_pgd, __idmap_text_start, + __idmap_text_end, 0); - pr_info("Setting up static identity map for 0x%llx - 0x%llx\n", - (long long)idmap_start, (long long)idmap_end); - identity_mapping_add(idmap_pgd, idmap_start, idmap_end); + ret = init_static_idmap_hyp(); /* Flush L1 for the hardware to see this page table content */ flush_cache_louis(); - return 0; + return ret; } early_initcall(init_static_idmap);