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