blob: dcf12bf73c67d6e4470485fd29f633a62f539bc8 [file] [log] [blame]
Benjamin Doronea13dc32023-06-20 12:21:27 -04001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <assert.h>
4#include <string.h>
5#include <smbios.h>
6#include <console/console.h>
7#include <version.h>
8#include <device/device.h>
9#include <device/dram/spd.h>
10#include <elog.h>
11#include <endian.h>
12#include <memory_info.h>
13#include <spd.h>
14#include <cbmem.h>
15#include <commonlib/helpers.h>
16#include <device/pci_ids.h>
17#include <device/pci.h>
Benjamin Doronea13dc32023-06-20 12:21:27 -040018#include <drivers/vpd/vpd.h>
19#include <stdlib.h>
20
21static u8 smbios_checksum(u8 *p, u32 length)
22{
23 u8 ret = 0;
24 while (length--)
25 ret += *p++;
26 return -ret;
27}
28
29int smbios_add_string(u8 *start, const char *str)
30{
31 int i = 1;
32 char *p = (char *)start;
33
34 /*
35 * Return 0 as required for empty strings.
36 * See Section 6.1.3 "Text Strings" of the SMBIOS specification.
37 */
38 if (str == NULL || *str == '\0')
39 return 0;
40
41 for (;;) {
42 if (!*p) {
43 strcpy(p, str);
44 p += strlen(str);
45 *p++ = '\0';
46 *p++ = '\0';
47 return i;
48 }
49
50 if (!strcmp(p, str))
51 return i;
52
53 p += strlen(p)+1;
54 i++;
55 }
56}
57
58int smbios_string_table_len(u8 *start)
59{
60 char *p = (char *)start;
61 int i, len = 0;
62
63 while (*p) {
64 i = strlen(p) + 1;
65 p += i;
66 len += i;
67 }
68
69 if (!len)
70 return 2;
71
72 return len + 1;
73}
74
75int smbios_full_table_len(struct smbios_header *header, u8 *str_table_start)
76{
77 return header->length + smbios_string_table_len(str_table_start);
78}
79
80void *smbios_carve_table(unsigned long start, u8 type, u8 length, u16 handle)
81{
82 struct smbios_header *t = (struct smbios_header *)start;
83
84 assert(length >= sizeof(*t));
85 memset(t, 0, length);
86 t->type = type;
87 t->length = length - 2;
88 t->handle = handle;
89 return t;
90}
91
92/* this function will fill the corresponding manufacturer */
93void smbios_fill_dimm_manufacturer_from_id(uint16_t mod_id, struct smbios_type17 *t)
94{
95 const char *const manufacturer = spd_manufacturer_name(mod_id);
96
97 if (manufacturer) {
98 t->manufacturer = smbios_add_string(t->eos, manufacturer);
99 } else {
100 char string_buffer[256];
101
102 snprintf(string_buffer, sizeof(string_buffer), "Unknown (%x)", mod_id);
103 t->manufacturer = smbios_add_string(t->eos, string_buffer);
104 }
105}
106
107static void trim_trailing_whitespace(char *buffer, size_t buffer_size)
108{
109 size_t len = strnlen(buffer, buffer_size);
110
111 if (len == 0)
112 return;
113
114 for (char *p = buffer + len - 1; p >= buffer; --p) {
115 if (*p == ' ')
116 *p = 0;
117 else
118 break;
119 }
120}
121
122/** This function will fill the corresponding part number */
123static void smbios_fill_dimm_part_number(const char *part_number, struct smbios_type17 *t)
124{
125 int invalid;
126 size_t i, len;
127 char trimmed_part_number[DIMM_INFO_PART_NUMBER_SIZE];
128
129 strncpy(trimmed_part_number, part_number, sizeof(trimmed_part_number));
130 trimmed_part_number[sizeof(trimmed_part_number) - 1] = '\0';
131
132 /*
133 * SPD mandates that unused characters be represented with a ' '.
134 * We don't want to publish the whitespace in the SMBIOS tables.
135 */
136 trim_trailing_whitespace(trimmed_part_number, sizeof(trimmed_part_number));
137
138 len = strlen(trimmed_part_number);
139
140 invalid = 0; /* assume valid */
141 for (i = 0; i < len; i++) {
142 if (trimmed_part_number[i] < ' ') {
143 invalid = 1;
144 trimmed_part_number[i] = '*';
145 }
146 }
147
148 if (len == 0) {
149 /* Null String in Part Number will have "None" instead. */
150 t->part_number = smbios_add_string(t->eos, "None");
151 } else if (invalid) {
152 char string_buffer[sizeof(trimmed_part_number) + 10];
153
154 snprintf(string_buffer, sizeof(string_buffer), "Invalid (%s)",
155 trimmed_part_number);
156 t->part_number = smbios_add_string(t->eos, string_buffer);
157 } else {
158 t->part_number = smbios_add_string(t->eos, trimmed_part_number);
159 }
160}
161
162/* Encodes the SPD serial number into hex */
163static void smbios_fill_dimm_serial_number(const struct dimm_info *dimm,
164 struct smbios_type17 *t)
165{
166 char serial[9];
167
168 snprintf(serial, sizeof(serial), "%02hhx%02hhx%02hhx%02hhx",
169 dimm->serial[0], dimm->serial[1], dimm->serial[2], dimm->serial[3]);
170
171 t->serial_number = smbios_add_string(t->eos, serial);
172}
173
174static const char *memory_device_type(u8 code)
175{
176 /* SMBIOS spec 3.6 7.18.2 */
177 static const char * const type[] = {
178 "Other",
179 "Unknown",
180 "DRAM",
181 "EDRAM",
182 "VRAM",
183 "SRAM",
184 "RAM",
185 "ROM",
186 "Flash",
187 "EEPROM",
188 "FEPROM",
189 "EPROM",
190 "CDRAM",
191 "3DRAM",
192 "SDRAM",
193 "SGRAM",
194 "RDRAM",
195 "DDR",
196 "DDR2",
197 "DDR2 FB-DIMM",
198 "Reserved",
199 "Reserved",
200 "Reserved",
201 "DDR3",
202 "FBD2",
203 "DDR4", /* 0x1A */
204 "LPDDR",
205 "LPDDR2",
206 "LPDDR3",
207 "LPDDR4",
208 "Logical non-volatile device",
209 "HBM",
210 "HBM2",
211 "DDR5",
212 "LPDDR5",
213 "HBM3", /* 0x24 */
214 };
215
216 if (code >= MEMORY_TYPE_OTHER && code <= MEMORY_TYPE_HBM3)
217 return type[code - 1];
Martin Roth3e25f852023-09-04 15:37:07 -0600218 return "Unsupported";
Benjamin Doronea13dc32023-06-20 12:21:27 -0400219}
220
221static void dump_smbios_type17(struct dimm_info *dimm)
222{
223 printk(BIOS_INFO, "memory at Channel-%d-DIMM-%d", dimm->channel_num, dimm->dimm_num);
224 printk(BIOS_INFO, " type is %s\n", memory_device_type(dimm->ddr_type));
225 printk(BIOS_INFO, "memory part number is %s\n", dimm->module_part_number);
226 if (dimm->max_speed_mts != 0)
227 printk(BIOS_INFO, "memory max speed is %d MT/s\n", dimm->max_speed_mts);
228 printk(BIOS_INFO, "memory speed is %d MT/s\n",
229 dimm->configured_speed_mts ? : dimm->ddr_frequency);
230 printk(BIOS_INFO, "memory size is %d MiB\n", dimm->dimm_size);
231}
232
233static int create_smbios_type17_for_dimm(struct dimm_info *dimm,
234 unsigned long *current, int *handle,
235 int type16_handle)
236{
237 struct spd_info info;
238 get_spd_info(dimm->ddr_type, dimm->mod_type, &info);
239
240 struct smbios_type17 *t = smbios_carve_table(*current, SMBIOS_MEMORY_DEVICE,
241 sizeof(*t), *handle);
242
243 t->memory_type = dimm->ddr_type;
244 if (dimm->configured_speed_mts != 0)
245 t->clock_speed = dimm->configured_speed_mts;
246 else
247 t->clock_speed = dimm->ddr_frequency;
248 if (dimm->max_speed_mts != 0)
249 t->speed = dimm->max_speed_mts;
250 else
251 t->speed = dimm->ddr_frequency;
252 if (dimm->dimm_size < 0x7fff) {
253 t->size = dimm->dimm_size;
254 } else {
255 t->size = 0x7fff;
256 t->extended_size = dimm->dimm_size & 0x7fffffff;
257 }
258 t->data_width = 8 * (1 << (dimm->bus_width & 0x7));
259 t->total_width = t->data_width + 8 * ((dimm->bus_width & 0x18) >> 3);
260 t->form_factor = info.form_factor;
261
262 smbios_fill_dimm_manufacturer_from_id(dimm->mod_id, t);
263 smbios_fill_dimm_serial_number(dimm, t);
264 smbios_fill_dimm_asset_tag(dimm, t);
265 smbios_fill_dimm_locator(dimm, t);
266
267 /* put '\0' in the end of data */
268 dimm->module_part_number[DIMM_INFO_PART_NUMBER_SIZE - 1] = '\0';
269 smbios_fill_dimm_part_number((char *)dimm->module_part_number, t);
270
271 /* Voltage Levels */
272 t->configured_voltage = dimm->vdd_voltage;
273 t->minimum_voltage = dimm->vdd_voltage;
274 t->maximum_voltage = dimm->vdd_voltage;
275
276 /* Fill in type detail */
277 t->type_detail = info.type_detail;
278
279 /* Synchronous = 1 */
280 t->type_detail |= MEMORY_TYPE_DETAIL_SYNCHRONOUS;
281 /* no handle for error information */
282 t->memory_error_information_handle = 0xFFFE;
283 t->attributes = dimm->rank_per_dimm;
284 t->phys_memory_array_handle = type16_handle;
285
286 *handle += 1;
287 return smbios_full_table_len(&t->header, t->eos);
288}
289
290static int create_smbios_type17_for_empty_slot(struct dimm_info *dimm,
291 unsigned long *current, int *handle,
292 int type16_handle)
293{
294 struct smbios_type17 *t = smbios_carve_table(*current, SMBIOS_MEMORY_DEVICE,
295 sizeof(*t), *handle);
296 t->phys_memory_array_handle = type16_handle;
297 /* no handle for error information */
298 t->memory_error_information_handle = 0xfffe;
299 t->total_width = 0xffff; /* Unknown */
300 t->data_width = 0xffff; /* Unknown */
301 t->form_factor = 0x2; /* Unknown */
302 smbios_fill_dimm_locator(dimm, t); /* Device and Bank */
303 t->memory_type = 0x2; /* Unknown */
304 t->type_detail = 0x2; /* Unknown */
305
306 *handle += 1;
307 if (CONFIG(DUMP_SMBIOS_TYPE17))
308 dump_smbios_type17(dimm);
309
310 return smbios_full_table_len(&t->header, t->eos);
311}
312
313#define VERSION_VPD "firmware_version"
314static const char *vpd_get_bios_version(void)
315{
316 int size;
317 const char *s;
318 char *version;
319
320 s = vpd_find(VERSION_VPD, &size, VPD_RO);
321 if (!s) {
322 printk(BIOS_ERR, "Find version from VPD %s failed\n", VERSION_VPD);
323 return NULL;
324 }
325
326 version = malloc(size + 1);
327 if (!version) {
328 printk(BIOS_ERR, "Failed to malloc %d bytes for VPD version\n", size + 1);
329 return NULL;
330 }
331 memcpy(version, s, size);
332 version[size] = '\0';
333 printk(BIOS_DEBUG, "Firmware version %s from VPD %s\n", version, VERSION_VPD);
334 return version;
335}
336
337static const char *get_bios_version(void)
338{
339 const char *s;
340
341#define SPACES \
342 " "
343
344 if (CONFIG(CHROMEOS))
345 return SPACES;
346
347 if (CONFIG(VPD_SMBIOS_VERSION)) {
348 s = vpd_get_bios_version();
349 if (s != NULL)
350 return s;
351 }
352
353 s = smbios_mainboard_bios_version();
354 if (s != NULL)
355 return s;
356
357 if (strlen(CONFIG_LOCALVERSION) != 0) {
358 printk(BIOS_DEBUG, "BIOS version set to CONFIG_LOCALVERSION: '%s'\n",
359 CONFIG_LOCALVERSION);
360 return CONFIG_LOCALVERSION;
361 }
362
363 printk(BIOS_DEBUG, "SMBIOS firmware version is set to coreboot_version: '%s'\n",
364 coreboot_version);
365 return coreboot_version;
366}
367
368static int smbios_write_type0(unsigned long *current, int handle)
369{
370 struct smbios_type0 *t = smbios_carve_table(*current, SMBIOS_BIOS_INFORMATION,
371 sizeof(*t), handle);
372
Hao Wang634c7a42022-06-14 10:56:40 +0800373 t->vendor = smbios_add_string(t->eos, CONFIG_BIOS_VENDOR);
Benjamin Doronea13dc32023-06-20 12:21:27 -0400374 t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date);
375
376 if (CONFIG(CHROMEOS_NVS)) {
377 uintptr_t version_address = (uintptr_t)t->eos;
378 /* SMBIOS offsets start at 1 rather than 0 */
379 version_address += (u32)smbios_string_table_len(t->eos) - 1;
380 smbios_type0_bios_version(version_address);
381 }
382 t->bios_version = smbios_add_string(t->eos, get_bios_version());
383 uint32_t rom_size = CONFIG_ROM_SIZE;
384 rom_size = MIN(CONFIG_ROM_SIZE, 16 * MiB);
385 t->bios_rom_size = (rom_size / 65535) - 1;
386
387 if (CONFIG_ROM_SIZE >= 1 * GiB)
388 t->extended_bios_rom_size = DIV_ROUND_UP(CONFIG_ROM_SIZE, GiB) | (1 << 14);
389 else
390 t->extended_bios_rom_size = DIV_ROUND_UP(CONFIG_ROM_SIZE, MiB);
391
392 t->system_bios_major_release = coreboot_major_revision;
393 t->system_bios_minor_release = coreboot_minor_revision;
394
395 smbios_ec_revision(&t->ec_major_release, &t->ec_minor_release);
396
397 t->bios_characteristics =
398 BIOS_CHARACTERISTICS_PCI_SUPPORTED |
399 BIOS_CHARACTERISTICS_SELECTABLE_BOOT |
400 BIOS_CHARACTERISTICS_UPGRADEABLE;
401
402 if (CONFIG(CARDBUS_PLUGIN_SUPPORT))
403 t->bios_characteristics |= BIOS_CHARACTERISTICS_PC_CARD;
404
405 if (CONFIG(HAVE_ACPI_TABLES))
406 t->bios_characteristics_ext1 = BIOS_EXT1_CHARACTERISTICS_ACPI;
407
408 t->bios_characteristics_ext2 = BIOS_EXT2_CHARACTERISTICS_TARGET;
409 const int len = smbios_full_table_len(&t->header, t->eos);
410 *current += len;
411 return len;
412}
413
414unsigned int __weak smbios_processor_external_clock(void)
415{
416 return 0; /* Unknown */
417}
418
419unsigned int __weak smbios_processor_characteristics(void)
420{
421 return 0;
422}
423
424unsigned int __weak smbios_cache_error_correction_type(u8 level)
425{
426 return SMBIOS_CACHE_ERROR_CORRECTION_UNKNOWN;
427}
428
429unsigned int __weak smbios_cache_sram_type(void)
430{
431 return SMBIOS_CACHE_SRAM_TYPE_UNKNOWN;
432}
433
434unsigned int __weak smbios_cache_conf_operation_mode(u8 level)
435{
436 return SMBIOS_CACHE_OP_MODE_UNKNOWN; /* Unknown */
437}
438
439/* Returns the processor voltage in 100mV units */
440unsigned int __weak smbios_cpu_get_voltage(void)
441{
442 return 0; /* Unknown */
443}
444
445static int smbios_write_type1(unsigned long *current, int handle)
446{
447 struct smbios_type1 *t = smbios_carve_table(*current, SMBIOS_SYSTEM_INFORMATION,
448 sizeof(*t), handle);
449
450 t->manufacturer = smbios_add_string(t->eos, smbios_system_manufacturer());
451 t->product_name = smbios_add_string(t->eos, smbios_system_product_name());
452 t->serial_number = smbios_add_string(t->eos, smbios_system_serial_number());
453 t->wakeup_type = smbios_system_wakeup_type();
454 t->sku = smbios_add_string(t->eos, smbios_system_sku());
455 t->version = smbios_add_string(t->eos, smbios_system_version());
456#ifdef CONFIG_MAINBOARD_FAMILY
457 t->family = smbios_add_string(t->eos, CONFIG_MAINBOARD_FAMILY);
458#endif
459 smbios_system_set_uuid(t->uuid);
460 const int len = smbios_full_table_len(&t->header, t->eos);
461 *current += len;
462 return len;
463}
464
465static int smbios_write_type2(unsigned long *current, int handle, const int chassis_handle)
466{
467 struct smbios_type2 *t = smbios_carve_table(*current, SMBIOS_BOARD_INFORMATION,
468 sizeof(*t), handle);
469
470 t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer());
471 t->product_name = smbios_add_string(t->eos, smbios_mainboard_product_name());
472 t->serial_number = smbios_add_string(t->eos, smbios_mainboard_serial_number());
473 t->version = smbios_add_string(t->eos, smbios_mainboard_version());
474 t->asset_tag = smbios_add_string(t->eos, smbios_mainboard_asset_tag());
475 t->feature_flags = smbios_mainboard_feature_flags();
476 t->location_in_chassis = smbios_add_string(t->eos,
477 smbios_mainboard_location_in_chassis());
478 t->board_type = smbios_mainboard_board_type();
479 t->chassis_handle = chassis_handle;
480 const int len = smbios_full_table_len(&t->header, t->eos);
481 *current += len;
482 return len;
483}
484
485static int smbios_write_type3(unsigned long *current, int handle)
486{
487 struct smbios_type3 *t = smbios_carve_table(*current, SMBIOS_SYSTEM_ENCLOSURE,
488 sizeof(*t), handle);
489
490 t->manufacturer = smbios_add_string(t->eos, smbios_system_manufacturer());
491 t->bootup_state = SMBIOS_STATE_SAFE;
492 t->power_supply_state = SMBIOS_STATE_SAFE;
493 t->thermal_state = SMBIOS_STATE_SAFE;
494 t->_type = smbios_mainboard_enclosure_type();
495 t->security_status = SMBIOS_STATE_SAFE;
496 t->number_of_power_cords = smbios_chassis_power_cords();
497 t->asset_tag_number = smbios_add_string(t->eos, smbios_mainboard_asset_tag());
498 t->version = smbios_add_string(t->eos, smbios_chassis_version());
499 t->serial_number = smbios_add_string(t->eos, smbios_chassis_serial_number());
500 const int len = smbios_full_table_len(&t->header, t->eos);
501 *current += len;
502 return len;
503}
504
505/*
506 * Write SMBIOS type 7.
507 * Fill in some fields with constant values, as gathering the information
508 * from CPUID is impossible.
509 */
510int smbios_write_type7(unsigned long *current,
511 const int handle,
512 const u8 level,
513 const u8 sram_type,
514 const enum smbios_cache_associativity associativity,
515 const enum smbios_cache_type type,
516 const size_t max_cache_size,
517 const size_t cache_size)
518{
519 char buf[8];
520
521 struct smbios_type7 *t = smbios_carve_table(*current, SMBIOS_CACHE_INFORMATION,
522 sizeof(*t), handle);
523
524 snprintf(buf, sizeof(buf), "CACHE%x", level);
525 t->socket_designation = smbios_add_string(t->eos, buf);
526
527 t->cache_configuration = SMBIOS_CACHE_CONF_LEVEL(level) |
528 SMBIOS_CACHE_CONF_LOCATION(0) | /* Internal */
529 SMBIOS_CACHE_CONF_ENABLED(1) | /* Enabled */
530 SMBIOS_CACHE_CONF_OPERATION_MODE(smbios_cache_conf_operation_mode(level));
531
532 if (max_cache_size < (SMBIOS_CACHE_SIZE_MASK * KiB)) {
533 t->max_cache_size = max_cache_size / KiB;
534 t->max_cache_size2 = t->max_cache_size;
535
536 t->max_cache_size |= SMBIOS_CACHE_SIZE_UNIT_1KB;
537 t->max_cache_size2 |= SMBIOS_CACHE_SIZE2_UNIT_1KB;
538 } else {
539 if (max_cache_size < (SMBIOS_CACHE_SIZE_MASK * 64 * KiB))
540 t->max_cache_size = max_cache_size / (64 * KiB);
541 else
542 t->max_cache_size = SMBIOS_CACHE_SIZE_OVERFLOW;
543 t->max_cache_size2 = max_cache_size / (64 * KiB);
544
545 t->max_cache_size |= SMBIOS_CACHE_SIZE_UNIT_64KB;
546 t->max_cache_size2 |= SMBIOS_CACHE_SIZE2_UNIT_64KB;
547 }
548
549 if (cache_size < (SMBIOS_CACHE_SIZE_MASK * KiB)) {
550 t->installed_size = cache_size / KiB;
551 t->installed_size2 = t->installed_size;
552
553 t->installed_size |= SMBIOS_CACHE_SIZE_UNIT_1KB;
554 t->installed_size2 |= SMBIOS_CACHE_SIZE2_UNIT_1KB;
555 } else {
556 if (cache_size < (SMBIOS_CACHE_SIZE_MASK * 64 * KiB))
557 t->installed_size = cache_size / (64 * KiB);
558 else
559 t->installed_size = SMBIOS_CACHE_SIZE_OVERFLOW;
560 t->installed_size2 = cache_size / (64 * KiB);
561
562 t->installed_size |= SMBIOS_CACHE_SIZE_UNIT_64KB;
563 t->installed_size2 |= SMBIOS_CACHE_SIZE2_UNIT_64KB;
564 }
565
566 t->associativity = associativity;
567 t->supported_sram_type = sram_type;
568 t->current_sram_type = sram_type;
569 t->cache_speed = 0; /* Unknown */
570 t->error_correction_type = smbios_cache_error_correction_type(level);
571 t->system_cache_type = type;
572
573 const int len = smbios_full_table_len(&t->header, t->eos);
574 *current += len;
575 return len;
576}
577
578/* Convert the associativity as integer to the SMBIOS enum if available */
579enum smbios_cache_associativity smbios_cache_associativity(const u8 num)
580{
581 switch (num) {
582 case 1:
583 return SMBIOS_CACHE_ASSOCIATIVITY_DIRECT;
584 case 2:
585 return SMBIOS_CACHE_ASSOCIATIVITY_2WAY;
586 case 4:
587 return SMBIOS_CACHE_ASSOCIATIVITY_4WAY;
588 case 8:
589 return SMBIOS_CACHE_ASSOCIATIVITY_8WAY;
590 case 12:
591 return SMBIOS_CACHE_ASSOCIATIVITY_12WAY;
592 case 16:
593 return SMBIOS_CACHE_ASSOCIATIVITY_16WAY;
594 case 20:
595 return SMBIOS_CACHE_ASSOCIATIVITY_20WAY;
596 case 24:
597 return SMBIOS_CACHE_ASSOCIATIVITY_24WAY;
598 case 32:
599 return SMBIOS_CACHE_ASSOCIATIVITY_32WAY;
600 case 48:
601 return SMBIOS_CACHE_ASSOCIATIVITY_48WAY;
602 case 64:
603 return SMBIOS_CACHE_ASSOCIATIVITY_64WAY;
604 case 0xff:
605 return SMBIOS_CACHE_ASSOCIATIVITY_FULL;
606 default:
607 return SMBIOS_CACHE_ASSOCIATIVITY_UNKNOWN;
608 };
609}
610
611int smbios_write_type8(unsigned long *current, int *handle,
612 const struct port_information *port,
613 size_t num_ports)
614{
615 unsigned int totallen = 0, i;
616
617 for (i = 0; i < num_ports; i++, port++) {
618 struct smbios_type8 *t = smbios_carve_table(*current,
619 SMBIOS_PORT_CONNECTOR_INFORMATION,
620 sizeof(*t), *handle);
621 t->internal_reference_designator =
622 smbios_add_string(t->eos, port->internal_reference_designator);
623 t->internal_connector_type = port->internal_connector_type;
624 t->external_reference_designator =
625 smbios_add_string(t->eos, port->external_reference_designator);
626 t->external_connector_type = port->external_connector_type;
627 t->port_type = port->port_type;
628 *handle += 1;
629 const int len = smbios_full_table_len(&t->header, t->eos);
630 *current += len;
631 totallen += len;
632 }
633 return totallen;
634}
635
636int smbios_write_type9(unsigned long *current, int *handle,
637 const char *name, const enum misc_slot_type type,
638 const enum slot_data_bus_bandwidth bandwidth,
639 const enum misc_slot_usage usage,
640 const enum misc_slot_length length,
Felix Heldd4594032024-01-11 21:50:36 +0100641 const u16 id, u8 slot_char1, u8 slot_char2,
642 u8 segment_group, u8 bus, u8 dev_func)
Benjamin Doronea13dc32023-06-20 12:21:27 -0400643{
644 struct smbios_type9 *t = smbios_carve_table(*current, SMBIOS_SYSTEM_SLOTS,
645 sizeof(*t), *handle);
646
647 t->slot_designation = smbios_add_string(t->eos, name ? name : "SLOT");
648 t->slot_type = type;
Martin Roth3e25f852023-09-04 15:37:07 -0600649 /* TODO add slot_id support, will be "_SUN" for ACPI devices */
Benjamin Doronea13dc32023-06-20 12:21:27 -0400650 t->slot_id = id;
651 t->slot_data_bus_width = bandwidth;
652 t->current_usage = usage;
653 t->slot_length = length;
654 t->slot_characteristics_1 = slot_char1;
655 t->slot_characteristics_2 = slot_char2;
Felix Heldd4594032024-01-11 21:50:36 +0100656 t->segment_group_number = segment_group;
Benjamin Doronea13dc32023-06-20 12:21:27 -0400657 t->bus_number = bus;
658 t->device_function_number = dev_func;
659 t->data_bus_width = SlotDataBusWidthOther;
660
661 const int len = smbios_full_table_len(&t->header, t->eos);
662 *current += len;
663 *handle += 1;
664 return len;
665}
666
667static int smbios_write_type11(unsigned long *current, int *handle)
668{
669 struct device *dev;
670 struct smbios_type11 *t = smbios_carve_table(*current, SMBIOS_OEM_STRINGS,
671 sizeof(*t), *handle);
672
673 for (dev = all_devices; dev; dev = dev->next) {
674 if (dev->ops && dev->ops->get_smbios_strings)
675 dev->ops->get_smbios_strings(dev, t);
676 }
677
678 if (t->count == 0) {
679 memset(t, 0, sizeof(*t));
680 return 0;
681 }
682
683 const int len = smbios_full_table_len(&t->header, t->eos);
684 *current += len;
685 (*handle)++;
686 return len;
687}
688
689static int smbios_write_type16(unsigned long *current, int *handle)
690{
691 int i;
692 uint64_t max_capacity;
693
694 struct memory_info *meminfo;
695 meminfo = cbmem_find(CBMEM_ID_MEMINFO);
696 if (meminfo == NULL)
697 return 0; /* can't find mem info in cbmem */
698
699 printk(BIOS_INFO, "Create SMBIOS type 16\n");
700
701 if (meminfo->max_capacity_mib == 0 || meminfo->number_of_devices == 0) {
702 /* Fill in defaults if not provided */
703 meminfo->number_of_devices = 0;
704 meminfo->max_capacity_mib = 0;
705 for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) {
706 meminfo->max_capacity_mib += meminfo->dimm[i].dimm_size;
707 meminfo->number_of_devices += !!meminfo->dimm[i].dimm_size;
708 }
709 }
710
711 struct smbios_type16 *t = smbios_carve_table(*current, SMBIOS_PHYS_MEMORY_ARRAY,
712 sizeof(*t), *handle);
713
714 t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD;
715 t->use = MEMORY_ARRAY_USE_SYSTEM;
716 t->memory_error_correction = meminfo->ecc_type;
717
718 /* no error information handle available */
719 t->memory_error_information_handle = 0xFFFE;
720 max_capacity = meminfo->max_capacity_mib;
721 if (max_capacity * (MiB / KiB) < SMBIOS_USE_EXTENDED_MAX_CAPACITY)
722 t->maximum_capacity = max_capacity * (MiB / KiB);
723 else {
724 t->maximum_capacity = SMBIOS_USE_EXTENDED_MAX_CAPACITY;
725 t->extended_maximum_capacity = max_capacity * MiB;
726 }
727 t->number_of_memory_devices = meminfo->number_of_devices;
728
729 const int len = smbios_full_table_len(&t->header, t->eos);
730 *current += len;
731 (*handle)++;
732 return len;
733}
734
735static int smbios_write_type17(unsigned long *current, int *handle, int type16)
736{
737 int totallen = 0;
738 int i;
739
740 struct memory_info *meminfo;
741 meminfo = cbmem_find(CBMEM_ID_MEMINFO);
742 if (meminfo == NULL)
743 return 0; /* can't find mem info in cbmem */
744
745 printk(BIOS_INFO, "Create SMBIOS type 17\n");
746 for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) {
747 struct dimm_info *d = &meminfo->dimm[i];
748 /*
749 * Windows 10 GetPhysicallyInstalledSystemMemory functions reads SMBIOS tables
750 * type 16 and type 17. The type 17 tables need to point to a type 16 table.
751 * Otherwise, the physical installed memory size is guessed from the system
752 * memory map, which results in a slightly smaller value than the actual size.
753 */
754 int len;
755 if (d->dimm_size > 0)
756 len = create_smbios_type17_for_dimm(d, current, handle, type16);
757 else
758 len = create_smbios_type17_for_empty_slot(d, current, handle, type16);
759
760 *current += len;
761 totallen += len;
762 }
763 return totallen;
764}
765
766static int smbios_write_type19(unsigned long *current, int *handle, int type16)
767{
768 int i;
769
770 struct memory_info *meminfo;
771 meminfo = cbmem_find(CBMEM_ID_MEMINFO);
772 if (meminfo == NULL)
773 return 0; /* can't find mem info in cbmem */
774
775 struct smbios_type19 *t = smbios_carve_table(*current,
776 SMBIOS_MEMORY_ARRAY_MAPPED_ADDRESS,
777 sizeof(*t), *handle);
778
779 t->memory_array_handle = type16;
780
781 for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) {
782 if (meminfo->dimm[i].dimm_size > 0) {
783 t->extended_ending_address += meminfo->dimm[i].dimm_size;
784 t->partition_width++;
785 }
786 }
787 t->extended_ending_address *= MiB;
788
789 /* Check if it fits into regular address */
790 if (t->extended_ending_address >= KiB &&
791 t->extended_ending_address < 0x40000000000ULL) {
792 /*
793 * FIXME: The starting address is SoC specific, but SMBIOS tables are only
794 * exported on x86 where it's always 0.
795 */
796
797 t->starting_address = 0;
798 t->ending_address = t->extended_ending_address / KiB - 1;
799 t->extended_starting_address = ~0;
800 t->extended_ending_address = ~0;
801 } else {
802 t->starting_address = ~0;
803 t->ending_address = ~0;
804 t->extended_starting_address = 0;
805 t->extended_ending_address--;
806 }
807
808 const int len = smbios_full_table_len(&t->header, t->eos);
809 *current += len;
810 *handle += 1;
811 return len;
812}
813
814static int smbios_write_type20_table(unsigned long *current, int *handle, u32 addr_start,
815 u32 addr_end, int type17_handle, int type19_handle)
816{
817 struct smbios_type20 *t = smbios_carve_table(*current, SMBIOS_MEMORY_DEVICE_MAPPED_ADDRESS,
818 sizeof(*t), *handle);
819
820 t->memory_device_handle = type17_handle;
821 t->memory_array_mapped_address_handle = type19_handle;
822 t->addr_start = addr_start;
823 t->addr_end = addr_end;
824 t->partition_row_pos = 0xff;
825 t->interleave_pos = 0xff;
826 t->interleave_depth = 0xff;
827
828 const int len = smbios_full_table_len(&t->header, t->eos);
829 *current += len;
830 *handle += 1;
831 return len;
832}
833
834static int smbios_write_type20(unsigned long *current, int *handle,
835 int type17_handle, int type19_handle)
836{
837 u32 start_addr = 0;
838 int totallen = 0;
839 int i;
840
841 struct memory_info *meminfo;
842 meminfo = cbmem_find(CBMEM_ID_MEMINFO);
843 if (meminfo == NULL)
844 return 0; /* can't find mem info in cbmem */
845
846 printk(BIOS_INFO, "Create SMBIOS type 20\n");
847 for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) {
848 struct dimm_info *dimm;
849 dimm = &meminfo->dimm[i];
850 if (dimm->dimm_size == 0)
851 continue;
852
853 u32 end_addr = start_addr + (dimm->dimm_size << 10) - 1;
854 totallen += smbios_write_type20_table(current, handle, start_addr, end_addr,
855 type17_handle, type19_handle);
856 start_addr = end_addr + 1;
857 }
858 return totallen;
859}
860
861int smbios_write_type28(unsigned long *current, int *handle,
862 const char *name,
863 const enum smbios_temp_location location,
864 const enum smbios_temp_status status,
865 u16 max_value, u16 min_value,
866 u16 resolution, u16 tolerance,
867 u16 accuracy,
868 u32 oem,
869 u16 nominal_value)
870{
871 struct smbios_type28 *t = smbios_carve_table(*current, SMBIOS_TEMPERATURE_PROBE,
872 sizeof(*t), *handle);
873
874 t->description = smbios_add_string(t->eos, name ? name : "Temperature");
875 t->location_and_status = location | (status << 5);
876 t->maximum_value = max_value;
877 t->minimum_value = min_value;
878 t->resolution = resolution;
879 t->tolerance = tolerance;
880 t->accuracy = accuracy;
881 t->oem_defined = oem;
882 t->nominal_value = nominal_value;
883
884 const int len = smbios_full_table_len(&t->header, t->eos);
885 *current += len;
886 *handle += 1;
887 return len;
888}
889
890static int smbios_write_type32(unsigned long *current, int handle)
891{
892 struct smbios_type32 *t = smbios_carve_table(*current, SMBIOS_SYSTEM_BOOT_INFORMATION,
893 sizeof(*t), handle);
894
895 const int len = smbios_full_table_len(&t->header, t->eos);
896 *current += len;
897 return len;
898}
899
900int smbios_write_type38(unsigned long *current, int *handle,
901 const enum smbios_bmc_interface_type interface_type,
902 const u8 ipmi_rev, const u8 i2c_addr, const u8 nv_addr,
903 const u64 base_addr, const u8 base_modifier,
904 const u8 irq)
905{
906 struct smbios_type38 *t = smbios_carve_table(*current, SMBIOS_IPMI_DEVICE_INFORMATION,
907 sizeof(*t), *handle);
908
909 t->interface_type = interface_type;
910 t->ipmi_rev = ipmi_rev;
911 t->i2c_slave_addr = i2c_addr;
912 t->nv_storage_addr = nv_addr;
913 t->base_address = base_addr;
914 t->base_address_modifier = base_modifier;
915 t->irq = irq;
916
917 const int len = smbios_full_table_len(&t->header, t->eos);
918 *current += len;
919 *handle += 1;
920 return len;
921}
922
923int smbios_write_type39(unsigned long *current, int *handle,
924 u8 unit_group, const char *loc, const char *dev_name,
925 const char *man, const char *serial_num,
926 const char *tag_num, const char *part_num,
927 const char *rev_lvl, u16 max_pow_cap,
928 const struct power_supply_ch *ps_ch)
929{
930 struct smbios_type39 *t = smbios_carve_table(*current,
931 SMBIOS_SYSTEM_POWER_SUPPLY,
932 sizeof(*t), *handle);
933
934 uint16_t val = 0;
935 uint16_t ps_type, ps_status, vol_switch, ps_unplug, ps_present, hot_rep;
936
937 t->power_unit_group = unit_group;
938 t->location = smbios_add_string(t->eos, loc);
939 t->device_name = smbios_add_string(t->eos, dev_name);
940 t->manufacturer = smbios_add_string(t->eos, man);
941 t->serial_number = smbios_add_string(t->eos, serial_num);
942 t->asset_tag_number = smbios_add_string(t->eos, tag_num);
943 t->model_part_number = smbios_add_string(t->eos, part_num);
944 t->revision_level = smbios_add_string(t->eos, rev_lvl);
945 t->max_power_capacity = max_pow_cap;
946
947 ps_type = ps_ch->power_supply_type & 0xF;
948 ps_status = ps_ch->power_supply_status & 0x7;
949 vol_switch = ps_ch->input_voltage_range_switch & 0xF;
950 ps_unplug = ps_ch->power_supply_unplugged & 0x1;
951 ps_present = ps_ch->power_supply_present & 0x1;
952 hot_rep = ps_ch->power_supply_hot_replaceble & 0x1;
953
954 val |= (ps_type << 10);
955 val |= (ps_status << 7);
956 val |= (vol_switch << 3);
957 val |= (ps_unplug << 2);
958 val |= (ps_present << 1);
959 val |= hot_rep;
960 t->power_supply_characteristics = val;
961
962 t->input_voltage_probe_handle = 0xFFFF;
963 t->cooling_device_handle = 0xFFFF;
964 t->input_current_probe_handle = 0xFFFF;
965
966 const int len = smbios_full_table_len(&t->header, t->eos);
967 *current += len;
968 *handle += 1;
969 return len;
970}
971
972int smbios_write_type41(unsigned long *current, int *handle,
Felix Held363ac8b2024-01-11 21:51:19 +0100973 const char *name, u8 instance, u16 segment_group,
Benjamin Doronea13dc32023-06-20 12:21:27 -0400974 u8 bus, u8 device, u8 function, u8 device_type)
975{
976 struct smbios_type41 *t = smbios_carve_table(*current,
977 SMBIOS_ONBOARD_DEVICES_EXTENDED_INFORMATION,
978 sizeof(*t), *handle);
979
980 t->reference_designation = smbios_add_string(t->eos, name);
981 t->device_type = device_type;
982 t->device_status = 1;
983 t->device_type_instance = instance;
Felix Held363ac8b2024-01-11 21:51:19 +0100984 t->segment_group_number = segment_group;
Benjamin Doronea13dc32023-06-20 12:21:27 -0400985 t->bus_number = bus;
986 t->device_number = device;
987 t->function_number = function;
988
989 const int len = smbios_full_table_len(&t->header, t->eos);
990 *current += len;
991 *handle += 1;
992 return len;
993}
994
995int smbios_write_type43(unsigned long *current, int *handle, const u32 vendor_id,
996 const u8 major_spec_ver, const u8 minor_spec_ver,
997 const u32 fw_ver1, const u32 fw_ver2, const char *description,
998 const u64 characteristics, const u32 oem_defined)
999{
1000 struct smbios_type43 *t = smbios_carve_table(*current, SMBIOS_TPM_DEVICE,
1001 sizeof(*t), *handle);
1002
1003 t->vendor_id = vendor_id;
1004 t->major_spec_ver = major_spec_ver;
1005 t->minor_spec_ver = minor_spec_ver;
1006 t->fw_ver1 = fw_ver1;
1007 t->fw_ver2 = fw_ver2;
1008 t->characteristics = characteristics;
1009 t->oem_defined = oem_defined;
1010 t->description = smbios_add_string(t->eos, description);
1011
1012 const int len = smbios_full_table_len(&t->header, t->eos);
1013 *current += len;
1014 *handle += 1;
1015 return len;
1016}
1017
1018static int smbios_write_type127(unsigned long *current, int handle)
1019{
1020 struct smbios_type127 *t = smbios_carve_table(*current, SMBIOS_END_OF_TABLE,
1021 sizeof(*t), handle);
1022
1023 const int len = smbios_full_table_len(&t->header, t->eos);
1024 *current += len;
1025 return len;
1026}
1027
1028/* Get the device type 41 from the dev struct */
1029static u8 smbios_get_device_type_from_dev(struct device *dev)
1030{
1031 u16 pci_basesubclass = (dev->class >> 8) & 0xFFFF;
1032
1033 switch (pci_basesubclass) {
1034 case PCI_CLASS_NOT_DEFINED:
1035 return SMBIOS_DEVICE_TYPE_OTHER;
1036 case PCI_CLASS_DISPLAY_VGA:
1037 case PCI_CLASS_DISPLAY_XGA:
1038 case PCI_CLASS_DISPLAY_3D:
1039 case PCI_CLASS_DISPLAY_OTHER:
1040 return SMBIOS_DEVICE_TYPE_VIDEO;
1041 case PCI_CLASS_STORAGE_SCSI:
1042 return SMBIOS_DEVICE_TYPE_SCSI;
1043 case PCI_CLASS_NETWORK_ETHERNET:
1044 return SMBIOS_DEVICE_TYPE_ETHERNET;
1045 case PCI_CLASS_NETWORK_TOKEN_RING:
1046 return SMBIOS_DEVICE_TYPE_TOKEN_RING;
1047 case PCI_CLASS_MULTIMEDIA_VIDEO:
1048 case PCI_CLASS_MULTIMEDIA_AUDIO:
1049 case PCI_CLASS_MULTIMEDIA_PHONE:
1050 case PCI_CLASS_MULTIMEDIA_OTHER:
1051 return SMBIOS_DEVICE_TYPE_SOUND;
1052 case PCI_CLASS_STORAGE_ATA:
1053 return SMBIOS_DEVICE_TYPE_PATA;
1054 case PCI_CLASS_STORAGE_SATA:
1055 return SMBIOS_DEVICE_TYPE_SATA;
1056 case PCI_CLASS_STORAGE_SAS:
1057 return SMBIOS_DEVICE_TYPE_SAS;
1058 default:
1059 return SMBIOS_DEVICE_TYPE_UNKNOWN;
1060 }
1061}
1062
1063static bool smbios_get_type41_instance_id(struct device *dev, u8 device_type, u8 *instance_id)
1064{
1065#if CONFIG(SMBIOS_TYPE41_PROVIDED_BY_DEVTREE)
1066 *instance_id = dev->smbios_instance_id;
1067 return dev->smbios_instance_id_valid;
1068#else
1069 static u8 type41_inst_cnt[SMBIOS_DEVICE_TYPE_COUNT + 1] = {};
1070
1071 if (device_type == SMBIOS_DEVICE_TYPE_OTHER ||
1072 device_type == SMBIOS_DEVICE_TYPE_UNKNOWN)
1073 return false;
1074
1075 if (device_type > SMBIOS_DEVICE_TYPE_COUNT)
1076 return false;
1077
1078 *instance_id = type41_inst_cnt[device_type]++;
1079 return true;
1080#endif
1081}
1082
1083static const char *smbios_get_type41_refdes(struct device *dev)
1084{
1085#if CONFIG(SMBIOS_TYPE41_PROVIDED_BY_DEVTREE)
1086 if (dev->smbios_refdes)
1087 return dev->smbios_refdes;
1088#endif
1089#if CONFIG(PCI)
1090 return get_pci_subclass_name(dev);
1091#else
1092 return "???";
1093#endif
1094}
1095
1096static int smbios_generate_type41_from_devtree(struct device *dev, int *handle,
1097 unsigned long *current)
1098{
1099 if (dev->path.type != DEVICE_PATH_PCI)
1100 return 0;
1101 if (!dev->on_mainboard)
1102 return 0;
1103
1104 const u8 device_type = smbios_get_device_type_from_dev(dev);
1105
1106 u8 instance_id;
1107
1108 if (!smbios_get_type41_instance_id(dev, device_type, &instance_id))
1109 return 0;
1110
1111 const char *name = smbios_get_type41_refdes(dev);
1112
1113 return smbios_write_type41(current, handle,
1114 name, // name
1115 instance_id, // inst
Arthur Heymans7fcd4d52023-08-24 15:12:19 +02001116 dev->upstream->segment_group, // segment group
1117 dev->upstream->secondary, //bus
Benjamin Doronea13dc32023-06-20 12:21:27 -04001118 PCI_SLOT(dev->path.pci.devfn), // device
1119 PCI_FUNC(dev->path.pci.devfn), // func
1120 device_type);
1121}
1122
1123static int smbios_generate_type9_from_devtree(struct device *dev, int *handle,
1124 unsigned long *current)
1125{
1126 enum misc_slot_usage usage;
1127 enum slot_data_bus_bandwidth bandwidth;
1128 enum misc_slot_type type;
1129 enum misc_slot_length length;
1130
1131 if (dev->path.type != DEVICE_PATH_PCI)
1132 return 0;
1133
1134 if (!dev->smbios_slot_type && !dev->smbios_slot_data_width &&
1135 !dev->smbios_slot_designation && !dev->smbios_slot_length)
1136 return 0;
1137
1138 if (dev_is_active_bridge(dev))
1139 usage = SlotUsageInUse;
1140 else if (dev->enabled)
1141 usage = SlotUsageAvailable;
1142 else
1143 usage = SlotUsageUnknown;
1144
1145 if (dev->smbios_slot_data_width)
1146 bandwidth = dev->smbios_slot_data_width;
1147 else
1148 bandwidth = SlotDataBusWidthUnknown;
1149
1150 if (dev->smbios_slot_type)
1151 type = dev->smbios_slot_type;
1152 else
1153 type = SlotTypeUnknown;
1154
1155 if (dev->smbios_slot_length)
1156 length = dev->smbios_slot_length;
1157 else
1158 length = SlotLengthUnknown;
1159
1160 return smbios_write_type9(current, handle,
1161 dev->smbios_slot_designation,
1162 type,
1163 bandwidth,
1164 usage,
1165 length,
1166 0,
1167 1,
1168 0,
Arthur Heymans7fcd4d52023-08-24 15:12:19 +02001169 dev->upstream->segment_group,
1170 dev->upstream->secondary,
Benjamin Doronea13dc32023-06-20 12:21:27 -04001171 dev->path.pci.devfn);
1172}
1173
1174int get_smbios_data(struct device *dev, int *handle, unsigned long *current)
1175{
1176 int len = 0;
1177
1178 len += smbios_generate_type9_from_devtree(dev, handle, current);
1179 len += smbios_generate_type41_from_devtree(dev, handle, current);
1180
1181 return len;
1182}
1183
1184static int smbios_walk_device_tree(struct device *tree, int *handle, unsigned long *current)
1185{
1186 struct device *dev;
1187 int len = 0;
1188
1189 for (dev = tree; dev; dev = dev->next) {
1190 if (!dev->enabled)
1191 continue;
1192
1193 if (dev->ops && dev->ops->get_smbios_data) {
1194 printk(BIOS_INFO, "%s (%s)\n", dev_path(dev), dev_name(dev));
1195 len += dev->ops->get_smbios_data(dev, handle, current);
1196 } else {
1197 len += get_smbios_data(dev, handle, current);
1198 }
1199 }
1200 return len;
1201}
1202
1203unsigned long smbios_write_tables(unsigned long current)
1204{
Maximilian Brune48169e82023-08-02 13:20:00 +02001205 struct smbios_entry *se = NULL;
Benjamin Doronea13dc32023-06-20 12:21:27 -04001206 struct smbios_entry30 *se3;
1207 unsigned long tables;
1208 int len = 0;
1209 int max_struct_size = 0;
1210 int handle = 0;
1211
1212 current = ALIGN_UP(current, 16);
1213 printk(BIOS_DEBUG, "%s: %08lx\n", __func__, current);
1214
Maximilian Brune48169e82023-08-02 13:20:00 +02001215 // only add a 32 bit entry point if SMBIOS table is below 4G
1216 if (current < UINT32_MAX) {
1217 se = (struct smbios_entry *)current;
1218 current += sizeof(*se);
1219 current = ALIGN_UP(current, 16);
1220 }
Benjamin Doronea13dc32023-06-20 12:21:27 -04001221
1222 se3 = (struct smbios_entry30 *)current;
1223 current += sizeof(*se3);
1224 current = ALIGN_UP(current, 16);
1225
1226 tables = current;
1227 update_max(len, max_struct_size, smbios_write_type0(&current, handle++));
1228 update_max(len, max_struct_size, smbios_write_type1(&current, handle++));
1229
1230 /* The chassis handle is the next one */
1231 update_max(len, max_struct_size, smbios_write_type2(&current, handle, handle + 1));
1232 handle++;
1233 update_max(len, max_struct_size, smbios_write_type3(&current, handle++));
1234
1235 struct smbios_type4 *type4 = (struct smbios_type4 *)current;
1236 update_max(len, max_struct_size, smbios_write_type4(&current, handle++));
1237 len += smbios_write_type7_cache_parameters(&current, &handle, &max_struct_size, type4);
1238 update_max(len, max_struct_size, smbios_write_type11(&current, &handle));
1239 if (CONFIG(ELOG))
1240 update_max(len, max_struct_size,
1241 elog_smbios_write_type15(&current, handle++));
1242
1243 const int type16 = handle;
1244 update_max(len, max_struct_size, smbios_write_type16(&current, &handle));
1245 const int type17 = handle;
1246 update_max(len, max_struct_size, smbios_write_type17(&current, &handle, type16));
1247 const int type19 = handle;
1248 update_max(len, max_struct_size, smbios_write_type19(&current, &handle, type16));
1249 update_max(len, max_struct_size,
1250 smbios_write_type20(&current, &handle, type17, type19));
1251 update_max(len, max_struct_size, smbios_write_type32(&current, handle++));
1252
1253 update_max(len, max_struct_size, smbios_walk_device_tree(all_devices,
1254 &handle, &current));
1255
1256 update_max(len, max_struct_size, smbios_write_type127(&current, handle++));
1257
Maximilian Brune48169e82023-08-02 13:20:00 +02001258 if (se) {
1259 /* Install SMBIOS 2.1 entry point */
1260 memset(se, 0, sizeof(*se));
1261 memcpy(se->anchor, "_SM_", 4);
1262 se->length = sizeof(*se);
1263 se->major_version = 3;
1264 se->minor_version = 0;
1265 se->max_struct_size = max_struct_size;
1266 se->struct_count = handle;
1267 memcpy(se->intermediate_anchor_string, "_DMI_", 5);
Benjamin Doronea13dc32023-06-20 12:21:27 -04001268
Maximilian Brune48169e82023-08-02 13:20:00 +02001269 se->struct_table_address = (u32)tables;
1270 se->struct_table_length = len;
Benjamin Doronea13dc32023-06-20 12:21:27 -04001271
Maximilian Brune48169e82023-08-02 13:20:00 +02001272 se->intermediate_checksum = smbios_checksum((u8 *)se + 0x10, sizeof(*se) - 0x10);
1273 se->checksum = smbios_checksum((u8 *)se, sizeof(*se));
1274 }
Benjamin Doronea13dc32023-06-20 12:21:27 -04001275
1276 /* Install SMBIOS 3.0 entry point */
1277 memset(se3, 0, sizeof(*se3));
1278 memcpy(se3->anchor, "_SM3_", 5);
1279 se3->length = sizeof(*se3);
1280 se3->major_version = 3;
1281 se3->minor_version = 0;
1282
1283 se3->struct_table_address = (u64)tables;
1284 se3->struct_table_length = len;
1285
1286 se3->checksum = smbios_checksum((u8 *)se3, sizeof(*se3));
1287
1288 return current;
1289}