Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | // SPDX-License-Identifier: GPL-2.0-or-later /* * The 'smbios' command displays information from the SMBIOS table. * * Copyright (c) 2023, Heinrich Schuchardt <heinrich.schuchardt@canonical.com> */ #include <command.h> #include <hexdump.h> #include <mapmem.h> #include <smbios.h> #include <tables_csum.h> #include <asm/global_data.h> DECLARE_GLOBAL_DATA_PTR; static const char * const wakeup_type_strings[] = { "Reserved", /* 0x00 */ "Other", /* 0x01 */ "Unknown", /* 0x02 */ "APM Timer", /* 0x03 */ "Modem Ring", /* 0x04 */ "Lan Remote", /* 0x05 */ "Power Switch", /* 0x06 */ "PCI PME#", /* 0x07 */ "AC Power Restored", /* 0x08 */ }; /** * smbios_get_string() - get SMBIOS string from table * * @table: SMBIOS table * @index: index of the string * Return: address of string, may point to empty string */ static const char *smbios_get_string(void *table, int index) { const char *str = (char *)table + ((struct smbios_header *)table)->length; static const char fallback[] = "Not Specified"; if (!index) return fallback; if (!*str) ++str; for (--index; *str && index; --index) str += strlen(str) + 1; return str; } static struct smbios_header *next_table(struct smbios_header *table) { const char *str; if (table->type == SMBIOS_END_OF_TABLE) return NULL; str = smbios_get_string(table, -1); return (struct smbios_header *)(++str); } static void smbios_print_generic(struct smbios_header *table) { char *str = (char *)table + table->length; if (CONFIG_IS_ENABLED(HEXDUMP)) { printf("Header and Data:\n"); print_hex_dump("\t", DUMP_PREFIX_OFFSET, 16, 1, table, table->length, false); } if (*str) { printf("Strings:\n"); for (int index = 1; *str; ++index) { printf("\tString %u: %s\n", index, str); str += strlen(str) + 1; } } } void smbios_print_str(const char *label, void *table, u8 index) { printf("\t%s: %s\n", label, smbios_get_string(table, index)); } const char *smbios_wakeup_type_str(u8 wakeup_type) { if (wakeup_type >= ARRAY_SIZE(wakeup_type_strings)) /* Values over 0x08 are reserved. */ wakeup_type = 0; return wakeup_type_strings[wakeup_type]; } static void smbios_print_type1(struct smbios_type1 *table) { printf("System Information\n"); smbios_print_str("Manufacturer", table, table->manufacturer); smbios_print_str("Product Name", table, table->product_name); smbios_print_str("Version", table, table->version); smbios_print_str("Serial Number", table, table->serial_number); if (table->length >= 0x19) { printf("\tUUID: %pUl\n", table->uuid); printf("\tWake-up Type: %s\n", smbios_wakeup_type_str(table->wakeup_type)); } if (table->length >= 0x1b) { smbios_print_str("SKU Number", table, table->sku_number); smbios_print_str("Family", table, table->family); } } static void smbios_print_type2(struct smbios_type2 *table) { u16 *handle; printf("Base Board Information\n"); smbios_print_str("Manufacturer", table, table->manufacturer); smbios_print_str("Product Name", table, table->product_name); smbios_print_str("Version", table, table->version); smbios_print_str("Serial Number", table, table->serial_number); smbios_print_str("Asset Tag", table, table->asset_tag_number); printf("\tFeature Flags: 0x%04x\n", table->feature_flags); smbios_print_str("Chassis Location", table, table->chassis_location); printf("\tChassis Handle: 0x%04x\n", table->chassis_handle); smbios_print_str("Board Type", table, table->board_type); printf("\tContained Object Handles: "); handle = (void *)table->eos; for (int i = 0; i < table->number_contained_objects; ++i) printf("0x%04x ", handle[i]); printf("\n"); } static void smbios_print_type127(struct smbios_type127 *table) { printf("End Of Table\n"); } static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { ulong addr; void *entry; u32 size; char version[12]; struct smbios_header *table; static const char smbios_sig[] = "_SM_"; static const char smbios3_sig[] = "_SM3_"; size_t count = 0; u32 table_maximum_size; addr = gd_smbios_start(); if (!addr) { log_warning("SMBIOS not available\n"); return CMD_RET_FAILURE; } entry = map_sysmem(addr, 0); if (!memcmp(entry, smbios3_sig, sizeof(smbios3_sig) - 1)) { struct smbios3_entry *entry3 = entry; table = (void *)(uintptr_t)entry3->struct_table_address; snprintf(version, sizeof(version), "%d.%d.%d", entry3->major_ver, entry3->minor_ver, entry3->doc_rev); table = (void *)(uintptr_t)entry3->struct_table_address; size = entry3->length; table_maximum_size = entry3->table_maximum_size; } else if (!memcmp(entry, smbios_sig, sizeof(smbios_sig) - 1)) { struct smbios_entry *entry2 = entry; snprintf(version, sizeof(version), "%d.%d", entry2->major_ver, entry2->minor_ver); table = (void *)(uintptr_t)entry2->struct_table_address; size = entry2->length; table_maximum_size = entry2->struct_table_length; } else { log_err("Unknown SMBIOS anchor format\n"); return CMD_RET_FAILURE; } if (table_compute_checksum(entry, size)) { log_err("Invalid anchor checksum\n"); return CMD_RET_FAILURE; } printf("SMBIOS %s present.\n", version); for (struct smbios_header *pos = table; pos; pos = next_table(pos)) ++count; printf("%zd structures occupying %d bytes\n", count, table_maximum_size); printf("Table at 0x%llx\n", (unsigned long long)map_to_sysmem(table)); for (struct smbios_header *pos = table; pos; pos = next_table(pos)) { printf("\nHandle 0x%04x, DMI type %d, %d bytes at 0x%llx\n", pos->handle, pos->type, pos->length, (unsigned long long)map_to_sysmem(pos)); switch (pos->type) { case 1: smbios_print_type1((struct smbios_type1 *)pos); break; case 2: smbios_print_type2((struct smbios_type2 *)pos); break; case 127: smbios_print_type127((struct smbios_type127 *)pos); break; default: smbios_print_generic(pos); break; } } return CMD_RET_SUCCESS; } U_BOOT_LONGHELP(smbios, "- display SMBIOS information"); U_BOOT_CMD(smbios, 1, 0, do_smbios, "display SMBIOS information", smbios_help_text); |