Skip to content

Commit 4996de7

Browse files
mro-github-12345Andy Bui
authored and
Andy Bui
committed
elfloader: setup pagetables as needed
This change sets up pagetables individually for: - The ELFloader image (Normal memory) - The DTB, whether supplied by EFI, cpio or u-boot (Normal mem) - The UART MMIO range (Strongly-Ordered mem) Thus, it removes the bulk 512 GiB 1:1 mapping that was there before. This resulted in problems, since the kernel image was mapped with Normal memory, but the same physical memory was part of the 1:1 Strongly-Ordered mapping. This fulfills the definition of "Mismatched memory attributes" from the ARM Architecture specification (ARM DDI 0487I.a, section B2.8). Even though I am currently unable to see where there would *occur* such a mismatched access, having such a mapping situation is certainly not desirable and should be avoided. Moreover, it is unclear whether there could arise problems from establishing the (Strongly-ordered) mapping if there is nothing behind a physical address (which is certainly true for some parts of the 512 GiB range). This commit solves the sporadics hangs while booting after the "Enabling MMU and ..." message. Tests on several different Orins (Muc and SJ) show promising results, i.e. no "hangs" occurred anymore. Note: The code in arm_switch_to_hyp_tables() still disables and re-enables both MMU & caches, but there are no memory accesses in between. That section has been engineered to be as short as possible and no memory accesses happen in between. Several barriers and code to invalidate instruction caches have been added, too, in order to be on the safe side. However, tests with just adding *that* code still showed the problem being present. The only change that showed behavior change was the change of translation tables. Thus, this *is* the actual solution to the instability problems. Moreover, we need to support crossing a 1 GiB page for placement of the ELFloader. This is due to the latest firmware on Orin0 in MUC, named "Jetson UEFI firmware (version 4.1-33958178)", which puts our image closely below a 1 GiB boundary. Only for tiny image sizes the boundary will not be crossed. Thus, we do not hard-code the writing of tables, because the logic for doing so while crossing a 1 GiB boundary is too complicated. Instead, we use a fully dynamic approach that walks the pagetables in software for a given VA and inserts missing levels on demand from a preallocated pool of pages. Only the two top-level pagetables are fixed. This allows for re-use of all pagetable code, where we only need to distinguish in one (!) place between hypervisor and non-hyp (or VHE). Signed-off-by: Matthias Rosenfelder <matthias.rosenfelder@nio.io>
1 parent 33f00c8 commit 4996de7

File tree

9 files changed

+444
-95
lines changed

9 files changed

+444
-95
lines changed

elfloader-tool/include/arch-arm/64/mode/structures.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66

77
#pragma once
88

9+
/* ARM VMSAv8-64 (with a fully populated last level) has the same number of PTEs
10+
* in all levels (we don't use concatenated pagetables in ELFloader) and each
11+
* table entry is always eight bytes large.
12+
*/
13+
#define BITS_PER_LEVEL (PAGE_BITS - 3)
14+
915
#define ARM_1GB_BLOCK_BITS 30
1016
#define ARM_2MB_BLOCK_BITS 21
1117

@@ -26,9 +32,5 @@
2632
#define GET_PMD_INDEX(x) (((word_t)(x) >> (ARM_2MB_BLOCK_BITS)) & MASK(PMD_BITS))
2733

2834
extern uint64_t _boot_pgd_up[BIT(PGD_BITS)];
29-
extern uint64_t _boot_pud_up[BIT(PUD_BITS)];
30-
extern uint64_t _boot_pmd_up[BIT(PMD_BITS)];
31-
3235
extern uint64_t _boot_pgd_down[BIT(PGD_BITS)];
33-
extern uint64_t _boot_pud_down[BIT(PUD_BITS)];
3436

elfloader-tool/include/arch-arm/elfloader.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,22 @@ typedef void (*init_arm_kernel_t)(word_t ui_p_reg_start,
2222

2323
/* Enable the mmu. */
2424
extern void arm_enable_mmu(void);
25+
26+
/* These functions are very similar however, there are some small differences
27+
* between the ARMv8 and legacy implementation.
28+
*
29+
* New ARMv8 implementation:
30+
* - Does the MMU disabling. This is to keep the time spent with MMU off low.
31+
* - Is only meant if seL4 runs in EL2.
32+
*/
33+
#if defined(CONFIG_ARCH_AARCH64)
34+
/* Switches MMU-related stuff: pagetables, MAIR & TCR etc. Works also if the MMU
35+
* was off initially. EL2 translation regime only.
36+
*/
37+
extern void arm_switch_to_hyp_tables(void);
38+
#else
2539
extern void arm_enable_hyp_mmu(void);
40+
#endif
2641

2742

2843
/* Setup boot VSpace. */

elfloader-tool/include/drivers/uart.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#pragma once
88

9+
#include <autoconf.h>
910
#include <drivers/common.h>
1011

1112
#define dev_get_uart(dev) ((struct elfloader_uart_ops *)(dev->drv->ops))
@@ -16,3 +17,7 @@ struct elfloader_uart_ops {
1617

1718
volatile void *uart_get_mmio(void);
1819
void uart_set_out(struct elfloader_device *out);
20+
#if defined(CONFIG_ARCH_AARCH64)
21+
/* Implemented in mmu.c */
22+
void mmu_set_uart_base(volatile void *base);
23+
#endif

0 commit comments

Comments
 (0)