blob: 485a812c77685742a4098dadc83f0ea6b14ccdba [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Bin Meng721e9922015-10-12 05:23:41 -07002/*
3 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
4 *
5 * Adapted from coreboot src/arch/x86/smbios.c
Bin Meng721e9922015-10-12 05:23:41 -07006 */
7
8#include <common.h>
Simon Glass78227d42020-11-05 06:32:07 -07009#include <dm.h>
Simon Glass7b51b572019-08-01 09:46:52 -060010#include <env.h>
Simon Glassa2505fc2018-11-22 13:46:37 -070011#include <mapmem.h>
Alexander Graf4b6dddc2016-08-19 01:23:23 +020012#include <smbios.h>
13#include <tables_csum.h>
Bin Meng721e9922015-10-12 05:23:41 -070014#include <version.h>
Alexander Graf96476202016-08-19 01:23:28 +020015#ifdef CONFIG_CPU
16#include <cpu.h>
Alexander Graf96476202016-08-19 01:23:28 +020017#include <dm/uclass-internal.h>
18#endif
Bin Meng721e9922015-10-12 05:23:41 -070019
Bin Meng721e9922015-10-12 05:23:41 -070020/**
Simon Glass44ffb6f2020-11-05 06:32:08 -070021 * struct smbios_write_method - Information about a table-writing function
22 *
23 * @write: Function to call
24 * @subnode_name: Name of subnode which has the information for this function,
25 * NULL if none
26 */
27struct smbios_write_method {
28 smbios_write_type write;
29 const char *subnode_name;
30};
31
32/**
Bin Meng721e9922015-10-12 05:23:41 -070033 * smbios_add_string() - add a string to the string area
34 *
35 * This adds a string to the string area which is appended directly after
36 * the formatted portion of an SMBIOS structure.
37 *
38 * @start: string area start address
39 * @str: string to add
Simon Glass78227d42020-11-05 06:32:07 -070040 * @return: string number in the string area (1 or more)
Bin Meng721e9922015-10-12 05:23:41 -070041 */
42static int smbios_add_string(char *start, const char *str)
43{
44 int i = 1;
45 char *p = start;
Heinrich Schuchardt00a871d2020-06-01 15:44:00 +020046 if (!*str)
47 str = "Unknown";
Bin Meng721e9922015-10-12 05:23:41 -070048
49 for (;;) {
50 if (!*p) {
51 strcpy(p, str);
52 p += strlen(str);
53 *p++ = '\0';
54 *p++ = '\0';
55
56 return i;
57 }
58
59 if (!strcmp(p, str))
60 return i;
61
62 p += strlen(p) + 1;
63 i++;
64 }
65}
66
67/**
Simon Glass44ffb6f2020-11-05 06:32:08 -070068 * smbios_add_prop() - Add a property from the device tree
69 *
70 * @start: string area start address
71 * @node: node containing the information to write (ofnode_null() if none)
72 * @prop: property to write
73 * @return 0 if not found, else SMBIOS string number (1 or more)
74 */
75static int smbios_add_prop(char *start, ofnode node, const char *prop)
76{
Simon Glasse4f8e542020-11-05 06:32:18 -070077
78 if (IS_ENABLED(CONFIG_OF_CONTROL)) {
79 const char *str;
80
81 str = ofnode_read_string(node, prop);
82 if (str)
83 return smbios_add_string(start, str);
84 }
85
86 return 0;
Simon Glass44ffb6f2020-11-05 06:32:08 -070087}
88
89/**
Bin Meng721e9922015-10-12 05:23:41 -070090 * smbios_string_table_len() - compute the string area size
91 *
92 * This computes the size of the string area including the string terminator.
93 *
94 * @start: string area start address
95 * @return: string area size
96 */
97static int smbios_string_table_len(char *start)
98{
99 char *p = start;
100 int i, len = 0;
101
102 while (*p) {
103 i = strlen(p) + 1;
104 p += i;
105 len += i;
106 }
107
108 return len + 1;
109}
110
Simon Glass78227d42020-11-05 06:32:07 -0700111static int smbios_write_type0(ulong *current, int handle, ofnode node)
Bin Meng721e9922015-10-12 05:23:41 -0700112{
Simon Glassa2505fc2018-11-22 13:46:37 -0700113 struct smbios_type0 *t;
Bin Meng721e9922015-10-12 05:23:41 -0700114 int len = sizeof(struct smbios_type0);
115
Simon Glassa2505fc2018-11-22 13:46:37 -0700116 t = map_sysmem(*current, len);
Bin Meng721e9922015-10-12 05:23:41 -0700117 memset(t, 0, sizeof(struct smbios_type0));
118 fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, handle);
119 t->vendor = smbios_add_string(t->eos, "U-Boot");
120 t->bios_ver = smbios_add_string(t->eos, PLAIN_VERSION);
121 t->bios_release_date = smbios_add_string(t->eos, U_BOOT_DMI_DATE);
Alexander Grafe663b352016-08-19 01:23:29 +0200122#ifdef CONFIG_ROM_SIZE
Bin Meng721e9922015-10-12 05:23:41 -0700123 t->bios_rom_size = (CONFIG_ROM_SIZE / 65536) - 1;
Alexander Grafe663b352016-08-19 01:23:29 +0200124#endif
Bin Meng721e9922015-10-12 05:23:41 -0700125 t->bios_characteristics = BIOS_CHARACTERISTICS_PCI_SUPPORTED |
126 BIOS_CHARACTERISTICS_SELECTABLE_BOOT |
127 BIOS_CHARACTERISTICS_UPGRADEABLE;
128#ifdef CONFIG_GENERATE_ACPI_TABLE
129 t->bios_characteristics_ext1 = BIOS_CHARACTERISTICS_EXT1_ACPI;
130#endif
Alexander Grafe663b352016-08-19 01:23:29 +0200131#ifdef CONFIG_EFI_LOADER
132 t->bios_characteristics_ext1 |= BIOS_CHARACTERISTICS_EXT1_UEFI;
133#endif
Bin Meng721e9922015-10-12 05:23:41 -0700134 t->bios_characteristics_ext2 = BIOS_CHARACTERISTICS_EXT2_TARGET;
Alexander Grafe663b352016-08-19 01:23:29 +0200135
Bin Meng721e9922015-10-12 05:23:41 -0700136 t->bios_major_release = 0xff;
137 t->bios_minor_release = 0xff;
138 t->ec_major_release = 0xff;
139 t->ec_minor_release = 0xff;
140
141 len = t->length + smbios_string_table_len(t->eos);
142 *current += len;
Simon Glassa2505fc2018-11-22 13:46:37 -0700143 unmap_sysmem(t);
Bin Meng721e9922015-10-12 05:23:41 -0700144
145 return len;
146}
147
Simon Glass78227d42020-11-05 06:32:07 -0700148static int smbios_write_type1(ulong *current, int handle, ofnode node)
Bin Meng721e9922015-10-12 05:23:41 -0700149{
Simon Glassa2505fc2018-11-22 13:46:37 -0700150 struct smbios_type1 *t;
Bin Meng721e9922015-10-12 05:23:41 -0700151 int len = sizeof(struct smbios_type1);
Simon Glass00caae62017-08-03 12:22:12 -0600152 char *serial_str = env_get("serial#");
Bin Meng721e9922015-10-12 05:23:41 -0700153
Simon Glassa2505fc2018-11-22 13:46:37 -0700154 t = map_sysmem(*current, len);
Bin Meng721e9922015-10-12 05:23:41 -0700155 memset(t, 0, sizeof(struct smbios_type1));
156 fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle);
Simon Glasse4f8e542020-11-05 06:32:18 -0700157 t->manufacturer = smbios_add_prop(t->eos, node, "manufacturer");
158 t->product_name = smbios_add_prop(t->eos, node, "product");
Simon Glassa3f5c8e2020-11-05 06:32:09 -0700159 t->version = smbios_add_prop(t->eos, node, "version");
Alexander Graf6fb580d2016-08-19 01:23:31 +0200160 if (serial_str) {
Alexander Graf6fb580d2016-08-19 01:23:31 +0200161 t->serial_number = smbios_add_string(t->eos, serial_str);
Simon Glass44ffb6f2020-11-05 06:32:08 -0700162 strncpy((char *)t->uuid, serial_str, sizeof(t->uuid));
163 } else {
164 t->serial_number = smbios_add_prop(t->eos, node, "serial");
Alexander Graf6fb580d2016-08-19 01:23:31 +0200165 }
Simon Glassa3f5c8e2020-11-05 06:32:09 -0700166 t->sku_number = smbios_add_prop(t->eos, node, "sku");
167 t->family = smbios_add_prop(t->eos, node, "family");
Bin Meng721e9922015-10-12 05:23:41 -0700168
169 len = t->length + smbios_string_table_len(t->eos);
170 *current += len;
Simon Glassa2505fc2018-11-22 13:46:37 -0700171 unmap_sysmem(t);
Bin Meng721e9922015-10-12 05:23:41 -0700172
173 return len;
174}
175
Simon Glass78227d42020-11-05 06:32:07 -0700176static int smbios_write_type2(ulong *current, int handle, ofnode node)
Bin Meng721e9922015-10-12 05:23:41 -0700177{
Simon Glassa2505fc2018-11-22 13:46:37 -0700178 struct smbios_type2 *t;
Bin Meng721e9922015-10-12 05:23:41 -0700179 int len = sizeof(struct smbios_type2);
180
Simon Glassa2505fc2018-11-22 13:46:37 -0700181 t = map_sysmem(*current, len);
Bin Meng721e9922015-10-12 05:23:41 -0700182 memset(t, 0, sizeof(struct smbios_type2));
183 fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle);
Simon Glasse4f8e542020-11-05 06:32:18 -0700184 t->manufacturer = smbios_add_prop(t->eos, node, "manufacturer");
185 t->product_name = smbios_add_prop(t->eos, node, "product");
Simon Glassa3f5c8e2020-11-05 06:32:09 -0700186 t->asset_tag_number = smbios_add_prop(t->eos, node, "asset-tag");
Bin Meng721e9922015-10-12 05:23:41 -0700187 t->feature_flags = SMBIOS_BOARD_FEATURE_HOSTING;
188 t->board_type = SMBIOS_BOARD_MOTHERBOARD;
189
190 len = t->length + smbios_string_table_len(t->eos);
191 *current += len;
Simon Glassa2505fc2018-11-22 13:46:37 -0700192 unmap_sysmem(t);
Bin Meng721e9922015-10-12 05:23:41 -0700193
194 return len;
195}
196
Simon Glass78227d42020-11-05 06:32:07 -0700197static int smbios_write_type3(ulong *current, int handle, ofnode node)
Bin Meng721e9922015-10-12 05:23:41 -0700198{
Simon Glassa2505fc2018-11-22 13:46:37 -0700199 struct smbios_type3 *t;
Bin Meng721e9922015-10-12 05:23:41 -0700200 int len = sizeof(struct smbios_type3);
201
Simon Glassa2505fc2018-11-22 13:46:37 -0700202 t = map_sysmem(*current, len);
Bin Meng721e9922015-10-12 05:23:41 -0700203 memset(t, 0, sizeof(struct smbios_type3));
204 fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle);
Simon Glasse4f8e542020-11-05 06:32:18 -0700205 t->manufacturer = smbios_add_prop(t->eos, node, "manufacturer");
Bin Meng721e9922015-10-12 05:23:41 -0700206 t->chassis_type = SMBIOS_ENCLOSURE_DESKTOP;
207 t->bootup_state = SMBIOS_STATE_SAFE;
208 t->power_supply_state = SMBIOS_STATE_SAFE;
209 t->thermal_state = SMBIOS_STATE_SAFE;
210 t->security_status = SMBIOS_SECURITY_NONE;
211
212 len = t->length + smbios_string_table_len(t->eos);
213 *current += len;
Simon Glassa2505fc2018-11-22 13:46:37 -0700214 unmap_sysmem(t);
Bin Meng721e9922015-10-12 05:23:41 -0700215
216 return len;
217}
218
Simon Glass78227d42020-11-05 06:32:07 -0700219static void smbios_write_type4_dm(struct smbios_type4 *t, ofnode node)
Alexander Graf96476202016-08-19 01:23:28 +0200220{
221 u16 processor_family = SMBIOS_PROCESSOR_FAMILY_UNKNOWN;
222 const char *vendor = "Unknown";
223 const char *name = "Unknown";
224
225#ifdef CONFIG_CPU
226 char processor_name[49];
227 char vendor_name[49];
Simon Glass78227d42020-11-05 06:32:07 -0700228 struct udevice *cpu = NULL;
Alexander Graf96476202016-08-19 01:23:28 +0200229
Simon Glass78227d42020-11-05 06:32:07 -0700230 uclass_find_first_device(UCLASS_CPU, &cpu);
231 if (cpu) {
232 struct cpu_platdata *plat = dev_get_parent_platdata(cpu);
Alexander Graf96476202016-08-19 01:23:28 +0200233
234 if (plat->family)
235 processor_family = plat->family;
236 t->processor_id[0] = plat->id[0];
237 t->processor_id[1] = plat->id[1];
238
Simon Glass78227d42020-11-05 06:32:07 -0700239 if (!cpu_get_vendor(cpu, vendor_name, sizeof(vendor_name)))
Alexander Graf96476202016-08-19 01:23:28 +0200240 vendor = vendor_name;
Simon Glass78227d42020-11-05 06:32:07 -0700241 if (!cpu_get_desc(cpu, processor_name, sizeof(processor_name)))
Alexander Graf96476202016-08-19 01:23:28 +0200242 name = processor_name;
243 }
244#endif
245
246 t->processor_family = processor_family;
247 t->processor_manufacturer = smbios_add_string(t->eos, vendor);
248 t->processor_version = smbios_add_string(t->eos, name);
249}
250
Simon Glass78227d42020-11-05 06:32:07 -0700251static int smbios_write_type4(ulong *current, int handle, ofnode node)
Bin Meng721e9922015-10-12 05:23:41 -0700252{
Simon Glassa2505fc2018-11-22 13:46:37 -0700253 struct smbios_type4 *t;
Bin Meng721e9922015-10-12 05:23:41 -0700254 int len = sizeof(struct smbios_type4);
Bin Meng721e9922015-10-12 05:23:41 -0700255
Simon Glassa2505fc2018-11-22 13:46:37 -0700256 t = map_sysmem(*current, len);
Bin Meng721e9922015-10-12 05:23:41 -0700257 memset(t, 0, sizeof(struct smbios_type4));
258 fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle);
259 t->processor_type = SMBIOS_PROCESSOR_TYPE_CENTRAL;
Simon Glass78227d42020-11-05 06:32:07 -0700260 smbios_write_type4_dm(t, node);
Bin Meng721e9922015-10-12 05:23:41 -0700261 t->status = SMBIOS_PROCESSOR_STATUS_ENABLED;
262 t->processor_upgrade = SMBIOS_PROCESSOR_UPGRADE_NONE;
263 t->l1_cache_handle = 0xffff;
264 t->l2_cache_handle = 0xffff;
265 t->l3_cache_handle = 0xffff;
266 t->processor_family2 = t->processor_family;
267
268 len = t->length + smbios_string_table_len(t->eos);
269 *current += len;
Simon Glassa2505fc2018-11-22 13:46:37 -0700270 unmap_sysmem(t);
Bin Meng721e9922015-10-12 05:23:41 -0700271
272 return len;
273}
274
Simon Glass78227d42020-11-05 06:32:07 -0700275static int smbios_write_type32(ulong *current, int handle, ofnode node)
Bin Meng721e9922015-10-12 05:23:41 -0700276{
Simon Glassa2505fc2018-11-22 13:46:37 -0700277 struct smbios_type32 *t;
Bin Meng721e9922015-10-12 05:23:41 -0700278 int len = sizeof(struct smbios_type32);
279
Simon Glassa2505fc2018-11-22 13:46:37 -0700280 t = map_sysmem(*current, len);
Bin Meng721e9922015-10-12 05:23:41 -0700281 memset(t, 0, sizeof(struct smbios_type32));
282 fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle);
283
284 *current += len;
Simon Glassa2505fc2018-11-22 13:46:37 -0700285 unmap_sysmem(t);
Bin Meng721e9922015-10-12 05:23:41 -0700286
287 return len;
288}
289
Simon Glass78227d42020-11-05 06:32:07 -0700290static int smbios_write_type127(ulong *current, int handle, ofnode node)
Bin Meng721e9922015-10-12 05:23:41 -0700291{
Simon Glassa2505fc2018-11-22 13:46:37 -0700292 struct smbios_type127 *t;
Bin Meng721e9922015-10-12 05:23:41 -0700293 int len = sizeof(struct smbios_type127);
294
Simon Glassa2505fc2018-11-22 13:46:37 -0700295 t = map_sysmem(*current, len);
Bin Meng721e9922015-10-12 05:23:41 -0700296 memset(t, 0, sizeof(struct smbios_type127));
297 fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle);
298
299 *current += len;
Simon Glassa2505fc2018-11-22 13:46:37 -0700300 unmap_sysmem(t);
Bin Meng721e9922015-10-12 05:23:41 -0700301
302 return len;
303}
304
Simon Glass44ffb6f2020-11-05 06:32:08 -0700305static struct smbios_write_method smbios_write_funcs[] = {
306 { smbios_write_type0, },
307 { smbios_write_type1, "system", },
308 { smbios_write_type2, "baseboard", },
309 { smbios_write_type3, "chassis", },
310 { smbios_write_type4, },
311 { smbios_write_type32, },
312 { smbios_write_type127 },
Bin Meng721e9922015-10-12 05:23:41 -0700313};
314
Simon Glass42fd8c12017-01-16 07:03:35 -0700315ulong write_smbios_table(ulong addr)
Bin Meng721e9922015-10-12 05:23:41 -0700316{
Simon Glass44ffb6f2020-11-05 06:32:08 -0700317 ofnode parent_node = ofnode_null();
Bin Meng721e9922015-10-12 05:23:41 -0700318 struct smbios_entry *se;
Simon Glass78227d42020-11-05 06:32:07 -0700319 struct udevice *dev;
Simon Glassa2505fc2018-11-22 13:46:37 -0700320 ulong table_addr;
Simon Glass42fd8c12017-01-16 07:03:35 -0700321 ulong tables;
Bin Meng721e9922015-10-12 05:23:41 -0700322 int len = 0;
323 int max_struct_size = 0;
324 int handle = 0;
325 char *istart;
326 int isize;
327 int i;
328
Simon Glass78227d42020-11-05 06:32:07 -0700329 if (IS_ENABLED(CONFIG_OF_CONTROL)) {
330 uclass_first_device(UCLASS_SYSINFO, &dev);
331 if (dev)
Simon Glass44ffb6f2020-11-05 06:32:08 -0700332 parent_node = dev_read_subnode(dev, "smbios");
Simon Glass78227d42020-11-05 06:32:07 -0700333 }
334
Bin Meng721e9922015-10-12 05:23:41 -0700335 /* 16 byte align the table address */
336 addr = ALIGN(addr, 16);
337
Simon Glassa2505fc2018-11-22 13:46:37 -0700338 se = map_sysmem(addr, sizeof(struct smbios_entry));
Bin Meng721e9922015-10-12 05:23:41 -0700339 memset(se, 0, sizeof(struct smbios_entry));
340
341 addr += sizeof(struct smbios_entry);
342 addr = ALIGN(addr, 16);
343 tables = addr;
344
345 /* populate minimum required tables */
346 for (i = 0; i < ARRAY_SIZE(smbios_write_funcs); i++) {
Simon Glass44ffb6f2020-11-05 06:32:08 -0700347 const struct smbios_write_method *method;
348 ofnode node = ofnode_null();
349 int tmp;
350
351 method = &smbios_write_funcs[i];
352 if (IS_ENABLED(CONFIG_OF_CONTROL) && method->subnode_name)
353 node = ofnode_find_subnode(parent_node,
354 method->subnode_name);
355 tmp = method->write((ulong *)&addr, handle++, node);
Christian Gmeiner60a4df32018-07-30 13:22:07 +0200356
Bin Meng721e9922015-10-12 05:23:41 -0700357 max_struct_size = max(max_struct_size, tmp);
358 len += tmp;
359 }
360
361 memcpy(se->anchor, "_SM_", 4);
362 se->length = sizeof(struct smbios_entry);
363 se->major_ver = SMBIOS_MAJOR_VER;
364 se->minor_ver = SMBIOS_MINOR_VER;
365 se->max_struct_size = max_struct_size;
366 memcpy(se->intermediate_anchor, "_DMI_", 5);
367 se->struct_table_length = len;
Simon Glassa2505fc2018-11-22 13:46:37 -0700368
369 /*
370 * We must use a pointer here so things work correctly on sandbox. The
371 * user of this table is not aware of the mapping of addresses to
372 * sandbox's DRAM buffer.
373 */
374 table_addr = (ulong)map_sysmem(tables, 0);
375 if (sizeof(table_addr) > sizeof(u32) && table_addr > (ulong)UINT_MAX) {
376 /*
377 * We need to put this >32-bit pointer into the table but the
378 * field is only 32 bits wide.
379 */
380 printf("WARNING: SMBIOS table_address overflow %llx\n",
381 (unsigned long long)table_addr);
382 table_addr = 0;
383 }
384 se->struct_table_address = table_addr;
385
Bin Meng721e9922015-10-12 05:23:41 -0700386 se->struct_count = handle;
387
388 /* calculate checksums */
389 istart = (char *)se + SMBIOS_INTERMEDIATE_OFFSET;
390 isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET;
391 se->intermediate_checksum = table_compute_checksum(istart, isize);
392 se->checksum = table_compute_checksum(se, sizeof(struct smbios_entry));
Simon Glassa2505fc2018-11-22 13:46:37 -0700393 unmap_sysmem(se);
Bin Meng721e9922015-10-12 05:23:41 -0700394
395 return addr;
396}