From 06f75a1f6200042aa36ad40afb44dd72107b25d6 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 19 Mar 2015 16:42:26 +0000 Subject: ARM, arm64: kvm: get rid of the bounce page The HYP init bounce page is a runtime construct that ensures that the HYP init code does not cross a page boundary. However, this is something we can do perfectly well at build time, by aligning the code appropriately. For arm64, we just align to 4 KB, and enforce that the code size is less than 4 KB, regardless of the chosen page size. For ARM, the whole code is less than 256 bytes, so we tweak the linker script to align at a power of 2 upper bound of the code size Note that this also fixes a benign off-by-one error in the original bounce page code, where a bounce page would be allocated unnecessarily if the code was exactly 1 page in size. On ARM, it also fixes an issue with very large kernels reported by Arnd Bergmann, where stub sections with linker emitted veneers could erroneously trigger the size/alignment ASSERT() in the linker script. Tested-by: Marc Zyngier Reviewed-by: Marc Zyngier Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- arch/arm/kernel/vmlinux.lds.S | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'arch/arm/kernel/vmlinux.lds.S') diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index b31aa73e8076..ba65f1217310 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -23,11 +23,20 @@ VMLINUX_SYMBOL(__idmap_text_start) = .; \ *(.idmap.text) \ VMLINUX_SYMBOL(__idmap_text_end) = .; \ - . = ALIGN(32); \ + . = ALIGN(1 << LOG2CEIL(__hyp_idmap_size)); \ VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ *(.hyp.idmap.text) \ VMLINUX_SYMBOL(__hyp_idmap_text_end) = .; +/* + * If the HYP idmap .text section is populated, it needs to be positioned + * such that it will not cross a page boundary in the final output image. + * So align it to the section size rounded up to the next power of 2. + * If __hyp_idmap_size is undefined, the section will be empty so define + * it as 0 in that case. + */ +PROVIDE(__hyp_idmap_size = 0); + #ifdef CONFIG_HOTPLUG_CPU #define ARM_CPU_DISCARD(x) #define ARM_CPU_KEEP(x) x @@ -346,8 +355,11 @@ SECTIONS */ ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support") ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined") + /* - * The HYP init code can't be more than a page long. + * The HYP init code can't be more than a page long, + * and should not cross a page boundary. * The above comment applies as well. */ -ASSERT(((__hyp_idmap_text_end - __hyp_idmap_text_start) <= PAGE_SIZE), "HYP init code too big") +ASSERT((__hyp_idmap_text_start & ~PAGE_MASK) + __hyp_idmap_size <= PAGE_SIZE, + "HYP init code too big or misaligned") -- cgit v1.2.3 From e60a1fec44a2fe2c85ac406a5c1161ca2957a4fa Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 23 Mar 2015 10:52:57 +0000 Subject: ARM: kvm: implement replacement for ld's LOG2CEIL() Commit 06f75a1f6200 ("ARM, arm64: kvm: get rid of the bounce page") uses ld's builtin function LOG2CEIL() to align the KVM init code to a log2 upper bound of its size. However, this function turns out to be a fairly recent addition to binutils, which breaks the build for older toolchains. So instead, implement a replacement LOG2_ROUNDUP() using the C preprocessor. Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- arch/arm/kernel/vmlinux.lds.S | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'arch/arm/kernel/vmlinux.lds.S') diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index ba65f1217310..2d760df0d57d 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -11,7 +11,27 @@ #ifdef CONFIG_ARM_KERNMEM_PERMS #include #endif - + +/* + * Poor man's version of LOG2CEIL(), which is + * not available in binutils before v2.24. + */ +#define LOG2_ROUNDUP(size) ( \ + __LOG2_ROUNDUP(size, 2) \ + __LOG2_ROUNDUP(size, 3) \ + __LOG2_ROUNDUP(size, 4) \ + __LOG2_ROUNDUP(size, 5) \ + __LOG2_ROUNDUP(size, 6) \ + __LOG2_ROUNDUP(size, 7) \ + __LOG2_ROUNDUP(size, 8) \ + __LOG2_ROUNDUP(size, 9) \ + __LOG2_ROUNDUP(size, 10) \ + __LOG2_ROUNDUP(size, 11) \ + 12) + +#define __LOG2_ROUNDUP(size, order) \ + (size) <= (1 << order) ? order : + #define PROC_INFO \ . = ALIGN(4); \ VMLINUX_SYMBOL(__proc_info_begin) = .; \ @@ -23,7 +43,7 @@ VMLINUX_SYMBOL(__idmap_text_start) = .; \ *(.idmap.text) \ VMLINUX_SYMBOL(__idmap_text_end) = .; \ - . = ALIGN(1 << LOG2CEIL(__hyp_idmap_size)); \ + . = ALIGN(1 << LOG2_ROUNDUP(__hyp_idmap_size)); \ VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ *(.hyp.idmap.text) \ VMLINUX_SYMBOL(__hyp_idmap_text_end) = .; -- cgit v1.2.3 From 12eb3e833961bfe532b763a6e4e817ec87f48bc7 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 24 Mar 2015 17:48:07 +0000 Subject: ARM: kvm: assert on HYP section boundaries not actual code size Using ASSERT() with an expression that involves a symbol that is only supplied through a PROVIDE() definition in the linker script itself is apparently not supported by some older versions of binutils. So instead, rewrite the expression so that only the section boundaries __hyp_idmap_text_start and __hyp_idmap_text_end are used. Note that this reverts the fix in 06f75a1f6200 ("ARM, arm64: kvm: get rid of the bounce page") for the ASSERT() being triggered erroneously when unrelated linker emitted veneers happen to end up in the HYP idmap region. Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- arch/arm/kernel/vmlinux.lds.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/kernel/vmlinux.lds.S') diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 2d760df0d57d..808398ec024e 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -381,5 +381,5 @@ ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined") * and should not cross a page boundary. * The above comment applies as well. */ -ASSERT((__hyp_idmap_text_start & ~PAGE_MASK) + __hyp_idmap_size <= PAGE_SIZE, +ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & PAGE_MASK) <= PAGE_SIZE, "HYP init code too big or misaligned") -- cgit v1.2.3 From a9fea8b388ed5838fe0744970e67f7019d420824 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 27 Mar 2015 10:18:01 +0000 Subject: ARM: kvm: round HYP section to page size instead of log2 upper bound Older binutils do not support expressions involving the values of external symbols so just round up the HYP region to the page size. Tested-by: Simon Horman Signed-off-by: Ard Biesheuvel [will: when will this ever end?!] Signed-off-by: Will Deacon --- arch/arm/kernel/vmlinux.lds.S | 31 +------------------------------ arch/arm/kvm/init.S | 3 --- 2 files changed, 1 insertion(+), 33 deletions(-) (limited to 'arch/arm/kernel/vmlinux.lds.S') diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 808398ec024e..f2db429ea75d 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -12,26 +12,6 @@ #include #endif -/* - * Poor man's version of LOG2CEIL(), which is - * not available in binutils before v2.24. - */ -#define LOG2_ROUNDUP(size) ( \ - __LOG2_ROUNDUP(size, 2) \ - __LOG2_ROUNDUP(size, 3) \ - __LOG2_ROUNDUP(size, 4) \ - __LOG2_ROUNDUP(size, 5) \ - __LOG2_ROUNDUP(size, 6) \ - __LOG2_ROUNDUP(size, 7) \ - __LOG2_ROUNDUP(size, 8) \ - __LOG2_ROUNDUP(size, 9) \ - __LOG2_ROUNDUP(size, 10) \ - __LOG2_ROUNDUP(size, 11) \ - 12) - -#define __LOG2_ROUNDUP(size, order) \ - (size) <= (1 << order) ? order : - #define PROC_INFO \ . = ALIGN(4); \ VMLINUX_SYMBOL(__proc_info_begin) = .; \ @@ -43,20 +23,11 @@ VMLINUX_SYMBOL(__idmap_text_start) = .; \ *(.idmap.text) \ VMLINUX_SYMBOL(__idmap_text_end) = .; \ - . = ALIGN(1 << LOG2_ROUNDUP(__hyp_idmap_size)); \ + . = ALIGN(PAGE_SIZE); \ VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ *(.hyp.idmap.text) \ VMLINUX_SYMBOL(__hyp_idmap_text_end) = .; -/* - * If the HYP idmap .text section is populated, it needs to be positioned - * such that it will not cross a page boundary in the final output image. - * So align it to the section size rounded up to the next power of 2. - * If __hyp_idmap_size is undefined, the section will be empty so define - * it as 0 in that case. - */ -PROVIDE(__hyp_idmap_size = 0); - #ifdef CONFIG_HOTPLUG_CPU #define ARM_CPU_DISCARD(x) #define ARM_CPU_KEEP(x) x diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S index 11fb1d56f449..3988e72d16ff 100644 --- a/arch/arm/kvm/init.S +++ b/arch/arm/kvm/init.S @@ -157,6 +157,3 @@ target: @ We're now in the trampoline code, switch page tables __kvm_hyp_init_end: .popsection - - .global __hyp_idmap_size - .set __hyp_idmap_size, __kvm_hyp_init_end - __kvm_hyp_init -- cgit v1.2.3