Skip to content

Commit 3f105a7

Browse files
Alexandre Ghitipalmer-dabbelt
authored andcommitted
riscv: Sync efi page table's kernel mappings before switching
The EFI page table is initially created as a copy of the kernel page table. With VMAP_STACK enabled, kernel stacks are allocated in the vmalloc area: if the stack is allocated in a new PGD (one that was not present at the moment of the efi page table creation or not synced in a previous vmalloc fault), the kernel will take a trap when switching to the efi page table when the vmalloc kernel stack is accessed, resulting in a kernel panic. Fix that by updating the efi kernel mappings before switching to the efi page table. Signed-off-by: Alexandre Ghiti <[email protected]> Fixes: b91540d ("RISC-V: Add EFI runtime services") Tested-by: Emil Renner Berthing <[email protected]> Reviewed-by: Atish Patra <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 1d6b5ed commit 3f105a7

File tree

2 files changed

+13
-4
lines changed

2 files changed

+13
-4
lines changed

arch/riscv/include/asm/efi.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <asm/mmu_context.h>
1111
#include <asm/ptrace.h>
1212
#include <asm/tlbflush.h>
13+
#include <asm/pgalloc.h>
1314

1415
#ifdef CONFIG_EFI
1516
extern void efi_init(void);
@@ -20,7 +21,10 @@ extern void efi_init(void);
2021
int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
2122
int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
2223

23-
#define arch_efi_call_virt_setup() efi_virtmap_load()
24+
#define arch_efi_call_virt_setup() ({ \
25+
sync_kernel_mappings(efi_mm.pgd); \
26+
efi_virtmap_load(); \
27+
})
2428
#define arch_efi_call_virt_teardown() efi_virtmap_unload()
2529

2630
#define ARCH_EFI_IRQ_FLAGS_MASK (SR_IE | SR_SPIE)

arch/riscv/include/asm/pgalloc.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,13 @@ static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d)
127127
#define __p4d_free_tlb(tlb, p4d, addr) p4d_free((tlb)->mm, p4d)
128128
#endif /* __PAGETABLE_PMD_FOLDED */
129129

130+
static inline void sync_kernel_mappings(pgd_t *pgd)
131+
{
132+
memcpy(pgd + USER_PTRS_PER_PGD,
133+
init_mm.pgd + USER_PTRS_PER_PGD,
134+
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
135+
}
136+
130137
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
131138
{
132139
pgd_t *pgd;
@@ -135,9 +142,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
135142
if (likely(pgd != NULL)) {
136143
memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
137144
/* Copy kernel mappings */
138-
memcpy(pgd + USER_PTRS_PER_PGD,
139-
init_mm.pgd + USER_PTRS_PER_PGD,
140-
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
145+
sync_kernel_mappings(pgd);
141146
}
142147
return pgd;
143148
}

0 commit comments

Comments
 (0)