All files in this directory relate to EFI, so set the log category consistently. Series-to: concept Series-cc: heinrich Cover-letter: efi: A few minor improvements This series mostly tidies up the efidebug command, but includes a few other pieces as well. END Signed-off-by: Simon Glass <sjg@chromium.org> Series-links: 1:20
212 lines
5.2 KiB
C
212 lines
5.2 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (c) 2015 Google, Inc
|
|
*
|
|
* Access to the EFI information table
|
|
*/
|
|
|
|
#define LOG_CATEGORY LOGC_EFI
|
|
|
|
#include <efi.h>
|
|
#include <efi_loader.h>
|
|
#include <efi_stub.h>
|
|
#include <errno.h>
|
|
#include <mapmem.h>
|
|
#include <asm/global_data.h>
|
|
#include <efi_api.h>
|
|
#include <dm/of.h>
|
|
#include <dm/ofnode.h>
|
|
#include <dm/of_access.h>
|
|
#include <log.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
int efi_info_get(enum efi_entry_t type, void **datap, int *sizep)
|
|
{
|
|
struct efi_entry_hdr *entry;
|
|
struct efi_info_hdr *info;
|
|
int ret;
|
|
|
|
if (!gd->arch.table)
|
|
return -ENODATA;
|
|
|
|
info = map_sysmem(gd->arch.table, 0);
|
|
if (info->version != EFI_TABLE_VERSION) {
|
|
ret = -EPROTONOSUPPORT;
|
|
goto err;
|
|
}
|
|
|
|
entry = (struct efi_entry_hdr *)((ulong)info + info->hdr_size);
|
|
while (entry->type != EFIET_END) {
|
|
if (entry->type == type) {
|
|
if (entry->addr)
|
|
*datap = map_sysmem(entry->addr, entry->size);
|
|
else
|
|
*datap = entry + 1;
|
|
*sizep = entry->size;
|
|
return 0;
|
|
}
|
|
entry = (struct efi_entry_hdr *)((ulong)entry + entry->link);
|
|
}
|
|
|
|
ret = -ENOENT;
|
|
err:
|
|
unmap_sysmem(info);
|
|
|
|
return -ENOSYS;
|
|
}
|
|
|
|
static int of_populate_framebuffer(struct device_node *root)
|
|
{
|
|
struct device_node *chosen, *fb;
|
|
struct efi_entry_gopmode *mode;
|
|
ofnode node;
|
|
int ret, size;
|
|
u64 reg[2];
|
|
char fb_node_name[50] = { 0 };
|
|
|
|
ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size);
|
|
if (ret) {
|
|
printf("EFI graphics output entry not found\n");
|
|
return ret;
|
|
}
|
|
|
|
fb = of_find_node_opts_by_path(root, "/chosen/framebuffer", NULL);
|
|
/* framebuffer already defined */
|
|
if (fb)
|
|
return 0;
|
|
|
|
chosen = of_find_node_opts_by_path(root, "/chosen", NULL);
|
|
if (!chosen) {
|
|
ret = of_add_subnode(root, "chosen", -1, &chosen);
|
|
if (ret) {
|
|
debug("Failed to add chosen node\n");
|
|
return ret;
|
|
}
|
|
}
|
|
node = np_to_ofnode(chosen);
|
|
ofnode_write_u32(node, "#address-cells", 2);
|
|
ofnode_write_u32(node, "#size-cells", 2);
|
|
/*
|
|
* In order for of_translate_one() to correctly detect an empty ranges property, the value
|
|
* pointer has to be non-null even though the length is 0.
|
|
*/
|
|
of_write_prop(chosen, "ranges", 0, (void *)FDT_ADDR_T_NONE);
|
|
|
|
snprintf(fb_node_name, sizeof(fb_node_name), "framebuffer@%llx", mode->fb_base);
|
|
ret = of_add_subnode(chosen, fb_node_name, -1, &fb);
|
|
if (ret) {
|
|
debug("Failed to add framebuffer node\n");
|
|
return ret;
|
|
}
|
|
node = np_to_ofnode(fb);
|
|
ofnode_write_string(node, "compatible", "simple-framebuffer");
|
|
reg[0] = cpu_to_fdt64(mode->fb_base);
|
|
reg[1] = cpu_to_fdt64(mode->fb_size);
|
|
ofnode_write_prop(node, "reg", reg, sizeof(reg), true);
|
|
ofnode_write_u32(node, "width", mode->info->width);
|
|
ofnode_write_u32(node, "height", mode->info->height);
|
|
ofnode_write_u32(node, "stride", mode->info->pixels_per_scanline * 4);
|
|
ofnode_write_string(node, "format", "a8r8g8b8");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int of_populate_from_efi(struct device_node *root)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (CONFIG_IS_ENABLED(VIDEO_SIMPLE) && CONFIG_IS_ENABLED(OF_LIVE))
|
|
ret = of_populate_framebuffer(root);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bool efi_mem_type_is_usable(u32 type)
|
|
{
|
|
switch (type) {
|
|
case EFI_CONVENTIONAL_MEMORY:
|
|
case EFI_LOADER_DATA:
|
|
case EFI_LOADER_CODE:
|
|
case EFI_BOOT_SERVICES_CODE:
|
|
return true;
|
|
case EFI_RESERVED_MEMORY_TYPE:
|
|
case EFI_UNUSABLE_MEMORY:
|
|
case EFI_UNACCEPTED_MEMORY_TYPE:
|
|
case EFI_RUNTIME_SERVICES_DATA:
|
|
case EFI_MMAP_IO:
|
|
case EFI_MMAP_IO_PORT:
|
|
case EFI_PERSISTENT_MEMORY_TYPE:
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int dram_init_banksize_from_efi(void)
|
|
{
|
|
struct efi_mem_desc *desc, *end;
|
|
struct efi_entry_memmap *map;
|
|
int ret, size, bank = 0;
|
|
int num_banks;
|
|
|
|
ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
|
|
if (ret) {
|
|
/* We should have stopped in dram_init(), something is wrong */
|
|
debug("%s: Missing memory map\n", __func__);
|
|
return -ENXIO;
|
|
}
|
|
end = (struct efi_mem_desc *)((ulong)map + size);
|
|
desc = map->desc;
|
|
for (num_banks = 0;
|
|
desc < end && num_banks < CONFIG_NR_DRAM_BANKS;
|
|
desc = efi_get_next_mem_desc(desc, map->desc_size)) {
|
|
/*
|
|
* We only use conventional memory and ignore
|
|
* anything less than 1MB.
|
|
*/
|
|
log_debug("EFI bank #%d: start %llx, size %llx type %u\n",
|
|
bank, desc->physical_start,
|
|
desc->num_pages << EFI_PAGE_SHIFT, desc->type);
|
|
bank++;
|
|
if (!efi_mem_type_is_usable(desc->type) ||
|
|
(desc->num_pages << EFI_PAGE_SHIFT) < 1 << 20)
|
|
continue;
|
|
gd->bd->bi_dram[num_banks].start = desc->physical_start;
|
|
gd->bd->bi_dram[num_banks].size = desc->num_pages <<
|
|
EFI_PAGE_SHIFT;
|
|
num_banks++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Called by U-Boot's EFI subsystem to add known memory. In our case
|
|
* we need to add some specific memory types from the original bootloaders
|
|
* EFI memory map
|
|
*/
|
|
void efi_add_known_memory_from_efi(void)
|
|
{
|
|
struct efi_mem_desc *desc, *end;
|
|
struct efi_entry_memmap *map;
|
|
int ret, size;
|
|
|
|
EFI_PRINT("Adding known memory from previous stage EFI bootloader\n");
|
|
|
|
ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
|
|
if (ret) {
|
|
EFI_PRINT("%s: Missing memory map\n", __func__);
|
|
return;
|
|
}
|
|
end = (struct efi_mem_desc *)((ulong)map + size);
|
|
|
|
for (desc = map->desc; desc < end; desc = efi_get_next_mem_desc(desc, map->desc_size)) {
|
|
switch (desc->type) {
|
|
case EFI_RESERVED_MEMORY_TYPE:
|
|
efi_add_memory_map_pg(desc->physical_start, desc->num_pages, desc->type, false);
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
}
|