1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> 4 * 5 * Adapted from coreboot src/arch/x86/smbios.c 6 */ 7 8 #include <common.h> 9 #include <smbios.h> 10 #include <tables_csum.h> 11 #include <version.h> 12 #ifdef CONFIG_CPU 13 #include <cpu.h> 14 #include <dm.h> 15 #include <dm/uclass-internal.h> 16 #endif 17 18 /** 19 * smbios_add_string() - add a string to the string area 20 * 21 * This adds a string to the string area which is appended directly after 22 * the formatted portion of an SMBIOS structure. 23 * 24 * @start: string area start address 25 * @str: string to add 26 * @return: string number in the string area 27 */ 28 static int smbios_add_string(char *start, const char *str) 29 { 30 int i = 1; 31 char *p = start; 32 33 for (;;) { 34 if (!*p) { 35 strcpy(p, str); 36 p += strlen(str); 37 *p++ = '\0'; 38 *p++ = '\0'; 39 40 return i; 41 } 42 43 if (!strcmp(p, str)) 44 return i; 45 46 p += strlen(p) + 1; 47 i++; 48 } 49 } 50 51 /** 52 * smbios_string_table_len() - compute the string area size 53 * 54 * This computes the size of the string area including the string terminator. 55 * 56 * @start: string area start address 57 * @return: string area size 58 */ 59 static int smbios_string_table_len(char *start) 60 { 61 char *p = start; 62 int i, len = 0; 63 64 while (*p) { 65 i = strlen(p) + 1; 66 p += i; 67 len += i; 68 } 69 70 return len + 1; 71 } 72 73 static int smbios_write_type0(ulong *current, int handle) 74 { 75 struct smbios_type0 *t = (struct smbios_type0 *)*current; 76 int len = sizeof(struct smbios_type0); 77 78 memset(t, 0, sizeof(struct smbios_type0)); 79 fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, handle); 80 t->vendor = smbios_add_string(t->eos, "U-Boot"); 81 t->bios_ver = smbios_add_string(t->eos, PLAIN_VERSION); 82 t->bios_release_date = smbios_add_string(t->eos, U_BOOT_DMI_DATE); 83 #ifdef CONFIG_ROM_SIZE 84 t->bios_rom_size = (CONFIG_ROM_SIZE / 65536) - 1; 85 #endif 86 t->bios_characteristics = BIOS_CHARACTERISTICS_PCI_SUPPORTED | 87 BIOS_CHARACTERISTICS_SELECTABLE_BOOT | 88 BIOS_CHARACTERISTICS_UPGRADEABLE; 89 #ifdef CONFIG_GENERATE_ACPI_TABLE 90 t->bios_characteristics_ext1 = BIOS_CHARACTERISTICS_EXT1_ACPI; 91 #endif 92 #ifdef CONFIG_EFI_LOADER 93 t->bios_characteristics_ext1 |= BIOS_CHARACTERISTICS_EXT1_UEFI; 94 #endif 95 t->bios_characteristics_ext2 = BIOS_CHARACTERISTICS_EXT2_TARGET; 96 97 t->bios_major_release = 0xff; 98 t->bios_minor_release = 0xff; 99 t->ec_major_release = 0xff; 100 t->ec_minor_release = 0xff; 101 102 len = t->length + smbios_string_table_len(t->eos); 103 *current += len; 104 105 return len; 106 } 107 108 static int smbios_write_type1(ulong *current, int handle) 109 { 110 struct smbios_type1 *t = (struct smbios_type1 *)*current; 111 int len = sizeof(struct smbios_type1); 112 char *serial_str = env_get("serial#"); 113 114 memset(t, 0, sizeof(struct smbios_type1)); 115 fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle); 116 t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); 117 t->product_name = smbios_add_string(t->eos, CONFIG_SMBIOS_PRODUCT_NAME); 118 if (serial_str) { 119 strncpy((char *)t->uuid, serial_str, sizeof(t->uuid)); 120 t->serial_number = smbios_add_string(t->eos, serial_str); 121 } 122 123 len = t->length + smbios_string_table_len(t->eos); 124 *current += len; 125 126 return len; 127 } 128 129 static int smbios_write_type2(ulong *current, int handle) 130 { 131 struct smbios_type2 *t = (struct smbios_type2 *)*current; 132 int len = sizeof(struct smbios_type2); 133 134 memset(t, 0, sizeof(struct smbios_type2)); 135 fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle); 136 t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); 137 t->product_name = smbios_add_string(t->eos, CONFIG_SMBIOS_PRODUCT_NAME); 138 t->feature_flags = SMBIOS_BOARD_FEATURE_HOSTING; 139 t->board_type = SMBIOS_BOARD_MOTHERBOARD; 140 141 len = t->length + smbios_string_table_len(t->eos); 142 *current += len; 143 144 return len; 145 } 146 147 static int smbios_write_type3(ulong *current, int handle) 148 { 149 struct smbios_type3 *t = (struct smbios_type3 *)*current; 150 int len = sizeof(struct smbios_type3); 151 152 memset(t, 0, sizeof(struct smbios_type3)); 153 fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle); 154 t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); 155 t->chassis_type = SMBIOS_ENCLOSURE_DESKTOP; 156 t->bootup_state = SMBIOS_STATE_SAFE; 157 t->power_supply_state = SMBIOS_STATE_SAFE; 158 t->thermal_state = SMBIOS_STATE_SAFE; 159 t->security_status = SMBIOS_SECURITY_NONE; 160 161 len = t->length + smbios_string_table_len(t->eos); 162 *current += len; 163 164 return len; 165 } 166 167 static void smbios_write_type4_dm(struct smbios_type4 *t) 168 { 169 u16 processor_family = SMBIOS_PROCESSOR_FAMILY_UNKNOWN; 170 const char *vendor = "Unknown"; 171 const char *name = "Unknown"; 172 173 #ifdef CONFIG_CPU 174 char processor_name[49]; 175 char vendor_name[49]; 176 struct udevice *dev = NULL; 177 178 uclass_find_first_device(UCLASS_CPU, &dev); 179 if (dev) { 180 struct cpu_platdata *plat = dev_get_parent_platdata(dev); 181 182 if (plat->family) 183 processor_family = plat->family; 184 t->processor_id[0] = plat->id[0]; 185 t->processor_id[1] = plat->id[1]; 186 187 if (!cpu_get_vendor(dev, vendor_name, sizeof(vendor_name))) 188 vendor = vendor_name; 189 if (!cpu_get_desc(dev, processor_name, sizeof(processor_name))) 190 name = processor_name; 191 } 192 #endif 193 194 t->processor_family = processor_family; 195 t->processor_manufacturer = smbios_add_string(t->eos, vendor); 196 t->processor_version = smbios_add_string(t->eos, name); 197 } 198 199 static int smbios_write_type4(ulong *current, int handle) 200 { 201 struct smbios_type4 *t = (struct smbios_type4 *)*current; 202 int len = sizeof(struct smbios_type4); 203 204 memset(t, 0, sizeof(struct smbios_type4)); 205 fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle); 206 t->processor_type = SMBIOS_PROCESSOR_TYPE_CENTRAL; 207 smbios_write_type4_dm(t); 208 t->status = SMBIOS_PROCESSOR_STATUS_ENABLED; 209 t->processor_upgrade = SMBIOS_PROCESSOR_UPGRADE_NONE; 210 t->l1_cache_handle = 0xffff; 211 t->l2_cache_handle = 0xffff; 212 t->l3_cache_handle = 0xffff; 213 t->processor_family2 = t->processor_family; 214 215 len = t->length + smbios_string_table_len(t->eos); 216 *current += len; 217 218 return len; 219 } 220 221 static int smbios_write_type32(ulong *current, int handle) 222 { 223 struct smbios_type32 *t = (struct smbios_type32 *)*current; 224 int len = sizeof(struct smbios_type32); 225 226 memset(t, 0, sizeof(struct smbios_type32)); 227 fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle); 228 229 *current += len; 230 231 return len; 232 } 233 234 static int smbios_write_type127(ulong *current, int handle) 235 { 236 struct smbios_type127 *t = (struct smbios_type127 *)*current; 237 int len = sizeof(struct smbios_type127); 238 239 memset(t, 0, sizeof(struct smbios_type127)); 240 fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle); 241 242 *current += len; 243 244 return len; 245 } 246 247 static smbios_write_type smbios_write_funcs[] = { 248 smbios_write_type0, 249 smbios_write_type1, 250 smbios_write_type2, 251 smbios_write_type3, 252 smbios_write_type4, 253 smbios_write_type32, 254 smbios_write_type127 255 }; 256 257 ulong write_smbios_table(ulong addr) 258 { 259 struct smbios_entry *se; 260 ulong tables; 261 int len = 0; 262 int max_struct_size = 0; 263 int handle = 0; 264 char *istart; 265 int isize; 266 int i; 267 268 /* 16 byte align the table address */ 269 addr = ALIGN(addr, 16); 270 271 se = (struct smbios_entry *)(uintptr_t)addr; 272 memset(se, 0, sizeof(struct smbios_entry)); 273 274 addr += sizeof(struct smbios_entry); 275 addr = ALIGN(addr, 16); 276 tables = addr; 277 278 /* populate minimum required tables */ 279 for (i = 0; i < ARRAY_SIZE(smbios_write_funcs); i++) { 280 int tmp = smbios_write_funcs[i]((ulong *)&addr, handle++); 281 282 max_struct_size = max(max_struct_size, tmp); 283 len += tmp; 284 } 285 286 memcpy(se->anchor, "_SM_", 4); 287 se->length = sizeof(struct smbios_entry); 288 se->major_ver = SMBIOS_MAJOR_VER; 289 se->minor_ver = SMBIOS_MINOR_VER; 290 se->max_struct_size = max_struct_size; 291 memcpy(se->intermediate_anchor, "_DMI_", 5); 292 se->struct_table_length = len; 293 se->struct_table_address = tables; 294 se->struct_count = handle; 295 296 /* calculate checksums */ 297 istart = (char *)se + SMBIOS_INTERMEDIATE_OFFSET; 298 isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET; 299 se->intermediate_checksum = table_compute_checksum(istart, isize); 300 se->checksum = table_compute_checksum(se, sizeof(struct smbios_entry)); 301 302 return addr; 303 } 304