On Mon, Jan 05, 2015 at 04:54:02PM +0000, Matt Fleming wrote:

> > +static efi_status_t get_memory_map(efi_system_table_t *sys_table_arg,
> > +                              efi_memory_desc_t **map,
> > +                              unsigned long *map_size,
> > +                              unsigned long *desc_size,
> > +                              u32 *desc_ver, unsigned long *key_ptr)
> > +{
> > +   efi_status_t status;
> > +
> > +   /*
> > +    * Call get_memory_map() with 0 size to retrieve the size of the
> > +    * required allocation.
> > +    */
> > +   *map_size = 0;
> > +   status = efi_call_early(get_memory_map, map_size, NULL,
> > +                           key_ptr, desc_size, desc_ver);
> > +   if (status != EFI_BUFFER_TOO_SMALL)
> > +           return EFI_LOAD_ERROR;
> > +
> > +   /*
> > +    * Add an additional efi_memory_desc_t to map_size because we're doing
> > +    * an allocation which may be in a new descriptor region. Then double it
> > +    * to give us some scratch space to prepare the input virtmap to give
> > +    * to SetVirtualAddressMap(). Note that this is EFI_LOADER_DATA memory,
> > +    * and the kernel memblock_reserve()'s only the size of the actual
> > +    * memory map, so the scratch space is freed again automatically.
> > +    */
> > +   *map_size += *desc_size;
> > +   status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
> > +                           *map_size * 2, (void **)map);
> > +   if (status != EFI_SUCCESS)
> > +           return status;
> > +
> > +   status = efi_call_early(get_memory_map, map_size, *map,
> > +                           key_ptr, desc_size, desc_ver);
> > +   if (status != EFI_SUCCESS)
> > +           efi_call_early(free_pool, *map);
> > +   return status;
> > +}
> 
> We've now got two (slightly different) versions of this function. Is
> there any way we could make do with just one?

I think all we really need above what efi_get_memory_map() provides is
the scratch space. Would we care about temporarily wasting a little
bit of EFI_LOADER_DATA on all platforms, or could we just swap the
function body in efi-stub-helper.c for Ard's version above?

(I would guess memory maps with <= 32 entries are uncommon anyway, so
the existing version would already make the bootservice call twice.)

> > +/*
> > + * This is the base address at which to start allocating virtual memory 
> > ranges
> > + * for UEFI Runtime Services. This is a userland range so that we can use 
> > any
> > + * allocation we choose, and eliminate the risk of a conflict after kexec.
> > + */
> > +#define EFI_RT_VIRTUAL_BASE        0x40000000
> > +
> > +static void update_memory_map(efi_memory_desc_t *memory_map,
> > +                         unsigned long map_size, unsigned long desc_size,
> > +                         int *count)
> > +{
> > +   u64 efi_virt_base = EFI_RT_VIRTUAL_BASE;
> > +   efi_memory_desc_t *out = (void *)memory_map + map_size;
> > +   int l;
> > +
> > +   for (l = 0; l < map_size; l += desc_size) {
> > +           efi_memory_desc_t *in = (void *)memory_map + l;
> > +           u64 paddr, size;
> > +
> > +           if (!(in->attribute & EFI_MEMORY_RUNTIME))
> > +                   continue;
> > +
> > +           /*
> > +            * Make the mapping compatible with 64k pages: this allows
> > +            * a 4k page size kernel to kexec a 64k page size kernel and
> > +            * vice versa.
> > +            */
> > +           paddr = round_down(in->phys_addr, SZ_64K);
> > +           size = round_up(in->num_pages * EFI_PAGE_SIZE +
> > +                           in->phys_addr - paddr, SZ_64K);
> > +
> > +           /*
> > +            * Avoid wasting memory on PTEs by choosing a virtual base that
> > +            * is compatible with section mappings if this region has the
> > +            * appropriate size and physical alignment. (Sections are 2 MB
> > +            * on 4k granule kernels)
> > +            */
> > +           if (IS_ALIGNED(in->phys_addr, SZ_2M) && size >= SZ_2M)
> > +                   efi_virt_base = round_up(efi_virt_base, SZ_2M);
> > +
> > +           in->virt_addr = efi_virt_base + in->phys_addr - paddr;
> > +           efi_virt_base += size;
> > +
> > +           memcpy(out, in, desc_size);
> > +           out = (void *)out + desc_size;
> > +           ++*count;
> > +   }
> > +}
> > +
> 
> fdt.c is starting to become a dumping ground for arm*-specific stuff :-(

Mmm, not optimal.
That said, the only arm*-specific things about this particular
function are the page sizes. Should this move to efi-stub-helper.c
with EFI_RT_VIRTUAL_BASE moved to arch/<x>/include/asm/efi.h and
joined by EFI_RT_VIRTUAL_BASE_ALIGN and EFI_RT_VIRTUAL_REGION_ALIGN?
 
> Is there no general solution for sharing code between arm and aarch64 in
> the kernel so we don't have to stick things like this in
> drivers/firmware/efi/?

Not currently.

/
    Leif
--
To unsubscribe from this list: send the line "unsubscribe linux-efi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to