blob: aabeb1046cbbdda7403b6c3ab08dcf6e930a0487 [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Sven Schnelle164bcfd2011-08-14 20:56:34 +02002
Sven Schnelle164bcfd2011-08-14 20:56:34 +02003#include <string.h>
4#include <smbios.h>
5#include <console/console.h>
Kyösti Mälkkic36af7b2014-11-18 12:41:16 +02006#include <version.h>
Sven Schnelle164bcfd2011-08-14 20:56:34 +02007#include <device/device.h>
8#include <arch/cpu.h>
9#include <cpu/x86/name.h>
Duncan Laurie472ec9c2012-06-23 16:13:42 -070010#include <elog.h>
Julius Werner9ff8f6f2015-02-23 14:31:09 -080011#include <endian.h>
Kane Chen33faac62014-07-27 12:54:44 -070012#include <memory_info.h>
13#include <spd.h>
14#include <cbmem.h>
Elyes HAOUASe2d152c2019-06-21 07:06:50 +020015#include <commonlib/helpers.h>
Christian Walter9e5b0622019-05-21 17:37:58 +020016#include <device/pci_ids.h>
17#include <device/pci_def.h>
18#include <device/pci.h>
Julius Wernercd49cce2019-03-05 16:53:33 -080019#if CONFIG(CHROMEOS)
Stefan Reinauerc6b21662012-04-03 16:02:54 -070020#include <vendorcode/google/chromeos/gnvs.h>
21#endif
Johnny Linc746a742020-06-03 11:44:22 +080022#include <drivers/vpd/vpd.h>
23#include <stdlib.h>
Sven Schnelle164bcfd2011-08-14 20:56:34 +020024
Patrick Rudolphfc5b8092019-03-30 17:37:28 +010025#define update_max(len, max_len, stmt) \
26 do { \
27 int tmp = stmt; \
28 \
29 max_len = MAX(max_len, tmp); \
30 len += tmp; \
31 } while (0)
32
Sven Schnelle164bcfd2011-08-14 20:56:34 +020033static u8 smbios_checksum(u8 *p, u32 length)
34{
35 u8 ret = 0;
36 while (length--)
37 ret += *p++;
38 return -ret;
39}
40
Christian Walter9e5b0622019-05-21 17:37:58 +020041/* Get the device type 41 from the dev struct */
42static u8 smbios_get_device_type_from_dev(struct device *dev)
43{
44 u16 pci_basesubclass = (dev->class >> 8) & 0xFFFF;
45
46 switch (pci_basesubclass) {
47 case PCI_CLASS_NOT_DEFINED:
48 return SMBIOS_DEVICE_TYPE_OTHER;
49 case PCI_CLASS_DISPLAY_VGA:
50 case PCI_CLASS_DISPLAY_XGA:
51 case PCI_CLASS_DISPLAY_3D:
52 case PCI_CLASS_DISPLAY_OTHER:
53 return SMBIOS_DEVICE_TYPE_VIDEO;
54 case PCI_CLASS_STORAGE_SCSI:
55 return SMBIOS_DEVICE_TYPE_SCSI;
56 case PCI_CLASS_NETWORK_ETHERNET:
57 return SMBIOS_DEVICE_TYPE_ETHERNET;
58 case PCI_CLASS_NETWORK_TOKEN_RING:
59 return SMBIOS_DEVICE_TYPE_TOKEN_RING;
60 case PCI_CLASS_MULTIMEDIA_VIDEO:
61 case PCI_CLASS_MULTIMEDIA_AUDIO:
62 case PCI_CLASS_MULTIMEDIA_PHONE:
63 case PCI_CLASS_MULTIMEDIA_OTHER:
64 return SMBIOS_DEVICE_TYPE_SOUND;
65 case PCI_CLASS_STORAGE_ATA:
66 return SMBIOS_DEVICE_TYPE_PATA;
67 case PCI_CLASS_STORAGE_SATA:
68 return SMBIOS_DEVICE_TYPE_SATA;
69 case PCI_CLASS_STORAGE_SAS:
70 return SMBIOS_DEVICE_TYPE_SAS;
71 default:
72 return SMBIOS_DEVICE_TYPE_UNKNOWN;
73 }
74}
75
Konstantin Aladyshevd0df1d72017-08-01 15:52:46 +030076int smbios_add_string(u8 *start, const char *str)
Sven Schnelle164bcfd2011-08-14 20:56:34 +020077{
78 int i = 1;
Konstantin Aladyshevd0df1d72017-08-01 15:52:46 +030079 char *p = (char *)start;
Sven Schnelle164bcfd2011-08-14 20:56:34 +020080
Ben Gardner6b07cba2015-12-09 11:24:35 -060081 /*
82 * Return 0 as required for empty strings.
83 * See Section 6.1.3 "Text Strings" of the SMBIOS specification.
84 */
85 if (*str == '\0')
86 return 0;
87
Elyes HAOUASdbf30672016-08-21 17:37:15 +020088 for (;;) {
Sven Schnelle164bcfd2011-08-14 20:56:34 +020089 if (!*p) {
90 strcpy(p, str);
91 p += strlen(str);
92 *p++ = '\0';
93 *p++ = '\0';
94 return i;
95 }
96
97 if (!strcmp(p, str))
98 return i;
99
100 p += strlen(p)+1;
101 i++;
102 }
103}
104
Konstantin Aladyshevd0df1d72017-08-01 15:52:46 +0300105int smbios_string_table_len(u8 *start)
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200106{
Konstantin Aladyshevd0df1d72017-08-01 15:52:46 +0300107 char *p = (char *)start;
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200108 int i, len = 0;
109
Lee Leahy024b13d2017-03-16 13:41:11 -0700110 while (*p) {
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200111 i = strlen(p) + 1;
112 p += i;
113 len += i;
114 }
Konstantin Aladyshevd0df1d72017-08-01 15:52:46 +0300115
116 if (!len)
117 return 2;
118
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200119 return len + 1;
120}
121
Konstantin Aladyshevd0df1d72017-08-01 15:52:46 +0300122static int smbios_cpu_vendor(u8 *start)
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200123{
Rudolf Marek06253cd2012-02-25 23:51:12 +0100124 if (cpu_have_cpuid()) {
Ryan Salsamendi1b5eda02017-06-11 18:50:32 -0700125 u32 tmp[4];
126 const struct cpuid_result res = cpuid(0);
127 tmp[0] = res.ebx;
128 tmp[1] = res.edx;
129 tmp[2] = res.ecx;
130 tmp[3] = 0;
131 return smbios_add_string(start, (const char *)tmp);
132 } else {
133 return smbios_add_string(start, "Unknown");
Rudolf Marek06253cd2012-02-25 23:51:12 +0100134 }
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200135}
136
Konstantin Aladyshevd0df1d72017-08-01 15:52:46 +0300137static int smbios_processor_name(u8 *start)
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200138{
Nico Huberaa9643e2017-06-20 14:49:04 +0200139 u32 tmp[13];
Ryan Salsamendi1b5eda02017-06-11 18:50:32 -0700140 const char *str = "Unknown Processor Name";
Rudolf Marek06253cd2012-02-25 23:51:12 +0100141 if (cpu_have_cpuid()) {
Ryan Salsamendi1b5eda02017-06-11 18:50:32 -0700142 int i;
143 struct cpuid_result res = cpuid(0x80000000);
Rudolf Marek06253cd2012-02-25 23:51:12 +0100144 if (res.eax >= 0x80000004) {
Ryan Salsamendi1b5eda02017-06-11 18:50:32 -0700145 int j = 0;
Rudolf Marek06253cd2012-02-25 23:51:12 +0100146 for (i = 0; i < 3; i++) {
147 res = cpuid(0x80000002 + i);
Ryan Salsamendi1b5eda02017-06-11 18:50:32 -0700148 tmp[j++] = res.eax;
149 tmp[j++] = res.ebx;
150 tmp[j++] = res.ecx;
151 tmp[j++] = res.edx;
Rudolf Marek06253cd2012-02-25 23:51:12 +0100152 }
Ryan Salsamendi1b5eda02017-06-11 18:50:32 -0700153 tmp[12] = 0;
154 str = (const char *)tmp;
Rudolf Marek06253cd2012-02-25 23:51:12 +0100155 }
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200156 }
Ryan Salsamendi1b5eda02017-06-11 18:50:32 -0700157 return smbios_add_string(start, str);
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200158}
159
Angel Pons9630ced2020-07-29 18:29:28 +0200160static const char *get_dimm_manufacturer_name(const uint16_t mod_id)
Kane Chen33faac62014-07-27 12:54:44 -0700161{
162 switch (mod_id) {
Lijian Zhao6eaa7812019-05-16 07:32:42 -0700163 case 0x9b85:
Angel Pons9630ced2020-07-29 18:29:28 +0200164 return "Crucial";
Lee Leahy0b5678f2017-03-16 16:01:40 -0700165 case 0x4304:
Angel Pons9630ced2020-07-29 18:29:28 +0200166 return "Ramaxel";
Lee Leahy0b5678f2017-03-16 16:01:40 -0700167 case 0x4f01:
Angel Pons9630ced2020-07-29 18:29:28 +0200168 return "Transcend";
Lee Leahy0b5678f2017-03-16 16:01:40 -0700169 case 0x9801:
Angel Pons9630ced2020-07-29 18:29:28 +0200170 return "Kingston";
Lee Leahy0b5678f2017-03-16 16:01:40 -0700171 case 0x987f:
Angel Pons9630ced2020-07-29 18:29:28 +0200172 return "Hynix";
Lee Leahy0b5678f2017-03-16 16:01:40 -0700173 case 0x9e02:
Angel Pons9630ced2020-07-29 18:29:28 +0200174 return "Corsair";
Lee Leahy0b5678f2017-03-16 16:01:40 -0700175 case 0xb004:
Angel Pons9630ced2020-07-29 18:29:28 +0200176 return "OCZ";
Lee Leahy0b5678f2017-03-16 16:01:40 -0700177 case 0xad80:
Angel Pons9630ced2020-07-29 18:29:28 +0200178 return "Hynix/Hyundai";
Lijian Zhao6eaa7812019-05-16 07:32:42 -0700179 case 0x3486:
Angel Pons9630ced2020-07-29 18:29:28 +0200180 return "Super Talent";
Lee Leahy0b5678f2017-03-16 16:01:40 -0700181 case 0xcd04:
Angel Pons9630ced2020-07-29 18:29:28 +0200182 return "GSkill";
Lee Leahy0b5678f2017-03-16 16:01:40 -0700183 case 0xce80:
Angel Pons9630ced2020-07-29 18:29:28 +0200184 return "Samsung";
Lee Leahy0b5678f2017-03-16 16:01:40 -0700185 case 0xfe02:
Angel Pons9630ced2020-07-29 18:29:28 +0200186 return "Elpida";
Lijian Zhao6eaa7812019-05-16 07:32:42 -0700187 case 0x2c80:
Angel Pons9630ced2020-07-29 18:29:28 +0200188 return "Micron";
189 default:
190 return NULL;
191 }
192}
Lee Leahy0b5678f2017-03-16 16:01:40 -0700193
Angel Pons9630ced2020-07-29 18:29:28 +0200194/* this function will fill the corresponding manufacturer */
195void smbios_fill_dimm_manufacturer_from_id(uint16_t mod_id, struct smbios_type17 *t)
196{
197 const char *const manufacturer = get_dimm_manufacturer_name(mod_id);
198
199 if (manufacturer) {
200 t->manufacturer = smbios_add_string(t->eos, manufacturer);
201 } else {
202 char string_buffer[256];
203
204 snprintf(string_buffer, sizeof(string_buffer), "Unknown (%x)", mod_id);
205 t->manufacturer = smbios_add_string(t->eos, string_buffer);
Kane Chen33faac62014-07-27 12:54:44 -0700206 }
207}
208
Raul E Rangel50021cd2018-03-20 12:40:55 -0600209static void trim_trailing_whitespace(char *buffer, size_t buffer_size)
Richard Spiegelbd654802018-02-22 10:03:39 -0700210{
Raul E Rangel50021cd2018-03-20 12:40:55 -0600211 size_t len = strnlen(buffer, buffer_size);
212
213 if (len == 0)
214 return;
215
216 for (char *p = buffer + len - 1; p >= buffer; --p) {
217 if (*p == ' ')
218 *p = 0;
219 else
220 break;
221 }
222}
223
224/** This function will fill the corresponding part number */
Angel Ponsbf2f91c2020-07-29 18:14:59 +0200225static void smbios_fill_dimm_part_number(const char *part_number, struct smbios_type17 *t)
Raul E Rangel50021cd2018-03-20 12:40:55 -0600226{
Raul E Rangel50021cd2018-03-20 12:40:55 -0600227 int invalid;
228 size_t i, len;
Jacob Garber9172b692019-06-26 16:18:16 -0600229 char trimmed_part_number[DIMM_INFO_PART_NUMBER_SIZE];
Raul E Rangel50021cd2018-03-20 12:40:55 -0600230
Jacob Garber9172b692019-06-26 16:18:16 -0600231 strncpy(trimmed_part_number, part_number, sizeof(trimmed_part_number));
232 trimmed_part_number[sizeof(trimmed_part_number) - 1] = '\0';
Raul E Rangel50021cd2018-03-20 12:40:55 -0600233
234 /*
235 * SPD mandates that unused characters be represented with a ' '.
236 * We don't want to publish the whitespace in the SMBIOS tables.
237 */
Jacob Garber9172b692019-06-26 16:18:16 -0600238 trim_trailing_whitespace(trimmed_part_number, sizeof(trimmed_part_number));
Raul E Rangel50021cd2018-03-20 12:40:55 -0600239
240 len = strlen(trimmed_part_number);
Richard Spiegelbd654802018-02-22 10:03:39 -0700241
242 invalid = 0; /* assume valid */
Lijian Zhaob1fc13a2018-03-26 18:27:02 -0700243 for (i = 0; i < len; i++) {
Raul E Rangel50021cd2018-03-20 12:40:55 -0600244 if (trimmed_part_number[i] < ' ') {
Richard Spiegelbd654802018-02-22 10:03:39 -0700245 invalid = 1;
Raul E Rangel50021cd2018-03-20 12:40:55 -0600246 trimmed_part_number[i] = '*';
Richard Spiegelbd654802018-02-22 10:03:39 -0700247 }
248 }
Raul E Rangel50021cd2018-03-20 12:40:55 -0600249
Lijian Zhaob1fc13a2018-03-26 18:27:02 -0700250 if (len == 0) {
251 /* Null String in Part Number will have "None" instead. */
252 t->part_number = smbios_add_string(t->eos, "None");
253 } else if (invalid) {
Jacob Garber9172b692019-06-26 16:18:16 -0600254 char string_buffer[sizeof(trimmed_part_number) + 10];
Richard Spiegelbd654802018-02-22 10:03:39 -0700255
256 snprintf(string_buffer, sizeof(string_buffer), "Invalid (%s)",
Raul E Rangel50021cd2018-03-20 12:40:55 -0600257 trimmed_part_number);
Richard Spiegelbd654802018-02-22 10:03:39 -0700258 t->part_number = smbios_add_string(t->eos, string_buffer);
Raul E Rangel50021cd2018-03-20 12:40:55 -0600259 } else {
260 t->part_number = smbios_add_string(t->eos, trimmed_part_number);
261 }
Richard Spiegelbd654802018-02-22 10:03:39 -0700262}
263
Raul E Rangel99f54a62018-04-11 10:58:14 -0600264/* Encodes the SPD serial number into hex */
265static void smbios_fill_dimm_serial_number(const struct dimm_info *dimm,
266 struct smbios_type17 *t)
267{
268 char serial[9];
269
270 snprintf(serial, sizeof(serial), "%02hhx%02hhx%02hhx%02hhx",
Angel Ponsbf2f91c2020-07-29 18:14:59 +0200271 dimm->serial[0], dimm->serial[1], dimm->serial[2], dimm->serial[3]);
Raul E Rangel99f54a62018-04-11 10:58:14 -0600272
273 t->serial_number = smbios_add_string(t->eos, serial);
274}
275
Kane Chen33faac62014-07-27 12:54:44 -0700276static int create_smbios_type17_for_dimm(struct dimm_info *dimm,
Patrick Rudolph5e007802020-07-27 15:37:43 +0200277 unsigned long *current, int *handle,
278 int type16_handle)
Kane Chen33faac62014-07-27 12:54:44 -0700279{
280 struct smbios_type17 *t = (struct smbios_type17 *)*current;
Kane Chen33faac62014-07-27 12:54:44 -0700281
282 memset(t, 0, sizeof(struct smbios_type17));
283 t->memory_type = dimm->ddr_type;
Rob Barnes327f1052020-09-01 10:26:57 -0600284 if (dimm->configured_speed_mts != 0)
285 t->clock_speed = dimm->configured_speed_mts;
286 else
287 t->clock_speed = dimm->ddr_frequency;
288 if (dimm->max_speed_mts != 0)
289 t->speed = dimm->max_speed_mts;
290 else
291 t->speed = dimm->ddr_frequency;
Kane Chen33faac62014-07-27 12:54:44 -0700292 t->type = SMBIOS_MEMORY_DEVICE;
Julien Viard de Galbert99891712018-01-24 11:04:46 +0100293 if (dimm->dimm_size < 0x7fff) {
294 t->size = dimm->dimm_size;
295 } else {
296 t->size = 0x7fff;
297 t->extended_size = dimm->dimm_size & 0x7fffffff;
298 }
Kane Chen33faac62014-07-27 12:54:44 -0700299 t->data_width = 8 * (1 << (dimm->bus_width & 0x7));
300 t->total_width = t->data_width + 8 * ((dimm->bus_width & 0x18) >> 3);
301
302 switch (dimm->mod_type) {
Lee Leahy0b5678f2017-03-16 16:01:40 -0700303 case SPD_RDIMM:
304 case SPD_MINI_RDIMM:
305 t->form_factor = MEMORY_FORMFACTOR_RIMM;
306 break;
307 case SPD_UDIMM:
308 case SPD_MICRO_DIMM:
309 case SPD_MINI_UDIMM:
310 t->form_factor = MEMORY_FORMFACTOR_DIMM;
311 break;
312 case SPD_SODIMM:
313 t->form_factor = MEMORY_FORMFACTOR_SODIMM;
314 break;
315 default:
316 t->form_factor = MEMORY_FORMFACTOR_UNKNOWN;
317 break;
Kane Chen33faac62014-07-27 12:54:44 -0700318 }
319
Timothy Pearson4785f2a2015-03-27 23:05:36 -0500320 smbios_fill_dimm_manufacturer_from_id(dimm->mod_id, t);
Raul E Rangel99f54a62018-04-11 10:58:14 -0600321 smbios_fill_dimm_serial_number(dimm, t);
Lijian Zhao10ea93c2019-04-11 00:45:10 -0700322 smbios_fill_dimm_locator(dimm, t);
Kane Chen33faac62014-07-27 12:54:44 -0700323
324 /* put '\0' in the end of data */
Richard Spiegelbd654802018-02-22 10:03:39 -0700325 dimm->module_part_number[DIMM_INFO_PART_NUMBER_SIZE - 1] = '\0';
326 smbios_fill_dimm_part_number((char *)dimm->module_part_number, t);
Kane Chen33faac62014-07-27 12:54:44 -0700327
Christian Walterf9723222019-05-28 10:37:24 +0200328 /* Voltage Levels */
329 t->configured_voltage = dimm->vdd_voltage;
330 t->minimum_voltage = dimm->vdd_voltage;
331 t->maximum_voltage = dimm->vdd_voltage;
332
Kane Chen33faac62014-07-27 12:54:44 -0700333 /* Synchronous = 1 */
Elyes HAOUAS41664402020-07-19 12:08:22 +0200334 t->type_detail = MEMORY_TYPE_DETAIL_SYNCHRONOUS;
Kane Chen33faac62014-07-27 12:54:44 -0700335 /* no handle for error information */
336 t->memory_error_information_handle = 0xFFFE;
337 t->attributes = dimm->rank_per_dimm;
338 t->handle = *handle;
Patrick Rudolph5e007802020-07-27 15:37:43 +0200339 t->phys_memory_array_handle = type16_handle;
340
Kane Chen33faac62014-07-27 12:54:44 -0700341 *handle += 1;
342 t->length = sizeof(struct smbios_type17) - 2;
343 return t->length + smbios_string_table_len(t->eos);
344}
345
Johnny Linc746a742020-06-03 11:44:22 +0800346#define VERSION_VPD "firmware_version"
347static const char *vpd_get_bios_version(void)
348{
349 int size;
350 const char *s;
351 char *version;
352
353 s = vpd_find(VERSION_VPD, &size, VPD_RO);
354 if (!s) {
355 printk(BIOS_ERR, "Find version from VPD %s failed\n", VERSION_VPD);
356 return NULL;
357 }
358
359 version = malloc(size + 1);
360 if (!version) {
361 printk(BIOS_ERR, "Failed to malloc %d bytes for VPD version\n", size + 1);
362 return NULL;
363 }
364 memcpy(version, s, size);
365 version[size] = '\0';
366 printk(BIOS_DEBUG, "Firmware version %s from VPD %s\n", version, VERSION_VPD);
367 return version;
368}
369
370static const char *get_bios_version(void)
371{
372 const char *s;
373
374#define SPACES \
375 " "
376
377 if (CONFIG(CHROMEOS))
378 return SPACES;
379
380 if (CONFIG(VPD_SMBIOS_VERSION)) {
381 s = vpd_get_bios_version();
382 if (s != NULL)
383 return s;
384 }
385
386 s = smbios_mainboard_bios_version();
387 if (s != NULL)
388 return s;
389
390 if (strlen(CONFIG_LOCALVERSION) != 0) {
391 printk(BIOS_DEBUG, "BIOS version set to CONFIG_LOCALVERSION: '%s'\n",
392 CONFIG_LOCALVERSION);
393 return CONFIG_LOCALVERSION;
394 }
395
396 printk(BIOS_DEBUG, "SMBIOS firmware version is set to coreboot_version: '%s'\n",
397 coreboot_version);
398 return coreboot_version;
399}
400
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200401static int smbios_write_type0(unsigned long *current, int handle)
402{
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200403 struct smbios_type0 *t = (struct smbios_type0 *)*current;
404 int len = sizeof(struct smbios_type0);
405
406 memset(t, 0, sizeof(struct smbios_type0));
407 t->type = SMBIOS_BIOS_INFORMATION;
408 t->handle = handle;
409 t->length = len - 2;
410
411 t->vendor = smbios_add_string(t->eos, "coreboot");
Kyösti Mälkkic36af7b2014-11-18 12:41:16 +0200412 t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date);
Christian Gmeiner5e272a42013-02-04 16:22:46 +0100413
Johnny Linc746a742020-06-03 11:44:22 +0800414#if CONFIG(CHROMEOS) && CONFIG(HAVE_ACPI_TABLES)
Stefan Reinauerc6b21662012-04-03 16:02:54 -0700415 u32 version_offset = (u32)smbios_string_table_len(t->eos);
Stefan Reinauerc6b21662012-04-03 16:02:54 -0700416 /* SMBIOS offsets start at 1 rather than 0 */
Johnny Linc746a742020-06-03 11:44:22 +0800417 chromeos_get_chromeos_acpi()->vbt10 = (u32)t->eos + (version_offset - 1);
Stefan Reinauerc6b21662012-04-03 16:02:54 -0700418#endif
Johnny Linc746a742020-06-03 11:44:22 +0800419 t->bios_version = smbios_add_string(t->eos, get_bios_version());
Lee Leahy67358712016-06-08 12:47:07 -0700420 uint32_t rom_size = CONFIG_ROM_SIZE;
421 rom_size = MIN(CONFIG_ROM_SIZE, 16 * MiB);
422 t->bios_rom_size = (rom_size / 65535) - 1;
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +0800423
Elyes HAOUAS358cbb32019-02-14 14:19:22 +0100424 if (CONFIG_ROM_SIZE >= 1 * GiB) {
Angel Ponsbf2f91c2020-07-29 18:14:59 +0200425 t->extended_bios_rom_size = DIV_ROUND_UP(CONFIG_ROM_SIZE, GiB) | (1 << 14);
Elyes HAOUAS358cbb32019-02-14 14:19:22 +0100426 } else {
427 t->extended_bios_rom_size = DIV_ROUND_UP(CONFIG_ROM_SIZE, MiB);
428 }
429
Elyes HAOUAS94ad3762019-02-15 17:39:56 +0100430 t->system_bios_major_release = coreboot_major_revision;
431 t->system_bios_minor_release = coreboot_minor_revision;
432
Tim Chuf2f53c42020-09-07 02:30:19 -0700433 smbios_ec_revision(&t->ec_major_release, &t->ec_minor_release);
434
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200435 t->bios_characteristics =
436 BIOS_CHARACTERISTICS_PCI_SUPPORTED |
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200437 BIOS_CHARACTERISTICS_SELECTABLE_BOOT |
438 BIOS_CHARACTERISTICS_UPGRADEABLE;
439
Julius Wernercd49cce2019-03-05 16:53:33 -0800440 if (CONFIG(CARDBUS_PLUGIN_SUPPORT))
Martin Roth898a7752017-06-01 11:39:59 -0600441 t->bios_characteristics |= BIOS_CHARACTERISTICS_PC_CARD;
442
Julius Wernercd49cce2019-03-05 16:53:33 -0800443 if (CONFIG(HAVE_ACPI_TABLES))
Martin Roth898a7752017-06-01 11:39:59 -0600444 t->bios_characteristics_ext1 = BIOS_EXT1_CHARACTERISTICS_ACPI;
445
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200446 t->bios_characteristics_ext2 = BIOS_EXT2_CHARACTERISTICS_TARGET;
447 len = t->length + smbios_string_table_len(t->eos);
448 *current += len;
449 return len;
450}
451
Elyes HAOUAS28fa33c2019-01-25 13:46:43 +0100452static int get_socket_type(void)
453{
454 if (CONFIG(CPU_INTEL_SLOT_1))
455 return 0x08;
456 if (CONFIG(CPU_INTEL_SOCKET_MPGA604))
457 return 0x13;
458 if (CONFIG(CPU_INTEL_SOCKET_LGA775))
459 return 0x15;
Morgan Jang92bcc4f2020-07-24 10:36:18 +0800460 if (CONFIG(XEON_SP_COMMON_BASE))
461 return 0x36;
Elyes HAOUAS28fa33c2019-01-25 13:46:43 +0100462
463 return 0x02; /* Unknown */
464}
465
Tim Chua96eaf82020-11-12 03:15:39 -0800466unsigned int __weak smbios_memory_error_correction_type(struct memory_info *meminfo)
467{
468 return meminfo->ecc_capable ?
469 MEMORY_ARRAY_ECC_SINGLE_BIT : MEMORY_ARRAY_ECC_NONE;
470}
471
Morgan Jang92bcc4f2020-07-24 10:36:18 +0800472unsigned int __weak smbios_processor_external_clock(void)
473{
474 return 0; /* Unknown */
475}
476
477unsigned int __weak smbios_processor_characteristics(void)
478{
479 return 0;
480}
481
482unsigned int __weak smbios_processor_family(struct cpuid_result res)
483{
484 return (res.eax > 0) ? 0x0c : 0x6;
485}
486
Morgan Jang8ae391d2020-10-06 16:26:17 +0800487unsigned int __weak smbios_cache_error_correction_type(u8 level)
488{
489 return SMBIOS_CACHE_ERROR_CORRECTION_UNKNOWN;
490}
491
492unsigned int __weak smbios_cache_sram_type(void)
493{
494 return SMBIOS_CACHE_SRAM_TYPE_UNKNOWN;
495}
496
497unsigned int __weak smbios_cache_conf_operation_mode(u8 level)
498{
499 return SMBIOS_CACHE_OP_MODE_UNKNOWN; /* Unknown */
500}
501
Patrick Rudolphb01ac7e2020-07-26 14:23:37 +0200502/* Returns the processor voltage in 100mV units */
503unsigned int __weak smbios_cpu_get_voltage(void)
504{
505 return 0; /* Unknown */
506}
507
Morgan Jang8ae391d2020-10-06 16:26:17 +0800508static size_t get_number_of_caches(struct cpuid_result res_deterministic_cache)
509{
510 size_t max_logical_cpus_sharing_cache = 0;
511 size_t number_of_cpus_per_package = 0;
512 size_t max_logical_cpus_per_package = 0;
513 struct cpuid_result res;
514
515 if (!cpu_have_cpuid())
516 return 1;
517
518 res = cpuid(1);
519
520 max_logical_cpus_per_package = (res.ebx >> 16) & 0xff;
521
522 max_logical_cpus_sharing_cache = ((res_deterministic_cache.eax >> 14) & 0xfff) + 1;
523
524 /* Check if it's last level cache */
525 if (max_logical_cpus_sharing_cache == max_logical_cpus_per_package)
526 return 1;
527
528 if (cpuid_get_max_func() >= 0xb) {
529 res = cpuid_ext(0xb, 1);
530 number_of_cpus_per_package = res.ebx & 0xff;
531 } else {
532 number_of_cpus_per_package = max_logical_cpus_per_package;
533 }
534
535 return number_of_cpus_per_package / max_logical_cpus_sharing_cache;
536}
537
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200538static int smbios_write_type1(unsigned long *current, int handle)
539{
540 struct smbios_type1 *t = (struct smbios_type1 *)*current;
541 int len = sizeof(struct smbios_type1);
542
543 memset(t, 0, sizeof(struct smbios_type1));
544 t->type = SMBIOS_SYSTEM_INFORMATION;
545 t->handle = handle;
546 t->length = len - 2;
Angel Ponsbf2f91c2020-07-29 18:14:59 +0200547 t->manufacturer = smbios_add_string(t->eos, smbios_system_manufacturer());
548 t->product_name = smbios_add_string(t->eos, smbios_system_product_name());
549 t->serial_number = smbios_add_string(t->eos, smbios_system_serial_number());
Nico Huberebd8a4f2017-11-01 09:49:16 +0100550 t->sku = smbios_add_string(t->eos, smbios_system_sku());
551 t->version = smbios_add_string(t->eos, smbios_system_version());
Marc Jonesf43ba9c2015-06-09 21:10:43 -0600552#ifdef CONFIG_MAINBOARD_FAMILY
Nico Huberebd8a4f2017-11-01 09:49:16 +0100553 t->family = smbios_add_string(t->eos, CONFIG_MAINBOARD_FAMILY);
Marc Jonesf43ba9c2015-06-09 21:10:43 -0600554#endif
Nico Huberebd8a4f2017-11-01 09:49:16 +0100555 smbios_system_set_uuid(t->uuid);
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200556 len = t->length + smbios_string_table_len(t->eos);
557 *current += len;
558 return len;
559}
560
Angel Ponsbf2f91c2020-07-29 18:14:59 +0200561static int smbios_write_type2(unsigned long *current, int handle, const int chassis_handle)
Vladimir Serbinenko47089f22014-03-02 19:14:44 +0100562{
563 struct smbios_type2 *t = (struct smbios_type2 *)*current;
564 int len = sizeof(struct smbios_type2);
565
566 memset(t, 0, sizeof(struct smbios_type2));
567 t->type = SMBIOS_BOARD_INFORMATION;
568 t->handle = handle;
569 t->length = len - 2;
Angel Ponsbf2f91c2020-07-29 18:14:59 +0200570 t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer());
571 t->product_name = smbios_add_string(t->eos, smbios_mainboard_product_name());
572 t->serial_number = smbios_add_string(t->eos, smbios_mainboard_serial_number());
Vladimir Serbinenko47089f22014-03-02 19:14:44 +0100573 t->version = smbios_add_string(t->eos, smbios_mainboard_version());
Julien Viard de Galbert9a31dfe2018-02-22 16:39:58 +0100574 t->asset_tag = smbios_add_string(t->eos, smbios_mainboard_asset_tag());
575 t->feature_flags = smbios_mainboard_feature_flags();
576 t->location_in_chassis = smbios_add_string(t->eos,
577 smbios_mainboard_location_in_chassis());
578 t->board_type = smbios_mainboard_board_type();
579 t->chassis_handle = chassis_handle;
Vladimir Serbinenko47089f22014-03-02 19:14:44 +0100580 len = t->length + smbios_string_table_len(t->eos);
581 *current += len;
582 return len;
583}
584
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200585static int smbios_write_type3(unsigned long *current, int handle)
586{
587 struct smbios_type3 *t = (struct smbios_type3 *)*current;
588 int len = sizeof(struct smbios_type3);
589
590 memset(t, 0, sizeof(struct smbios_type3));
591 t->type = SMBIOS_SYSTEM_ENCLOSURE;
592 t->handle = handle;
593 t->length = len - 2;
Angel Ponsbf2f91c2020-07-29 18:14:59 +0200594 t->manufacturer = smbios_add_string(t->eos, smbios_system_manufacturer());
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200595 t->bootup_state = SMBIOS_STATE_SAFE;
596 t->power_supply_state = SMBIOS_STATE_SAFE;
597 t->thermal_state = SMBIOS_STATE_SAFE;
Mathew Kinga7d55cf2019-07-31 15:50:15 -0600598 t->_type = smbios_mainboard_enclosure_type();
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200599 t->security_status = SMBIOS_STATE_SAFE;
Johnny Lind3440542020-01-30 18:21:22 +0800600 t->asset_tag_number = smbios_add_string(t->eos, smbios_mainboard_asset_tag());
601 t->version = smbios_add_string(t->eos, smbios_chassis_version());
602 t->serial_number = smbios_add_string(t->eos, smbios_chassis_serial_number());
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200603 len = t->length + smbios_string_table_len(t->eos);
604 *current += len;
605 return len;
606}
607
608static int smbios_write_type4(unsigned long *current, int handle)
609{
Patrick Rudolphb01ac7e2020-07-26 14:23:37 +0200610 unsigned int cpu_voltage;
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200611 struct cpuid_result res;
612 struct smbios_type4 *t = (struct smbios_type4 *)*current;
613 int len = sizeof(struct smbios_type4);
Morgan Jang92bcc4f2020-07-24 10:36:18 +0800614 uint16_t characteristics = 0;
Tim Chu27bf0c82020-09-16 00:34:08 -0700615 static unsigned int cnt = 0;
616 char buf[8];
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200617
Rudolf Marek06253cd2012-02-25 23:51:12 +0100618 /* Provide sane defaults even for CPU without CPUID */
619 res.eax = res.edx = 0;
620 res.ebx = 0x10000;
621
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700622 if (cpu_have_cpuid())
Rudolf Marek06253cd2012-02-25 23:51:12 +0100623 res = cpuid(1);
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200624
625 memset(t, 0, sizeof(struct smbios_type4));
626 t->type = SMBIOS_PROCESSOR_INFORMATION;
627 t->handle = handle;
628 t->length = len - 2;
Tim Chu27bf0c82020-09-16 00:34:08 -0700629
630 snprintf(buf, sizeof(buf), "CPU%d", cnt++);
631 t->socket_designation = smbios_add_string(t->eos, buf);
632
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200633 t->processor_id[0] = res.eax;
634 t->processor_id[1] = res.edx;
635 t->processor_manufacturer = smbios_cpu_vendor(t->eos);
636 t->processor_version = smbios_processor_name(t->eos);
Morgan Jang92bcc4f2020-07-24 10:36:18 +0800637 t->processor_family = smbios_processor_family(res);
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200638 t->processor_type = 3; /* System Processor */
Andrey Petrov515ef382019-11-15 13:19:08 -0800639 /*
640 * If CPUID leaf 11 is available, calculate "core count" by dividing
641 * SMT_ID (logical processors in a core) by Core_ID (number of cores).
642 * This seems to be the way to arrive to a number of cores mentioned on
643 * ark.intel.com.
644 */
645 if (cpu_have_cpuid() && cpuid_get_max_func() >= 0xb) {
646 uint32_t leaf_b_cores = 0, leaf_b_threads = 0;
647 res = cpuid_ext(0xb, 1);
648 leaf_b_cores = res.ebx;
649 res = cpuid_ext(0xb, 0);
650 leaf_b_threads = res.ebx;
651 /* if hyperthreading is not available, pretend this is 1 */
652 if (leaf_b_threads == 0) {
653 leaf_b_threads = 1;
654 }
Patrick Rudolph7a835822020-07-22 16:00:53 +0200655 t->core_count2 = leaf_b_cores / leaf_b_threads;
656 t->core_count = t->core_count2 > 0xff ? 0xff : t->core_count2;
Francois Toguo597922e2019-03-27 18:13:07 -0700657 t->thread_count2 = leaf_b_cores;
658 t->thread_count = t->thread_count2 > 0xff ? 0xff : t->thread_count2;
Andrey Petrov515ef382019-11-15 13:19:08 -0800659 } else {
660 t->core_count = (res.ebx >> 16) & 0xff;
Patrick Rudolph7a835822020-07-22 16:00:53 +0200661 t->core_count2 = t->core_count;
662 t->thread_count2 = t->core_count2;
Francois Toguo597922e2019-03-27 18:13:07 -0700663 t->thread_count = t->thread_count2;
Andrey Petrov515ef382019-11-15 13:19:08 -0800664 }
Andrey Petrov2e032f02019-10-23 15:31:51 -0700665 /* Assume we enable all the cores always, capped only by MAX_CPUS */
Andrey Petrova7fb2302019-11-07 09:48:41 -0800666 t->core_enabled = MIN(t->core_count, CONFIG_MAX_CPUS);
Patrick Rudolph7a835822020-07-22 16:00:53 +0200667 t->core_enabled2 = MIN(t->core_count2, CONFIG_MAX_CPUS);
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200668 t->l1_cache_handle = 0xffff;
669 t->l2_cache_handle = 0xffff;
670 t->l3_cache_handle = 0xffff;
Johnny Lind3440542020-01-30 18:21:22 +0800671 t->serial_number = smbios_add_string(t->eos, smbios_processor_serial_number());
Angel Ponsbf2f91c2020-07-29 18:14:59 +0200672 t->status = SMBIOS_PROCESSOR_STATUS_CPU_ENABLED | SMBIOS_PROCESSOR_STATUS_POPULATED;
Elyes HAOUAS28fa33c2019-01-25 13:46:43 +0100673 t->processor_upgrade = get_socket_type();
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200674 len = t->length + smbios_string_table_len(t->eos);
Andrey Petrov2e032f02019-10-23 15:31:51 -0700675 if (cpu_have_cpuid() && cpuid_get_max_func() >= 0x16) {
676 t->max_speed = cpuid_ebx(0x16);
677 t->current_speed = cpuid_eax(0x16); /* base frequency */
Morgan Jang92bcc4f2020-07-24 10:36:18 +0800678 t->external_clock = cpuid_ecx(0x16);
Andrey Petrov2e032f02019-10-23 15:31:51 -0700679 } else {
680 t->max_speed = smbios_cpu_get_max_speed_mhz();
681 t->current_speed = smbios_cpu_get_current_speed_mhz();
Morgan Jang92bcc4f2020-07-24 10:36:18 +0800682 t->external_clock = smbios_processor_external_clock();
Andrey Petrov2e032f02019-10-23 15:31:51 -0700683 }
Morgan Jang92bcc4f2020-07-24 10:36:18 +0800684
685 if (cpu_have_cpuid()) {
686 res = cpuid(1);
687
688 if ((res.ecx) & BIT(5))
689 characteristics |= BIT(6); /* BIT6: Enhanced Virtualization */
690
691 if ((res.edx) & BIT(28))
692 characteristics |= BIT(4); /* BIT4: Hardware Thread */
693
694 if (((cpuid_eax(0x80000000) - 0x80000000) + 1) > 2) {
695 res = cpuid(0x80000001);
696
697 if ((res.edx) & BIT(20))
698 characteristics |= BIT(5); /* BIT5: Execute Protection */
699 }
700 }
701 t->processor_characteristics = characteristics | smbios_processor_characteristics();
Patrick Rudolphb01ac7e2020-07-26 14:23:37 +0200702 cpu_voltage = smbios_cpu_get_voltage();
703 if (cpu_voltage > 0)
704 t->voltage = 0x80 | cpu_voltage;
Morgan Jang92bcc4f2020-07-24 10:36:18 +0800705
Sven Schnelle164bcfd2011-08-14 20:56:34 +0200706 *current += len;
707 return len;
708}
709
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100710/*
711 * Write SMBIOS type 7.
712 * Fill in some fields with constant values, as gathering the information
713 * from CPUID is impossible.
714 */
Angel Ponsbf2f91c2020-07-29 18:14:59 +0200715static int smbios_write_type7(unsigned long *current,
716 const int handle,
717 const u8 level,
718 const u8 sram_type,
719 const enum smbios_cache_associativity associativity,
720 const enum smbios_cache_type type,
721 const size_t max_cache_size,
722 const size_t cache_size)
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100723{
724 struct smbios_type7 *t = (struct smbios_type7 *)*current;
725 int len = sizeof(struct smbios_type7);
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100726 char buf[8];
727
728 memset(t, 0, sizeof(struct smbios_type7));
729 t->type = SMBIOS_CACHE_INFORMATION;
730 t->handle = handle;
731 t->length = len - 2;
732
Morgan Jang8ae391d2020-10-06 16:26:17 +0800733 snprintf(buf, sizeof(buf), "CACHE%x", level);
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100734 t->socket_designation = smbios_add_string(t->eos, buf);
735
736 t->cache_configuration = SMBIOS_CACHE_CONF_LEVEL(level) |
737 SMBIOS_CACHE_CONF_LOCATION(0) | /* Internal */
738 SMBIOS_CACHE_CONF_ENABLED(1) | /* Enabled */
Morgan Jang8ae391d2020-10-06 16:26:17 +0800739 SMBIOS_CACHE_CONF_OPERATION_MODE(smbios_cache_conf_operation_mode(level));
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100740
741 if (max_cache_size < (SMBIOS_CACHE_SIZE_MASK * KiB)) {
742 t->max_cache_size = max_cache_size / KiB;
743 t->max_cache_size2 = t->max_cache_size;
744
745 t->max_cache_size |= SMBIOS_CACHE_SIZE_UNIT_1KB;
746 t->max_cache_size2 |= SMBIOS_CACHE_SIZE2_UNIT_1KB;
747 } else {
Patrick Rudolph8f702672019-04-13 09:44:02 +0200748 if (max_cache_size < (SMBIOS_CACHE_SIZE_MASK * 64 * KiB))
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100749 t->max_cache_size = max_cache_size / (64 * KiB);
750 else
751 t->max_cache_size = SMBIOS_CACHE_SIZE_OVERFLOW;
752 t->max_cache_size2 = max_cache_size / (64 * KiB);
753
754 t->max_cache_size |= SMBIOS_CACHE_SIZE_UNIT_64KB;
755 t->max_cache_size2 |= SMBIOS_CACHE_SIZE2_UNIT_64KB;
756 }
757
758 if (cache_size < (SMBIOS_CACHE_SIZE_MASK * KiB)) {
759 t->installed_size = cache_size / KiB;
760 t->installed_size2 = t->installed_size;
761
762 t->installed_size |= SMBIOS_CACHE_SIZE_UNIT_1KB;
763 t->installed_size2 |= SMBIOS_CACHE_SIZE2_UNIT_1KB;
764 } else {
765 if (cache_size < (SMBIOS_CACHE_SIZE_MASK * 64 * KiB))
766 t->installed_size = cache_size / (64 * KiB);
767 else
768 t->installed_size = SMBIOS_CACHE_SIZE_OVERFLOW;
769 t->installed_size2 = cache_size / (64 * KiB);
770
771 t->installed_size |= SMBIOS_CACHE_SIZE_UNIT_64KB;
772 t->installed_size2 |= SMBIOS_CACHE_SIZE2_UNIT_64KB;
773 }
774
775 t->associativity = associativity;
776 t->supported_sram_type = sram_type;
777 t->current_sram_type = sram_type;
778 t->cache_speed = 0; /* Unknown */
Morgan Jang8ae391d2020-10-06 16:26:17 +0800779 t->error_correction_type = smbios_cache_error_correction_type(level);
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100780 t->system_cache_type = type;
781
782 len = t->length + smbios_string_table_len(t->eos);
783 *current += len;
784 return len;
785}
786
787/* Convert the associativity as integer to the SMBIOS enum if available */
Angel Ponsbf2f91c2020-07-29 18:14:59 +0200788static enum smbios_cache_associativity smbios_cache_associativity(const u8 num)
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100789{
790 switch (num) {
791 case 1:
792 return SMBIOS_CACHE_ASSOCIATIVITY_DIRECT;
793 case 2:
794 return SMBIOS_CACHE_ASSOCIATIVITY_2WAY;
795 case 4:
796 return SMBIOS_CACHE_ASSOCIATIVITY_4WAY;
797 case 8:
798 return SMBIOS_CACHE_ASSOCIATIVITY_8WAY;
799 case 12:
800 return SMBIOS_CACHE_ASSOCIATIVITY_12WAY;
801 case 16:
802 return SMBIOS_CACHE_ASSOCIATIVITY_16WAY;
803 case 20:
804 return SMBIOS_CACHE_ASSOCIATIVITY_20WAY;
805 case 24:
806 return SMBIOS_CACHE_ASSOCIATIVITY_24WAY;
807 case 32:
808 return SMBIOS_CACHE_ASSOCIATIVITY_32WAY;
809 case 48:
810 return SMBIOS_CACHE_ASSOCIATIVITY_48WAY;
811 case 64:
812 return SMBIOS_CACHE_ASSOCIATIVITY_64WAY;
813 case 0xff:
814 return SMBIOS_CACHE_ASSOCIATIVITY_FULL;
815 default:
816 return SMBIOS_CACHE_ASSOCIATIVITY_UNKNOWN;
817 };
818}
819
820/*
821 * Parse the "Deterministic Cache Parameters" as provided by Intel in
822 * leaf 4 or AMD in extended leaf 0x8000001d.
823 *
824 * @param current Pointer to memory address to write the tables to
825 * @param handle Pointer to handle for the tables
826 * @param max_struct_size Pointer to maximum struct size
Patrick Rudolph15589b42019-03-30 17:51:06 +0100827 * @param type4 Pointer to SMBIOS type 4 structure
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100828 */
829static int smbios_write_type7_cache_parameters(unsigned long *current,
830 int *handle,
Patrick Rudolph15589b42019-03-30 17:51:06 +0100831 int *max_struct_size,
832 struct smbios_type4 *type4)
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100833{
834 struct cpuid_result res;
835 unsigned int cnt = 0;
836 int len = 0;
837 u32 leaf;
838
839 if (!cpu_have_cpuid())
840 return len;
841
842 if (cpu_is_intel()) {
843 res = cpuid(0);
844 if (res.eax < 4)
845 return len;
846 leaf = 4;
847 } else if (cpu_is_amd()) {
848 res = cpuid(0x80000000);
849 if (res.eax < 0x80000001)
850 return len;
851
852 res = cpuid(0x80000001);
853 if (!(res.ecx & (1 << 22)))
854 return len;
855
856 leaf = 0x8000001d;
857 } else {
858 printk(BIOS_DEBUG, "SMBIOS: Unknown CPU\n");
859 return len;
860 }
861
862 while (1) {
863 enum smbios_cache_associativity associativity;
864 enum smbios_cache_type type;
865
866 res = cpuid_ext(leaf, cnt++);
867
868 const u8 cache_type = CPUID_CACHE_TYPE(res);
869 const u8 level = CPUID_CACHE_LEVEL(res);
870 const size_t assoc = CPUID_CACHE_WAYS_OF_ASSOC(res) + 1;
871 const size_t partitions = CPUID_CACHE_PHYS_LINE(res) + 1;
872 const size_t cache_line_size = CPUID_CACHE_COHER_LINE(res) + 1;
873 const size_t number_of_sets = CPUID_CACHE_NO_OF_SETS(res) + 1;
Morgan Jang8ae391d2020-10-06 16:26:17 +0800874 const size_t cache_size = assoc * partitions * cache_line_size * number_of_sets
875 * get_number_of_caches(res);
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100876
877 if (!cache_type)
878 /* No more caches in the system */
879 break;
880
881 switch (cache_type) {
882 case 1:
883 type = SMBIOS_CACHE_TYPE_DATA;
884 break;
885 case 2:
886 type = SMBIOS_CACHE_TYPE_INSTRUCTION;
887 break;
888 case 3:
889 type = SMBIOS_CACHE_TYPE_UNIFIED;
890 break;
891 default:
892 type = SMBIOS_CACHE_TYPE_UNKNOWN;
893 break;
894 }
895
896 if (CPUID_CACHE_FULL_ASSOC(res))
897 associativity = SMBIOS_CACHE_ASSOCIATIVITY_FULL;
898 else
899 associativity = smbios_cache_associativity(assoc);
900
Patrick Rudolph15589b42019-03-30 17:51:06 +0100901 const int h = (*handle)++;
902
903 update_max(len, *max_struct_size, smbios_write_type7(current, h,
Morgan Jang8ae391d2020-10-06 16:26:17 +0800904 level, smbios_cache_sram_type(), associativity,
Patrick Rudolph15589b42019-03-30 17:51:06 +0100905 type, cache_size, cache_size));
906
907 if (type4) {
908 switch (level) {
909 case 1:
910 type4->l1_cache_handle = h;
911 break;
912 case 2:
913 type4->l2_cache_handle = h;
914 break;
915 case 3:
916 type4->l3_cache_handle = h;
917 break;
918 }
919 }
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100920 };
921
922 return len;
923}
BryantOu4a8e58f2020-04-20 19:45:20 -0700924
925int smbios_write_type8(unsigned long *current, int *handle,
926 const struct port_information *port,
927 size_t num_ports)
928{
929 int len = sizeof(struct smbios_type8);
930 unsigned int totallen = 0, i;
931
932 for (i = 0; i < num_ports; i++, port++) {
933 struct smbios_type8 *t = (struct smbios_type8 *)*current;
934 memset(t, 0, sizeof(struct smbios_type8));
935 t->type = SMBIOS_PORT_CONNECTOR_INFORMATION;
936 t->handle = *handle;
937 t->length = len - 2;
938 t->internal_reference_designator =
939 smbios_add_string(t->eos, port->internal_reference_designator);
940 t->internal_connector_type = port->internal_connector_type;
941 t->external_reference_designator =
942 smbios_add_string(t->eos, port->external_reference_designator);
943 t->external_connector_type = port->external_connector_type;
944 t->port_type = port->port_type;
945 *handle += 1;
946 *current += t->length + smbios_string_table_len(t->eos);
947 totallen += t->length + smbios_string_table_len(t->eos);
948 }
949 return totallen;
950}
951
Lijian Zhaoe98a7512019-04-11 23:28:09 -0700952int smbios_write_type9(unsigned long *current, int *handle,
953 const char *name, const enum misc_slot_type type,
954 const enum slot_data_bus_bandwidth bandwidth,
955 const enum misc_slot_usage usage,
956 const enum misc_slot_length length,
957 u8 slot_char1, u8 slot_char2, u8 bus, u8 dev_func)
958{
959 struct smbios_type9 *t = (struct smbios_type9 *)*current;
960 int len = sizeof(struct smbios_type9);
961
962 memset(t, 0, sizeof(struct smbios_type9));
963 t->type = SMBIOS_SYSTEM_SLOTS;
964 t->handle = *handle;
965 t->length = len - 2;
Angel Pons3c13da72020-07-29 18:23:23 +0200966 t->slot_designation = smbios_add_string(t->eos, name ? name : "SLOT");
Lijian Zhaoe98a7512019-04-11 23:28:09 -0700967 t->slot_type = type;
968 /* TODO add slot_id supoort, will be "_SUN" for ACPI devices */
969 t->slot_data_bus_width = bandwidth;
970 t->current_usage = usage;
971 t->slot_length = length;
972 t->slot_characteristics_1 = slot_char1;
973 t->slot_characteristics_2 = slot_char2;
974 t->segment_group_number = 0;
975 t->bus_number = bus;
976 t->device_function_number = dev_func;
977 t->data_bus_width = SlotDataBusWidthOther;
978
979 len = t->length + smbios_string_table_len(t->eos);
980 *current += len;
981 *handle += 1;
982 return len;
983}
Patrick Rudolphfc5b8092019-03-30 17:37:28 +0100984
Vladimir Serbinenko6abb33c2014-08-27 23:42:45 +0200985static int smbios_write_type11(unsigned long *current, int *handle)
Peter Stugec392b642013-07-06 19:51:12 +0200986{
987 struct smbios_type11 *t = (struct smbios_type11 *)*current;
Vladimir Serbinenko6abb33c2014-08-27 23:42:45 +0200988 int len;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100989 struct device *dev;
Peter Stugec392b642013-07-06 19:51:12 +0200990
Lee Leahy0b5678f2017-03-16 16:01:40 -0700991 memset(t, 0, sizeof(*t));
Peter Stugec392b642013-07-06 19:51:12 +0200992 t->type = SMBIOS_OEM_STRINGS;
Vladimir Serbinenko6abb33c2014-08-27 23:42:45 +0200993 t->handle = *handle;
Lee Leahy0b5678f2017-03-16 16:01:40 -0700994 t->length = len = sizeof(*t) - 2;
Peter Stugec392b642013-07-06 19:51:12 +0200995
Elyes HAOUASdbf30672016-08-21 17:37:15 +0200996 for (dev = all_devices; dev; dev = dev->next) {
Vladimir Serbinenko6abb33c2014-08-27 23:42:45 +0200997 if (dev->ops && dev->ops->get_smbios_strings)
998 dev->ops->get_smbios_strings(dev, t);
999 }
1000
1001 if (t->count == 0) {
Lee Leahy0b5678f2017-03-16 16:01:40 -07001002 memset(t, 0, sizeof(*t));
Vladimir Serbinenko6abb33c2014-08-27 23:42:45 +02001003 return 0;
1004 }
Peter Stugec392b642013-07-06 19:51:12 +02001005
1006 len += smbios_string_table_len(t->eos);
Vladimir Serbinenko6abb33c2014-08-27 23:42:45 +02001007
Peter Stugec392b642013-07-06 19:51:12 +02001008 *current += len;
Vladimir Serbinenko6abb33c2014-08-27 23:42:45 +02001009 (*handle)++;
Peter Stugec392b642013-07-06 19:51:12 +02001010 return len;
1011}
1012
Patrick Rudolph5e007802020-07-27 15:37:43 +02001013static int smbios_write_type16(unsigned long *current, int *handle)
1014{
1015 struct smbios_type16 *t = (struct smbios_type16 *)*current;
1016
1017 int len;
1018 int i;
1019
1020 struct memory_info *meminfo;
1021 meminfo = cbmem_find(CBMEM_ID_MEMINFO);
1022 if (meminfo == NULL)
1023 return 0; /* can't find mem info in cbmem */
1024
1025 printk(BIOS_INFO, "Create SMBIOS type 16\n");
1026
1027 if (meminfo->max_capacity_mib == 0 || meminfo->number_of_devices == 0) {
1028 /* Fill in defaults if not provided */
1029 meminfo->number_of_devices = 0;
1030 meminfo->max_capacity_mib = 0;
1031 for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) {
1032 meminfo->max_capacity_mib += meminfo->dimm[i].dimm_size;
1033 meminfo->number_of_devices += !!meminfo->dimm[i].dimm_size;
1034 }
1035 }
1036
1037 memset(t, 0, sizeof(*t));
1038 t->type = SMBIOS_PHYS_MEMORY_ARRAY;
1039 t->handle = *handle;
1040 t->length = len = sizeof(*t) - 2;
1041
1042 t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD;
1043 t->use = MEMORY_ARRAY_USE_SYSTEM;
Tim Chua96eaf82020-11-12 03:15:39 -08001044 t->memory_error_correction = smbios_memory_error_correction_type(meminfo);
Patrick Rudolph5e007802020-07-27 15:37:43 +02001045
1046 /* no error information handle available */
1047 t->memory_error_information_handle = 0xFFFE;
1048 t->maximum_capacity = meminfo->max_capacity_mib * (MiB / KiB);
1049 t->number_of_memory_devices = meminfo->number_of_devices;
1050
1051 len += smbios_string_table_len(t->eos);
1052
1053 *current += len;
1054 (*handle)++;
1055 return len;
1056}
1057
1058static int smbios_write_type17(unsigned long *current, int *handle, int type16)
Kane Chen33faac62014-07-27 12:54:44 -07001059{
1060 int len = sizeof(struct smbios_type17);
Iru Cai36775202016-03-09 23:22:58 +08001061 int totallen = 0;
Kane Chen33faac62014-07-27 12:54:44 -07001062 int i;
1063
1064 struct memory_info *meminfo;
1065 meminfo = cbmem_find(CBMEM_ID_MEMINFO);
1066 if (meminfo == NULL)
1067 return 0; /* can't find mem info in cbmem */
1068
1069 printk(BIOS_INFO, "Create SMBIOS type 17\n");
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001070 for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) {
Kane Chen33faac62014-07-27 12:54:44 -07001071 struct dimm_info *dimm;
1072 dimm = &meminfo->dimm[i];
Patrick Rudolph5e007802020-07-27 15:37:43 +02001073 /*
1074 * Windows 10 GetPhysicallyInstalledSystemMemory functions reads SMBIOS tables
1075 * type 16 and type 17. The type 17 tables need to point to a type 16 table.
1076 * Otherwise, the physical installed memory size is guessed from the system
1077 * memory map, which results in a slightly smaller value than the actual size.
1078 */
1079 len = create_smbios_type17_for_dimm(dimm, current, handle, type16);
Kane Chen33faac62014-07-27 12:54:44 -07001080 *current += len;
Iru Cai36775202016-03-09 23:22:58 +08001081 totallen += len;
Kane Chen33faac62014-07-27 12:54:44 -07001082 }
Iru Cai36775202016-03-09 23:22:58 +08001083 return totallen;
Kane Chen33faac62014-07-27 12:54:44 -07001084}
1085
Tim Chue41f5952020-11-02 21:33:52 -08001086static int smbios_write_type19(unsigned long *current, int *handle, int type16)
Patrick Rudolph604295e2020-07-21 14:53:37 +02001087{
1088 struct smbios_type19 *t = (struct smbios_type19 *)*current;
1089 int len = sizeof(struct smbios_type19);
1090 int i;
1091
1092 struct memory_info *meminfo;
1093 meminfo = cbmem_find(CBMEM_ID_MEMINFO);
1094 if (meminfo == NULL)
1095 return 0; /* can't find mem info in cbmem */
1096
1097 memset(t, 0, sizeof(struct smbios_type19));
1098
1099 t->type = SMBIOS_MEMORY_ARRAY_MAPPED_ADDRESS;
1100 t->length = len - 2;
1101 t->handle = *handle;
Tim Chue41f5952020-11-02 21:33:52 -08001102 t->memory_array_handle = type16;
Patrick Rudolph604295e2020-07-21 14:53:37 +02001103
1104 for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) {
1105 if (meminfo->dimm[i].dimm_size > 0) {
1106 t->extended_ending_address += meminfo->dimm[i].dimm_size;
1107 t->partition_width++;
1108 }
1109 }
1110 t->extended_ending_address *= MiB;
1111
1112 /* Check if it fits into regular address */
1113 if (t->extended_ending_address >= KiB &&
1114 t->extended_ending_address < 0x40000000000ULL) {
1115 /*
1116 * FIXME: The starting address is SoC specific, but SMBIOS tables are only
1117 * exported on x86 where it's always 0.
1118 */
1119
1120 t->starting_address = 0;
1121 t->ending_address = t->extended_ending_address / KiB - 1;
1122 t->extended_starting_address = ~0;
1123 t->extended_ending_address = ~0;
1124 } else {
1125 t->starting_address = ~0;
1126 t->ending_address = ~0;
1127 t->extended_starting_address = 0;
1128 t->extended_ending_address--;
1129 }
1130
1131 len = t->length + smbios_string_table_len(t->eos);
1132 *current += len;
1133 *handle += 1;
1134 return len;
1135}
1136
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001137static int smbios_write_type32(unsigned long *current, int handle)
1138{
1139 struct smbios_type32 *t = (struct smbios_type32 *)*current;
1140 int len = sizeof(struct smbios_type32);
1141
1142 memset(t, 0, sizeof(struct smbios_type32));
1143 t->type = SMBIOS_SYSTEM_BOOT_INFORMATION;
1144 t->handle = handle;
1145 t->length = len - 2;
1146 *current += len;
1147 return len;
1148}
1149
Patrick Rudolphfe98e902018-03-27 16:17:12 +02001150int smbios_write_type38(unsigned long *current, int *handle,
1151 const enum smbios_bmc_interface_type interface_type,
1152 const u8 ipmi_rev, const u8 i2c_addr, const u8 nv_addr,
1153 const u64 base_addr, const u8 base_modifier,
1154 const u8 irq)
1155{
1156 struct smbios_type38 *t = (struct smbios_type38 *)*current;
1157 int len = sizeof(struct smbios_type38);
1158
1159 memset(t, 0, sizeof(struct smbios_type38));
1160 t->type = SMBIOS_IPMI_DEVICE_INFORMATION;
1161 t->handle = *handle;
1162 t->length = len - 2;
1163 t->interface_type = interface_type;
1164 t->ipmi_rev = ipmi_rev;
1165 t->i2c_slave_addr = i2c_addr;
1166 t->nv_storage_addr = nv_addr;
1167 t->base_address = base_addr;
1168 t->base_address_modifier = base_modifier;
1169 t->irq = irq;
1170
1171 *current += len;
1172 *handle += 1;
1173
1174 return len;
1175}
1176
Duncan Laurie21a78702013-05-23 14:17:05 -07001177int smbios_write_type41(unsigned long *current, int *handle,
1178 const char *name, u8 instance, u16 segment,
Christian Waltere6afab12019-05-21 17:22:49 +02001179 u8 bus, u8 device, u8 function, u8 device_type)
Duncan Laurie21a78702013-05-23 14:17:05 -07001180{
1181 struct smbios_type41 *t = (struct smbios_type41 *)*current;
1182 int len = sizeof(struct smbios_type41);
1183
1184 memset(t, 0, sizeof(struct smbios_type41));
1185 t->type = SMBIOS_ONBOARD_DEVICES_EXTENDED_INFORMATION;
1186 t->handle = *handle;
1187 t->length = len - 2;
1188 t->reference_designation = smbios_add_string(t->eos, name);
Christian Waltere6afab12019-05-21 17:22:49 +02001189 t->device_type = device_type;
Duncan Laurie21a78702013-05-23 14:17:05 -07001190 t->device_status = 1;
1191 t->device_type_instance = instance;
1192 t->segment_group_number = segment;
1193 t->bus_number = bus;
1194 t->device_number = device;
1195 t->function_number = function;
1196
1197 len = t->length + smbios_string_table_len(t->eos);
1198 *current += len;
1199 *handle += 1;
1200 return len;
1201}
1202
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001203static int smbios_write_type127(unsigned long *current, int handle)
1204{
1205 struct smbios_type127 *t = (struct smbios_type127 *)*current;
1206 int len = sizeof(struct smbios_type127);
1207
1208 memset(t, 0, sizeof(struct smbios_type127));
1209 t->type = SMBIOS_END_OF_TABLE;
1210 t->handle = handle;
1211 t->length = len - 2;
1212 *current += len;
1213 return len;
1214}
1215
Christian Walter9e5b0622019-05-21 17:37:58 +02001216/* Generate Type41 entries from devicetree */
1217static int smbios_walk_device_tree_type41(struct device *dev, int *handle,
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001218 unsigned long *current)
Christian Walter9e5b0622019-05-21 17:37:58 +02001219{
1220 static u8 type41_inst_cnt[SMBIOS_DEVICE_TYPE_COUNT + 1] = {};
1221
1222 if (dev->path.type != DEVICE_PATH_PCI)
1223 return 0;
1224 if (!dev->on_mainboard)
1225 return 0;
1226
1227 u8 device_type = smbios_get_device_type_from_dev(dev);
1228
1229 if (device_type == SMBIOS_DEVICE_TYPE_OTHER ||
1230 device_type == SMBIOS_DEVICE_TYPE_UNKNOWN)
1231 return 0;
1232
1233 if (device_type > SMBIOS_DEVICE_TYPE_COUNT)
1234 return 0;
1235
1236 const char *name = get_pci_subclass_name(dev);
1237
1238 return smbios_write_type41(current, handle,
1239 name, // name
1240 type41_inst_cnt[device_type]++, // inst
1241 0, // segment
1242 dev->bus->secondary, //bus
1243 PCI_SLOT(dev->path.pci.devfn), // device
1244 PCI_FUNC(dev->path.pci.devfn), // func
1245 device_type);
1246}
1247
Patrick Rudolphf5b93692019-04-12 15:59:40 +02001248/* Generate Type9 entries from devicetree */
1249static int smbios_walk_device_tree_type9(struct device *dev, int *handle,
1250 unsigned long *current)
1251{
1252 enum misc_slot_usage usage;
1253 enum slot_data_bus_bandwidth bandwidth;
1254 enum misc_slot_type type;
1255 enum misc_slot_length length;
1256
1257 if (dev->path.type != DEVICE_PATH_PCI)
1258 return 0;
1259
1260 if (!dev->smbios_slot_type && !dev->smbios_slot_data_width &&
1261 !dev->smbios_slot_designation && !dev->smbios_slot_length)
1262 return 0;
1263
1264 if (dev_is_active_bridge(dev))
1265 usage = SlotUsageInUse;
1266 else if (dev->enabled)
1267 usage = SlotUsageAvailable;
1268 else
1269 usage = SlotUsageUnknown;
1270
1271 if (dev->smbios_slot_data_width)
1272 bandwidth = dev->smbios_slot_data_width;
1273 else
1274 bandwidth = SlotDataBusWidthUnknown;
1275
1276 if (dev->smbios_slot_type)
1277 type = dev->smbios_slot_type;
1278 else
1279 type = SlotTypeUnknown;
1280
1281 if (dev->smbios_slot_length)
1282 length = dev->smbios_slot_length;
1283 else
1284 length = SlotLengthUnknown;
1285
1286 return smbios_write_type9(current, handle,
1287 dev->smbios_slot_designation,
1288 type,
1289 bandwidth,
1290 usage,
1291 length,
1292 1,
1293 0,
1294 dev->bus->secondary,
1295 dev->path.pci.devfn);
1296}
1297
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001298static int smbios_walk_device_tree(struct device *tree, int *handle, unsigned long *current)
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001299{
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +11001300 struct device *dev;
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001301 int len = 0;
1302
Elyes HAOUASdbf30672016-08-21 17:37:15 +02001303 for (dev = tree; dev; dev = dev->next) {
Naresh G Solanki20c893e2018-06-05 18:58:53 +05301304 if (dev->enabled && dev->ops && dev->ops->get_smbios_data) {
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001305 printk(BIOS_INFO, "%s (%s)\n", dev_path(dev), dev_name(dev));
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001306 len += dev->ops->get_smbios_data(dev, handle, current);
Naresh G Solanki20c893e2018-06-05 18:58:53 +05301307 }
Patrick Rudolphf5b93692019-04-12 15:59:40 +02001308 len += smbios_walk_device_tree_type9(dev, handle, current);
Christian Walter9e5b0622019-05-21 17:37:58 +02001309 len += smbios_walk_device_tree_type41(dev, handle, current);
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001310 }
1311 return len;
1312}
1313
1314unsigned long smbios_write_tables(unsigned long current)
1315{
1316 struct smbios_entry *se;
Patrick Rudolph7a835822020-07-22 16:00:53 +02001317 struct smbios_entry30 *se3;
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001318 unsigned long tables;
Ben Frisch72af5d72015-05-09 19:52:18 -05001319 int len = 0;
1320 int max_struct_size = 0;
1321 int handle = 0;
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001322
Felix Heldfcbb3c52019-06-20 14:01:54 +02001323 current = ALIGN_UP(current, 16);
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001324 printk(BIOS_DEBUG, "%s: %08lx\n", __func__, current);
1325
1326 se = (struct smbios_entry *)current;
1327 current += sizeof(struct smbios_entry);
Felix Heldfcbb3c52019-06-20 14:01:54 +02001328 current = ALIGN_UP(current, 16);
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001329
Patrick Rudolph7a835822020-07-22 16:00:53 +02001330 se3 = (struct smbios_entry30 *)current;
1331 current += sizeof(struct smbios_entry30);
1332 current = ALIGN_UP(current, 16);
1333
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001334 tables = current;
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001335 update_max(len, max_struct_size, smbios_write_type0(&current, handle++));
1336 update_max(len, max_struct_size, smbios_write_type1(&current, handle++));
1337
1338 /* The chassis handle is the next one */
1339 update_max(len, max_struct_size, smbios_write_type2(&current, handle, handle + 1));
Julien Viard de Galbert9a31dfe2018-02-22 16:39:58 +01001340 handle++;
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001341 update_max(len, max_struct_size, smbios_write_type3(&current, handle++));
Patrick Rudolph15589b42019-03-30 17:51:06 +01001342
1343 struct smbios_type4 *type4 = (struct smbios_type4 *)current;
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001344 update_max(len, max_struct_size, smbios_write_type4(&current, handle++));
1345 len += smbios_write_type7_cache_parameters(&current, &handle, &max_struct_size, type4);
1346 update_max(len, max_struct_size, smbios_write_type11(&current, &handle));
Julius Wernercd49cce2019-03-05 16:53:33 -08001347 if (CONFIG(ELOG))
Martin Roth898a7752017-06-01 11:39:59 -06001348 update_max(len, max_struct_size,
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001349 elog_smbios_write_type15(&current, handle++));
Patrick Rudolph5e007802020-07-27 15:37:43 +02001350
1351 const int type16 = handle;
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001352 update_max(len, max_struct_size, smbios_write_type16(&current, &handle));
1353 update_max(len, max_struct_size, smbios_write_type17(&current, &handle, type16));
Tim Chue41f5952020-11-02 21:33:52 -08001354 update_max(len, max_struct_size, smbios_write_type19(&current, &handle, type16));
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001355 update_max(len, max_struct_size, smbios_write_type32(&current, handle++));
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001356
Lee Leahy6f80ccc2017-03-16 15:18:22 -07001357 update_max(len, max_struct_size, smbios_walk_device_tree(all_devices,
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001358 &handle, &current));
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001359
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001360 update_max(len, max_struct_size, smbios_write_type127(&current, handle++));
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001361
Patrick Rudolph7a835822020-07-22 16:00:53 +02001362 /* Install SMBIOS 2.1 entry point */
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001363 memset(se, 0, sizeof(struct smbios_entry));
1364 memcpy(se->anchor, "_SM_", 4);
1365 se->length = sizeof(struct smbios_entry);
Patrick Rudolph7a835822020-07-22 16:00:53 +02001366 se->major_version = 3;
1367 se->minor_version = 0;
Ben Frisch72af5d72015-05-09 19:52:18 -05001368 se->max_struct_size = max_struct_size;
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001369 se->struct_count = handle;
1370 memcpy(se->intermediate_anchor_string, "_DMI_", 5);
1371
1372 se->struct_table_address = (u32)tables;
1373 se->struct_table_length = len;
1374
1375 se->intermediate_checksum = smbios_checksum((u8 *)se + 0x10,
Angel Ponsbf2f91c2020-07-29 18:14:59 +02001376 sizeof(struct smbios_entry) - 0x10);
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001377 se->checksum = smbios_checksum((u8 *)se, sizeof(struct smbios_entry));
Patrick Rudolph7a835822020-07-22 16:00:53 +02001378
1379 /* Install SMBIOS 3.0 entry point */
1380 memset(se3, 0, sizeof(struct smbios_entry30));
1381 memcpy(se3->anchor, "_SM3_", 5);
1382 se3->length = sizeof(struct smbios_entry30);
1383 se3->major_version = 3;
1384 se3->minor_version = 0;
1385
1386 se3->struct_table_address = (u64)tables;
1387 se3->struct_table_length = len;
1388
1389 se3->checksum = smbios_checksum((u8 *)se3, sizeof(struct smbios_entry30));
1390
Sven Schnelle164bcfd2011-08-14 20:56:34 +02001391 return current;
1392}