"Das U-Boot" Source Tree
at master 330 lines 8.2 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2015 Google, Inc 4 * Written by Simon Glass <sjg@chromium.org> 5 */ 6 7#include <command.h> 8#include <efi.h> 9#include <efi_api.h> 10#include <errno.h> 11#include <log.h> 12#include <malloc.h> 13#include <sort.h> 14#include <u-boot/uuid.h> 15#include <asm/global_data.h> 16 17DECLARE_GLOBAL_DATA_PTR; 18 19static const char *const type_name[] = { 20 "reserved", 21 "loader_code", 22 "loader_data", 23 "bs_code", 24 "bs_data", 25 "rt_code", 26 "rt_data", 27 "conv", 28 "unusable", 29 "acpi_reclaim", 30 "acpi_nvs", 31 "io", 32 "io_port", 33 "pal_code", 34}; 35 36static struct attr_info { 37 u64 val; 38 const char *name; 39} mem_attr[] = { 40 { EFI_MEMORY_UC, "uncached" }, 41 { EFI_MEMORY_WC, "write-coalescing" }, 42 { EFI_MEMORY_WT, "write-through" }, 43 { EFI_MEMORY_WB, "write-back" }, 44 { EFI_MEMORY_UCE, "uncached & exported" }, 45 { EFI_MEMORY_WP, "write-protect" }, 46 { EFI_MEMORY_RP, "read-protect" }, 47 { EFI_MEMORY_XP, "execute-protect" }, 48 { EFI_MEMORY_NV, "non-volatile" }, 49 { EFI_MEMORY_MORE_RELIABLE, "higher reliability" }, 50 { EFI_MEMORY_RO, "read-only" }, 51 { EFI_MEMORY_SP, "specific purpose" }, 52 { EFI_MEMORY_RUNTIME, "needs runtime mapping" } 53}; 54 55/* Maximum different attribute values we can track */ 56#define ATTR_SEEN_MAX 30 57 58static inline bool is_boot_services(int type) 59{ 60 return type == EFI_LOADER_CODE || type == EFI_LOADER_DATA || 61 type == EFI_BOOT_SERVICES_CODE || 62 type == EFI_BOOT_SERVICES_DATA; 63} 64 65static int h_cmp_entry(const void *v1, const void *v2) 66{ 67 const struct efi_mem_desc *desc1 = v1; 68 const struct efi_mem_desc *desc2 = v2; 69 int64_t diff = desc1->physical_start - desc2->physical_start; 70 71 /* 72 * Manually calculate the difference to avoid sign loss in the 64-bit 73 * to 32-bit conversion 74 */ 75 return diff < 0 ? -1 : diff > 0 ? 1 : 0; 76} 77 78/** 79 * efi_build_mem_table() - make a sorted copy of the memory table 80 * 81 * @desc_base: Pointer to EFI memory map table 82 * @size: Size of table in bytes 83 * @desc_size: Size of each @desc_base record 84 * @skip_bs: True to skip boot-time memory and merge it with conventional 85 * memory. This will significantly reduce the number of table 86 * entries. 87 * Return: pointer to the new table. It should be freed with free() by the 88 * caller. 89 */ 90static void *efi_build_mem_table(struct efi_mem_desc *desc_base, int size, 91 int desc_size, bool skip_bs) 92{ 93 struct efi_mem_desc *desc, *end, *base, *dest, *prev; 94 int count; 95 u64 addr; 96 97 base = malloc(size + sizeof(*desc)); 98 if (!base) { 99 debug("%s: Cannot allocate %#x bytes\n", __func__, size); 100 return NULL; 101 } 102 end = (void *)desc_base + size; 103 count = ((ulong)end - (ulong)desc_base) / desc_size; 104 memcpy(base, desc_base, (ulong)end - (ulong)desc_base); 105 qsort(base, count, desc_size, h_cmp_entry); 106 prev = NULL; 107 addr = 0; 108 dest = base; 109 end = (struct efi_mem_desc *)((ulong)base + count * desc_size); 110 for (desc = base; desc < end; 111 desc = efi_get_next_mem_desc(desc, desc_size)) { 112 bool merge = true; 113 u32 type = desc->type; 114 115 if (type >= EFI_MAX_MEMORY_TYPE) { 116 printf("Memory map contains invalid entry type %u\n", 117 type); 118 continue; 119 } 120 121 if (skip_bs && is_boot_services(desc->type)) 122 type = EFI_CONVENTIONAL_MEMORY; 123 124 memcpy(dest, desc, desc_size); 125 dest->type = type; 126 if (!skip_bs || !prev) 127 merge = false; 128 else if (desc->physical_start != addr) 129 merge = false; 130 else if (type != EFI_CONVENTIONAL_MEMORY) 131 merge = false; 132 else if (prev->type != EFI_CONVENTIONAL_MEMORY) 133 merge = false; 134 135 if (merge) { 136 prev->num_pages += desc->num_pages; 137 } else { 138 prev = dest; 139 dest = efi_get_next_mem_desc(dest, desc_size); 140 } 141 addr = desc->physical_start + (desc->num_pages << 142 EFI_PAGE_SHIFT); 143 } 144 145 /* Mark the end */ 146 dest->type = EFI_MAX_MEMORY_TYPE; 147 148 return base; 149} 150 151static void efi_print_mem_table(struct efi_mem_desc *desc, int desc_size, 152 bool skip_bs) 153{ 154 u64 attr_seen[ATTR_SEEN_MAX]; 155 int attr_seen_count; 156 int upto, i; 157 u64 addr; 158 159 printf(" # %-14s %10s %10s %10s %s\n", "Type", "Physical", 160 "Virtual", "Size", "Attributes"); 161 162 /* Keep track of all the different attributes we have seen */ 163 attr_seen_count = 0; 164 addr = 0; 165 for (upto = 0; desc->type != EFI_MAX_MEMORY_TYPE; 166 upto++, desc = efi_get_next_mem_desc(desc, desc_size)) { 167 const char *name; 168 u64 size; 169 170 if (skip_bs && is_boot_services(desc->type)) 171 continue; 172 if (desc->physical_start != addr) { 173 printf(" %-14s %010llx %10s %010llx\n", "<gap>", 174 addr, "", desc->physical_start - addr); 175 } 176 size = desc->num_pages << EFI_PAGE_SHIFT; 177 178 name = desc->type < ARRAY_SIZE(type_name) ? 179 type_name[desc->type] : "<invalid>"; 180 printf("%2d %x:%-12s %010llx %010llx %010llx ", upto, 181 desc->type, name, desc->physical_start, 182 desc->virtual_start, size); 183 if (desc->attribute & EFI_MEMORY_RUNTIME) 184 putc('r'); 185 printf("%llx", desc->attribute & ~EFI_MEMORY_RUNTIME); 186 putc('\n'); 187 188 for (i = 0; i < attr_seen_count; i++) { 189 if (attr_seen[i] == desc->attribute) 190 break; 191 } 192 if (i == attr_seen_count && i < ATTR_SEEN_MAX) 193 attr_seen[attr_seen_count++] = desc->attribute; 194 addr = desc->physical_start + size; 195 } 196 197 printf("\nAttributes key:\n"); 198 for (i = 0; i < attr_seen_count; i++) { 199 u64 attr = attr_seen[i]; 200 bool first; 201 int j; 202 203 printf("%c%llx: ", (attr & EFI_MEMORY_RUNTIME) ? 'r' : ' ', 204 attr & ~EFI_MEMORY_RUNTIME); 205 for (j = 0, first = true; j < ARRAY_SIZE(mem_attr); j++) { 206 if (attr & mem_attr[j].val) { 207 if (first) 208 first = false; 209 else 210 printf(", "); 211 printf("%s", mem_attr[j].name); 212 } 213 } 214 putc('\n'); 215 } 216 if (skip_bs) 217 printf("*Some areas are merged (use 'all' to see)\n"); 218} 219 220static int do_efi_mem(struct cmd_tbl *cmdtp, int flag, int argc, 221 char *const argv[]) 222{ 223 struct efi_mem_desc *orig, *desc; 224 uint version, key; 225 int desc_size; 226 int size, ret; 227 bool skip_bs; 228 229 skip_bs = !argc || *argv[0] != 'a'; 230 if (IS_ENABLED(CONFIG_EFI_APP)) { 231 ret = efi_get_mmap(&orig, &size, &key, &desc_size, &version); 232 if (ret) { 233 printf("Cannot read memory map (err=%d)\n", ret); 234 return CMD_RET_FAILURE; 235 } 236 } else { 237 struct efi_entry_memmap *map; 238 239 ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); 240 switch (ret) { 241 case -ENOENT: 242 printf("No EFI table available\n"); 243 goto done; 244 case -EPROTONOSUPPORT: 245 printf("Incorrect EFI table version\n"); 246 goto done; 247 } 248 orig = map->desc; 249 desc_size = map->desc_size; 250 version = map->version; 251 } 252 printf("EFI table at %lx, memory map %p, size %x, key %x, version %x, descr. size %#x\n", 253 gd->arch.table, orig, size, key, version, desc_size); 254 if (version != EFI_MEM_DESC_VERSION) { 255 printf("Incorrect memory map version\n"); 256 ret = -EPROTONOSUPPORT; 257 goto done; 258 } 259 260 desc = efi_build_mem_table(orig, size, desc_size, skip_bs); 261 if (!desc) { 262 ret = -ENOMEM; 263 goto done; 264 } 265 266 efi_print_mem_table(desc, desc_size, skip_bs); 267 free(desc); 268 if (IS_ENABLED(CONFIG_EFI_APP)) 269 free(orig); 270done: 271 if (ret) 272 printf("Error: %d\n", ret); 273 274 return ret ? CMD_RET_FAILURE : 0; 275} 276 277static int do_efi_tables(struct cmd_tbl *cmdtp, int flag, int argc, 278 char *const argv[]) 279{ 280 struct efi_system_table *systab; 281 282 if (IS_ENABLED(CONFIG_EFI_APP)) { 283 systab = efi_get_sys_table(); 284 if (!systab) { 285 printf("Cannot read system table\n"); 286 return CMD_RET_FAILURE; 287 } 288 } else { 289 int size; 290 int ret; 291 292 ret = efi_info_get(EFIET_SYS_TABLE, (void **)&systab, &size); 293 if (ret) /* this should not happen */ 294 return CMD_RET_FAILURE; 295 } 296 297 efi_show_tables(systab); 298 299 return 0; 300} 301 302static struct cmd_tbl efi_commands[] = { 303 U_BOOT_CMD_MKENT(mem, 1, 1, do_efi_mem, "", ""), 304 U_BOOT_CMD_MKENT(tables, 1, 1, do_efi_tables, "", ""), 305}; 306 307static int do_efi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) 308{ 309 struct cmd_tbl *efi_cmd; 310 int ret; 311 312 if (argc < 2) 313 return CMD_RET_USAGE; 314 efi_cmd = find_cmd_tbl(argv[1], efi_commands, ARRAY_SIZE(efi_commands)); 315 argc -= 2; 316 argv += 2; 317 if (!efi_cmd || argc > efi_cmd->maxargs) 318 return CMD_RET_USAGE; 319 320 ret = efi_cmd->cmd(efi_cmd, flag, argc, argv); 321 322 return cmd_process_error(efi_cmd, ret); 323} 324 325U_BOOT_CMD( 326 efi, 3, 1, do_efi, 327 "EFI access", 328 "mem [all] Dump memory information [include boot services]\n" 329 "tables Dump tables" 330);