1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
5 * Adapted from coreboot src/arch/x86/smbios.c
13 #include <tables_csum.h>
17 #include <dm/uclass-internal.h>
21 * struct smbios_write_method - Information about a table-writing function
23 * @write: Function to call
24 * @subnode_name: Name of subnode which has the information for this function,
27 struct smbios_write_method {
28 smbios_write_type write;
29 const char *subnode_name;
33 * smbios_add_string() - add a string to the string area
35 * This adds a string to the string area which is appended directly after
36 * the formatted portion of an SMBIOS structure.
38 * @start: string area start address
40 * @return: string number in the string area (1 or more)
42 static int smbios_add_string(char *start, const char *str)
68 * smbios_add_prop() - Add a property from the device tree
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)
75 static int smbios_add_prop(char *start, ofnode node, const char *prop)
78 if (IS_ENABLED(CONFIG_OF_CONTROL)) {
81 str = ofnode_read_string(node, prop);
83 return smbios_add_string(start, str);
90 * smbios_string_table_len() - compute the string area size
92 * This computes the size of the string area including the string terminator.
94 * @start: string area start address
95 * @return: string area size
97 static int smbios_string_table_len(char *start)
111 static int smbios_write_type0(ulong *current, int handle, ofnode node)
113 struct smbios_type0 *t;
114 int len = sizeof(struct smbios_type0);
116 t = map_sysmem(*current, len);
117 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);
122 #ifdef CONFIG_ROM_SIZE
123 t->bios_rom_size = (CONFIG_ROM_SIZE / 65536) - 1;
125 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;
131 #ifdef CONFIG_EFI_LOADER
132 t->bios_characteristics_ext1 |= BIOS_CHARACTERISTICS_EXT1_UEFI;
134 t->bios_characteristics_ext2 = BIOS_CHARACTERISTICS_EXT2_TARGET;
136 t->bios_major_release = 0xff;
137 t->bios_minor_release = 0xff;
138 t->ec_major_release = 0xff;
139 t->ec_minor_release = 0xff;
141 len = t->length + smbios_string_table_len(t->eos);
148 static int smbios_write_type1(ulong *current, int handle, ofnode node)
150 struct smbios_type1 *t;
151 int len = sizeof(struct smbios_type1);
152 char *serial_str = env_get("serial#");
154 t = map_sysmem(*current, len);
155 memset(t, 0, sizeof(struct smbios_type1));
156 fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle);
157 t->manufacturer = smbios_add_prop(t->eos, node, "manufacturer");
158 t->product_name = smbios_add_prop(t->eos, node, "product");
159 t->version = smbios_add_prop(t->eos, node, "version");
161 t->serial_number = smbios_add_string(t->eos, serial_str);
162 strncpy((char *)t->uuid, serial_str, sizeof(t->uuid));
164 t->serial_number = smbios_add_prop(t->eos, node, "serial");
166 t->sku_number = smbios_add_prop(t->eos, node, "sku");
167 t->family = smbios_add_prop(t->eos, node, "family");
169 len = t->length + smbios_string_table_len(t->eos);
176 static int smbios_write_type2(ulong *current, int handle, ofnode node)
178 struct smbios_type2 *t;
179 int len = sizeof(struct smbios_type2);
181 t = map_sysmem(*current, len);
182 memset(t, 0, sizeof(struct smbios_type2));
183 fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle);
184 t->manufacturer = smbios_add_prop(t->eos, node, "manufacturer");
185 t->product_name = smbios_add_prop(t->eos, node, "product");
186 t->asset_tag_number = smbios_add_prop(t->eos, node, "asset-tag");
187 t->feature_flags = SMBIOS_BOARD_FEATURE_HOSTING;
188 t->board_type = SMBIOS_BOARD_MOTHERBOARD;
190 len = t->length + smbios_string_table_len(t->eos);
197 static int smbios_write_type3(ulong *current, int handle, ofnode node)
199 struct smbios_type3 *t;
200 int len = sizeof(struct smbios_type3);
202 t = map_sysmem(*current, len);
203 memset(t, 0, sizeof(struct smbios_type3));
204 fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle);
205 t->manufacturer = smbios_add_prop(t->eos, node, "manufacturer");
206 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;
212 len = t->length + smbios_string_table_len(t->eos);
219 static void smbios_write_type4_dm(struct smbios_type4 *t, ofnode node)
221 u16 processor_family = SMBIOS_PROCESSOR_FAMILY_UNKNOWN;
222 const char *vendor = "Unknown";
223 const char *name = "Unknown";
226 char processor_name[49];
227 char vendor_name[49];
228 struct udevice *cpu = NULL;
230 uclass_find_first_device(UCLASS_CPU, &cpu);
232 struct cpu_platdata *plat = dev_get_parent_plat(cpu);
235 processor_family = plat->family;
236 t->processor_id[0] = plat->id[0];
237 t->processor_id[1] = plat->id[1];
239 if (!cpu_get_vendor(cpu, vendor_name, sizeof(vendor_name)))
240 vendor = vendor_name;
241 if (!cpu_get_desc(cpu, processor_name, sizeof(processor_name)))
242 name = processor_name;
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);
251 static int smbios_write_type4(ulong *current, int handle, ofnode node)
253 struct smbios_type4 *t;
254 int len = sizeof(struct smbios_type4);
256 t = map_sysmem(*current, len);
257 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;
260 smbios_write_type4_dm(t, node);
261 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;
268 len = t->length + smbios_string_table_len(t->eos);
275 static int smbios_write_type32(ulong *current, int handle, ofnode node)
277 struct smbios_type32 *t;
278 int len = sizeof(struct smbios_type32);
280 t = map_sysmem(*current, len);
281 memset(t, 0, sizeof(struct smbios_type32));
282 fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle);
290 static int smbios_write_type127(ulong *current, int handle, ofnode node)
292 struct smbios_type127 *t;
293 int len = sizeof(struct smbios_type127);
295 t = map_sysmem(*current, len);
296 memset(t, 0, sizeof(struct smbios_type127));
297 fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle);
305 static 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 },
315 ulong write_smbios_table(ulong addr)
317 ofnode parent_node = ofnode_null();
318 struct smbios_entry *se;
323 int max_struct_size = 0;
329 if (IS_ENABLED(CONFIG_OF_CONTROL)) {
330 uclass_first_device(UCLASS_SYSINFO, &dev);
332 parent_node = dev_read_subnode(dev, "smbios");
335 /* 16 byte align the table address */
336 addr = ALIGN(addr, 16);
338 se = map_sysmem(addr, sizeof(struct smbios_entry));
339 memset(se, 0, sizeof(struct smbios_entry));
341 addr += sizeof(struct smbios_entry);
342 addr = ALIGN(addr, 16);
345 /* populate minimum required tables */
346 for (i = 0; i < ARRAY_SIZE(smbios_write_funcs); i++) {
347 const struct smbios_write_method *method;
348 ofnode node = ofnode_null();
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);
357 max_struct_size = max(max_struct_size, tmp);
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;
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.
374 table_addr = (ulong)map_sysmem(tables, 0);
375 if (sizeof(table_addr) > sizeof(u32) && table_addr > (ulong)UINT_MAX) {
377 * We need to put this >32-bit pointer into the table but the
378 * field is only 32 bits wide.
380 printf("WARNING: SMBIOS table_address overflow %llx\n",
381 (unsigned long long)table_addr);
384 se->struct_table_address = table_addr;
386 se->struct_count = handle;
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));