1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2015 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
14 #include <u-boot/uuid.h>
15 #include <asm/global_data.h>
17 DECLARE_GLOBAL_DATA_PTR
;
19 static const char *const type_name
[] = {
36 static struct attr_info
{
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" }
55 /* Maximum different attribute values we can track */
56 #define ATTR_SEEN_MAX 30
58 static inline bool is_boot_services(int type
)
60 return type
== EFI_LOADER_CODE
|| type
== EFI_LOADER_DATA
||
61 type
== EFI_BOOT_SERVICES_CODE
||
62 type
== EFI_BOOT_SERVICES_DATA
;
65 static int h_cmp_entry(const void *v1
, const void *v2
)
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
;
72 * Manually calculate the difference to avoid sign loss in the 64-bit
73 * to 32-bit conversion
75 return diff
< 0 ? -1 : diff
> 0 ? 1 : 0;
79 * efi_build_mem_table() - make a sorted copy of the memory table
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
87 * Return: pointer to the new table. It should be freed with free() by the
90 static void *efi_build_mem_table(struct efi_mem_desc
*desc_base
, int size
,
91 int desc_size
, bool skip_bs
)
93 struct efi_mem_desc
*desc
, *end
, *base
, *dest
, *prev
;
97 base
= malloc(size
+ sizeof(*desc
));
99 debug("%s: Cannot allocate %#x bytes\n", __func__
, size
);
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
);
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
)) {
113 u32 type
= desc
->type
;
115 if (type
>= EFI_MAX_MEMORY_TYPE
) {
116 printf("Memory map contains invalid entry type %u\n",
121 if (skip_bs
&& is_boot_services(desc
->type
))
122 type
= EFI_CONVENTIONAL_MEMORY
;
124 memcpy(dest
, desc
, desc_size
);
126 if (!skip_bs
|| !prev
)
128 else if (desc
->physical_start
!= addr
)
130 else if (type
!= EFI_CONVENTIONAL_MEMORY
)
132 else if (prev
->type
!= EFI_CONVENTIONAL_MEMORY
)
136 prev
->num_pages
+= desc
->num_pages
;
139 dest
= efi_get_next_mem_desc(dest
, desc_size
);
141 addr
= desc
->physical_start
+ (desc
->num_pages
<<
146 dest
->type
= EFI_MAX_MEMORY_TYPE
;
151 static void efi_print_mem_table(struct efi_mem_desc
*desc
, int desc_size
,
154 u64 attr_seen
[ATTR_SEEN_MAX
];
159 printf(" # %-14s %10s %10s %10s %s\n", "Type", "Physical",
160 "Virtual", "Size", "Attributes");
162 /* Keep track of all the different attributes we have seen */
165 for (upto
= 0; desc
->type
!= EFI_MAX_MEMORY_TYPE
;
166 upto
++, desc
= efi_get_next_mem_desc(desc
, desc_size
)) {
170 if (skip_bs
&& is_boot_services(desc
->type
))
172 if (desc
->physical_start
!= addr
) {
173 printf(" %-14s %010llx %10s %010llx\n", "<gap>",
174 addr
, "", desc
->physical_start
- addr
);
176 size
= desc
->num_pages
<< EFI_PAGE_SHIFT
;
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
)
185 printf("%llx", desc
->attribute
& ~EFI_MEMORY_RUNTIME
);
188 for (i
= 0; i
< attr_seen_count
; i
++) {
189 if (attr_seen
[i
] == desc
->attribute
)
192 if (i
== attr_seen_count
&& i
< ATTR_SEEN_MAX
)
193 attr_seen
[attr_seen_count
++] = desc
->attribute
;
194 addr
= desc
->physical_start
+ size
;
197 printf("\nAttributes key:\n");
198 for (i
= 0; i
< attr_seen_count
; i
++) {
199 u64 attr
= attr_seen
[i
];
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
) {
211 printf("%s", mem_attr
[j
].name
);
217 printf("*Some areas are merged (use 'all' to see)\n");
220 static int do_efi_mem(struct cmd_tbl
*cmdtp
, int flag
, int argc
,
223 struct efi_mem_desc
*orig
, *desc
;
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
);
233 printf("Cannot read memory map (err=%d)\n", ret
);
234 return CMD_RET_FAILURE
;
237 struct efi_entry_memmap
*map
;
239 ret
= efi_info_get(EFIET_MEMORY_MAP
, (void **)&map
, &size
);
242 printf("No EFI table available\n");
244 case -EPROTONOSUPPORT
:
245 printf("Incorrect EFI table version\n");
249 desc_size
= map
->desc_size
;
250 version
= map
->version
;
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
;
260 desc
= efi_build_mem_table(orig
, size
, desc_size
, skip_bs
);
266 efi_print_mem_table(desc
, desc_size
, skip_bs
);
268 if (IS_ENABLED(CONFIG_EFI_APP
))
272 printf("Error: %d\n", ret
);
274 return ret
? CMD_RET_FAILURE
: 0;
277 static int do_efi_tables(struct cmd_tbl
*cmdtp
, int flag
, int argc
,
280 struct efi_system_table
*systab
;
282 if (IS_ENABLED(CONFIG_EFI_APP
)) {
283 systab
= efi_get_sys_table();
285 printf("Cannot read system table\n");
286 return CMD_RET_FAILURE
;
292 ret
= efi_info_get(EFIET_SYS_TABLE
, (void **)&systab
, &size
);
293 if (ret
) /* this should not happen */
294 return CMD_RET_FAILURE
;
297 efi_show_tables(systab
);
302 static 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
, "", ""),
307 static int do_efi(struct cmd_tbl
*cmdtp
, int flag
, int argc
, char *const argv
[])
309 struct cmd_tbl
*efi_cmd
;
313 return CMD_RET_USAGE
;
314 efi_cmd
= find_cmd_tbl(argv
[1], efi_commands
, ARRAY_SIZE(efi_commands
));
317 if (!efi_cmd
|| argc
> efi_cmd
->maxargs
)
318 return CMD_RET_USAGE
;
320 ret
= efi_cmd
->cmd(efi_cmd
, flag
, argc
, argv
);
322 return cmd_process_error(efi_cmd
, ret
);
328 "mem [all] Dump memory information [include boot services]\n"