2011-08-14 20:56:34 +02:00
|
|
|
/*
|
|
|
|
* This file is part of the coreboot project.
|
|
|
|
*
|
2015-03-28 04:47:25 +01:00
|
|
|
* Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
|
2011-08-14 20:56:34 +02:00
|
|
|
* Copyright (C) 2011 Sven Schnelle <svens@stackframe.org>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; version 2 of
|
|
|
|
* the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <smbios.h>
|
|
|
|
#include <console/console.h>
|
2014-11-18 11:41:16 +01:00
|
|
|
#include <version.h>
|
2011-08-14 20:56:34 +02:00
|
|
|
#include <device/device.h>
|
|
|
|
#include <arch/cpu.h>
|
|
|
|
#include <cpu/x86/name.h>
|
2012-06-24 01:13:42 +02:00
|
|
|
#include <elog.h>
|
Unify byte order macros and clrsetbits
This patch removes quite a bit of code duplication between cpu_to_le32()
and clrsetbits_le32() style macros on the different architectures. This
also syncs those macros back up to the new write32(a, v) style IO
accessor macros that are now used on ARM and ARM64.
CQ-DEPEND=CL:254862
BRANCH=none
BUG=chromium:444723
TEST=Compiled Cosmos, Daisy, Blaze, Falco, Pinky, Pit, Rambi, Ryu,
Storm and Urara. Booted on Jerry. Tried to compare binary images...
unfortunately something about the new macro notation makes the compiler
evaluate it more efficiently (not recalculating the address between the
read and the write), so this was of limited value.
Change-Id: If8ab62912c952d68a67a0f71e82b038732cd1317
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: fd43bf446581bfb84bec4f2ebb56b5de95971c3b
Original-Change-Id: I7d301b5bb5ac0db7f5ff39e3adc2b28a1f402a72
Original-Signed-off-by: Julius Werner <jwerner@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/254866
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/9838
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-23 23:31:09 +01:00
|
|
|
#include <endian.h>
|
2014-07-27 21:54:44 +02:00
|
|
|
#include <memory_info.h>
|
|
|
|
#include <spd.h>
|
|
|
|
#include <cbmem.h>
|
2012-04-04 01:02:54 +02:00
|
|
|
#if CONFIG_CHROMEOS
|
|
|
|
#include <vendorcode/google/chromeos/gnvs.h>
|
|
|
|
#endif
|
2011-08-14 20:56:34 +02:00
|
|
|
|
|
|
|
static u8 smbios_checksum(u8 *p, u32 length)
|
|
|
|
{
|
|
|
|
u8 ret = 0;
|
|
|
|
while (length--)
|
|
|
|
ret += *p++;
|
|
|
|
return -ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int smbios_add_string(char *start, const char *str)
|
|
|
|
{
|
|
|
|
int i = 1;
|
|
|
|
char *p = start;
|
|
|
|
|
2015-12-09 18:24:35 +01:00
|
|
|
/*
|
|
|
|
* Return 0 as required for empty strings.
|
|
|
|
* See Section 6.1.3 "Text Strings" of the SMBIOS specification.
|
|
|
|
*/
|
|
|
|
if (*str == '\0')
|
|
|
|
return 0;
|
|
|
|
|
2011-08-14 20:56:34 +02:00
|
|
|
for(;;) {
|
|
|
|
if (!*p) {
|
|
|
|
strcpy(p, str);
|
|
|
|
p += strlen(str);
|
|
|
|
*p++ = '\0';
|
|
|
|
*p++ = '\0';
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(p, str))
|
|
|
|
return i;
|
|
|
|
|
|
|
|
p += strlen(p)+1;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int smbios_string_table_len(char *start)
|
|
|
|
{
|
|
|
|
char *p = start;
|
|
|
|
int i, len = 0;
|
|
|
|
|
|
|
|
while(*p) {
|
|
|
|
i = strlen(p) + 1;
|
|
|
|
p += i;
|
|
|
|
len += i;
|
|
|
|
}
|
|
|
|
return len + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int smbios_cpu_vendor(char *start)
|
|
|
|
{
|
2012-02-25 23:51:12 +01:00
|
|
|
char tmp[13] = "Unknown";
|
2011-08-14 20:56:34 +02:00
|
|
|
u32 *_tmp = (u32 *)tmp;
|
2012-02-25 23:51:12 +01:00
|
|
|
struct cpuid_result res;
|
2011-08-14 20:56:34 +02:00
|
|
|
|
2012-02-25 23:51:12 +01:00
|
|
|
if (cpu_have_cpuid()) {
|
|
|
|
res = cpuid(0);
|
|
|
|
_tmp[0] = res.ebx;
|
|
|
|
_tmp[1] = res.edx;
|
|
|
|
_tmp[2] = res.ecx;
|
|
|
|
tmp[12] = '\0';
|
|
|
|
}
|
2011-08-14 20:56:34 +02:00
|
|
|
|
2012-02-25 23:51:12 +01:00
|
|
|
return smbios_add_string(start, tmp);
|
2011-08-14 20:56:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int smbios_processor_name(char *start)
|
|
|
|
{
|
2012-02-25 23:51:12 +01:00
|
|
|
char tmp[49] = "Unknown Processor Name";
|
2011-08-14 20:56:34 +02:00
|
|
|
u32 *_tmp = (u32 *)tmp;
|
|
|
|
struct cpuid_result res;
|
|
|
|
int i;
|
|
|
|
|
2012-02-25 23:51:12 +01:00
|
|
|
if (cpu_have_cpuid()) {
|
|
|
|
res = cpuid(0x80000000);
|
|
|
|
if (res.eax >= 0x80000004) {
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
res = cpuid(0x80000002 + i);
|
|
|
|
_tmp[i * 4 + 0] = res.eax;
|
|
|
|
_tmp[i * 4 + 1] = res.ebx;
|
|
|
|
_tmp[i * 4 + 2] = res.ecx;
|
|
|
|
_tmp[i * 4 + 3] = res.edx;
|
|
|
|
}
|
|
|
|
tmp[48] = 0;
|
|
|
|
}
|
2011-08-14 20:56:34 +02:00
|
|
|
}
|
|
|
|
return smbios_add_string(start, tmp);
|
|
|
|
}
|
|
|
|
|
2014-07-27 21:54:44 +02:00
|
|
|
/* this function will fill the corresponding manufacturer */
|
2015-03-28 05:05:36 +01:00
|
|
|
void smbios_fill_dimm_manufacturer_from_id(uint16_t mod_id, struct smbios_type17 *t)
|
2014-07-27 21:54:44 +02:00
|
|
|
{
|
|
|
|
switch (mod_id) {
|
2015-07-28 16:22:59 +02:00
|
|
|
case 0x2c80:
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
"Crucial");
|
|
|
|
break;
|
2016-02-29 19:19:46 +01:00
|
|
|
case 0x4f01:
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
"Transcend");
|
|
|
|
break;
|
2015-06-26 01:37:58 +02:00
|
|
|
case 0x9801:
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
"Kingston");
|
|
|
|
break;
|
2015-03-28 04:47:25 +01:00
|
|
|
case 0x987f:
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
"Hynix");
|
|
|
|
break;
|
2015-06-26 01:37:58 +02:00
|
|
|
case 0x9e02:
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
"Corsair");
|
|
|
|
break;
|
2016-02-29 19:19:46 +01:00
|
|
|
case 0xb004:
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
"OCZ");
|
|
|
|
break;
|
2014-07-27 21:54:44 +02:00
|
|
|
case 0xad80:
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
"Hynix/Hyundai");
|
|
|
|
break;
|
2016-05-08 00:25:42 +02:00
|
|
|
case 0xb502:
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
"SuperTalent");
|
|
|
|
break;
|
2016-02-29 19:19:46 +01:00
|
|
|
case 0xcd04:
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
"GSkill");
|
|
|
|
break;
|
2014-07-27 21:54:44 +02:00
|
|
|
case 0xce80:
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
"Samsung");
|
|
|
|
break;
|
|
|
|
case 0xfe02:
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
"Elpida");
|
|
|
|
break;
|
2015-03-28 04:47:25 +01:00
|
|
|
case 0xff2c:
|
2014-07-27 21:54:44 +02:00
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
2015-03-28 04:47:25 +01:00
|
|
|
"Micron");
|
2014-07-27 21:54:44 +02:00
|
|
|
break;
|
2015-03-28 04:47:25 +01:00
|
|
|
default: {
|
|
|
|
char string_buffer[256];
|
|
|
|
snprintf(string_buffer, sizeof(string_buffer),
|
|
|
|
"Unknown (%x)", mod_id);
|
|
|
|
t->manufacturer = smbios_add_string(t->eos,
|
|
|
|
string_buffer);
|
|
|
|
break;
|
|
|
|
}
|
2014-07-27 21:54:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int create_smbios_type17_for_dimm(struct dimm_info *dimm,
|
|
|
|
unsigned long *current, int *handle)
|
|
|
|
{
|
|
|
|
struct smbios_type17 *t = (struct smbios_type17 *)*current;
|
|
|
|
uint8_t length;
|
|
|
|
char locator[40];
|
|
|
|
|
|
|
|
memset(t, 0, sizeof(struct smbios_type17));
|
|
|
|
t->memory_type = dimm->ddr_type;
|
|
|
|
t->clock_speed = dimm->ddr_frequency;
|
|
|
|
t->speed = dimm->ddr_frequency;
|
|
|
|
t->type = SMBIOS_MEMORY_DEVICE;
|
|
|
|
t->size = dimm->dimm_size;
|
|
|
|
t->data_width = 8 * (1 << (dimm->bus_width & 0x7));
|
|
|
|
t->total_width = t->data_width + 8 * ((dimm->bus_width & 0x18) >> 3);
|
|
|
|
|
|
|
|
switch (dimm->mod_type) {
|
|
|
|
case SPD_RDIMM:
|
|
|
|
case SPD_MINI_RDIMM:
|
|
|
|
t->form_factor = MEMORY_FORMFACTOR_RIMM;
|
|
|
|
break;
|
|
|
|
case SPD_UDIMM:
|
|
|
|
case SPD_MICRO_DIMM:
|
|
|
|
case SPD_MINI_UDIMM:
|
|
|
|
t->form_factor = MEMORY_FORMFACTOR_DIMM;
|
|
|
|
break;
|
|
|
|
case SPD_SODIMM:
|
|
|
|
t->form_factor = MEMORY_FORMFACTOR_SODIMM;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
t->form_factor = MEMORY_FORMFACTOR_UNKNOWN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-03-28 05:05:36 +01:00
|
|
|
smbios_fill_dimm_manufacturer_from_id(dimm->mod_id, t);
|
2014-07-27 21:54:44 +02:00
|
|
|
/* put '\0' in the end of data */
|
|
|
|
length = sizeof(dimm->serial);
|
|
|
|
dimm->serial[length - 1] = '\0';
|
|
|
|
if (dimm->serial[0] == 0)
|
|
|
|
t->serial_number = smbios_add_string(t->eos, "None");
|
|
|
|
else
|
|
|
|
t->serial_number = smbios_add_string(t->eos,
|
|
|
|
(const char *)dimm->serial);
|
|
|
|
|
|
|
|
snprintf(locator, sizeof(locator), "Channel-%d-DIMM-%d",
|
|
|
|
dimm->channel_num, dimm->dimm_num);
|
|
|
|
t->device_locator = smbios_add_string(t->eos, locator);
|
|
|
|
|
|
|
|
snprintf(locator, sizeof(locator), "BANK %d", dimm->bank_locator);
|
|
|
|
t->bank_locator = smbios_add_string(t->eos, locator);
|
|
|
|
|
|
|
|
/* put '\0' in the end of data */
|
|
|
|
length = sizeof(dimm->module_part_number);
|
|
|
|
dimm->module_part_number[length - 1] = '\0';
|
|
|
|
t->part_number = smbios_add_string(t->eos,
|
|
|
|
(const char *)dimm->module_part_number);
|
|
|
|
|
|
|
|
/* Synchronous = 1 */
|
|
|
|
t->type_detail = 0x0080;
|
|
|
|
/* no handle for error information */
|
|
|
|
t->memory_error_information_handle = 0xFFFE;
|
|
|
|
t->attributes = dimm->rank_per_dimm;
|
|
|
|
t->handle = *handle;
|
|
|
|
*handle += 1;
|
|
|
|
t->length = sizeof(struct smbios_type17) - 2;
|
|
|
|
return t->length + smbios_string_table_len(t->eos);
|
|
|
|
}
|
|
|
|
|
2014-06-01 00:26:48 +02:00
|
|
|
const char *__attribute__((weak)) smbios_mainboard_bios_version(void)
|
|
|
|
{
|
|
|
|
if (strlen(CONFIG_LOCALVERSION))
|
|
|
|
return CONFIG_LOCALVERSION;
|
|
|
|
else
|
2014-11-18 11:41:16 +01:00
|
|
|
return coreboot_version;
|
2014-06-01 00:26:48 +02:00
|
|
|
}
|
|
|
|
|
2011-08-14 20:56:34 +02:00
|
|
|
static int smbios_write_type0(unsigned long *current, int handle)
|
|
|
|
{
|
|
|
|
struct smbios_type0 *t = (struct smbios_type0 *)*current;
|
|
|
|
int len = sizeof(struct smbios_type0);
|
|
|
|
|
|
|
|
memset(t, 0, sizeof(struct smbios_type0));
|
|
|
|
t->type = SMBIOS_BIOS_INFORMATION;
|
|
|
|
t->handle = handle;
|
|
|
|
t->length = len - 2;
|
|
|
|
|
|
|
|
t->vendor = smbios_add_string(t->eos, "coreboot");
|
2012-04-04 01:02:54 +02:00
|
|
|
#if !CONFIG_CHROMEOS
|
2014-11-18 11:41:16 +01:00
|
|
|
t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date);
|
2013-02-04 16:22:46 +01:00
|
|
|
|
2014-06-01 00:26:48 +02:00
|
|
|
t->bios_version = smbios_add_string(t->eos, smbios_mainboard_bios_version());
|
2012-04-04 01:02:54 +02:00
|
|
|
#else
|
|
|
|
#define SPACES \
|
|
|
|
" "
|
2014-11-18 11:41:16 +01:00
|
|
|
t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date);
|
2015-02-26 23:33:18 +01:00
|
|
|
#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
|
2012-04-04 01:02:54 +02:00
|
|
|
u32 version_offset = (u32)smbios_string_table_len(t->eos);
|
2015-02-26 23:33:18 +01:00
|
|
|
#endif
|
2012-04-04 01:02:54 +02:00
|
|
|
t->bios_version = smbios_add_string(t->eos, SPACES);
|
2015-02-26 23:33:18 +01:00
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
|
2012-04-04 01:02:54 +02:00
|
|
|
/* SMBIOS offsets start at 1 rather than 0 */
|
|
|
|
vboot_data->vbt10 = (u32)t->eos + (version_offset - 1);
|
|
|
|
#endif
|
2015-02-26 23:33:18 +01:00
|
|
|
#endif /* CONFIG_CHROMEOS */
|
2011-08-14 20:56:34 +02:00
|
|
|
|
2016-06-08 21:47:07 +02:00
|
|
|
/* As a work around to prevent a compiler error, temporarily specify
|
|
|
|
* 16 MiB flash sizes when ROM size >= 16 MiB. An update is necessary
|
|
|
|
* once the SMBIOS specification addresses ROM sizes > 16 MiB.
|
|
|
|
*/
|
|
|
|
uint32_t rom_size = CONFIG_ROM_SIZE;
|
|
|
|
rom_size = MIN(CONFIG_ROM_SIZE, 16 * MiB);
|
|
|
|
t->bios_rom_size = (rom_size / 65535) - 1;
|
Extend CBFS to support arbitrary ROM source media.
Summary:
Isolate CBFS underlying I/O to board/arch-specific implementations as
"media stream", to allow loading and booting romstage on non-x86.
CBFS functions now all take a new "media source" parameter; use
CBFS_DEFAULT_MEDIA if you simply want to load from main firmware.
API Changes:
cbfs_find => cbfs_get_file.
cbfs_find_file => cbfs_get_file_content.
cbfs_get_file => cbfs_get_file_content with correct type.
CBFS used to work only on memory-mapped ROM (all x86). For platforms like ARM,
the ROM may come from USB, UART, or SPI -- any serial devices and not available
for memory mapping.
To support these devices (and allowing CBFS to read from multiple source
at the same time), CBFS operations are now virtual-ized into "cbfs_media". To
simplify porting existing code, every media source must support both "reading
into pre-allocated memory (read)" and "read and return an allocated buffer
(map)". For devices without native memory-mapped ROM, "cbfs_simple_buffer*"
provides simple memory mapping simulation.
Every CBFS function now takes a cbfs_media* as parameter. CBFS_DEFAULT_MEDIA
is defined for CBFS functions to automatically initialize a per-board default
media (CBFS will internally calls init_default_cbfs_media). Also revised CBFS
function names relying on memory mapped backend (ex, "cbfs_find" => actually
loads files). Now we only have two getters:
struct cbfs_file *entry = cbfs_get_file(media, name);
void *data = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, name, type);
Test results:
- Verified to work on x86/qemu.
- Compiles on ARM, and follow up commit will provide working SPI driver.
Change-Id: Iac911ded25a6f2feffbf3101a81364625bb07746
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-on: http://review.coreboot.org/2182
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
2013-01-22 11:57:56 +01:00
|
|
|
|
2011-08-14 20:56:34 +02:00
|
|
|
t->system_bios_major_release = 4;
|
|
|
|
t->bios_characteristics =
|
|
|
|
BIOS_CHARACTERISTICS_PCI_SUPPORTED |
|
|
|
|
#if CONFIG_CARDBUS_PLUGIN_SUPPORT
|
|
|
|
BIOS_CHARACTERISTICS_PC_CARD |
|
|
|
|
#endif
|
|
|
|
BIOS_CHARACTERISTICS_SELECTABLE_BOOT |
|
|
|
|
BIOS_CHARACTERISTICS_UPGRADEABLE;
|
|
|
|
|
2014-01-03 15:55:40 +01:00
|
|
|
#if CONFIG_HAVE_ACPI_TABLES
|
2011-08-14 20:56:34 +02:00
|
|
|
t->bios_characteristics_ext1 = BIOS_EXT1_CHARACTERISTICS_ACPI;
|
|
|
|
#endif
|
|
|
|
t->bios_characteristics_ext2 = BIOS_EXT2_CHARACTERISTICS_TARGET;
|
|
|
|
len = t->length + smbios_string_table_len(t->eos);
|
|
|
|
*current += len;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2015-05-30 23:08:26 +02:00
|
|
|
#if !CONFIG_SMBIOS_PROVIDED_BY_MOBO
|
|
|
|
|
2012-07-25 13:42:40 +02:00
|
|
|
const char *__attribute__((weak)) smbios_mainboard_serial_number(void)
|
|
|
|
{
|
|
|
|
return CONFIG_MAINBOARD_SERIAL_NUMBER;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *__attribute__((weak)) smbios_mainboard_version(void)
|
|
|
|
{
|
|
|
|
return CONFIG_MAINBOARD_VERSION;
|
|
|
|
}
|
|
|
|
|
2013-11-13 13:37:23 +01:00
|
|
|
const char *__attribute__((weak)) smbios_mainboard_manufacturer(void)
|
|
|
|
{
|
|
|
|
return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *__attribute__((weak)) smbios_mainboard_product_name(void)
|
|
|
|
{
|
|
|
|
return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
void __attribute__((weak)) smbios_mainboard_set_uuid(u8 *uuid)
|
|
|
|
{
|
|
|
|
/* leave all zero */
|
|
|
|
}
|
2015-05-30 23:08:26 +02:00
|
|
|
#endif
|
2013-11-13 13:37:23 +01:00
|
|
|
|
2016-05-30 15:52:31 +02:00
|
|
|
const char *__attribute__((weak)) smbios_mainboard_sku(void)
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2014-09-09 03:40:30 +02:00
|
|
|
#ifdef CONFIG_MAINBOARD_FAMILY
|
|
|
|
const char *smbios_mainboard_family(void)
|
|
|
|
{
|
|
|
|
return CONFIG_MAINBOARD_FAMILY;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_MAINBOARD_FAMILY */
|
|
|
|
|
2011-08-14 20:56:34 +02:00
|
|
|
static int smbios_write_type1(unsigned long *current, int handle)
|
|
|
|
{
|
|
|
|
struct smbios_type1 *t = (struct smbios_type1 *)*current;
|
|
|
|
int len = sizeof(struct smbios_type1);
|
|
|
|
|
|
|
|
memset(t, 0, sizeof(struct smbios_type1));
|
|
|
|
t->type = SMBIOS_SYSTEM_INFORMATION;
|
|
|
|
t->handle = handle;
|
|
|
|
t->length = len - 2;
|
2013-11-13 13:37:23 +01:00
|
|
|
t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer());
|
|
|
|
t->product_name = smbios_add_string(t->eos, smbios_mainboard_product_name());
|
2012-07-25 13:42:40 +02:00
|
|
|
t->serial_number = smbios_add_string(t->eos, smbios_mainboard_serial_number());
|
2016-05-30 15:52:31 +02:00
|
|
|
t->sku = smbios_add_string(t->eos, smbios_mainboard_sku());
|
2012-07-25 13:42:40 +02:00
|
|
|
t->version = smbios_add_string(t->eos, smbios_mainboard_version());
|
2015-06-10 05:10:43 +02:00
|
|
|
#ifdef CONFIG_MAINBOARD_FAMILY
|
|
|
|
t->family = smbios_add_string(t->eos, smbios_mainboard_family());
|
|
|
|
#endif
|
2013-11-13 13:37:23 +01:00
|
|
|
smbios_mainboard_set_uuid(t->uuid);
|
2011-08-14 20:56:34 +02:00
|
|
|
len = t->length + smbios_string_table_len(t->eos);
|
|
|
|
*current += len;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2014-03-02 19:14:44 +01:00
|
|
|
static int smbios_write_type2(unsigned long *current, int handle)
|
|
|
|
{
|
|
|
|
struct smbios_type2 *t = (struct smbios_type2 *)*current;
|
|
|
|
int len = sizeof(struct smbios_type2);
|
|
|
|
|
|
|
|
memset(t, 0, sizeof(struct smbios_type2));
|
|
|
|
t->type = SMBIOS_BOARD_INFORMATION;
|
|
|
|
t->handle = handle;
|
|
|
|
t->length = len - 2;
|
|
|
|
t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer());
|
|
|
|
t->product_name = smbios_add_string(t->eos, smbios_mainboard_product_name());
|
|
|
|
t->serial_number = smbios_add_string(t->eos, smbios_mainboard_serial_number());
|
|
|
|
t->version = smbios_add_string(t->eos, smbios_mainboard_version());
|
|
|
|
len = t->length + smbios_string_table_len(t->eos);
|
|
|
|
*current += len;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2011-08-14 20:56:34 +02:00
|
|
|
static int smbios_write_type3(unsigned long *current, int handle)
|
|
|
|
{
|
|
|
|
struct smbios_type3 *t = (struct smbios_type3 *)*current;
|
|
|
|
int len = sizeof(struct smbios_type3);
|
|
|
|
|
|
|
|
memset(t, 0, sizeof(struct smbios_type3));
|
|
|
|
t->type = SMBIOS_SYSTEM_ENCLOSURE;
|
|
|
|
t->handle = handle;
|
|
|
|
t->length = len - 2;
|
2015-05-30 23:09:53 +02:00
|
|
|
t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer());
|
2011-08-14 20:56:34 +02:00
|
|
|
t->bootup_state = SMBIOS_STATE_SAFE;
|
|
|
|
t->power_supply_state = SMBIOS_STATE_SAFE;
|
|
|
|
t->thermal_state = SMBIOS_STATE_SAFE;
|
2014-10-16 13:21:47 +02:00
|
|
|
if(IS_ENABLED(CONFIG_SYSTEM_TYPE_LAPTOP)) {
|
|
|
|
t->_type = SMBIOS_ENCLOSURE_NOTEBOOK;
|
|
|
|
} else {
|
|
|
|
t->_type = SMBIOS_ENCLOSURE_DESKTOP;
|
|
|
|
}
|
2011-08-14 20:56:34 +02:00
|
|
|
t->security_status = SMBIOS_STATE_SAFE;
|
|
|
|
len = t->length + smbios_string_table_len(t->eos);
|
|
|
|
*current += len;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int smbios_write_type4(unsigned long *current, int handle)
|
|
|
|
{
|
|
|
|
struct cpuid_result res;
|
|
|
|
struct smbios_type4 *t = (struct smbios_type4 *)*current;
|
|
|
|
int len = sizeof(struct smbios_type4);
|
|
|
|
|
2012-02-25 23:51:12 +01:00
|
|
|
/* Provide sane defaults even for CPU without CPUID */
|
|
|
|
res.eax = res.edx = 0;
|
|
|
|
res.ebx = 0x10000;
|
|
|
|
|
|
|
|
if (cpu_have_cpuid()) {
|
|
|
|
res = cpuid(1);
|
|
|
|
}
|
2011-08-14 20:56:34 +02:00
|
|
|
|
|
|
|
memset(t, 0, sizeof(struct smbios_type4));
|
|
|
|
t->type = SMBIOS_PROCESSOR_INFORMATION;
|
|
|
|
t->handle = handle;
|
|
|
|
t->length = len - 2;
|
|
|
|
t->processor_id[0] = res.eax;
|
|
|
|
t->processor_id[1] = res.edx;
|
|
|
|
t->processor_manufacturer = smbios_cpu_vendor(t->eos);
|
|
|
|
t->processor_version = smbios_processor_name(t->eos);
|
2012-02-25 23:51:12 +01:00
|
|
|
t->processor_family = (res.eax > 0) ? 0x0c : 0x6;
|
2011-08-14 20:56:34 +02:00
|
|
|
t->processor_type = 3; /* System Processor */
|
|
|
|
t->processor_upgrade = 0x06;
|
|
|
|
t->core_count = (res.ebx >> 16) & 0xff;
|
|
|
|
t->l1_cache_handle = 0xffff;
|
|
|
|
t->l2_cache_handle = 0xffff;
|
|
|
|
t->l3_cache_handle = 0xffff;
|
|
|
|
t->processor_upgrade = 1;
|
|
|
|
len = t->length + smbios_string_table_len(t->eos);
|
|
|
|
*current += len;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2014-08-27 23:42:45 +02:00
|
|
|
static int smbios_write_type11(unsigned long *current, int *handle)
|
2013-07-06 19:51:12 +02:00
|
|
|
{
|
|
|
|
struct smbios_type11 *t = (struct smbios_type11 *)*current;
|
2014-08-27 23:42:45 +02:00
|
|
|
int len;
|
2014-10-27 13:29:29 +01:00
|
|
|
struct device *dev;
|
2013-07-06 19:51:12 +02:00
|
|
|
|
|
|
|
memset(t, 0, sizeof *t);
|
|
|
|
t->type = SMBIOS_OEM_STRINGS;
|
2014-08-27 23:42:45 +02:00
|
|
|
t->handle = *handle;
|
2013-07-06 19:51:12 +02:00
|
|
|
t->length = len = sizeof *t - 2;
|
|
|
|
|
2014-08-27 23:42:45 +02:00
|
|
|
for(dev = all_devices; dev; dev = dev->next) {
|
|
|
|
if (dev->ops && dev->ops->get_smbios_strings)
|
|
|
|
dev->ops->get_smbios_strings(dev, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t->count == 0) {
|
|
|
|
memset(t, 0, sizeof *t);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-07-06 19:51:12 +02:00
|
|
|
|
|
|
|
len += smbios_string_table_len(t->eos);
|
2014-08-27 23:42:45 +02:00
|
|
|
|
2013-07-06 19:51:12 +02:00
|
|
|
*current += len;
|
2014-08-27 23:42:45 +02:00
|
|
|
(*handle)++;
|
2013-07-06 19:51:12 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2014-07-27 21:54:44 +02:00
|
|
|
static int smbios_write_type17(unsigned long *current, int *handle)
|
|
|
|
{
|
|
|
|
int len = sizeof(struct smbios_type17);
|
2016-03-09 16:22:58 +01:00
|
|
|
int totallen = 0;
|
2014-07-27 21:54:44 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
struct memory_info *meminfo;
|
|
|
|
meminfo = cbmem_find(CBMEM_ID_MEMINFO);
|
|
|
|
if (meminfo == NULL)
|
|
|
|
return 0; /* can't find mem info in cbmem */
|
|
|
|
|
|
|
|
printk(BIOS_INFO, "Create SMBIOS type 17\n");
|
|
|
|
for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) {
|
|
|
|
struct dimm_info *dimm;
|
|
|
|
dimm = &meminfo->dimm[i];
|
|
|
|
len = create_smbios_type17_for_dimm(dimm, current, handle);
|
|
|
|
*current += len;
|
2016-03-09 16:22:58 +01:00
|
|
|
totallen += len;
|
2014-07-27 21:54:44 +02:00
|
|
|
}
|
2016-03-09 16:22:58 +01:00
|
|
|
return totallen;
|
2014-07-27 21:54:44 +02:00
|
|
|
}
|
|
|
|
|
2011-08-14 20:56:34 +02:00
|
|
|
static int smbios_write_type32(unsigned long *current, int handle)
|
|
|
|
{
|
|
|
|
struct smbios_type32 *t = (struct smbios_type32 *)*current;
|
|
|
|
int len = sizeof(struct smbios_type32);
|
|
|
|
|
|
|
|
memset(t, 0, sizeof(struct smbios_type32));
|
|
|
|
t->type = SMBIOS_SYSTEM_BOOT_INFORMATION;
|
|
|
|
t->handle = handle;
|
|
|
|
t->length = len - 2;
|
|
|
|
*current += len;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2013-05-23 23:17:05 +02:00
|
|
|
int smbios_write_type41(unsigned long *current, int *handle,
|
|
|
|
const char *name, u8 instance, u16 segment,
|
|
|
|
u8 bus, u8 device, u8 function)
|
|
|
|
{
|
|
|
|
struct smbios_type41 *t = (struct smbios_type41 *)*current;
|
|
|
|
int len = sizeof(struct smbios_type41);
|
|
|
|
|
|
|
|
memset(t, 0, sizeof(struct smbios_type41));
|
|
|
|
t->type = SMBIOS_ONBOARD_DEVICES_EXTENDED_INFORMATION;
|
|
|
|
t->handle = *handle;
|
|
|
|
t->length = len - 2;
|
|
|
|
t->reference_designation = smbios_add_string(t->eos, name);
|
|
|
|
t->device_type = SMBIOS_DEVICE_TYPE_OTHER;
|
|
|
|
t->device_status = 1;
|
|
|
|
t->device_type_instance = instance;
|
|
|
|
t->segment_group_number = segment;
|
|
|
|
t->bus_number = bus;
|
|
|
|
t->device_number = device;
|
|
|
|
t->function_number = function;
|
|
|
|
|
|
|
|
len = t->length + smbios_string_table_len(t->eos);
|
|
|
|
*current += len;
|
|
|
|
*handle += 1;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2011-08-14 20:56:34 +02:00
|
|
|
static int smbios_write_type127(unsigned long *current, int handle)
|
|
|
|
{
|
|
|
|
struct smbios_type127 *t = (struct smbios_type127 *)*current;
|
|
|
|
int len = sizeof(struct smbios_type127);
|
|
|
|
|
|
|
|
memset(t, 0, sizeof(struct smbios_type127));
|
|
|
|
t->type = SMBIOS_END_OF_TABLE;
|
|
|
|
t->handle = handle;
|
|
|
|
t->length = len - 2;
|
|
|
|
*current += len;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2014-10-27 13:29:29 +01:00
|
|
|
static int smbios_walk_device_tree(struct device *tree, int *handle, unsigned long *current)
|
2011-08-14 20:56:34 +02:00
|
|
|
{
|
2014-10-27 13:29:29 +01:00
|
|
|
struct device *dev;
|
2011-08-14 20:56:34 +02:00
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
for(dev = tree; dev; dev = dev->next) {
|
2012-10-07 14:57:15 +02:00
|
|
|
printk(BIOS_INFO, "%s (%s)\n", dev_path(dev), dev_name(dev));
|
2011-08-14 20:56:34 +02:00
|
|
|
|
|
|
|
if (dev->ops && dev->ops->get_smbios_data)
|
|
|
|
len += dev->ops->get_smbios_data(dev, handle, current);
|
|
|
|
}
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2015-05-10 02:52:18 +02:00
|
|
|
#define update_max(len, max_len, stmt) do { int tmp = stmt; max_len = MAX(max_len, tmp); len += tmp; } while(0)
|
2011-08-14 20:56:34 +02:00
|
|
|
unsigned long smbios_write_tables(unsigned long current)
|
|
|
|
{
|
|
|
|
struct smbios_entry *se;
|
|
|
|
unsigned long tables;
|
2015-05-10 02:52:18 +02:00
|
|
|
int len = 0;
|
|
|
|
int max_struct_size = 0;
|
|
|
|
int handle = 0;
|
2011-08-14 20:56:34 +02:00
|
|
|
|
|
|
|
current = ALIGN(current, 16);
|
|
|
|
printk(BIOS_DEBUG, "%s: %08lx\n", __func__, current);
|
|
|
|
|
|
|
|
se = (struct smbios_entry *)current;
|
|
|
|
current += sizeof(struct smbios_entry);
|
|
|
|
current = ALIGN(current, 16);
|
|
|
|
|
|
|
|
tables = current;
|
2015-05-10 02:52:18 +02:00
|
|
|
update_max(len, max_struct_size, smbios_write_type0(¤t, handle++));
|
|
|
|
update_max(len, max_struct_size, smbios_write_type1(¤t, handle++));
|
|
|
|
update_max(len, max_struct_size, smbios_write_type2(¤t, handle++));
|
|
|
|
update_max(len, max_struct_size, smbios_write_type3(¤t, handle++));
|
|
|
|
update_max(len, max_struct_size, smbios_write_type4(¤t, handle++));
|
|
|
|
update_max(len, max_struct_size, smbios_write_type11(¤t, &handle));
|
2012-06-24 01:13:42 +02:00
|
|
|
#if CONFIG_ELOG
|
2015-07-07 17:29:43 +02:00
|
|
|
update_max(len, max_struct_size, elog_smbios_write_type15(¤t, handle++));
|
2012-06-24 01:13:42 +02:00
|
|
|
#endif
|
2015-05-10 02:52:18 +02:00
|
|
|
update_max(len, max_struct_size, smbios_write_type17(¤t, &handle));
|
|
|
|
update_max(len, max_struct_size, smbios_write_type32(¤t, handle++));
|
2011-08-14 20:56:34 +02:00
|
|
|
|
2015-05-10 02:52:18 +02:00
|
|
|
update_max(len, max_struct_size, smbios_walk_device_tree(all_devices, &handle, ¤t));
|
2011-08-14 20:56:34 +02:00
|
|
|
|
2015-05-10 02:52:18 +02:00
|
|
|
update_max(len, max_struct_size, smbios_write_type127(¤t, handle++));
|
2011-08-14 20:56:34 +02:00
|
|
|
|
|
|
|
memset(se, 0, sizeof(struct smbios_entry));
|
|
|
|
memcpy(se->anchor, "_SM_", 4);
|
|
|
|
se->length = sizeof(struct smbios_entry);
|
|
|
|
se->major_version = 2;
|
|
|
|
se->minor_version = 7;
|
2015-05-10 02:52:18 +02:00
|
|
|
se->max_struct_size = max_struct_size;
|
2011-08-14 20:56:34 +02:00
|
|
|
se->struct_count = handle;
|
|
|
|
memcpy(se->intermediate_anchor_string, "_DMI_", 5);
|
|
|
|
|
|
|
|
se->struct_table_address = (u32)tables;
|
|
|
|
se->struct_table_length = len;
|
|
|
|
|
|
|
|
se->intermediate_checksum = smbios_checksum((u8 *)se + 0x10,
|
|
|
|
sizeof(struct smbios_entry) - 0x10);
|
|
|
|
se->checksum = smbios_checksum((u8 *)se, sizeof(struct smbios_entry));
|
|
|
|
return current;
|
|
|
|
}
|