Skip to content

Commit 2aa85f2

Browse files
swahlhpesuryasaimadhu
authored andcommitted
x86/boot/64: Make level2_kernel_pgt pages invalid outside kernel area
Our hardware (UV aka Superdome Flex) has address ranges marked reserved by the BIOS. Access to these ranges is caught as an error, causing the BIOS to halt the system. Initial page tables mapped a large range of physical addresses that were not checked against the list of BIOS reserved addresses, and sometimes included reserved addresses in part of the mapped range. Including the reserved range in the map allowed processor speculative accesses to the reserved range, triggering a BIOS halt. Used early in booting, the page table level2_kernel_pgt addresses 1 GiB divided into 2 MiB pages, and it was set up to linearly map a full 1 GiB of physical addresses that included the physical address range of the kernel image, as chosen by KASLR. But this also included a large range of unused addresses on either side of the kernel image. And unlike the kernel image's physical address range, this extra mapped space was not checked against the BIOS tables of usable RAM addresses. So there were times when the addresses chosen by KASLR would result in processor accessible mappings of BIOS reserved physical addresses. The kernel code did not directly access any of this extra mapped space, but having it mapped allowed the processor to issue speculative accesses into reserved memory, causing system halts. This was encountered somewhat rarely on a normal system boot, and much more often when starting the crash kernel if "crashkernel=512M,high" was specified on the command line (this heavily restricts the physical address of the crash kernel, in our case usually within 1 GiB of reserved space). The solution is to invalidate the pages of this table outside the kernel image's space before the page table is activated. It fixes this problem on our hardware. [ bp: Touchups. ] Signed-off-by: Steve Wahl <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Acked-by: Dave Hansen <[email protected]> Acked-by: Kirill A. Shutemov <[email protected]> Cc: Baoquan He <[email protected]> Cc: Brijesh Singh <[email protected]> Cc: [email protected] Cc: Feng Tang <[email protected]> Cc: "H. Peter Anvin" <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Jordan Borgner <[email protected]> Cc: Juergen Gross <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: Thomas Gleixner <[email protected]> Cc: x86-ml <[email protected]> Cc: Zhenzhong Duan <[email protected]> Link: https://lkml.kernel.org/r/9c011ee51b081534a7a15065b1681d200298b530.1569358539.git.steve.wahl@hpe.com
1 parent 8d7c6ac commit 2aa85f2

File tree

1 file changed

+20
-2
lines changed

1 file changed

+20
-2
lines changed

arch/x86/kernel/head64.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,31 @@ unsigned long __head __startup_64(unsigned long physaddr,
222222
* we might write invalid pmds, when the kernel is relocated
223223
* cleanup_highmap() fixes this up along with the mappings
224224
* beyond _end.
225+
*
226+
* Only the region occupied by the kernel image has so far
227+
* been checked against the table of usable memory regions
228+
* provided by the firmware, so invalidate pages outside that
229+
* region. A page table entry that maps to a reserved area of
230+
* memory would allow processor speculation into that area,
231+
* and on some hardware (particularly the UV platform) even
232+
* speculative access to some reserved areas is caught as an
233+
* error, causing the BIOS to halt the system.
225234
*/
226235

227236
pmd = fixup_pointer(level2_kernel_pgt, physaddr);
228-
for (i = 0; i < PTRS_PER_PMD; i++) {
237+
238+
/* invalidate pages before the kernel image */
239+
for (i = 0; i < pmd_index((unsigned long)_text); i++)
240+
pmd[i] &= ~_PAGE_PRESENT;
241+
242+
/* fixup pages that are part of the kernel image */
243+
for (; i <= pmd_index((unsigned long)_end); i++)
229244
if (pmd[i] & _PAGE_PRESENT)
230245
pmd[i] += load_delta;
231-
}
246+
247+
/* invalidate pages after the kernel image */
248+
for (; i < PTRS_PER_PMD; i++)
249+
pmd[i] &= ~_PAGE_PRESENT;
232250

233251
/*
234252
* Fixup phys_base - remove the memory encryption mask to obtain

0 commit comments

Comments
 (0)