1*4b6dddc2SAlexander Graf /* 2*4b6dddc2SAlexander Graf * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> 3*4b6dddc2SAlexander Graf * 4*4b6dddc2SAlexander Graf * Adapted from coreboot src/arch/x86/smbios.c 5*4b6dddc2SAlexander Graf * 6*4b6dddc2SAlexander Graf * SPDX-License-Identifier: GPL-2.0+ 7*4b6dddc2SAlexander Graf */ 8*4b6dddc2SAlexander Graf 9*4b6dddc2SAlexander Graf #include <common.h> 10*4b6dddc2SAlexander Graf #include <smbios.h> 11*4b6dddc2SAlexander Graf #include <tables_csum.h> 12*4b6dddc2SAlexander Graf #include <version.h> 13*4b6dddc2SAlexander Graf #include <asm/cpu.h> 14*4b6dddc2SAlexander Graf 15*4b6dddc2SAlexander Graf DECLARE_GLOBAL_DATA_PTR; 16*4b6dddc2SAlexander Graf 17*4b6dddc2SAlexander Graf /** 18*4b6dddc2SAlexander Graf * smbios_add_string() - add a string to the string area 19*4b6dddc2SAlexander Graf * 20*4b6dddc2SAlexander Graf * This adds a string to the string area which is appended directly after 21*4b6dddc2SAlexander Graf * the formatted portion of an SMBIOS structure. 22*4b6dddc2SAlexander Graf * 23*4b6dddc2SAlexander Graf * @start: string area start address 24*4b6dddc2SAlexander Graf * @str: string to add 25*4b6dddc2SAlexander Graf * @return: string number in the string area 26*4b6dddc2SAlexander Graf */ 27*4b6dddc2SAlexander Graf static int smbios_add_string(char *start, const char *str) 28*4b6dddc2SAlexander Graf { 29*4b6dddc2SAlexander Graf int i = 1; 30*4b6dddc2SAlexander Graf char *p = start; 31*4b6dddc2SAlexander Graf 32*4b6dddc2SAlexander Graf for (;;) { 33*4b6dddc2SAlexander Graf if (!*p) { 34*4b6dddc2SAlexander Graf strcpy(p, str); 35*4b6dddc2SAlexander Graf p += strlen(str); 36*4b6dddc2SAlexander Graf *p++ = '\0'; 37*4b6dddc2SAlexander Graf *p++ = '\0'; 38*4b6dddc2SAlexander Graf 39*4b6dddc2SAlexander Graf return i; 40*4b6dddc2SAlexander Graf } 41*4b6dddc2SAlexander Graf 42*4b6dddc2SAlexander Graf if (!strcmp(p, str)) 43*4b6dddc2SAlexander Graf return i; 44*4b6dddc2SAlexander Graf 45*4b6dddc2SAlexander Graf p += strlen(p) + 1; 46*4b6dddc2SAlexander Graf i++; 47*4b6dddc2SAlexander Graf } 48*4b6dddc2SAlexander Graf } 49*4b6dddc2SAlexander Graf 50*4b6dddc2SAlexander Graf /** 51*4b6dddc2SAlexander Graf * smbios_string_table_len() - compute the string area size 52*4b6dddc2SAlexander Graf * 53*4b6dddc2SAlexander Graf * This computes the size of the string area including the string terminator. 54*4b6dddc2SAlexander Graf * 55*4b6dddc2SAlexander Graf * @start: string area start address 56*4b6dddc2SAlexander Graf * @return: string area size 57*4b6dddc2SAlexander Graf */ 58*4b6dddc2SAlexander Graf static int smbios_string_table_len(char *start) 59*4b6dddc2SAlexander Graf { 60*4b6dddc2SAlexander Graf char *p = start; 61*4b6dddc2SAlexander Graf int i, len = 0; 62*4b6dddc2SAlexander Graf 63*4b6dddc2SAlexander Graf while (*p) { 64*4b6dddc2SAlexander Graf i = strlen(p) + 1; 65*4b6dddc2SAlexander Graf p += i; 66*4b6dddc2SAlexander Graf len += i; 67*4b6dddc2SAlexander Graf } 68*4b6dddc2SAlexander Graf 69*4b6dddc2SAlexander Graf return len + 1; 70*4b6dddc2SAlexander Graf } 71*4b6dddc2SAlexander Graf 72*4b6dddc2SAlexander Graf static int smbios_write_type0(u32 *current, int handle) 73*4b6dddc2SAlexander Graf { 74*4b6dddc2SAlexander Graf struct smbios_type0 *t = (struct smbios_type0 *)*current; 75*4b6dddc2SAlexander Graf int len = sizeof(struct smbios_type0); 76*4b6dddc2SAlexander Graf 77*4b6dddc2SAlexander Graf memset(t, 0, sizeof(struct smbios_type0)); 78*4b6dddc2SAlexander Graf fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, handle); 79*4b6dddc2SAlexander Graf t->vendor = smbios_add_string(t->eos, "U-Boot"); 80*4b6dddc2SAlexander Graf t->bios_ver = smbios_add_string(t->eos, PLAIN_VERSION); 81*4b6dddc2SAlexander Graf t->bios_release_date = smbios_add_string(t->eos, U_BOOT_DMI_DATE); 82*4b6dddc2SAlexander Graf t->bios_rom_size = (CONFIG_ROM_SIZE / 65536) - 1; 83*4b6dddc2SAlexander Graf t->bios_characteristics = BIOS_CHARACTERISTICS_PCI_SUPPORTED | 84*4b6dddc2SAlexander Graf BIOS_CHARACTERISTICS_SELECTABLE_BOOT | 85*4b6dddc2SAlexander Graf BIOS_CHARACTERISTICS_UPGRADEABLE; 86*4b6dddc2SAlexander Graf #ifdef CONFIG_GENERATE_ACPI_TABLE 87*4b6dddc2SAlexander Graf t->bios_characteristics_ext1 = BIOS_CHARACTERISTICS_EXT1_ACPI; 88*4b6dddc2SAlexander Graf #endif 89*4b6dddc2SAlexander Graf t->bios_characteristics_ext2 = BIOS_CHARACTERISTICS_EXT2_TARGET; 90*4b6dddc2SAlexander Graf t->bios_major_release = 0xff; 91*4b6dddc2SAlexander Graf t->bios_minor_release = 0xff; 92*4b6dddc2SAlexander Graf t->ec_major_release = 0xff; 93*4b6dddc2SAlexander Graf t->ec_minor_release = 0xff; 94*4b6dddc2SAlexander Graf 95*4b6dddc2SAlexander Graf len = t->length + smbios_string_table_len(t->eos); 96*4b6dddc2SAlexander Graf *current += len; 97*4b6dddc2SAlexander Graf 98*4b6dddc2SAlexander Graf return len; 99*4b6dddc2SAlexander Graf } 100*4b6dddc2SAlexander Graf 101*4b6dddc2SAlexander Graf static int smbios_write_type1(u32 *current, int handle) 102*4b6dddc2SAlexander Graf { 103*4b6dddc2SAlexander Graf struct smbios_type1 *t = (struct smbios_type1 *)*current; 104*4b6dddc2SAlexander Graf int len = sizeof(struct smbios_type1); 105*4b6dddc2SAlexander Graf 106*4b6dddc2SAlexander Graf memset(t, 0, sizeof(struct smbios_type1)); 107*4b6dddc2SAlexander Graf fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle); 108*4b6dddc2SAlexander Graf t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); 109*4b6dddc2SAlexander Graf t->product_name = smbios_add_string(t->eos, CONFIG_SMBIOS_PRODUCT_NAME); 110*4b6dddc2SAlexander Graf 111*4b6dddc2SAlexander Graf len = t->length + smbios_string_table_len(t->eos); 112*4b6dddc2SAlexander Graf *current += len; 113*4b6dddc2SAlexander Graf 114*4b6dddc2SAlexander Graf return len; 115*4b6dddc2SAlexander Graf } 116*4b6dddc2SAlexander Graf 117*4b6dddc2SAlexander Graf static int smbios_write_type2(u32 *current, int handle) 118*4b6dddc2SAlexander Graf { 119*4b6dddc2SAlexander Graf struct smbios_type2 *t = (struct smbios_type2 *)*current; 120*4b6dddc2SAlexander Graf int len = sizeof(struct smbios_type2); 121*4b6dddc2SAlexander Graf 122*4b6dddc2SAlexander Graf memset(t, 0, sizeof(struct smbios_type2)); 123*4b6dddc2SAlexander Graf fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle); 124*4b6dddc2SAlexander Graf t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); 125*4b6dddc2SAlexander Graf t->product_name = smbios_add_string(t->eos, CONFIG_SMBIOS_PRODUCT_NAME); 126*4b6dddc2SAlexander Graf t->feature_flags = SMBIOS_BOARD_FEATURE_HOSTING; 127*4b6dddc2SAlexander Graf t->board_type = SMBIOS_BOARD_MOTHERBOARD; 128*4b6dddc2SAlexander Graf 129*4b6dddc2SAlexander Graf len = t->length + smbios_string_table_len(t->eos); 130*4b6dddc2SAlexander Graf *current += len; 131*4b6dddc2SAlexander Graf 132*4b6dddc2SAlexander Graf return len; 133*4b6dddc2SAlexander Graf } 134*4b6dddc2SAlexander Graf 135*4b6dddc2SAlexander Graf static int smbios_write_type3(u32 *current, int handle) 136*4b6dddc2SAlexander Graf { 137*4b6dddc2SAlexander Graf struct smbios_type3 *t = (struct smbios_type3 *)*current; 138*4b6dddc2SAlexander Graf int len = sizeof(struct smbios_type3); 139*4b6dddc2SAlexander Graf 140*4b6dddc2SAlexander Graf memset(t, 0, sizeof(struct smbios_type3)); 141*4b6dddc2SAlexander Graf fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle); 142*4b6dddc2SAlexander Graf t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); 143*4b6dddc2SAlexander Graf t->chassis_type = SMBIOS_ENCLOSURE_DESKTOP; 144*4b6dddc2SAlexander Graf t->bootup_state = SMBIOS_STATE_SAFE; 145*4b6dddc2SAlexander Graf t->power_supply_state = SMBIOS_STATE_SAFE; 146*4b6dddc2SAlexander Graf t->thermal_state = SMBIOS_STATE_SAFE; 147*4b6dddc2SAlexander Graf t->security_status = SMBIOS_SECURITY_NONE; 148*4b6dddc2SAlexander Graf 149*4b6dddc2SAlexander Graf len = t->length + smbios_string_table_len(t->eos); 150*4b6dddc2SAlexander Graf *current += len; 151*4b6dddc2SAlexander Graf 152*4b6dddc2SAlexander Graf return len; 153*4b6dddc2SAlexander Graf } 154*4b6dddc2SAlexander Graf 155*4b6dddc2SAlexander Graf static int smbios_write_type4(u32 *current, int handle) 156*4b6dddc2SAlexander Graf { 157*4b6dddc2SAlexander Graf struct smbios_type4 *t = (struct smbios_type4 *)*current; 158*4b6dddc2SAlexander Graf int len = sizeof(struct smbios_type4); 159*4b6dddc2SAlexander Graf const char *vendor; 160*4b6dddc2SAlexander Graf char *name; 161*4b6dddc2SAlexander Graf char processor_name[CPU_MAX_NAME_LEN]; 162*4b6dddc2SAlexander Graf struct cpuid_result res; 163*4b6dddc2SAlexander Graf 164*4b6dddc2SAlexander Graf memset(t, 0, sizeof(struct smbios_type4)); 165*4b6dddc2SAlexander Graf fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle); 166*4b6dddc2SAlexander Graf t->processor_type = SMBIOS_PROCESSOR_TYPE_CENTRAL; 167*4b6dddc2SAlexander Graf t->processor_family = gd->arch.x86; 168*4b6dddc2SAlexander Graf vendor = cpu_vendor_name(gd->arch.x86_vendor); 169*4b6dddc2SAlexander Graf t->processor_manufacturer = smbios_add_string(t->eos, vendor); 170*4b6dddc2SAlexander Graf res = cpuid(1); 171*4b6dddc2SAlexander Graf t->processor_id[0] = res.eax; 172*4b6dddc2SAlexander Graf t->processor_id[1] = res.edx; 173*4b6dddc2SAlexander Graf name = cpu_get_name(processor_name); 174*4b6dddc2SAlexander Graf t->processor_version = smbios_add_string(t->eos, name); 175*4b6dddc2SAlexander Graf t->status = SMBIOS_PROCESSOR_STATUS_ENABLED; 176*4b6dddc2SAlexander Graf t->processor_upgrade = SMBIOS_PROCESSOR_UPGRADE_NONE; 177*4b6dddc2SAlexander Graf t->l1_cache_handle = 0xffff; 178*4b6dddc2SAlexander Graf t->l2_cache_handle = 0xffff; 179*4b6dddc2SAlexander Graf t->l3_cache_handle = 0xffff; 180*4b6dddc2SAlexander Graf t->processor_family2 = t->processor_family; 181*4b6dddc2SAlexander Graf 182*4b6dddc2SAlexander Graf len = t->length + smbios_string_table_len(t->eos); 183*4b6dddc2SAlexander Graf *current += len; 184*4b6dddc2SAlexander Graf 185*4b6dddc2SAlexander Graf return len; 186*4b6dddc2SAlexander Graf } 187*4b6dddc2SAlexander Graf 188*4b6dddc2SAlexander Graf static int smbios_write_type32(u32 *current, int handle) 189*4b6dddc2SAlexander Graf { 190*4b6dddc2SAlexander Graf struct smbios_type32 *t = (struct smbios_type32 *)*current; 191*4b6dddc2SAlexander Graf int len = sizeof(struct smbios_type32); 192*4b6dddc2SAlexander Graf 193*4b6dddc2SAlexander Graf memset(t, 0, sizeof(struct smbios_type32)); 194*4b6dddc2SAlexander Graf fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle); 195*4b6dddc2SAlexander Graf 196*4b6dddc2SAlexander Graf *current += len; 197*4b6dddc2SAlexander Graf 198*4b6dddc2SAlexander Graf return len; 199*4b6dddc2SAlexander Graf } 200*4b6dddc2SAlexander Graf 201*4b6dddc2SAlexander Graf static int smbios_write_type127(u32 *current, int handle) 202*4b6dddc2SAlexander Graf { 203*4b6dddc2SAlexander Graf struct smbios_type127 *t = (struct smbios_type127 *)*current; 204*4b6dddc2SAlexander Graf int len = sizeof(struct smbios_type127); 205*4b6dddc2SAlexander Graf 206*4b6dddc2SAlexander Graf memset(t, 0, sizeof(struct smbios_type127)); 207*4b6dddc2SAlexander Graf fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle); 208*4b6dddc2SAlexander Graf 209*4b6dddc2SAlexander Graf *current += len; 210*4b6dddc2SAlexander Graf 211*4b6dddc2SAlexander Graf return len; 212*4b6dddc2SAlexander Graf } 213*4b6dddc2SAlexander Graf 214*4b6dddc2SAlexander Graf static smbios_write_type smbios_write_funcs[] = { 215*4b6dddc2SAlexander Graf smbios_write_type0, 216*4b6dddc2SAlexander Graf smbios_write_type1, 217*4b6dddc2SAlexander Graf smbios_write_type2, 218*4b6dddc2SAlexander Graf smbios_write_type3, 219*4b6dddc2SAlexander Graf smbios_write_type4, 220*4b6dddc2SAlexander Graf smbios_write_type32, 221*4b6dddc2SAlexander Graf smbios_write_type127 222*4b6dddc2SAlexander Graf }; 223*4b6dddc2SAlexander Graf 224*4b6dddc2SAlexander Graf u32 write_smbios_table(u32 addr) 225*4b6dddc2SAlexander Graf { 226*4b6dddc2SAlexander Graf struct smbios_entry *se; 227*4b6dddc2SAlexander Graf u32 tables; 228*4b6dddc2SAlexander Graf int len = 0; 229*4b6dddc2SAlexander Graf int max_struct_size = 0; 230*4b6dddc2SAlexander Graf int handle = 0; 231*4b6dddc2SAlexander Graf char *istart; 232*4b6dddc2SAlexander Graf int isize; 233*4b6dddc2SAlexander Graf int i; 234*4b6dddc2SAlexander Graf 235*4b6dddc2SAlexander Graf /* 16 byte align the table address */ 236*4b6dddc2SAlexander Graf addr = ALIGN(addr, 16); 237*4b6dddc2SAlexander Graf 238*4b6dddc2SAlexander Graf se = (struct smbios_entry *)addr; 239*4b6dddc2SAlexander Graf memset(se, 0, sizeof(struct smbios_entry)); 240*4b6dddc2SAlexander Graf 241*4b6dddc2SAlexander Graf addr += sizeof(struct smbios_entry); 242*4b6dddc2SAlexander Graf addr = ALIGN(addr, 16); 243*4b6dddc2SAlexander Graf tables = addr; 244*4b6dddc2SAlexander Graf 245*4b6dddc2SAlexander Graf /* populate minimum required tables */ 246*4b6dddc2SAlexander Graf for (i = 0; i < ARRAY_SIZE(smbios_write_funcs); i++) { 247*4b6dddc2SAlexander Graf int tmp = smbios_write_funcs[i](&addr, handle++); 248*4b6dddc2SAlexander Graf max_struct_size = max(max_struct_size, tmp); 249*4b6dddc2SAlexander Graf len += tmp; 250*4b6dddc2SAlexander Graf } 251*4b6dddc2SAlexander Graf 252*4b6dddc2SAlexander Graf memcpy(se->anchor, "_SM_", 4); 253*4b6dddc2SAlexander Graf se->length = sizeof(struct smbios_entry); 254*4b6dddc2SAlexander Graf se->major_ver = SMBIOS_MAJOR_VER; 255*4b6dddc2SAlexander Graf se->minor_ver = SMBIOS_MINOR_VER; 256*4b6dddc2SAlexander Graf se->max_struct_size = max_struct_size; 257*4b6dddc2SAlexander Graf memcpy(se->intermediate_anchor, "_DMI_", 5); 258*4b6dddc2SAlexander Graf se->struct_table_length = len; 259*4b6dddc2SAlexander Graf se->struct_table_address = tables; 260*4b6dddc2SAlexander Graf se->struct_count = handle; 261*4b6dddc2SAlexander Graf 262*4b6dddc2SAlexander Graf /* calculate checksums */ 263*4b6dddc2SAlexander Graf istart = (char *)se + SMBIOS_INTERMEDIATE_OFFSET; 264*4b6dddc2SAlexander Graf isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET; 265*4b6dddc2SAlexander Graf se->intermediate_checksum = table_compute_checksum(istart, isize); 266*4b6dddc2SAlexander Graf se->checksum = table_compute_checksum(se, sizeof(struct smbios_entry)); 267*4b6dddc2SAlexander Graf 268*4b6dddc2SAlexander Graf return addr; 269*4b6dddc2SAlexander Graf } 270