Allow mainboard vendor name and part number override in SMBIOS tables
[gnutoo-for-coreboot:coreboot.git] / src / arch / x86 / boot / smbios.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2011 Sven Schnelle <svens@stackframe.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; version 2 of
9  * the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19  * MA 02110-1301 USA
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <smbios.h>
25 #include <console/console.h>
26 #include <build.h>
27 #include <device/device.h>
28 #include <arch/cpu.h>
29 #include <cpu/x86/name.h>
30 #include <cbfs_core.h>
31 #include <arch/byteorder.h>
32 #include <elog.h>
33 #if CONFIG_CHROMEOS
34 #include <vendorcode/google/chromeos/gnvs.h>
35 #endif
36
37 static u8 smbios_checksum(u8 *p, u32 length)
38 {
39         u8 ret = 0;
40         while (length--)
41                 ret += *p++;
42         return -ret;
43 }
44
45
46 int smbios_add_string(char *start, const char *str)
47 {
48         int i = 1;
49         char *p = start;
50
51         for(;;) {
52                 if (!*p) {
53                         strcpy(p, str);
54                         p += strlen(str);
55                         *p++ = '\0';
56                         *p++ = '\0';
57                         return i;
58                 }
59
60                 if (!strcmp(p, str))
61                         return i;
62
63                 p += strlen(p)+1;
64                 i++;
65         }
66 }
67
68 int smbios_string_table_len(char *start)
69 {
70         char *p = start;
71         int i, len = 0;
72
73         while(*p) {
74                 i = strlen(p) + 1;
75                 p += i;
76                 len += i;
77         }
78         return len + 1;
79 }
80
81 static int smbios_cpu_vendor(char *start)
82 {
83         char tmp[13] = "Unknown";
84         u32 *_tmp = (u32 *)tmp;
85         struct cpuid_result res;
86
87         if (cpu_have_cpuid()) {
88                 res = cpuid(0);
89                 _tmp[0] = res.ebx;
90                 _tmp[1] = res.edx;
91                 _tmp[2] = res.ecx;
92                 tmp[12] = '\0';
93         }
94
95         return smbios_add_string(start, tmp);
96 }
97
98 static int smbios_processor_name(char *start)
99 {
100         char tmp[49] = "Unknown Processor Name";
101         u32  *_tmp = (u32 *)tmp;
102         struct cpuid_result res;
103         int i;
104
105         if (cpu_have_cpuid()) {
106                 res = cpuid(0x80000000);
107                 if (res.eax >= 0x80000004) {
108                         for (i = 0; i < 3; i++) {
109                                 res = cpuid(0x80000002 + i);
110                                 _tmp[i * 4 + 0] = res.eax;
111                                 _tmp[i * 4 + 1] = res.ebx;
112                                 _tmp[i * 4 + 2] = res.ecx;
113                                 _tmp[i * 4 + 3] = res.edx;
114                         }
115                         tmp[48] = 0;
116                 }
117         }
118         return smbios_add_string(start, tmp);
119 }
120
121 static int smbios_write_type0(unsigned long *current, int handle)
122 {
123         struct smbios_type0 *t = (struct smbios_type0 *)*current;
124         int len = sizeof(struct smbios_type0);
125
126         memset(t, 0, sizeof(struct smbios_type0));
127         t->type = SMBIOS_BIOS_INFORMATION;
128         t->handle = handle;
129         t->length = len - 2;
130
131         t->vendor = smbios_add_string(t->eos, "coreboot");
132 #if !CONFIG_CHROMEOS
133         t->bios_release_date = smbios_add_string(t->eos, COREBOOT_DMI_DATE);
134
135         if (strlen(CONFIG_LOCALVERSION))
136                 t->bios_version = smbios_add_string(t->eos, CONFIG_LOCALVERSION);
137         else
138                 t->bios_version = smbios_add_string(t->eos, COREBOOT_VERSION);
139 #else
140 #define SPACES \
141         "                                                                  "
142         t->bios_release_date = smbios_add_string(t->eos, COREBOOT_DMI_DATE);
143         u32 version_offset = (u32)smbios_string_table_len(t->eos);
144         t->bios_version = smbios_add_string(t->eos, SPACES);
145         /* SMBIOS offsets start at 1 rather than 0 */
146         vboot_data->vbt10 = (u32)t->eos + (version_offset - 1);
147 #endif
148
149         {
150                 const struct cbfs_header *header;
151                 u32 romsize = CONFIG_ROM_SIZE;
152                 header = cbfs_get_header(CBFS_DEFAULT_MEDIA);
153                 if (header != CBFS_HEADER_INVALID_ADDRESS)
154                         romsize = ntohl(header->romsize);
155                 t->bios_rom_size = (romsize / 65535) - 1;
156         }
157
158         t->system_bios_major_release = 4;
159         t->bios_characteristics =
160                 BIOS_CHARACTERISTICS_PCI_SUPPORTED |
161 #if CONFIG_CARDBUS_PLUGIN_SUPPORT
162                 BIOS_CHARACTERISTICS_PC_CARD |
163 #endif
164                 BIOS_CHARACTERISTICS_SELECTABLE_BOOT |
165                 BIOS_CHARACTERISTICS_UPGRADEABLE;
166
167 #if CONFIG_GENERATE_ACPI_TABLES
168         t->bios_characteristics_ext1 = BIOS_EXT1_CHARACTERISTICS_ACPI;
169 #endif
170         t->bios_characteristics_ext2 = BIOS_EXT2_CHARACTERISTICS_TARGET;
171         len = t->length + smbios_string_table_len(t->eos);
172         *current += len;
173         return len;
174 }
175
176 const char *__attribute__((weak)) smbios_mainboard_serial_number(void)
177 {
178         return CONFIG_MAINBOARD_SERIAL_NUMBER;
179 }
180
181 const char *__attribute__((weak)) smbios_mainboard_version(void)
182 {
183         return CONFIG_MAINBOARD_VERSION;
184 }
185
186 static int smbios_write_type1(unsigned long *current, int handle)
187 {
188         struct smbios_type1 *t = (struct smbios_type1 *)*current;
189         int len = sizeof(struct smbios_type1);
190
191         memset(t, 0, sizeof(struct smbios_type1));
192         t->type = SMBIOS_SYSTEM_INFORMATION;
193         t->handle = handle;
194         t->length = len - 2;
195         t->manufacturer = smbios_add_string(t->eos, CONFIG_MAINBOARD_SMBIOS_VENDOR);
196         t->product_name = smbios_add_string(t->eos, CONFIG_MAINBOARD_SMBIOS_PART_NUMBER);
197         t->serial_number = smbios_add_string(t->eos, smbios_mainboard_serial_number());
198         t->version = smbios_add_string(t->eos, smbios_mainboard_version());
199         len = t->length + smbios_string_table_len(t->eos);
200         *current += len;
201         return len;
202 }
203
204 static int smbios_write_type3(unsigned long *current, int handle)
205 {
206         struct smbios_type3 *t = (struct smbios_type3 *)*current;
207         int len = sizeof(struct smbios_type3);
208
209         memset(t, 0, sizeof(struct smbios_type3));
210         t->type = SMBIOS_SYSTEM_ENCLOSURE;
211         t->handle = handle;
212         t->length = len - 2;
213         t->manufacturer = smbios_add_string(t->eos, CONFIG_MAINBOARD_SMBIOS_VENDOR);
214         t->bootup_state = SMBIOS_STATE_SAFE;
215         t->power_supply_state = SMBIOS_STATE_SAFE;
216         t->thermal_state = SMBIOS_STATE_SAFE;
217         t->_type = 3;
218         t->security_status = SMBIOS_STATE_SAFE;
219         len = t->length + smbios_string_table_len(t->eos);
220         *current += len;
221         return len;
222 }
223
224 static int smbios_write_type4(unsigned long *current, int handle)
225 {
226         struct cpuid_result res;
227         struct smbios_type4 *t = (struct smbios_type4 *)*current;
228         int len = sizeof(struct smbios_type4);
229
230         /* Provide sane defaults even for CPU without CPUID */
231         res.eax = res.edx = 0;
232         res.ebx = 0x10000;
233
234         if (cpu_have_cpuid()) {
235                 res = cpuid(1);
236         }
237
238         memset(t, 0, sizeof(struct smbios_type4));
239         t->type = SMBIOS_PROCESSOR_INFORMATION;
240         t->handle = handle;
241         t->length = len - 2;
242         t->processor_id[0] = res.eax;
243         t->processor_id[1] = res.edx;
244         t->processor_manufacturer = smbios_cpu_vendor(t->eos);
245         t->processor_version = smbios_processor_name(t->eos);
246         t->processor_family = (res.eax > 0) ? 0x0c : 0x6;
247         t->processor_type = 3; /* System Processor */
248         t->processor_upgrade = 0x06;
249         t->core_count = (res.ebx >> 16) & 0xff;
250         t->l1_cache_handle = 0xffff;
251         t->l2_cache_handle = 0xffff;
252         t->l3_cache_handle = 0xffff;
253         t->processor_upgrade = 1;
254         len = t->length + smbios_string_table_len(t->eos);
255         *current += len;
256         return len;
257 }
258
259 static int smbios_write_type32(unsigned long *current, int handle)
260 {
261         struct smbios_type32 *t = (struct smbios_type32 *)*current;
262         int len = sizeof(struct smbios_type32);
263
264         memset(t, 0, sizeof(struct smbios_type32));
265         t->type = SMBIOS_SYSTEM_BOOT_INFORMATION;
266         t->handle = handle;
267         t->length = len - 2;
268         *current += len;
269         return len;
270 }
271
272 static int smbios_write_type127(unsigned long *current, int handle)
273 {
274         struct smbios_type127 *t = (struct smbios_type127 *)*current;
275         int len = sizeof(struct smbios_type127);
276
277         memset(t, 0, sizeof(struct smbios_type127));
278         t->type = SMBIOS_END_OF_TABLE;
279         t->handle = handle;
280         t->length = len - 2;
281         *current += len;
282         return len;
283 }
284
285 static int smbios_walk_device_tree(device_t tree, int *handle, unsigned long *current)
286 {
287         device_t dev;
288         int len = 0;
289
290         for(dev = tree; dev; dev = dev->next) {
291                 printk(BIOS_INFO, "%s (%s)\n", dev_path(dev), dev_name(dev));
292
293                 if (dev->ops && dev->ops->get_smbios_data)
294                         len += dev->ops->get_smbios_data(dev, handle, current);
295         }
296         return len;
297 }
298
299 unsigned long smbios_write_tables(unsigned long current)
300 {
301         struct smbios_entry *se;
302         unsigned long tables;
303         int len, handle = 0;
304
305         current = ALIGN(current, 16);
306         printk(BIOS_DEBUG, "%s: %08lx\n", __func__, current);
307
308         se = (struct smbios_entry *)current;
309         current += sizeof(struct smbios_entry);
310         current = ALIGN(current, 16);
311
312         tables = current;
313         len = smbios_write_type0(&current, handle++);
314         len += smbios_write_type1(&current, handle++);
315         len += smbios_write_type3(&current, handle++);
316         len += smbios_write_type4(&current, handle++);
317 #if CONFIG_ELOG
318         len += elog_smbios_write_type15(&current, handle++);
319 #endif
320         len += smbios_write_type32(&current, handle++);
321
322         len += smbios_walk_device_tree(all_devices, &handle, &current);
323
324         len += smbios_write_type127(&current, handle++);
325
326         memset(se, 0, sizeof(struct smbios_entry));
327         memcpy(se->anchor, "_SM_", 4);
328         se->length = sizeof(struct smbios_entry);
329         se->major_version = 2;
330         se->minor_version = 7;
331         se->max_struct_size = 24;
332         se->struct_count = handle;
333         memcpy(se->intermediate_anchor_string, "_DMI_", 5);
334
335         se->struct_table_address = (u32)tables;
336         se->struct_table_length = len;
337
338         se->intermediate_checksum = smbios_checksum((u8 *)se + 0x10,
339                                                     sizeof(struct smbios_entry) - 0x10);
340         se->checksum = smbios_checksum((u8 *)se, sizeof(struct smbios_entry));
341         return current;
342 }