summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig4
-rw-r--r--lib/efi/efi.c72
-rw-r--r--lib/efi/efi_app.c42
-rw-r--r--lib/efi/efi_stub.c66
-rw-r--r--lib/efi_loader/efi_dt_fixup.c33
-rw-r--r--lib/efi_loader/efi_firmware.c7
-rw-r--r--lib/image-sparse.c69
7 files changed, 226 insertions, 67 deletions
diff --git a/lib/Kconfig b/lib/Kconfig
index 1883ac734d6..35fc9e418c8 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -837,11 +837,11 @@ config LMB_RESERVED_REGIONS
Define the number of supported reserved regions in the library logical
memory blocks.
-endmenu
-
config PHANDLE_CHECK_SEQ
bool "Enable phandle check while getting sequence number"
help
When there are multiple device tree nodes with same name,
enable this config option to distinguish them using
phandles in fdtdec_get_alias_seq() function.
+
+endmenu
diff --git a/lib/efi/efi.c b/lib/efi/efi.c
index cd6bf47b180..aa42f1842f3 100644
--- a/lib/efi/efi.c
+++ b/lib/efi/efi.c
@@ -135,3 +135,75 @@ void efi_free(struct efi_priv *priv, void *ptr)
boot->free_pool(ptr);
}
+
+int efi_store_memory_map(struct efi_priv *priv)
+{
+ struct efi_boot_services *boot = priv->sys_table->boottime;
+ efi_uintn_t size, desc_size;
+ efi_status_t ret;
+
+ /* Get the memory map so we can switch off EFI */
+ size = 0;
+ ret = boot->get_memory_map(&size, NULL, &priv->memmap_key,
+ &priv->memmap_desc_size,
+ &priv->memmap_version);
+ if (ret != EFI_BUFFER_TOO_SMALL) {
+ /*
+ * Note this function avoids using printf() since it is not
+ * available in the stub
+ */
+ printhex2(EFI_BITS_PER_LONG);
+ putc(' ');
+ printhex2(ret);
+ puts(" No memory map\n");
+ return ret;
+ }
+ /*
+ * Since doing a malloc() may change the memory map and also we want to
+ * be able to read the memory map in efi_call_exit_boot_services()
+ * below, after more changes have happened
+ */
+ priv->memmap_alloc = size + 1024;
+ priv->memmap_size = priv->memmap_alloc;
+ priv->memmap_desc = efi_malloc(priv, size, &ret);
+ if (!priv->memmap_desc) {
+ printhex2(ret);
+ puts(" No memory for memory descriptor\n");
+ return ret;
+ }
+
+ ret = boot->get_memory_map(&priv->memmap_size, priv->memmap_desc,
+ &priv->memmap_key, &desc_size,
+ &priv->memmap_version);
+ if (ret) {
+ printhex2(ret);
+ puts(" Can't get memory map\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int efi_call_exit_boot_services(void)
+{
+ struct efi_priv *priv = efi_get_priv();
+ const struct efi_boot_services *boot = priv->boot;
+ efi_uintn_t size;
+ u32 version;
+ efi_status_t ret;
+
+ size = priv->memmap_alloc;
+ ret = boot->get_memory_map(&size, priv->memmap_desc,
+ &priv->memmap_key,
+ &priv->memmap_desc_size, &version);
+ if (ret) {
+ printhex2(ret);
+ puts(" Can't get memory map\n");
+ return ret;
+ }
+ ret = boot->exit_boot_services(priv->parent_image, priv->memmap_key);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c
index d60f2f6c28f..6980933d7ea 100644
--- a/lib/efi/efi_app.c
+++ b/lib/efi/efi_app.c
@@ -32,6 +32,39 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep)
return -ENOSYS;
}
+int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp,
+ int *desc_sizep, uint *versionp)
+{
+ struct efi_priv *priv = efi_get_priv();
+ struct efi_boot_services *boot = priv->sys_table->boottime;
+ efi_uintn_t size, desc_size, key;
+ struct efi_mem_desc *desc;
+ efi_status_t ret;
+ u32 version;
+
+ /* Get the memory map so we can switch off EFI */
+ size = 0;
+ ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version);
+ if (ret != EFI_BUFFER_TOO_SMALL)
+ return log_msg_ret("get", -ENOMEM);
+
+ desc = malloc(size);
+ if (!desc)
+ return log_msg_ret("mem", -ENOMEM);
+
+ ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version);
+ if (ret)
+ return log_msg_ret("get", -EINVAL);
+
+ *descp = desc;
+ *sizep = size;
+ *desc_sizep = desc_size;
+ *versionp = version;
+ *keyp = key;
+
+ return 0;
+}
+
/**
* efi_bind_block() - bind a new block device to an EFI device
*
@@ -321,6 +354,15 @@ efi_status_t EFIAPI efi_main(efi_handle_t image,
return ret;
}
+ /*
+ * We could store the EFI memory map here, but it changes all the time,
+ * so this is only useful for debugging.
+ *
+ * ret = efi_store_memory_map(priv);
+ * if (ret)
+ * return ret;
+ */
+
printf("starting\n");
board_init_f(GD_FLG_SKIP_RELOC);
diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c
index c89ae7c9072..646cde3214c 100644
--- a/lib/efi/efi_stub.c
+++ b/lib/efi/efi_stub.c
@@ -304,15 +304,12 @@ efi_status_t EFIAPI efi_main(efi_handle_t image,
{
struct efi_priv local_priv, *priv = &local_priv;
struct efi_boot_services *boot = sys_table->boottime;
- struct efi_mem_desc *desc;
struct efi_entry_memmap map;
struct efi_gop *gop;
struct efi_entry_gopmode mode;
struct efi_entry_systable table;
efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
- efi_uintn_t key, desc_size, size;
efi_status_t ret;
- u32 version;
int cs32;
ret = efi_init(priv, "Payload", image, sys_table);
@@ -327,24 +324,11 @@ efi_status_t EFIAPI efi_main(efi_handle_t image,
if (cs32 < 0)
return EFI_UNSUPPORTED;
- /* Get the memory map so we can switch off EFI */
- size = 0;
- ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version);
- if (ret != EFI_BUFFER_TOO_SMALL) {
- printhex2(EFI_BITS_PER_LONG);
- putc(' ');
- printhex2(ret);
- puts(" No memory map\n");
- return ret;
- }
- size += 1024; /* Since doing a malloc() may change the memory map! */
- desc = efi_malloc(priv, size, &ret);
- if (!desc) {
- printhex2(ret);
- puts(" No memory for memory descriptor\n");
+ ret = efi_store_memory_map(priv);
+ if (ret)
return ret;
- }
- ret = setup_info_table(priv, size + 128);
+
+ ret = setup_info_table(priv, priv->memmap_size + 128);
if (ret)
return ret;
@@ -360,48 +344,20 @@ efi_status_t EFIAPI efi_main(efi_handle_t image,
sizeof(struct efi_gop_mode_info));
}
- ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version);
- if (ret) {
- printhex2(ret);
- puts(" Can't get memory map\n");
- return ret;
- }
-
table.sys_table = (ulong)sys_table;
add_entry_addr(priv, EFIET_SYS_TABLE, &table, sizeof(table), NULL, 0);
- ret = boot->exit_boot_services(image, key);
- if (ret) {
- /*
- * Unfortunately it happens that we cannot exit boot services
- * the first time. But the second time it work. I don't know
- * why but this seems to be a repeatable problem. To get
- * around it, just try again.
- */
- printhex2(ret);
- puts(" Can't exit boot services\n");
- size = sizeof(desc);
- ret = boot->get_memory_map(&size, desc, &key, &desc_size,
- &version);
- if (ret) {
- printhex2(ret);
- puts(" Can't get memory map\n");
- return ret;
- }
- ret = boot->exit_boot_services(image, key);
- if (ret) {
- printhex2(ret);
- puts(" Can't exit boot services 2\n");
- return ret;
- }
- }
+ ret = efi_call_exit_boot_services();
+ if (ret)
+ return ret;
/* The EFI UART won't work now, switch to a debug one */
use_uart = true;
- map.version = version;
- map.desc_size = desc_size;
- add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), desc, size);
+ map.version = priv->memmap_version;
+ map.desc_size = priv->memmap_desc_size;
+ add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map),
+ priv->memmap_desc, priv->memmap_size);
add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0);
memcpy((void *)CONFIG_SYS_TEXT_BASE, _binary_u_boot_bin_start,
diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c
index b6fe5d2e5a3..d3923e5dba1 100644
--- a/lib/efi_loader/efi_dt_fixup.c
+++ b/lib/efi_loader/efi_dt_fixup.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <efi_dt_fixup.h>
#include <efi_loader.h>
+#include <efi_rng.h>
#include <fdtdec.h>
#include <mapmem.h>
@@ -41,6 +42,38 @@ static void efi_reserve_memory(u64 addr, u64 size, bool nomap)
}
/**
+ * efi_try_purge_kaslr_seed() - Remove unused kaslr-seed
+ *
+ * Kernel's EFI STUB only relies on EFI_RNG_PROTOCOL for randomization
+ * and completely ignores the kaslr-seed for its own randomness needs
+ * (i.e the randomization of the physical placement of the kernel).
+ * Weed it out from the DTB we hand over, which would mess up our DTB
+ * TPM measurements as well.
+ *
+ * @fdt: Pointer to device tree
+ */
+void efi_try_purge_kaslr_seed(void *fdt)
+{
+ const efi_guid_t efi_guid_rng_protocol = EFI_RNG_PROTOCOL_GUID;
+ struct efi_handler *handler;
+ efi_status_t ret;
+ int nodeoff = 0;
+ int err = 0;
+
+ ret = efi_search_protocol(efi_root, &efi_guid_rng_protocol, &handler);
+ if (ret != EFI_SUCCESS)
+ return;
+
+ nodeoff = fdt_path_offset(fdt, "/chosen");
+ if (nodeoff < 0)
+ return;
+
+ err = fdt_delprop(fdt, nodeoff, "kaslr-seed");
+ if (err < 0 && err != -FDT_ERR_NOTFOUND)
+ log_err("Error deleting kaslr-seed\n");
+}
+
+/**
* efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
*
* The mem_rsv entries of the FDT are added to the memory map. Any failures are
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index a1b88dbfc28..519a47267ca 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -128,8 +128,11 @@ static efi_status_t efi_get_dfu_info(
size_t names_len, total_size;
int dfu_num, i;
u16 *name, *next;
+ int ret;
- dfu_init_env_entities(NULL, NULL);
+ ret = dfu_init_env_entities(NULL, NULL);
+ if (ret)
+ return EFI_SUCCESS;
names_len = 0;
dfu_num = 0;
@@ -138,7 +141,7 @@ static efi_status_t efi_get_dfu_info(
dfu_num++;
}
if (!dfu_num) {
- log_warning("Probably dfu_alt_info not defined\n");
+ log_warning("No entities in dfu_alt_info\n");
*image_info_size = 0;
dfu_free_entities();
diff --git a/lib/image-sparse.c b/lib/image-sparse.c
index d80fdbbf58e..5ec0f94ab3e 100644
--- a/lib/image-sparse.c
+++ b/lib/image-sparse.c
@@ -46,9 +46,66 @@
#include <asm/cache.h>
#include <linux/math64.h>
+#include <linux/err.h>
static void default_log(const char *ignored, char *response) {}
+static lbaint_t write_sparse_chunk_raw(struct sparse_storage *info,
+ lbaint_t blk, lbaint_t blkcnt,
+ void *data,
+ char *response)
+{
+ lbaint_t n = blkcnt, write_blks, blks = 0, aligned_buf_blks = 100;
+ uint32_t *aligned_buf = NULL;
+
+ if (CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) {
+ write_blks = info->write(info, blk, n, data);
+ if (write_blks < n)
+ goto write_fail;
+
+ return write_blks;
+ }
+
+ aligned_buf = memalign(ARCH_DMA_MINALIGN, info->blksz * aligned_buf_blks);
+ if (!aligned_buf) {
+ info->mssg("Malloc failed for: CHUNK_TYPE_RAW", response);
+ return -ENOMEM;
+ }
+
+ while (blkcnt > 0) {
+ n = min(aligned_buf_blks, blkcnt);
+ memcpy(aligned_buf, data, n * info->blksz);
+
+ /* write_blks might be > n due to NAND bad-blocks */
+ write_blks = info->write(info, blk + blks, n, aligned_buf);
+ if (write_blks < n) {
+ free(aligned_buf);
+ goto write_fail;
+ }
+
+ blks += write_blks;
+ data += n * info->blksz;
+ blkcnt -= n;
+ }
+
+ free(aligned_buf);
+ return blks;
+
+write_fail:
+ if (IS_ERR_VALUE(write_blks)) {
+ printf("%s: Write failed, block #" LBAFU " [" LBAFU "] (%lld)\n",
+ __func__, blk + blks, n, (long long)write_blks);
+ info->mssg("flash write failure", response);
+ return write_blks;
+ }
+
+ /* write_blks < n */
+ printf("%s: Write failed, block #" LBAFU " [" LBAFU "]\n",
+ __func__, blk + blks, n);
+ info->mssg("flash write failure(incomplete)", response);
+ return -1;
+}
+
int write_sparse_image(struct sparse_storage *info,
const char *part_name, void *data, char *response)
{
@@ -152,15 +209,11 @@ int write_sparse_image(struct sparse_storage *info,
return -1;
}
- blks = info->write(info, blk, blkcnt, data);
- /* blks might be > blkcnt (eg. NAND bad-blocks) */
- if (blks < blkcnt) {
- printf("%s: %s" LBAFU " [" LBAFU "]\n",
- __func__, "Write failed, block #",
- blk, blks);
- info->mssg("flash write failure", response);
+ blks = write_sparse_chunk_raw(info, blk, blkcnt,
+ data, response);
+ if (blks < 0)
return -1;
- }
+
blk += blks;
bytes_written += ((u64)blkcnt) * info->blksz;
total_blocks += chunk_header->chunk_sz;