mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2024-11-23 08:26:23 -06:00
Fix an issue where DDR4 Bank switch fail because DMI tables have multiples Type 17 structs reporting unpopulated slots as Type 2 (unknown), overwriting the valid struct with the populated slot. Code cleanup to improve readability
This commit is contained in:
parent
caa07482a0
commit
d901f9e8a1
@ -5,8 +5,6 @@
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
#include "display.h"
|
||||
static const uint8_t * table_start = NULL;
|
||||
static uint32_t table_length = 0; // 16-bit in SMBIOS v2, 32-bit in SMBIOS v3.
|
||||
|
||||
#include "boot.h"
|
||||
#include "bootparams.h"
|
||||
@ -16,6 +14,9 @@ static uint32_t table_length = 0; // 16-bit in SMBIOS v2, 32-bit in SMBIOS v3.
|
||||
|
||||
#define LINE_DMI 23
|
||||
|
||||
static const uint8_t *table_start = NULL;
|
||||
static uint32_t table_length = 0; // 16-bit in SMBIOS v2, 32-bit in SMBIOS v3.
|
||||
|
||||
static const efi_guid_t SMBIOS2_GUID = { 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} };
|
||||
|
||||
// SMBIOS v3 compliant FW must include an SMBIOS v2 table, but maybe parse SM3 table later...
|
||||
@ -25,24 +26,26 @@ struct system_info *dmi_system_info;
|
||||
struct baseboard_info *dmi_baseboard_info;
|
||||
struct mem_dev *dmi_memory_device;
|
||||
|
||||
static char * get_tstruct_string(struct tstruct_header * header, uint16_t maxlen, int n) {
|
||||
static char *get_tstruct_string(struct tstruct_header *header, uint16_t maxlen, int n)
|
||||
{
|
||||
if (n < 1)
|
||||
return NULL;
|
||||
char * a = (char *) header + header->length;
|
||||
char *a = (char *) header + header->length;
|
||||
n--;
|
||||
do {
|
||||
if (! * a)
|
||||
if (! *a)
|
||||
n--;
|
||||
if (!n && * a)
|
||||
if (!n && *a)
|
||||
return a;
|
||||
a++;
|
||||
} while (a < ((char *) header + maxlen) && !( * a == 0 && * (a - 1) == 0));
|
||||
} while (a < ((char *) header + maxlen) && !( *a == 0 && *(a - 1) == 0));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
static smbiosv2_t * find_smbiosv2_in_efi64_system_table(efi64_system_table_t * system_table) {
|
||||
efi64_config_table_t * config_tables = (efi64_config_table_t *) map_region(system_table->config_tables, system_table->num_config_tables * sizeof(efi64_config_table_t), true);
|
||||
static smbiosv2_t *find_smbiosv2_in_efi64_system_table(efi64_system_table_t *system_table)
|
||||
{
|
||||
efi64_config_table_t *config_tables = (efi64_config_table_t *) map_region(system_table->config_tables, system_table->num_config_tables * sizeof(efi64_config_table_t), true);
|
||||
if (config_tables == NULL) return NULL;
|
||||
|
||||
uintptr_t table_addr = 0;
|
||||
@ -55,8 +58,9 @@ static smbiosv2_t * find_smbiosv2_in_efi64_system_table(efi64_system_table_t * s
|
||||
}
|
||||
#endif
|
||||
|
||||
static smbiosv2_t * find_smbiosv2_in_efi32_system_table(efi32_system_table_t * system_table) {
|
||||
efi32_config_table_t * config_tables = (efi32_config_table_t *) map_region(system_table->config_tables, system_table->num_config_tables * sizeof(efi32_config_table_t), true);
|
||||
static smbiosv2_t *find_smbiosv2_in_efi32_system_table(efi32_system_table_t *system_table)
|
||||
{
|
||||
efi32_config_table_t *config_tables = (efi32_config_table_t *) map_region(system_table->config_tables, system_table->num_config_tables * sizeof(efi32_config_table_t), true);
|
||||
if (config_tables == NULL) return NULL;
|
||||
|
||||
uintptr_t table_addr = 0;
|
||||
@ -68,11 +72,12 @@ static smbiosv2_t * find_smbiosv2_in_efi32_system_table(efi32_system_table_t * s
|
||||
return (smbiosv2_t *) table_addr;
|
||||
}
|
||||
|
||||
static uintptr_t find_smbiosv2_adr(void) {
|
||||
const boot_params_t * boot_params = (boot_params_t *) boot_params_addr;
|
||||
const efi_info_t * efi_info = & boot_params->efi_info;
|
||||
static uintptr_t find_smbiosv2_adr(void)
|
||||
{
|
||||
const boot_params_t *boot_params = (boot_params_t *) boot_params_addr;
|
||||
const efi_info_t *efi_info = & boot_params->efi_info;
|
||||
|
||||
smbiosv2_t * rp = NULL;
|
||||
smbiosv2_t *rp = NULL;
|
||||
|
||||
if (efi_info->loader_signature == EFI32_LOADER_SIGNATURE) {
|
||||
// EFI32
|
||||
@ -100,11 +105,11 @@ static uintptr_t find_smbiosv2_adr(void) {
|
||||
#endif
|
||||
if (rp == NULL) {
|
||||
// BIOS
|
||||
uint8_t * dmi, * dmi_search_start;
|
||||
uint8_t *dmi, *dmi_search_start;
|
||||
dmi_search_start = (uint8_t *) 0x000F0000;
|
||||
|
||||
for (dmi = dmi_search_start; dmi < dmi_search_start + 0xffff0; dmi += 16) {
|
||||
if ( * dmi == '_' && * (dmi + 1) == 'S' && * (dmi + 2) == 'M' && * (dmi + 3) == '_')
|
||||
if ( *dmi == '_' && *(dmi + 1) == 'S' && *(dmi + 2) == 'M' && *(dmi + 3) == '_')
|
||||
return (uintptr_t) dmi;
|
||||
}
|
||||
}
|
||||
@ -112,18 +117,20 @@ static uintptr_t find_smbiosv2_adr(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_dmi(uint16_t numstructs) {
|
||||
const uint8_t * dmi = table_start;
|
||||
static int parse_dmi(uint16_t numstructs)
|
||||
{
|
||||
const uint8_t *dmi = table_start;
|
||||
int tstruct_count = 0;
|
||||
|
||||
// Struct type 1 is one of the mandatory types, so we're dealing with invalid data if its size is lower than that of a minimal type 1 struct (plus a couple bytes).
|
||||
// Struct type 1 is one of the mandatory types, so we're dealing with invalid data
|
||||
// if its size is lower than that of a minimal type 1 struct (plus a couple bytes).
|
||||
if (table_length < sizeof(struct system_info)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Parse all structs (currently restricted to Type 2 only)
|
||||
// Parse structs
|
||||
while (dmi < table_start + table_length - 2) { // -2 for header type and length.
|
||||
const struct tstruct_header * header = (struct tstruct_header *) dmi;
|
||||
const struct tstruct_header *header = (struct tstruct_header *) dmi;
|
||||
|
||||
// Type 1 - System Information
|
||||
if (header->type == 1 && header->length > offsetof(struct system_info, wut)) {
|
||||
@ -137,7 +144,12 @@ static int parse_dmi(uint16_t numstructs) {
|
||||
}
|
||||
// Type 17 - Memory Device
|
||||
else if (header->type == 17 && header->length > offsetof(struct mem_dev, partnum)) {
|
||||
dmi_memory_device = (struct mem_dev *) dmi;
|
||||
// Multiple type 17 structs are allowed, with unpopulated slots sometimes
|
||||
// reported as type 2 (unknown). If type is 0 (uninitialized) or 1/2 (previously
|
||||
// initialized with unknown value) => set or overwrite the struct
|
||||
if (dmi_memory_device->type <= 2) {
|
||||
dmi_memory_device = (struct mem_dev *) dmi;
|
||||
}
|
||||
}
|
||||
|
||||
dmi += header->length;
|
||||
@ -160,14 +172,14 @@ static int parse_dmi(uint16_t numstructs) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smbios_init(void) {
|
||||
int smbios_init(void)
|
||||
{
|
||||
uintptr_t smb_adr;
|
||||
const uint8_t * dmi_start;
|
||||
const smbiosv2_t * eps;
|
||||
const uint8_t *dmi_start;
|
||||
const smbiosv2_t *eps;
|
||||
|
||||
// Get SMBIOS Address
|
||||
smb_adr = find_smbiosv2_adr();
|
||||
@ -181,10 +193,10 @@ int smbios_init(void) {
|
||||
|
||||
// Verify checksum
|
||||
int8_t checksum = 0;
|
||||
const uint8_t * dmi = dmi_start;
|
||||
const uint8_t *dmi = dmi_start;
|
||||
|
||||
for (; dmi < (dmi_start + eps->length); dmi++) {
|
||||
checksum += * dmi;
|
||||
checksum += *dmi;
|
||||
}
|
||||
|
||||
if (checksum) {
|
||||
@ -202,21 +214,30 @@ int smbios_init(void) {
|
||||
return parse_dmi(eps->numstructs);
|
||||
}
|
||||
|
||||
void print_smbios_startup_info(void) {
|
||||
// Use baseboard info (struct type 2) as primary source of information, and fall back to system info (struct type 1).
|
||||
// Indeed, while the latter may contain less useful information than the former, its presence is mandated by the successive revisions of the SMBIOS standard.
|
||||
// NOTE: we can get away with this ugly cast because the offsets of .manufacturer and .productname are the same in system_info and baseboard_info.
|
||||
struct system_info * ptr = dmi_baseboard_info != NULL ? (struct system_info *)dmi_baseboard_info : dmi_system_info;
|
||||
void print_smbios_startup_info(void)
|
||||
{
|
||||
// Use baseboard info (struct type 2) as primary source of information,
|
||||
// and fall back to system info (struct type 1). Indeed, while the later
|
||||
// may contain less useful information than the former, its presence is
|
||||
// mandated by the successive revisions of the SMBIOS standard.
|
||||
// NOTE: we can get away with this ugly cast because the offsets of
|
||||
// .manufacturer and .productname are the same in system_info and baseboard_info.
|
||||
|
||||
struct system_info *ptr = dmi_baseboard_info != NULL ?
|
||||
(struct system_info *)dmi_baseboard_info : dmi_system_info;
|
||||
|
||||
if (ptr != NULL) {
|
||||
char * sys_man, * sys_sku;
|
||||
char *sys_man, *sys_sku;
|
||||
|
||||
int sl1, sl2, dmicol;
|
||||
|
||||
sys_man = get_tstruct_string(&ptr->header, table_length - ((uint8_t *)&ptr->header - (uint8_t *)table_start), ptr->manufacturer);
|
||||
uint16_t struct_length = table_length - ((uint8_t *)&ptr->header - (uint8_t *)table_start);
|
||||
|
||||
sys_man = get_tstruct_string(&ptr->header, struct_length, ptr->manufacturer);
|
||||
if (sys_man != NULL) {
|
||||
sl1 = strlen(sys_man);
|
||||
|
||||
sys_sku = get_tstruct_string(&ptr->header, table_length - ((uint8_t *)&ptr->header - (uint8_t *)table_start), ptr->productname);
|
||||
sys_sku = get_tstruct_string(&ptr->header, struct_length, ptr->productname);
|
||||
if (sys_sku != NULL) {
|
||||
sl2 = strlen(sys_sku);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user