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