arm64 UEFI early FDT handling
Subsystems (6)
cover arm64 UEFI early FDT handling
This is a followup to the "arm64: update/clarify/relax Image and FDT placement rules" series I sent a while ago:
(http://article.gmane.org/gmane.linux.ports.arm.kernel/407148)
This has now been split in two series: this first series deals with the early FDT handling, primarily in the context of UEFI, but not exclusively.
A number of minor issues exist in the early UEFI/FDT handling path, such as:
- the FDT placement by the stub may violate the arm64/linux boot protocol in some corner cases;
- when booting via UEFI, memreserve entries are removed from the device tree but the /reserved-memory node is not
- memory nodes are removed from the device tree in a way that is not officially supported by the libfdt API (i.e., you cannot delete nodes while traversing the tree)
- removal of memory nodes may discard annotations (such as NUMA topology) that should ideally be retained.
Patch #1 splits off the reservation of the FDT image from the reservation of the memreserve entries and /reserved-memory node.
Patch #2 relaxes the boot protocol requirement on the placement of the FDT.
Patch #3 introduces an arm64 specific version of early_init_dt_add_memory_arch() so that we can modify it later to ignore DT memory nodes if booting via UEFI. Note that having this specific version is desirable for other reasons as well, this is covered by the other followup series.
Patch #4 moves some UEFI+FDT init code around before making changes to it.
Patch #5 moves the UEFI initialization to before the early FDT scanning so we know at that point whether we are booting via UEFI or not.
Patch #6 changes the UEFI init code so that memory nodes are simply ignored, so that they don't have to be removed by the stub anymore.
Patch #7 does the same as #6, but for memreserves and the /reserved-memory node.
Patch #8 adapts the FDT placement logic used by the stub to take into account the new relaxed rules.
Ard Biesheuvel (8):
of/fdt: split off FDT self reservation from memreserve processing
arm64: use fixmap region for permanent FDT mapping
arm64: override early_init_dt_add_memory_arch()
efi: move FDT handling to separate object file arm64/efi: move EFI init before early FDT processing arm64/efi: ignore DT memory nodes instead of removing them arm64/efi: ignore DT memreserve entries instead of removing them arm64/efi: adapt to relaxed FDT placement requirements
Documentation/arm64/booting.txt | 13 +++-- arch/arm/mm/init.c | 1 + arch/arm64/include/asm/boot.h | 14 ++++++ arch/arm64/include/asm/efi.h | 14 ++---- arch/arm64/include/asm/fixmap.h | 15 ++++++ arch/arm64/include/asm/mmu.h | 1 + arch/arm64/kernel/efi.c | 14 ++---- arch/arm64/kernel/head.S | 39 +-------------- arch/arm64/kernel/setup.c | 34 +++++-------- arch/arm64/mm/Makefile | 2 + arch/arm64/mm/init.c | 35 +++++++++++++- arch/arm64/mm/mmu.c | 66 +++++++++++++++++++++++++ arch/powerpc/kernel/prom.c | 1 + drivers/firmware/efi/Makefile | 2 + drivers/firmware/efi/efi-fdt.c | 77 +++++++++++++++++++++++++++++ drivers/firmware/efi/efi.c | 86 --------------------------------- drivers/firmware/efi/libstub/arm-stub.c | 5 +- drivers/firmware/efi/libstub/efistub.h | 1 - drivers/firmware/efi/libstub/fdt.c | 51 ++++--------------- drivers/of/fdt.c | 19 ++++++-- include/linux/efi.h | 3 +- include/linux/of_fdt.h | 2 + 22 files changed, 274 insertions(+), 221 deletions(-) create mode 100644 arch/arm64/include/asm/boot.h create mode 100644 drivers/firmware/efi/efi-fdt.c
Signature · 1 line
1.9.1
PATCH 1/8 of/fdt: split off FDT self reservation from memreserve processing
This splits off the reservation of the memory occupied by the FDT binary itself from the processing of the memory reservations it contains. This is necessary because the physical address of the FDT, which is needed to perform the reservation, may not be known to the FDT driver core, i.e., it may be mapped outside the linear direct mapping, in which case __pa() returns a bogus value.
--- arch/arm/mm/init.c | 1 + arch/arm64/mm/init.c | 1 + arch/powerpc/kernel/prom.c | 1 + drivers/of/fdt.c | 19 ++++++++++++++----- include/linux/of_fdt.h | 2 ++ 5 files changed, 19 insertions(+), 5 deletions(-)
arch/arm/mm/init.c +1 -0
@@ -268,6 +268,7 @@ void __init arm_memblock_init(const struct machine_desc *mdesc)if (mdesc->reserve) mdesc->reserve (); +early_init_fdt_reserve_self ();early_init_fdt_scan_reserved_mem ();/* reserve memory for DMA contiguous allocations */
arch/arm64/mm/init.c +1 -0
@@ -170,6 +170,7 @@ void __init arm64_memblock_init(void)memblock_reserve (__virt_to_phys (initrd_start), initrd_end - initrd_start);#endif +early_init_fdt_reserve_self ();early_init_fdt_scan_reserved_mem ();/* 4GB maximum for 32-bit only capable devices */
arch/powerpc/kernel/prom.c +1 -0
@@ -573,6 +573,7 @@ static void __init early_reserve_mem_dt(void)int len;const __be32 *prop; +early_init_fdt_reserve_self ();early_init_fdt_scan_reserved_mem (); dt_root =of_get_flat_dt_root ();
drivers/of/fdt.c +14 -5
@@ -580,11 +580,6 @@ void __init early_init_fdt_scan_reserved_mem(void)if (!initial_boot_params)return ; -/* Reserve the dtb region */ -early_init_dt_reserve_memory_arch (__pa (initial_boot_params), -fdt_totalsize (initial_boot_params), -0 ); -/* Process header /memreserve/ fields */ for (n =0 ; ; n++) {fdt_get_mem_rsv (initial_boot_params, n, &base, &size);
@@ -598,6 +593,20 @@ void __init early_init_fdt_scan_reserved_mem(void) }/** +* early_init_fdt_reserve_self() - reserve the memory used by the FDT blob +*/ +void __init early_init_fdt_reserve_self (void ) +{ +if (!initial_boot_params) +return ; + +/* Reserve the dtb region */ +early_init_dt_reserve_memory_arch (__pa (initial_boot_params), +fdt_totalsize (initial_boot_params), +0 ); +} + +/** * of_scan_flat_dt - scan flattened tree blob and call callback on each. * @it: callback function * @data: context data pointer
include/linux/of_fdt.h +2 -0
@@ -64,6 +64,7 @@ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,extern int early_init_dt_scan_memory (unsigned long node,const char *uname,int depth,void *data);extern void early_init_fdt_scan_reserved_mem (void ); +extern void early_init_fdt_reserve_self (void );extern void early_init_dt_add_memory_arch (u64 base,u64 size);extern int early_init_dt_reserve_memory_arch (phys_addr_t base,phys_addr_t size,bool no_map);
@@ -91,6 +92,7 @@ extern u64 fdt_translate_address(const void *blob, int node_offset);extern void of_fdt_limit_memory (int limit);#else /* CONFIG_OF_FLATTREE */ static inline void early_init_fdt_scan_reserved_mem (void ) {} +static inline void early_init_fdt_reserve_self (void ) {}static inline const char *of_flat_dt_get_machine_name (void ) {return NULL ; }static inline void unflatten_device_tree (void ) {}static inline void unflatten_and_copy_device_tree (void ) {}
Signature · 1 line
1.9.1
Catalin Marinas
maintainerPATCH 1/8 of/fdt: split off FDT self reservation from memreserve processing
Quoted 7 lines · Ard Biesheuvel
This splits off the reservation of the memory occupied by the FDT binary itself from the processing of the memory reservations it contains. This is necessary because the physical address of the FDT, which is needed to perform the reservation, may not be known to the FDT driver core, i.e., it may be mapped outside the linear direct mapping, in which case
__pa()returns a bogus value.
Quoted 6 lines
Cc Russell King <[email protected]>Cc Benjamin Herrenschmidt <[email protected]>Cc Paul Mackerras <[email protected]>Acked-by Rob Herring <[email protected]>Acked-by Mark Rutland <[email protected]>Signed-off-by Ard Biesheuvel <[email protected]>
For the arm64 part:
PATCH 1/8 of/fdt: split off FDT self reservation from memreserve processing
(snip non-LAKML CCs)
Quoted 15 lines · Catalin Marinas
Quoted 7 lines · Ard Biesheuvel
This splits off the reservation of the memory occupied by the FDT binary itself from the processing of the memory reservations it contains. This is necessary because the physical address of the FDT, which is needed to perform the reservation, may not be known to the FDT driver core, i.e., it may be mapped outside the linear direct mapping, in which case
__pa()returns a bogus value.Quoted 6 lines
Cc Russell King <[email protected]>Cc Benjamin Herrenschmidt <[email protected]>Cc Paul Mackerras <[email protected]>Acked-by Rob Herring <[email protected]>Acked-by Mark Rutland <[email protected]>Signed-off-by Ard Biesheuvel <[email protected]>
Quoted 3 lines
For the arm64 part:
Acked-by Catalin Marinas <[email protected]>
Thanks Catalin,
Since there has been virtually no discussion about these patches, I guess they have missed the window for being considered for inclusion in v4.2
May I suggest that you at least consider these patches regarding the ID map
http://article.gmane.org/gmane.linux.ports.arm.kernel/411720
http://article.gmane.org/gmane.linux.ports.arm.kernel/411721
since they are self-contained and the first one does fix a potential problem where the Image placement logic in the stub does not take the 512 MB alignment boundary into account. The second one is a trivial cleanup.
Perhaps Mark can comment on the desirability to include the FDT remapping patch (which depends on this 1/8).
http://article.gmane.org/gmane.linux.kernel.efi/5738
I don't have strong preference either way, although it would be good to get some patches off my personal queue.
Regards,
Ard.
Mark Rutland
reviewerPATCH 1/8 of/fdt: split off FDT self reservation from memreserve processing
Quoted 30 lines · Ard Biesheuvel
(snip non-LAKML CCs)
Quoted 15 lines · Catalin Marinas
Quoted 7 lines · Ard Biesheuvel
This splits off the reservation of the memory occupied by the FDT binary itself from the processing of the memory reservations it contains. This is necessary because the physical address of the FDT, which is needed to perform the reservation, may not be known to the FDT driver core, i.e., it may be mapped outside the linear direct mapping, in which case
__pa()returns a bogus value.Quoted 6 lines
Cc Russell King <[email protected]>Cc Benjamin Herrenschmidt <[email protected]>Cc Paul Mackerras <[email protected]>Acked-by Rob Herring <[email protected]>Acked-by Mark Rutland <[email protected]>Signed-off-by Ard Biesheuvel <[email protected]>Quoted 3 lines
For the arm64 part:
Acked-by Catalin Marinas <[email protected]>Thanks Catalin,
Since there has been virtually no discussion about these patches, I guess they have missed the window for being considered for inclusion in v4.2
May I suggest that you at least consider these patches regarding the ID map
Quoted 7 lines
http://article.gmane.org/gmane.linux.ports.arm.kernel/411720
http://article.gmane.org/gmane.linux.ports.arm.kernel/411721since they are self-contained and the first one does fix a potential problem where the Image placement logic in the stub does not take the 512 MB alignment boundary into account. The second one is a trivial cleanup.
FWIW both of these look good to me.
Quoted 4 lines
Perhaps Mark can comment on the desirability to include the FDT remapping patch (which depends on this 1/8).
I would like to see that taken if possible.
Thanks,
Mark.
PATCH 1/8 of/fdt: split off FDT self reservation from memreserve processing
Quoted 39 lines · Mark Rutland
Quoted 30 lines · Ard Biesheuvel
(snip non-LAKML CCs)
Quoted 15 lines · Catalin Marinas
Quoted 7 lines · Ard Biesheuvel
This splits off the reservation of the memory occupied by the FDT binary itself from the processing of the memory reservations it contains. This is necessary because the physical address of the FDT, which is needed to perform the reservation, may not be known to the FDT driver core, i.e., it may be mapped outside the linear direct mapping, in which case
__pa()returns a bogus value.Quoted 6 lines
Cc Russell King <[email protected]>Cc Benjamin Herrenschmidt <[email protected]>Cc Paul Mackerras <[email protected]>Acked-by Rob Herring <[email protected]>Acked-by Mark Rutland <[email protected]>Signed-off-by Ard Biesheuvel <[email protected]>Quoted 3 lines
For the arm64 part:
Acked-by Catalin Marinas <[email protected]>Thanks Catalin,
Since there has been virtually no discussion about these patches, I guess they have missed the window for being considered for inclusion in v4.2
May I suggest that you at least consider these patches regarding the ID map
Quoted 7 lines
http://article.gmane.org/gmane.linux.ports.arm.kernel/411720
http://article.gmane.org/gmane.linux.ports.arm.kernel/411721since they are self-contained and the first one does fix a potential problem where the Image placement logic in the stub does not take the 512 MB alignment boundary into account. The second one is a trivial cleanup.
Quoted 9 lines
FWIW both of these look good to me.
Quoted 4 lines
Perhaps Mark can comment on the desirability to include the FDT remapping patch (which depends on this 1/8).
I would like to see that taken if possible.
Thanks.
Actually, it does make kind of sense to take these four (i.e., this 1/8 plus the three referenced above) patches as a set, since together they address all the known shortcomings in the EFI stub regarding the placement of both the FDT and the kernel image. All the other stuff can easily be deferred.
I will respin these 4 with the new tags added.
Mark Rutland
reviewerPATCH 1/8 of/fdt: split off FDT self reservation from memreserve processing
Quoted 50 lines · Ard Biesheuvel
Quoted 39 lines · Mark Rutland
Quoted 30 lines · Ard Biesheuvel
(snip non-LAKML CCs)
Quoted 15 lines · Catalin Marinas
Quoted 7 lines · Ard Biesheuvel
This splits off the reservation of the memory occupied by the FDT binary itself from the processing of the memory reservations it contains. This is necessary because the physical address of the FDT, which is needed to perform the reservation, may not be known to the FDT driver core, i.e., it may be mapped outside the linear direct mapping, in which case
__pa()returns a bogus value.Quoted 6 lines
Cc Russell King <[email protected]>Cc Benjamin Herrenschmidt <[email protected]>Cc Paul Mackerras <[email protected]>Acked-by Rob Herring <[email protected]>Acked-by Mark Rutland <[email protected]>Signed-off-by Ard Biesheuvel <[email protected]>Quoted 3 lines
For the arm64 part:
Acked-by Catalin Marinas <[email protected]>Thanks Catalin,
Since there has been virtually no discussion about these patches, I guess they have missed the window for being considered for inclusion in v4.2
May I suggest that you at least consider these patches regarding the ID map
Quoted 7 lines
http://article.gmane.org/gmane.linux.ports.arm.kernel/411720
http://article.gmane.org/gmane.linux.ports.arm.kernel/411721since they are self-contained and the first one does fix a potential problem where the Image placement logic in the stub does not take the 512 MB alignment boundary into account. The second one is a trivial cleanup.
Quoted 9 lines
FWIW both of these look good to me.
Quoted 4 lines
Perhaps Mark can comment on the desirability to include the FDT remapping patch (which depends on this 1/8).
I would like to see that taken if possible.
Quoted 7 lines
Thanks.
Actually, it does make kind of sense to take these four (i.e., this 1/8 plus the three referenced above) patches as a set, since together they address all the known shortcomings in the EFI stub regarding the placement of both the FDT and the kernel image. All the other stuff can easily be deferred.
Putting those together as a cleanup+preparation series makes sense to me, if that makes it easy for Catalin to pick them up now.
Do we have/need acks from Ben or Paul on this reservation patch?
Thanks,
Mark.
PATCH 1/8 of/fdt: split off FDT self reservation from memreserve processing
Quoted 59 lines · Mark Rutland
Quoted 50 lines · Ard Biesheuvel
Quoted 39 lines · Mark Rutland
Quoted 30 lines · Ard Biesheuvel
(snip non-LAKML CCs)
Quoted 15 lines · Catalin Marinas
Quoted 7 lines · Ard Biesheuvel
This splits off the reservation of the memory occupied by the FDT binary itself from the processing of the memory reservations it contains. This is necessary because the physical address of the FDT, which is needed to perform the reservation, may not be known to the FDT driver core, i.e., it may be mapped outside the linear direct mapping, in which case
__pa()returns a bogus value.Quoted 6 lines
Cc Russell King <[email protected]>Cc Benjamin Herrenschmidt <[email protected]>Cc Paul Mackerras <[email protected]>Acked-by Rob Herring <[email protected]>Acked-by Mark Rutland <[email protected]>Signed-off-by Ard Biesheuvel <[email protected]>Quoted 3 lines
For the arm64 part:
Acked-by Catalin Marinas <[email protected]>Thanks Catalin,
Since there has been virtually no discussion about these patches, I guess they have missed the window for being considered for inclusion in v4.2
May I suggest that you at least consider these patches regarding the ID map
Quoted 7 lines
http://article.gmane.org/gmane.linux.ports.arm.kernel/411720
http://article.gmane.org/gmane.linux.ports.arm.kernel/411721since they are self-contained and the first one does fix a potential problem where the Image placement logic in the stub does not take the 512 MB alignment boundary into account. The second one is a trivial cleanup.
Quoted 9 lines
FWIW both of these look good to me.
Quoted 4 lines
Perhaps Mark can comment on the desirability to include the FDT remapping patch (which depends on this 1/8).
I would like to see that taken if possible.
Quoted 7 lines
Thanks.
Actually, it does make kind of sense to take these four (i.e., this 1/8 plus the three referenced above) patches as a set, since together they address all the known shortcomings in the EFI stub regarding the placement of both the FDT and the kernel image. All the other stuff can easily be deferred.
Quoted 5 lines
Putting those together as a cleanup+preparation series makes sense to me, if that makes it easy for Catalin to pick them up now.
Do we have/need acks from Ben or Paul on this reservation patch?
Considering that this patch is essentially a partial revert of d1552ce449eb0 ("of/fdt: move memreserve and dtb memory reservations into core") by Rob, who acked this patch and submitted his patch without the acks of either Ben or Paul, and the fact that Ben and Paul (and Russell) have all been cc'ed at least 3 times on this patch, my take would be that it should be fine to go ahead without them. But it is ultimately up to Catalin, of course.
Mark Rutland
reviewerPATCH 1/8 of/fdt: split off FDT self reservation from memreserve processing
Quoted 10 lines
Quoted 2 lines
Do we have/need acks from Ben or Paul on this reservation patch?
Considering that this patch is essentially a partial revert of
d1552ce449eb0("of/fdt: move memreserve and dtb memory reservations into core") by Rob, who acked this patch and submitted his patch without the acks of either Ben or Paul, and the fact that Ben and Paul (and Russell) have all been cc'ed at least 3 times on this patch, my take would be that it should be fine to go ahead without them. But it is ultimately up to Catalin, of course.
That sounds fine to me also, just thought I should check.
Mark.
PATCH 2/8 arm64: use fixmap region for permanent FDT mapping
In reply to Ard BiesheuvelCurrently, the FDT blob needs to be in the same 512 MB region as the kernel, so that it can be mapped into the kernel virtual memory space very early on using a minimal set of statically allocated translation tables.
Now that we have early fixmap support, we can relax this restriction, by moving the permanent FDT mapping to the fixmap region instead. This way, the FDT blob may be anywhere in memory.
This also moves the vetting of the FDT to mmu.c, since the early init code in head.S does not handle mapping of the FDT anymore. At the same time, fix up some comments in head.S that have gone stale.
--- Documentation/arm64/booting.txt | 13 ++++---- arch/arm64/include/asm/boot.h | 14 +++++++++ arch/arm64/include/asm/fixmap.h | 15 ++++++++++ arch/arm64/include/asm/mmu.h | 1 + arch/arm64/kernel/head.S | 39 +----------------------- arch/arm64/kernel/setup.c | 30 +++++++------------ arch/arm64/mm/Makefile | 2 ++ arch/arm64/mm/init.c | 1 - arch/arm64/mm/mmu.c | 66 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 117 insertions(+), 64 deletions(-) create mode 100644 arch/arm64/include/asm/boot.h
Documentation/arm64/booting.txt +8 -5
@@ -45,11 +45,14 @@ sees fit.) Requirement: MANDATORY -The device tree blob (dtb) must be placed on an 8-byte boundary within -the first 512 megabytes from the start of the kernel image and must not -cross a 2-megabyte boundary. This is to allow the kernel to map the -blob using a single section mapping in the initial page tables. - +The device tree blob (dtb) must be placed on an 8-byte boundary and must +not exceed 2 megabytes in size. Since the dtb will be mapped cacheable using +blocks of up to 2 megabytes in size, it should not be placed within 2 megabytes +of memreserves or other special carveouts that may be mapped with non-matching +attributes. + +NOTE: versions prior to v4.2 also require that the DTB be placed within +the 512 MB region starting at text_offset bytes below the kernel Image. 3. Decompress the kernel image ------------------------------
arch/arm64/include/asm/boot.h new file +14 -0
@@ -0,0 +1,14 @@ + +#ifndef __ASM_BOOT_H +#define __ASM_BOOT_H + +#include <asm/sizes.h> + +/* +* arm64 requires the DTB to be 8 byte aligned and +* not exceed 2MB in size. +*/ +#define MIN_FDT_ALIGN 8 +#define MAX_FDT_SIZE SZ_2M + +#endif
arch/arm64/include/asm/fixmap.h +15 -0
@@ -17,6 +17,7 @@#ifndef __ASSEMBLY__#include <linux/kernel.h> +#include <asm/boot.h> #include <asm/page.h> /*
@@ -32,6 +33,20 @@*/ enum fixed_addresses {FIX_HOLE , + +/* +* Reserve a virtual window for the FDT that is 2 MB larger than the +* maximum supported size, and put it at the top of the fixmap region. +* The additional space ensures that any FDT that does not exceed +* MAX_FDT_SIZE can be mapped regardless of whether it crosses any +* 2 MB alignment boundaries. +* +* Keep this at the top so it remains 2 MB aligned. +*/ +#define FIX_FDT_SIZE (MAX_FDT_SIZE + SZ_2M) + FIX_FDT_END, +FIX_FDT =FIX_FDT_END +FIX_FDT_SIZE /PAGE_SIZE -1 , +FIX_EARLYCON_MEM_BASE ,FIX_TEXT_POKE0 , __end_of_permanent_fixed_addresses,
arch/arm64/include/asm/mmu.h +1 -0
@@ -34,5 +34,6 @@ extern void init_mem_pgprot(void);extern void create_pgd_mapping (struct mm_struct *mm,phys_addr_t phys,unsigned long virt,phys_addr_t size,pgprot_t prot); +extern void *fixmap_remap_fdt (phys_addr_t dt_phys);#endif
arch/arm64/kernel/head.S +1 -38
@@ -237,8 +237,6 @@ ENTRY(stext) bl el2_setup // Drop to EL1, w20=cpu_boot_mode adrp x24, __PHYS_OFFSET bl set_cpu_boot_mode_flag - - bl __vet_fdt bl __create_page_tables // x25=TTBR0, x26=TTBR1 /* * The following calls CPU setup code, see arch/arm64/mm/proc.S for
@@ -270,24 +268,6 @@ preserve_boot_args: ENDPROC(preserve_boot_args) /* - * Determine validity of the x21 FDT pointer. - * The dtb must be 8-byte aligned and live in the first 512M of memory. - */ -__vet_fdt: - tst x21, #0x7 - b.ne 1f - cmp x21, x24 - b.lt 1f - mov x0, #(1 << 29) - add x0, x0, x24 - cmp x21, x0 - b.ge 1f - ret -1: - mov x21, #0 - ret -ENDPROC(__vet_fdt) -/* * Macro to create a table entry to the next page. * * tbl: page table address
@@ -348,8 +328,7 @@ ENDPROC(__vet_fdt) * required to get the kernel running. The following sections are required: * - identity mapping to enable the MMU (low address, TTBR0) * - first few MB of the kernel linear mapping to jump to once the MMU has - * been enabled, including the FDT blob (TTBR1) - * - pgd entry for fixed mappings (TTBR1) + * been enabled */ __create_page_tables: adrp x25, idmap_pg_dir
@@ -439,22 +418,6 @@ __create_page_tables: create_block_map x0, x7, x3, x5, x6 /* - * Map the FDT blob (maximum 2MB; must be within 512MB of - * PHYS_OFFSET). - */ - mov x3, x21 // FDT phys address - and x3, x3, #~((1 << 21) - 1) // 2MB aligned - mov x6, #PAGE_OFFSET - sub x5, x3, x24 // subtract PHYS_OFFSET - tst x5, #~((1 << 29) - 1) // within 512MB? - csel x21, xzr, x21, ne // zero the FDT pointer - b.ne 1f - add x5, x5, x6 // __va(FDT blob) - add x6, x5, #1 << 21 // 2MB for the FDT blob - sub x6, x6, #1 // inclusive range - create_block_map x0, x7, x3, x5, x6 -1: - /* * Since the page tables have been populated with non-cacheable * accesses (MMU disabled), invalidate the idmap and swapper page * tables again to remove any speculatively loaded cache lines.
arch/arm64/kernel/setup.c +10 -20
@@ -105,18 +105,6 @@ static struct resource mem_res[] = {#define kernel_code mem_res[0]#define kernel_data mem_res[1] -void __init early_print (const char *str, ...) -{ -char buf[256 ]; -va_list ap; - -va_start (ap, str); -vsnprintf (buf,sizeof (buf), str, ap); -va_end (ap); - -printk ("%s" , buf); -} -/* * The recorded values of x0 .. x3 upon kernel entry. */
@@ -326,12 +314,14 @@ static void __init setup_processor(void)static void __init setup_machine_fdt (phys_addr_t dt_phys) { -if (!dt_phys || !early_init_dt_scan (phys_to_virt (dt_phys))) { -early_print ("\n" -"Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n" -"The dtb must be 8-byte aligned and passed in the first 512MB of memory\n" -"\nPlease check your bootloader.\n" , - dt_phys,phys_to_virt (dt_phys)); +void *dt_virt =fixmap_remap_fdt (dt_phys); + +if (!dt_virt || !early_init_dt_scan (dt_virt)) { +pr_crit ("\n" +"Error: invalid device tree blob@physical address %pa (virtual address 0x%p)\n" +"The dtb must be 8-byte aligned and must not exceed 2 MB in size\n" +"\nPlease check your bootloader." , + &dt_phys, dt_virt);while (true)cpu_relax ();
@@ -374,8 +364,6 @@ void __init setup_arch(char **cmdline_p) {setup_processor (); -setup_machine_fdt (__fdt_pointer); - init_mm.start_code = (unsigned long ) _text; init_mm.end_code = (unsigned long ) _etext; init_mm.end_data = (unsigned long ) _edata;
@@ -386,6 +374,8 @@ void __init setup_arch(char **cmdline_p)early_fixmap_init ();early_ioremap_init (); +setup_machine_fdt (__fdt_pointer); +parse_early_param ();/*
arch/arm64/mm/Makefile +2 -0
@@ -4,3 +4,5 @@ obj-y := dma-mapping.o extable.o fault.o init.o \ context.o proc.o pageattr.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_ARM64_PTDUMP) += dump.o + +CFLAGS_mmu.o := -I$(srctree)/scripts/dtc/libfdt/
arch/arm64/mm/init.c +0 -1
@@ -170,7 +170,6 @@ void __init arm64_memblock_init(void)memblock_reserve (__virt_to_phys (initrd_start), initrd_end - initrd_start);#endif -early_init_fdt_reserve_self ();early_init_fdt_scan_reserved_mem ();/* 4GB maximum for 32-bit only capable devices */
arch/arm64/mm/mmu.c +66 -0
75 lines not on this page · raw message
Signature · 1 line
1.9.1
Mark Rutland
reviewerPATCH 2/8 arm64: use fixmap region for permanent FDT mapping
Hi Ard,
Sorry for the silence on this.
Quoted 9 lines · Ard Biesheuvel
Currently, the FDT blob needs to be in the same 512 MB region as the kernel, so that it can be mapped into the kernel virtual memory space very early on using a minimal set of statically allocated translation tables.
Now that we have early fixmap support, we can relax this restriction, by moving the permanent FDT mapping to the fixmap region instead. This way, the FDT blob may be anywhere in memory.
Quoted 5 lines
This also moves the vetting of the FDT to
mmu.c, since the early init code inhead.Sdoes not handle mapping of the FDT anymore. At the same time, fix up some comments inhead.Sthat have gone stale.Signed-off-by Ard Biesheuvel <[email protected]>
The patch looks good to me. I've just given this some testing loading DTBs at weird offsets and large disances from the kernel, and that seems to work, so:
Thanks,
Mark.
Quoted 340 lines
--- Documentation/arm64/booting.txt | 13 ++++---- arch/arm64/include/asm/boot.h | 14 +++++++++ arch/arm64/include/asm/fixmap.h | 15 ++++++++++ arch/arm64/include/asm/mmu.h | 1 + arch/arm64/kernel/head.S | 39 +----------------------- arch/arm64/kernel/setup.c | 30 +++++++------------ arch/arm64/mm/Makefile | 2 ++ arch/arm64/mm/init.c | 1 - arch/arm64/mm/mmu.c | 66 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 117 insertions(+), 64 deletions(-) create mode 100644 arch/arm64/include/asm/boot.hDocumentation/arm64/booting.txt +8
-5@@ -45,11 +45,14 @@ sees fit.) Requirement: MANDATORY -The device tree blob (dtb) must be placed on an 8-byte boundary within -the first 512 megabytes from the start of the kernel image and must not -cross a 2-megabyte boundary. This is to allow the kernel to map the -blob using a single section mapping in the initial page tables. - +The device tree blob (dtb) must be placed on an 8-byte boundary and must +not exceed 2 megabytes in size. Since the dtb will be mapped cacheable using +blocks of up to 2 megabytes in size, it should not be placed within 2 megabytes +of memreserves or other special carveouts that may be mapped with non-matching +attributes. + +NOTE: versions prior to v4.2 also require that the DTB be placed within +the 512 MB region starting at text_offset bytes below the kernel Image. 3. Decompress the kernel image ------------------------------arch/arm64/include/asm/boot.h new file +14
-0@@ -0,0 +1,14 @@ + +#ifndef __ASM_BOOT_H +#define __ASM_BOOT_H + +#include <asm/sizes.h> + +/* +* arm64 requires the DTB to be 8 byte aligned and +* not exceed 2MB in size. +*/ +#define MIN_FDT_ALIGN 8 +#define MAX_FDT_SIZE SZ_2M + +#endif arch/arm64/include/asm/fixmap.h +15
-0@@ -17,6 +17,7 @@#ifndef __ASSEMBLY__#include <linux/kernel.h> +#include <asm/boot.h> #include <asm/page.h> /* @@ -32,6 +33,20 @@*/ enum fixed_addresses {FIX_HOLE , + +/* +* Reserve a virtual window for the FDT that is 2 MB larger than the +* maximum supported size, and put it at the top of the fixmap region. +* The additional space ensures that any FDT that does not exceed +* MAX_FDT_SIZE can be mapped regardless of whether it crosses any +* 2 MB alignment boundaries. +* +* Keep this at the top so it remains 2 MB aligned. +*/ +#define FIX_FDT_SIZE (MAX_FDT_SIZE + SZ_2M) + FIX_FDT_END, +FIX_FDT =FIX_FDT_END +FIX_FDT_SIZE /PAGE_SIZE -1 , +FIX_EARLYCON_MEM_BASE ,FIX_TEXT_POKE0 , __end_of_permanent_fixed_addresses,arch/arm64/include/asm/mmu.h +1
-0@@ -34,5 +34,6 @@ extern void init_mem_pgprot(void);extern void create_pgd_mapping (struct mm_struct *mm,phys_addr_t phys,unsigned long virt,phys_addr_t size,pgprot_t prot); +extern void *fixmap_remap_fdt (phys_addr_t dt_phys);#endif arch/arm64/kernel/head.S +1
-38@@ -237,8 +237,6 @@ ENTRY(stext) bl el2_setup // Drop to EL1, w20=cpu_boot_mode adrp x24, __PHYS_OFFSET bl set_cpu_boot_mode_flag - - bl __vet_fdt bl __create_page_tables // x25=TTBR0, x26=TTBR1 /* * The following calls CPU setup code, see arch/arm64/mm/proc.S for@@ -270,24 +268,6 @@ preserve_boot_args: ENDPROC(preserve_boot_args) /* - * Determine validity of the x21 FDT pointer. - * The dtb must be 8-byte aligned and live in the first 512M of memory. - */ -__vet_fdt: - tst x21, #0x7 - b.ne 1f - cmp x21, x24 - b.lt 1f - mov x0, #(1 << 29) - add x0, x0, x24 - cmp x21, x0 - b.ge 1f - ret -1: - mov x21, #0 - ret -ENDPROC(__vet_fdt) -/* * Macro to create a table entry to the next page. * * tbl: page table address@@ -348,8 +328,7 @@ ENDPROC(__vet_fdt) * required to get the kernel running. The following sections are required: * - identity mapping to enable the MMU (low address, TTBR0) * - first few MB of the kernel linear mapping to jump to once the MMU has - * been enabled, including the FDT blob (TTBR1) - * - pgd entry for fixed mappings (TTBR1) + * been enabled */ __create_page_tables: adrp x25, idmap_pg_dir@@ -439,22 +418,6 @@ __create_page_tables: create_block_map x0, x7, x3, x5, x6 /* - * Map the FDT blob (maximum 2MB; must be within 512MB of - * PHYS_OFFSET). - */ - mov x3, x21 // FDT phys address - and x3, x3, #~((1 << 21) - 1) // 2MB aligned - mov x6, #PAGE_OFFSET - sub x5, x3, x24 // subtract PHYS_OFFSET - tst x5, #~((1 << 29) - 1) // within 512MB? - csel x21, xzr, x21, ne // zero the FDT pointer - b.ne 1f - add x5, x5, x6 // __va(FDT blob) - add x6, x5, #1 << 21 // 2MB for the FDT blob - sub x6, x6, #1 // inclusive range - create_block_map x0, x7, x3, x5, x6 -1: - /* * Since the page tables have been populated with non-cacheable * accesses (MMU disabled), invalidate the idmap and swapper page * tables again to remove any speculatively loaded cache lines.arch/arm64/kernel/setup.c +10
-20@@ -105,18 +105,6 @@ static struct resource mem_res[] = {#define kernel_code mem_res[0]#define kernel_data mem_res[1] -void __init early_print (const char *str, ...) -{ -char buf[256 ]; -va_list ap; - -va_start (ap, str); -vsnprintf (buf,sizeof (buf), str, ap); -va_end (ap); - -printk ("%s" , buf); -} -/* * The recorded values of x0 .. x3 upon kernel entry. */ @@ -326,12 +314,14 @@ static void __init setup_processor(void)static void __init setup_machine_fdt (phys_addr_t dt_phys) { -if (!dt_phys || !early_init_dt_scan (phys_to_virt (dt_phys))) { -early_print ("\n" -"Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n" -"The dtb must be 8-byte aligned and passed in the first 512MB of memory\n" -"\nPlease check your bootloader.\n" , - dt_phys,phys_to_virt (dt_phys)); +void *dt_virt =fixmap_remap_fdt (dt_phys); + +if (!dt_virt || !early_init_dt_scan (dt_virt)) { +pr_crit ("\n" +"Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n" +"The dtb must be 8-byte aligned and must not exceed 2 MB in size\n" +"\nPlease check your bootloader." , + &dt_phys, dt_virt);while (true)cpu_relax ();@@ -374,8 +364,6 @@ void __init setup_arch(char **cmdline_p) {setup_processor (); -setup_machine_fdt (__fdt_pointer); - init_mm.start_code = (unsigned long ) _text; init_mm.end_code = (unsigned long ) _etext; init_mm.end_data = (unsigned long ) _edata;@@ -386,6 +374,8 @@ void __init setup_arch(char **cmdline_p)early_fixmap_init ();early_ioremap_init (); +setup_machine_fdt (__fdt_pointer); +parse_early_param ();/* arch/arm64/mm/Makefile +2
-0@@ -4,3 +4,5 @@ obj-y := dma-mapping.o extable.o fault.o init.o \ context.o proc.o pageattr.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_ARM64_PTDUMP) += dump.o + +CFLAGS_mmu.o := -I$(srctree)/scripts/dtc/libfdt/arch/arm64/mm/init.c +0
-1@@ -170,7 +170,6 @@ void __init arm64_memblock_init(void)memblock_reserve (__virt_to_phys (initrd_start), initrd_end - initrd_start);#endif -early_init_fdt_reserve_self ();early_init_fdt_scan_reserved_mem ();/* 4GB maximum for 32-bit only capable devices */ arch/arm64/mm/mmu.c +66
-1@@ -21,6 +21,7 @@#include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/libfdt.h> #include <linux/mman.h> #include <linux/nodemask.h> #include <linux/memblock.h> @@ -643,3 +644,68 @@ void __set_fixmap(enum fixed_addresses idx,flush_tlb_kernel_range (addr, addr+PAGE_SIZE ); } } + +void *__init fixmap_remap_fdt (phys_addr_t dt_phys) +{ +const u64 dt_virt_base =__fix_to_virt (FIX_FDT ); +pgprot_t prot =PAGE_KERNEL |PTE_RDONLY ; +int granularity, size, offset; +void *dt_virt; + +/* +* Check whether the physical FDT address is set and meets the minimum +* alignment requirement. Since we are relying on MIN_FDT_ALIGN to be +* at least 8 bytes so that we can always access the size field of the +* FDT header after mapping the first chunk, double check here if that +* is indeed the case. +*/ +BUILD_BUG_ON (MIN_FDT_ALIGN <8 ); +if (!dt_phys || dt_phys %MIN_FDT_ALIGN ) +return NULL ; + +/* +* Make sure that the FDT region can be mapped without the need to +* allocate additional translation table pages, so that it is safe +* to call create_mapping() this early. +* +* On 64k pages, the FDT will be mapped using PTEs, so we need to +* be in the same PMD as the rest of the fixmap. +* On 4k pages, we'll use section mappings for the FDT so we only +* have to be in the same PUD. +*/ +BUILD_BUG_ON (dt_virt_base %SZ_2M ); + +if (IS_ENABLED (CONFIG_ARM64_64K_PAGES )) { +BUILD_BUG_ON (__fix_to_virt (FIX_FDT_END ) >>PMD_SHIFT != +__fix_to_virt (FIX_BTMAP_BEGIN ) >>PMD_SHIFT ); + + granularity =PAGE_SIZE ; + }else { +BUILD_BUG_ON (__fix_to_virt (FIX_FDT_END ) >>PUD_SHIFT != +__fix_to_virt (FIX_BTMAP_BEGIN ) >>PUD_SHIFT ); + + granularity =PMD_SIZE ; + } + + offset = dt_phys % granularity; + dt_virt = (void *)dt_virt_base + offset; + +/* map the first chunk so we can read the size from the header */ +create_mapping (round_down (dt_phys, granularity), dt_virt_base, + granularity, prot); + +if (fdt_check_header (dt_virt) !=0 ) +return NULL ; + + size =fdt_totalsize (dt_virt); +if (size >MAX_FDT_SIZE ) +return NULL ; + +if (offset + size > granularity) +create_mapping (round_down (dt_phys, granularity), dt_virt_base, +round_up (offset + size, granularity), prot); + +memblock_reserve (dt_phys, size); + +return dt_virt; +} --1.9.1
PATCH 2/8 arm64: use fixmap region for permanent FDT mapping
Quoted 18 lines · Mark Rutland
Hi Ard,
Sorry for the silence on this.
Quoted 13 lines · Ard Biesheuvel
Currently, the FDT blob needs to be in the same 512 MB region as the kernel, so that it can be mapped into the kernel virtual memory space very early on using a minimal set of statically allocated translation tables.
Now that we have early fixmap support, we can relax this restriction, by moving the permanent FDT mapping to the fixmap region instead. This way, the FDT blob may be anywhere in memory.
This also moves the vetting of the FDT to
mmu.c, since the early init code inhead.Sdoes not handle mapping of the FDT anymore. At the same time, fix up some comments inhead.Sthat have gone stale.
Quoted 9 lines
Quoted 1 line
Signed-off-by Ard Biesheuvel <[email protected]>The patch looks good to me. I've just given this some testing loading DTBs at weird offsets and large disances from the kernel, and that seems to work, so:
Reviewed-by Mark Rutland <[email protected]>Tested-by Mark Rutland <[email protected]>
Thank you.
I noticed that I forgot to make the Documentation change you requested last time around, so I will roll that into the next version (with your tags).
Signature · 1 line
Ard.
Quoted 340 lines
Quoted 340 lines
--- Documentation/arm64/booting.txt | 13 ++++---- arch/arm64/include/asm/boot.h | 14 +++++++++ arch/arm64/include/asm/fixmap.h | 15 ++++++++++ arch/arm64/include/asm/mmu.h | 1 + arch/arm64/kernel/head.S | 39 +----------------------- arch/arm64/kernel/setup.c | 30 +++++++------------ arch/arm64/mm/Makefile | 2 ++ arch/arm64/mm/init.c | 1 - arch/arm64/mm/mmu.c | 66 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 117 insertions(+), 64 deletions(-) create mode 100644 arch/arm64/include/asm/boot.hDocumentation/arm64/booting.txt +8
-5@@ -45,11 +45,14 @@ sees fit.) Requirement: MANDATORY -The device tree blob (dtb) must be placed on an 8-byte boundary within -the first 512 megabytes from the start of the kernel image and must not -cross a 2-megabyte boundary. This is to allow the kernel to map the -blob using a single section mapping in the initial page tables. - +The device tree blob (dtb) must be placed on an 8-byte boundary and must +not exceed 2 megabytes in size. Since the dtb will be mapped cacheable using +blocks of up to 2 megabytes in size, it should not be placed within 2 megabytes +of memreserves or other special carveouts that may be mapped with non-matching +attributes. + +NOTE: versions prior to v4.2 also require that the DTB be placed within +the 512 MB region starting at text_offset bytes below the kernel Image. 3. Decompress the kernel image ------------------------------arch/arm64/include/asm/boot.h new file +14
-0@@ -0,0 +1,14 @@ + +#ifndef __ASM_BOOT_H +#define __ASM_BOOT_H + +#include <asm/sizes.h> + +/* +* arm64 requires the DTB to be 8 byte aligned and +* not exceed 2MB in size. +*/ +#define MIN_FDT_ALIGN 8 +#define MAX_FDT_SIZE SZ_2M + +#endif arch/arm64/include/asm/fixmap.h +15
-0@@ -17,6 +17,7 @@#ifndef __ASSEMBLY__#include <linux/kernel.h> +#include <asm/boot.h> #include <asm/page.h> /* @@ -32,6 +33,20 @@*/ enum fixed_addresses {FIX_HOLE , + +/* +* Reserve a virtual window for the FDT that is 2 MB larger than the +* maximum supported size, and put it at the top of the fixmap region. +* The additional space ensures that any FDT that does not exceed +* MAX_FDT_SIZE can be mapped regardless of whether it crosses any +* 2 MB alignment boundaries. +* +* Keep this at the top so it remains 2 MB aligned. +*/ +#define FIX_FDT_SIZE (MAX_FDT_SIZE + SZ_2M) + FIX_FDT_END, +FIX_FDT =FIX_FDT_END +FIX_FDT_SIZE /PAGE_SIZE -1 , +FIX_EARLYCON_MEM_BASE ,FIX_TEXT_POKE0 , __end_of_permanent_fixed_addresses,arch/arm64/include/asm/mmu.h +1
-0@@ -34,5 +34,6 @@ extern void init_mem_pgprot(void);extern void create_pgd_mapping (struct mm_struct *mm,phys_addr_t phys,unsigned long virt,phys_addr_t size,pgprot_t prot); +extern void *fixmap_remap_fdt (phys_addr_t dt_phys);#endif arch/arm64/kernel/head.S +1
-38@@ -237,8 +237,6 @@ ENTRY(stext) bl el2_setup // Drop to EL1, w20=cpu_boot_mode adrp x24, __PHYS_OFFSET bl set_cpu_boot_mode_flag - - bl __vet_fdt bl __create_page_tables // x25=TTBR0, x26=TTBR1 /* * The following calls CPU setup code, see arch/arm64/mm/proc.S for@@ -270,24 +268,6 @@ preserve_boot_args: ENDPROC(preserve_boot_args) /* - * Determine validity of the x21 FDT pointer. - * The dtb must be 8-byte aligned and live in the first 512M of memory. - */ -__vet_fdt: - tst x21, #0x7 - b.ne 1f - cmp x21, x24 - b.lt 1f - mov x0, #(1 << 29) - add x0, x0, x24 - cmp x21, x0 - b.ge 1f - ret -1: - mov x21, #0 - ret -ENDPROC(__vet_fdt) -/* * Macro to create a table entry to the next page. * * tbl: page table address@@ -348,8 +328,7 @@ ENDPROC(__vet_fdt) * required to get the kernel running. The following sections are required: * - identity mapping to enable the MMU (low address, TTBR0) * - first few MB of the kernel linear mapping to jump to once the MMU has - * been enabled, including the FDT blob (TTBR1) - * - pgd entry for fixed mappings (TTBR1) + * been enabled */ __create_page_tables: adrp x25, idmap_pg_dir@@ -439,22 +418,6 @@ __create_page_tables: create_block_map x0, x7, x3, x5, x6 /* - * Map the FDT blob (maximum 2MB; must be within 512MB of - * PHYS_OFFSET). - */ - mov x3, x21 // FDT phys address - and x3, x3, #~((1 << 21) - 1) // 2MB aligned - mov x6, #PAGE_OFFSET - sub x5, x3, x24 // subtract PHYS_OFFSET - tst x5, #~((1 << 29) - 1) // within 512MB? - csel x21, xzr, x21, ne // zero the FDT pointer - b.ne 1f - add x5, x5, x6 // __va(FDT blob) - add x6, x5, #1 << 21 // 2MB for the FDT blob - sub x6, x6, #1 // inclusive range - create_block_map x0, x7, x3, x5, x6 -1: - /* * Since the page tables have been populated with non-cacheable * accesses (MMU disabled), invalidate the idmap and swapper page * tables again to remove any speculatively loaded cache lines.arch/arm64/kernel/setup.c +10
-20@@ -105,18 +105,6 @@ static struct resource mem_res[] = {#define kernel_code mem_res[0]#define kernel_data mem_res[1] -void __init early_print (const char *str, ...) -{ -char buf[256 ]; -va_list ap; - -va_start (ap, str); -vsnprintf (buf,sizeof (buf), str, ap); -va_end (ap); - -printk ("%s" , buf); -} -/* * The recorded values of x0 .. x3 upon kernel entry. */ @@ -326,12 +314,14 @@ static void __init setup_processor(void)static void __init setup_machine_fdt (phys_addr_t dt_phys) { -if (!dt_phys || !early_init_dt_scan (phys_to_virt (dt_phys))) { -early_print ("\n" -"Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n" -"The dtb must be 8-byte aligned and passed in the first 512MB of memory\n" -"\nPlease check your bootloader.\n" , - dt_phys,phys_to_virt (dt_phys)); +void *dt_virt =fixmap_remap_fdt (dt_phys); + +if (!dt_virt || !early_init_dt_scan (dt_virt)) { +pr_crit ("\n" +"Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n" +"The dtb must be 8-byte aligned and must not exceed 2 MB in size\n" +"\nPlease check your bootloader." , + &dt_phys, dt_virt);while (true)cpu_relax ();@@ -374,8 +364,6 @@ void __init setup_arch(char **cmdline_p) {setup_processor (); -setup_machine_fdt (__fdt_pointer); - init_mm.start_code = (unsigned long ) _text; init_mm.end_code = (unsigned long ) _etext; init_mm.end_data = (unsigned long ) _edata;@@ -386,6 +374,8 @@ void __init setup_arch(char **cmdline_p)early_fixmap_init ();early_ioremap_init (); +setup_machine_fdt (__fdt_pointer); +parse_early_param ();/* arch/arm64/mm/Makefile +2
-0@@ -4,3 +4,5 @@ obj-y := dma-mapping.o extable.o fault.o init.o \ context.o proc.o pageattr.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_ARM64_PTDUMP) += dump.o + +CFLAGS_mmu.o := -I$(srctree)/scripts/dtc/libfdt/arch/arm64/mm/init.c +0
-1@@ -170,7 +170,6 @@ void __init arm64_memblock_init(void)memblock_reserve (__virt_to_phys (initrd_start), initrd_end - initrd_start);#endif -early_init_fdt_reserve_self ();early_init_fdt_scan_reserved_mem ();/* 4GB maximum for 32-bit only capable devices */ arch/arm64/mm/mmu.c +66
-1@@ -21,6 +21,7 @@#include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/libfdt.h> #include <linux/mman.h> #include <linux/nodemask.h> #include <linux/memblock.h> @@ -643,3 +644,68 @@ void __set_fixmap(enum fixed_addresses idx,flush_tlb_kernel_range (addr, addr+PAGE_SIZE ); } } + +void *__init fixmap_remap_fdt (phys_addr_t dt_phys) +{ +const u64 dt_virt_base =__fix_to_virt (FIX_FDT ); +pgprot_t prot =PAGE_KERNEL |PTE_RDONLY ; +int granularity, size, offset; +void *dt_virt; + +/* +* Check whether the physical FDT address is set and meets the minimum +* alignment requirement. Since we are relying on MIN_FDT_ALIGN to be +* at least 8 bytes so that we can always access the size field of the +* FDT header after mapping the first chunk, double check here if that +* is indeed the case. +*/ +BUILD_BUG_ON (MIN_FDT_ALIGN <8 ); +if (!dt_phys || dt_phys %MIN_FDT_ALIGN ) +return NULL ; + +/* +* Make sure that the FDT region can be mapped without the need to +* allocate additional translation table pages, so that it is safe +* to call create_mapping() this early. +* +* On 64k pages, the FDT will be mapped using PTEs, so we need to +* be in the same PMD as the rest of the fixmap. +* On 4k pages, we'll use section mappings for the FDT so we only +* have to be in the same PUD. +*/ +BUILD_BUG_ON (dt_virt_base %SZ_2M ); + +if (IS_ENABLED (CONFIG_ARM64_64K_PAGES )) { +BUILD_BUG_ON (__fix_to_virt (FIX_FDT_END ) >>PMD_SHIFT != +__fix_to_virt (FIX_BTMAP_BEGIN ) >>PMD_SHIFT ); + + granularity =PAGE_SIZE ; + }else { +BUILD_BUG_ON (__fix_to_virt (FIX_FDT_END ) >>PUD_SHIFT != +__fix_to_virt (FIX_BTMAP_BEGIN ) >>PUD_SHIFT ); + + granularity =PMD_SIZE ; + } + + offset = dt_phys % granularity; + dt_virt = (void *)dt_virt_base + offset; + +/* map the first chunk so we can read the size from the header */ +create_mapping (round_down (dt_phys, granularity), dt_virt_base, + granularity, prot); + +if (fdt_check_header (dt_virt) !=0 ) +return NULL ; + + size =fdt_totalsize (dt_virt); +if (size >MAX_FDT_SIZE ) +return NULL ; + +if (offset + size > granularity) +create_mapping (round_down (dt_phys, granularity), dt_virt_base, +round_up (offset + size, granularity), prot); + +memblock_reserve (dt_phys, size); + +return dt_virt; +} --1.9.1
PATCH 3/8 arm64: override early_init_dt_add_memory_arch()
In reply to Ard BiesheuvelOverride the __weak early_init_dt_add_memory_arch() with our own version. This allows us to relax the imposed restrictions at memory discovery time, which is needed if we want to defer the assignment of PHYS_OFFSET and make it independent of where the kernel Image is placed in physical memory.
So copy the generic original, but only retain the check against regions whose sizes become zero when clipped to page alignment.
For now, we will remove the range below PHYS_OFFSET explicitly until we rework that logic in a subsequent patch. Any memory that we will not be able to map due to insufficient size of the linear region is also removed.
--- arch/arm64/mm/init.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
arch/arm64/mm/init.c +25 -0
@@ -158,6 +158,15 @@ early_param("mem", early_mem);void __init arm64_memblock_init (void ) { +/* +* Remove the memory that we will not be able to cover +* with the linear mapping. +*/ +const s64 linear_region_size = -(s64 )PAGE_OFFSET ; + +memblock_remove (0 , memstart_addr); +memblock_remove (memstart_addr + linear_region_size,ULLONG_MAX ); +memblock_enforce_memory_limit (memory_limit);/*
@@ -374,3 +383,19 @@ static int __init keepinitrd_setup(char *__unused)__setup ("keepinitrd" , keepinitrd_setup);#endif + +void __init early_init_dt_add_memory_arch (u64 base,u64 size) +{ +if (!PAGE_ALIGNED (base)) { +if (size <PAGE_SIZE - (base & ~PAGE_MASK )) { +pr_warn ("Ignoring memory block 0x%llx - 0x%llx\n" , + base, base + size); +return ; + } + size -=PAGE_SIZE - (base & ~PAGE_MASK ); + base =PAGE_ALIGN (base); + } + size &=PAGE_MASK ; + +memblock_add (base, size); +}
Signature · 1 line
1.9.1
PATCH 4/8 efi: move FDT handling to separate object file
In reply to Ard BiesheuvelThe EFI specific FDT handling is compiled conditionally, and is logically independent of the rest of efi.o. So move it to a separate file before making changes to it in subsequent patches.
--- drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/efi-fdt.c | 93 ++++++++++++++++++++++++++++++++++++++++++ drivers/firmware/efi/efi.c | 86 -------------------------------------- 3 files changed, 94 insertions(+), 86 deletions(-) create mode 100644 drivers/firmware/efi/efi-fdt.c
drivers/firmware/efi/Makefile +1 -0
@@ -8,3 +8,4 @@ obj-$(CONFIG_UEFI_CPER) += cper.o obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o obj-$(CONFIG_EFI_STUB) += libstub/ +obj-$(CONFIG_EFI_PARAMS_FROM_FDT) += efi-fdt.o
drivers/firmware/efi/efi-fdt.c new file +93 -0
93 lines not on this page · raw message
drivers/firmware/efi/efi.c +0 -86
98 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH 4/8 efi: move FDT handling to separate object file
Quoted 11 lines · Ard Biesheuvel
The EFI specific FDT handling is compiled conditionally, and is logically independent of the rest of efi.o. So move it to a separate file before making changes to it in subsequent patches.
Signed-off-by Ard Biesheuvel <[email protected]>--- drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/efi-fdt.c | 93 ++++++++++++++++++++++++++++++++++++++++++ drivers/firmware/efi/efi.c | 86 -------------------------------------- 3 files changed, 94 insertions(+), 86 deletions(-) create mode 100644 drivers/firmware/efi/efi-fdt.c
Sorry for the delay,
Signature · 1 line
Matt Fleming, Intel Open Source Technology Center
PATCH 5/8 arm64/efi: move EFI init before early FDT processing
In reply to Ard BiesheuvelThe early FDT processing is responsible for enumerating the DT memory nodes and installing them as memblocks. This should only be done if we are not booting via EFI, but at this point, we don't know yet if that is the case or not.
So move the EFI init to before the early FDT processing. This involves making some changes to the way EFI discovers the locations of the EFI system table and the memory map, since those values are retrieved from the FDT as well. Instead the of_scan infrastructure, it now uses libfdt directly to access the /chosen node.
--- arch/arm64/include/asm/efi.h | 4 +-- arch/arm64/kernel/efi.c | 14 +++----- arch/arm64/kernel/setup.c | 4 ++- drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/efi-fdt.c | 74 +++++++++++++++++------------------------- include/linux/efi.h | 3 +- 6 files changed, 41 insertions(+), 59 deletions(-)
arch/arm64/include/asm/efi.h +2 -2
@@ -5,9 +5,9 @@#include <asm/neon.h> #ifdef CONFIG_EFI -extern void efi_init (void ); +extern void efi_init_fdt (void *fdt);#else -#define efi_init () +#define efi_init_fdt (x)#endif #define efi_call_virt (f, ...) \
arch/arm64/kernel/efi.c +4 -10
@@ -51,14 +51,7 @@ static struct mm_struct efi_mm = { INIT_MM_CONTEXT(efi_mm) }; -static int uefi_debug__initdata ; -static int __init uefi_debug_setup (char *str) -{ - uefi_debug =1 ; - -return 0 ; -} -early_param ("uefi_debug" , uefi_debug_setup); +static bool uefi_debug__initdata ;static int __init is_normal_ram (efi_memory_desc_t *md) {
@@ -204,14 +197,15 @@ static __init void reserve_regions(void)set_bit (EFI_MEMMAP , &efi.flags); } -void __init efi_init (void ) +void __init efi_init_fdt (void *fdt) {struct efi_fdt_params params;/* Grab UEFI information placed in FDT by stub */ -if (!efi_get_fdt_params (¶ms, uefi_debug)) +if (!efi_get_fdt_params (fdt, ¶ms))return ; + uefi_debug = params.verbose; efi_system_table = params.system_table; memblock_reserve(params.mmap & PAGE_MASK,
arch/arm64/kernel/setup.c +3 -1
@@ -316,6 +316,9 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys) {void *dt_virt =fixmap_remap_fdt (dt_phys); +if (dt_virt) +efi_init_fdt (dt_virt); +if (!dt_virt || !early_init_dt_scan (dt_virt)) {pr_crit ("\n" "Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n"
@@ -384,7 +387,6 @@ void __init setup_arch(char **cmdline_p)*/ local_async_enable (); -efi_init ();arm64_memblock_init ();/* Parse the ACPI tables for possible boot-time configuration */
drivers/firmware/efi/Makefile +1 -0
@@ -9,3 +9,4 @@ obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o obj-$(CONFIG_EFI_STUB) += libstub/ obj-$(CONFIG_EFI_PARAMS_FROM_FDT) += efi-fdt.o +CFLAGS_efi-fdt.o := -I$(srctree)/scripts/dtc/libfdt/
drivers/firmware/efi/efi-fdt.c +29 -45
99 lines not on this page · raw message
include/linux/efi.h +2 -1
@@ -684,6 +684,7 @@ struct efi_fdt_params {u32 mmap_size;u32 desc_size;u32 desc_ver; +bool verbose; }; typedef struct {
@@ -886,7 +887,7 @@ extern void efi_initialize_iomem_resources(struct resource *code_resource, struct resource *data_resource, struct resource *bss_resource);extern void efi_get_time (struct timespec *now);extern void efi_reserve_boot_services (void ); -extern int efi_get_fdt_params (struct efi_fdt_params *params,int verbose); +extern bool efi_get_fdt_params (void *fdt,struct efi_fdt_params *params);extern struct efi_memory_map memmap;extern int efi_reboot_quirk_mode;
Signature · 1 line
1.9.1
PATCH 6/8 arm64/efi: ignore DT memory nodes instead of removing them
In reply to Ard BiesheuvelThere are two problems with the UEFI stub DT memory node removal routine:
- it deletes nodes as it traverses the tree, which happens to work but is not supported, as deletion invalidates the node iterator;
- deleting memory nodes entirely may discard annotations in the form of additional properties on the nodes.
Now that the UEFI initialization has moved to an earlier stage, we can actually just ignore any memblocks that are installed after we have processed the UEFI memory map. This way, it is no longer necessary to remove the nodes, so we can remove that logic from the stub as well.
--- arch/arm64/mm/init.c | 7 +++++++ drivers/firmware/efi/libstub/fdt.c | 24 +----------------------- 2 files changed, 8 insertions(+), 23 deletions(-)
arch/arm64/mm/init.c +7 -0
@@ -386,6 +386,13 @@ __setup("keepinitrd", keepinitrd_setup);void __init early_init_dt_add_memory_arch (u64 base,u64 size) { +/* +* EFI_MEMMAP will be set /after/ UEFI has installed all memory based +* on the content of the UEFI memory map. +*/ +if (efi_enabled (EFI_MEMMAP )) +return ; +if (!PAGE_ALIGNED (base)) {if (size <PAGE_SIZE - (base & ~PAGE_MASK )) { pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
drivers/firmware/efi/libstub/fdt.c +1 -23
@@ -24,7 +24,7 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long map_size, unsigned long desc_size, u32 desc_ver) { - int node, prev, num_rsv; + int node, num_rsv;int status;u32 fdt_val32;u64 fdt_val64;
@@ -54,28 +54,6 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, goto fdt_set_fail;/* -* Delete any memory nodes present. We must delete nodes which -* early_init_dt_scan_memory may try to use. -*/ - prev =0 ; -for (;;) { -const char *type; -int len; - - node =fdt_next_node (fdt, prev,NULL ); -if (node <0 ) -break ; - - type =fdt_getprop (fdt, node,"device_type" , &len); -if (type &&strncmp (type,"memory" , len) ==0 ) { -fdt_del_node (fdt, node); -continue ; - } - - prev = node; - } - -/* * Delete all memory reserve map entries. When booting via UEFI, * kernel will use the UEFI memory map to find reserved regions. */
Signature · 1 line
1.9.1
PATCH 6/8 arm64/efi: ignore DT memory nodes instead of removing them
Quoted 82 lines · Ard Biesheuvel
There are two problems with the UEFI stub DT memory node removal routine:
- it deletes nodes as it traverses the tree, which happens to work but is not supported, as deletion invalidates the node iterator;
- deleting memory nodes entirely may discard annotations in the form of additional properties on the nodes.Now that the UEFI initialization has moved to an earlier stage, we can actually just ignore any memblocks that are installed after we have processed the UEFI memory map. This way, it is no longer necessary to remove the nodes, so we can remove that logic from the stub as well.
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/mm/init.c | 7 +++++++ drivers/firmware/efi/libstub/fdt.c | 24 +----------------------- 2 files changed, 8 insertions(+), 23 deletions(-)arch/arm64/mm/init.c +7
-0@@ -386,6 +386,13 @@ __setup("keepinitrd", keepinitrd_setup);void __init early_init_dt_add_memory_arch (u64 base,u64 size) { +/* +* EFI_MEMMAP will be set /after/ UEFI has installed all memory based +* on the content of the UEFI memory map. +*/ +if (efi_enabled (EFI_MEMMAP )) +return ; +if (!PAGE_ALIGNED (base)) {if (size <PAGE_SIZE - (base & ~PAGE_MASK )) { pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",drivers/firmware/efi/libstub/fdt.c +1
-24@@ -24,7 +24,7 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long map_size, unsigned long desc_size, u32 desc_ver) { - int node, prev, num_rsv; + int node, num_rsv;int status;u32 fdt_val32;u64 fdt_val64;@@ -54,28 +54,6 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, goto fdt_set_fail;/* -* Delete any memory nodes present. We must delete nodes which -* early_init_dt_scan_memory may try to use. -*/ - prev =0 ; -for (;;) { -const char *type; -int len; - - node =fdt_next_node (fdt, prev,NULL ); -if (node <0 ) -break ; - - type =fdt_getprop (fdt, node,"device_type" , &len); -if (type &&strncmp (type,"memory" , len) ==0 ) { -fdt_del_node (fdt, node); -continue ; - } - - prev = node; - } - -/* * Delete all memory reserve map entries. When booting via UEFI, * kernel will use the UEFI memory map to find reserved regions. */ --1.9.1
Quoted 4 lines
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Thanks Ard.
Tested this patch on my numa setup.
thanks
Ganapat
PATCH 6/8 arm64/efi: ignore DT memory nodes instead of removing them
In reply to Ard BiesheuvelQuoted 11 lines · Ard Biesheuvel
There are two problems with the UEFI stub DT memory node removal routine:
- it deletes nodes as it traverses the tree, which happens to work but is not supported, as deletion invalidates the node iterator;
- deleting memory nodes entirely may discard annotations in the form of additional properties on the nodes.Now that the UEFI initialization has moved to an earlier stage, we can actually just ignore any memblocks that are installed after we have processed the UEFI memory map. This way, it is no longer necessary to remove the nodes, so we can remove that logic from the stub as well.
So ... I don't have an issue with this patch as such, but keeping the memory nodes around for NUMA topology when the UEFI memory map is the one being used for memblock leads to a spooky redefinition of what that memory node _is_; it would now describe a region which may only partially be populated with RAM.
/
Leif
Quoted 69 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/mm/init.c | 7 +++++++ drivers/firmware/efi/libstub/fdt.c | 24 +----------------------- 2 files changed, 8 insertions(+), 23 deletions(-)arch/arm64/mm/init.c +7
-0@@ -386,6 +386,13 @@ __setup("keepinitrd", keepinitrd_setup);void __init early_init_dt_add_memory_arch (u64 base,u64 size) { +/* +* EFI_MEMMAP will be set /after/ UEFI has installed all memory based +* on the content of the UEFI memory map. +*/ +if (efi_enabled (EFI_MEMMAP )) +return ; +if (!PAGE_ALIGNED (base)) {if (size <PAGE_SIZE - (base & ~PAGE_MASK )) { pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",drivers/firmware/efi/libstub/fdt.c +1
-23@@ -24,7 +24,7 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long map_size, unsigned long desc_size, u32 desc_ver) { - int node, prev, num_rsv; + int node, num_rsv;int status;u32 fdt_val32;u64 fdt_val64;@@ -54,28 +54,6 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, goto fdt_set_fail;/* -* Delete any memory nodes present. We must delete nodes which -* early_init_dt_scan_memory may try to use. -*/ - prev =0 ; -for (;;) { -const char *type; -int len; - - node =fdt_next_node (fdt, prev,NULL ); -if (node <0 ) -break ; - - type =fdt_getprop (fdt, node,"device_type" , &len); -if (type &&strncmp (type,"memory" , len) ==0 ) { -fdt_del_node (fdt, node); -continue ; - } - - prev = node; - } - -/* * Delete all memory reserve map entries. When booting via UEFI, * kernel will use the UEFI memory map to find reserved regions. */ Signature · 1 line
1.9.1
PATCH 6/8 arm64/efi: ignore DT memory nodes instead of removing them
Quoted 13 lines · Leif Lindholm
Quoted 11 lines · Ard Biesheuvel
There are two problems with the UEFI stub DT memory node removal routine:
- it deletes nodes as it traverses the tree, which happens to work but is not supported, as deletion invalidates the node iterator;
- deleting memory nodes entirely may discard annotations in the form of additional properties on the nodes.Now that the UEFI initialization has moved to an earlier stage, we can actually just ignore any memblocks that are installed after we have processed the UEFI memory map. This way, it is no longer necessary to remove the nodes, so we can remove that logic from the stub as well.
Quoted 6 lines
So ... I don't have an issue with this patch as such, but keeping the memory nodes around for NUMA topology when the UEFI memory map is the one being used for memblock leads to a spooky redefinition of what that memory node _is_; it would now describe a region which may only partially be populated with RAM.
How does that not apply to ACPI? It is still the responsibility of the firmware to ensure that all information it supplies is consistent with itself.
But I agree that we should carefully consider this interaction before accepting any NUMA changes to the memnode bindings and implementation.
Signature · 1 line
Ard.
Quoted 69 lines
Quoted 69 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/mm/init.c | 7 +++++++ drivers/firmware/efi/libstub/fdt.c | 24 +----------------------- 2 files changed, 8 insertions(+), 23 deletions(-)arch/arm64/mm/init.c +7
-0@@ -386,6 +386,13 @@ __setup("keepinitrd", keepinitrd_setup);void __init early_init_dt_add_memory_arch (u64 base,u64 size) { +/* +* EFI_MEMMAP will be set /after/ UEFI has installed all memory based +* on the content of the UEFI memory map. +*/ +if (efi_enabled (EFI_MEMMAP )) +return ; +if (!PAGE_ALIGNED (base)) {if (size <PAGE_SIZE - (base & ~PAGE_MASK )) { pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",drivers/firmware/efi/libstub/fdt.c +1
-24@@ -24,7 +24,7 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long map_size, unsigned long desc_size, u32 desc_ver) { - int node, prev, num_rsv; + int node, num_rsv;int status;u32 fdt_val32;u64 fdt_val64;@@ -54,28 +54,6 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, goto fdt_set_fail;/* -* Delete any memory nodes present. We must delete nodes which -* early_init_dt_scan_memory may try to use. -*/ - prev =0 ; -for (;;) { -const char *type; -int len; - - node =fdt_next_node (fdt, prev,NULL ); -if (node <0 ) -break ; - - type =fdt_getprop (fdt, node,"device_type" , &len); -if (type &&strncmp (type,"memory" , len) ==0 ) { -fdt_del_node (fdt, node); -continue ; - } - - prev = node; - } - -/* * Delete all memory reserve map entries. When booting via UEFI, * kernel will use the UEFI memory map to find reserved regions. */ --1.9.1
PATCH 7/8 arm64/efi: ignore DT memreserve entries instead of removing them
In reply to Ard BiesheuvelNow that the reservation of the FDT image itself is split off, we can make the DT scanning of memreserves conditional on whether we booted via UEFI and have its memory map available. This allows us to drop deletion of these memreserves in the stub. It also fixes the issue where the /reserved-memory/ node (which offers another way of reserving memory ranges) was not being ignored under UEFI.
--- arch/arm64/mm/init.c | 3 ++- drivers/firmware/efi/libstub/fdt.c | 11 +---------- 2 files changed, 3 insertions(+), 11 deletions(-)
arch/arm64/mm/init.c +2 -1
@@ -179,7 +179,8 @@ void __init arm64_memblock_init(void)memblock_reserve (__virt_to_phys (initrd_start), initrd_end - initrd_start);#endif -early_init_fdt_scan_reserved_mem (); +if (!efi_enabled (EFI_MEMMAP )) +early_init_fdt_scan_reserved_mem ();/* 4GB maximum for 32-bit only capable devices */ if (IS_ENABLED (CONFIG_ZONE_DMA ))
drivers/firmware/efi/libstub/fdt.c +1 -10
@@ -24,8 +24,7 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long map_size, unsigned long desc_size, u32 desc_ver) { - int node, num_rsv; -int status; + int node, status;u32 fdt_val32;u64 fdt_val64;
@@ -53,14 +52,6 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,if (status !=0 ) goto fdt_set_fail; -/* -* Delete all memory reserve map entries. When booting via UEFI, -* kernel will use the UEFI memory map to find reserved regions. -*/ - num_rsv =fdt_num_mem_rsv (fdt); -while (num_rsv-- >0 ) -fdt_del_mem_rsv (fdt, num_rsv); - node =fdt_subnode_offset (fdt,0 ,"chosen" );if (node <0 ) { node =fdt_add_subnode (fdt,0 ,"chosen" );
Signature · 1 line
1.9.1
PATCH 8/8 arm64/efi: adapt to relaxed FDT placement requirements
In reply to Ard BiesheuvelWith the relaxed FDT placement requirements in place, we can change the allocation strategy used by the stub to put the FDT image higher up in memory. At the same time, reduce the minimal alignment to 8 bytes, and impose a 2 MB size limit, as per the new requirements.
--- arch/arm64/include/asm/efi.h | 10 +++------- drivers/firmware/efi/libstub/arm-stub.c | 5 ++--- drivers/firmware/efi/libstub/efistub.h | 1 - drivers/firmware/efi/libstub/fdt.c | 18 +++++++++--------- 4 files changed, 14 insertions(+), 20 deletions(-)
arch/arm64/include/asm/efi.h +3 -7
@@ -1,6 +1,7 @@#ifndef _ASM_EFI_H#define _ASM_EFI_H +#include <asm/boot.h> #include <asm/io.h> #include <asm/neon.h>
@@ -38,13 +39,8 @@ extern void efi_init_fdt(void *fdt);/* arch specific definitions used by the stub code */ -/* -* AArch64 requires the DTB to be 8-byte aligned in the first 512MiB from -* start of kernel and may not cross a 2MiB boundary. We set alignment to -* 2MiB so we know it won't cross a 2MiB boundary. -*/ -#define EFI_FDT_ALIGN SZ_2M/* used by allocate_new_fdt_and_exit_boot() */ -#define MAX_FDT_OFFSET SZ_512M +#define EFI_FDT_ALIGN MIN_FDT_ALIGN +#define EFI_FDT_MAX_SIZE MAX_FDT_SIZE#define efi_call_early (f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
drivers/firmware/efi/libstub/arm-stub.c +2 -3
@@ -268,9 +268,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, new_fdt_addr = fdt_addr; status =allocate_new_fdt_and_exit_boot (sys_table, handle, - &new_fdt_addr, dram_base +MAX_FDT_OFFSET , - initrd_addr, initrd_size, cmdline_ptr, - fdt_addr, fdt_size); + &new_fdt_addr, initrd_addr, initrd_size, + cmdline_ptr, fdt_addr, fdt_size);/* * If all went well, we need to return the FDT address to the
drivers/firmware/efi/libstub/efistub.h +0 -1
@@ -35,7 +35,6 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, void *handle, unsigned long *new_fdt_addr, - unsigned long max_addr, u64 initrd_addr, u64 initrd_size, char *cmdline_ptr, unsigned long fdt_addr,
drivers/firmware/efi/libstub/fdt.c +9 -9
@@ -134,10 +134,6 @@ fdt_set_fail:return EFI_LOAD_ERROR ; } -#ifndef EFI_FDT_ALIGN -#define EFI_FDT_ALIGN EFI_PAGE_SIZE -#endif -/* * Allocate memory for a new FDT, then add EFI, commandline, and * initrd related fields to the FDT. This routine increases the
@@ -155,7 +151,6 @@ fdt_set_fail: efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, void *handle, unsigned long *new_fdt_addr, - unsigned long max_addr, u64 initrd_addr, u64 initrd_size, char *cmdline_ptr, unsigned long fdt_addr,
@@ -192,8 +187,13 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,*/ new_fdt_size = fdt_size +EFI_PAGE_SIZE ;while (1 ) { - status =efi_high_alloc (sys_table, new_fdt_size,EFI_FDT_ALIGN , - new_fdt_addr, max_addr); +if (new_fdt_size >EFI_FDT_MAX_SIZE ) { +pr_efi_err (sys_table,"FDT size exceeds EFI_FDT_MAX_SIZE.\n" ); + goto fail; + } + status = sys_table->boottime->allocate_pool (EFI_LOADER_DATA , + new_fdt_size, + (void **)new_fdt_addr);if (status !=EFI_SUCCESS ) {pr_efi_err (sys_table,"Unable to allocate memory for new device tree.\n" ); goto fail;
@@ -227,7 +227,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,* to get new one that reflects the free/alloc we do * on the device tree buffer. */ -efi_free (sys_table, new_fdt_size, *new_fdt_addr); + sys_table->boottime->free_pool ((void *)*new_fdt_addr); sys_table->boottime->free_pool (memory_map); new_fdt_size +=EFI_PAGE_SIZE ; }else {
@@ -285,7 +285,7 @@ fail_free_mmap: sys_table->boottime->free_pool (memory_map); fail_free_new_fdt: -efi_free (sys_table, new_fdt_size, *new_fdt_addr); + sys_table->boottime->free_pool ((void *)*new_fdt_addr); fail: sys_table->boottime->free_pool (runtime_map);
Signature · 1 line
1.9.1