> -Original Message-
> From: Ard Biesheuvel
> Sent: 04 August 2019 09:57
> To: Chester Lin ; li...@armlinux.org.uk
> Cc: a...@linux-foundation.org; r...@linux.ibm.com; ren_...@c-sky.com;
> Juergen Gross ; ge...@linux-m68k.org; mi...@kernel.org;
> linux-arm-ker...@lists.infradead.org; linux-ker...@vger.kernel.org; linux-
> e...@vger.kernel.org; Guillaume Gardet ; Joey Lee
> ; Gary Lin
> Subject: Re: [PATCH] efi/arm: fix allocation failure when reserving the kernel
> base
>
> Hello Chester,
>
> On Fri, 2 Aug 2019 at 08:40, Chester Lin wrote:
> >
> > In some cases the arm32 efistub could fail to allocate memory for
> > uncompressed kernel. For example, we got the following error message
> > when verifying EFI stub on Raspberry Pi-2 [kernel-5.2.1 + grub-2.04] :
> >
> > EFI stub: Booting Linux Kernel...
> > EFI stub: ERROR: Unable to allocate memory for uncompressed kernel.
> > EFI stub: ERROR: Failed to relocate kernel
> >
> > After checking the EFI memory map we found that the first page [0 -
> > 0xfff] had been reserved by Raspberry Pi-2's firmware, and the efistub
> > tried to set the dram base at 0, which was actually in a reserved region.
> >
>
> This by itself is a violation of the Linux boot protocol for 32-bit ARM when
> using
> the decompressor. The decompressor rounds down its own base address to a
> multiple of 128 MB, and assumes the whole area is available for the
> decompressed kernel and related data structures.
> (The first TEXT_OFFSET bytes are no longer used in practice, which is why
> putting
> a reserved region of 4 KB bytes works at the moment, but this is fragile).
> Note
> that the decompressor does not look at any DT or EFI provided memory maps
> *at all*.
>
> So unfortunately, this is not something we can fix in the kernel, but we
> should fix
> it in the bootloader or in GRUB, so it does not put any reserved regions in
> the
> first 128 MB of memory,
FYI, this is in Raspberry Pi firmware:
https://github.com/raspberrypi/firmware/issues/1199
>
>
> > grub> lsefimmap
> > Type Physical start - end #PagesSize Attributes
> > reserved -0fff 0001 4KiB WB
> > conv-mem 1000-07ef5fff 7ef5 130004KiB WB
> > RT-data 07ef6000-07f09fff 0014 80KiB RT WB
> > conv-mem 07f0a000-2d871fff 00025968 615840KiB WB
> > .
> >
> > To avoid a reserved address, we have to ignore the memory regions
> > which are marked as EFI_RESERVED_TYPE, and only conventional memory
> > regions can be chosen. If the region before the kernel base is
> > unaligned, it will be marked as EFI_RESERVED_TYPE and let kernel
> > ignore it so that memblock_limit will not be sticked with a very low address
> such as 0x1000.
> >
> > Signed-off-by: Chester Lin
> > ---
> > arch/arm/mm/mmu.c | 3 ++
> > drivers/firmware/efi/libstub/arm32-stub.c | 43
> > ++-
> > 2 files changed, 37 insertions(+), 9 deletions(-)
> >
> > diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index
> > f3ce34113f89..909b11ba48d8 100644
> > --- a/arch/arm/mm/mmu.c
> > +++ b/arch/arm/mm/mmu.c
> > @@ -1184,6 +1184,9 @@ void __init adjust_lowmem_bounds(void)
> > phys_addr_t block_start = reg->base;
> > phys_addr_t block_end = reg->base + reg->size;
> >
> > + if (memblock_is_nomap(reg))
> > + continue;
> > +
> > if (reg->base < vmalloc_limit) {
> > if (block_end > lowmem_limit)
> > /*
> > diff --git a/drivers/firmware/efi/libstub/arm32-stub.c
> > b/drivers/firmware/efi/libstub/arm32-stub.c
> > index e8f7aefb6813..10d33d36df00 100644
> > --- a/drivers/firmware/efi/libstub/arm32-stub.c
> > +++ b/drivers/firmware/efi/libstub/arm32-stub.c
> > @@ -128,7 +128,7 @@ static efi_status_t
> > reserve_kernel_base(efi_system_table_t *sys_table_arg,
> >
> > for (l = 0; l < map_size; l += desc_size) {
> > efi_memory_desc_t *desc;
> > - u64 start, end;
> > + u64 start, end, spare, kernel_base;
> >
> > desc = (void *)memory_map + l;
> > start = desc->phys_addr; @@ -144,27 +144,52 @@ static
> > efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg,
> > case EFI_BOOT_SERVICES_DATA:
> > /* Ignore types that are released to the OS anyway
> > */
> > continue;
> > -
> > + case EFI_RESERVED_TYPE:
> > + /* Ignore reserved regions */
> > + continue;
> > case EFI_CONVENTIONAL_MEMORY:
> > /*
> > * Reserve the intersection between this entry and
> > the
> > * region.
> > */
> > start =