1 | /* $NetBSD: platform.c,v 1.15 2014/03/26 08:04:19 christos Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include "isa.h" |
30 | |
31 | #include <sys/cdefs.h> |
32 | __KERNEL_RCSID(0, "$NetBSD: platform.c,v 1.15 2014/03/26 08:04:19 christos Exp $" ); |
33 | |
34 | #include <sys/types.h> |
35 | #include <sys/param.h> |
36 | #include <sys/kernel.h> |
37 | #include <sys/sysctl.h> |
38 | #include <sys/uuid.h> |
39 | #include <sys/pmf.h> |
40 | |
41 | #if NISA > 0 |
42 | #include <dev/isa/isavar.h> |
43 | #endif |
44 | |
45 | #include <arch/x86/include/smbiosvar.h> |
46 | |
47 | static int platform_dminode = CTL_EOL; |
48 | |
49 | void platform_init(void); /* XXX */ |
50 | static void platform_add(struct smbtable *, const char *, int); |
51 | static void platform_add_date(struct smbtable *, const char *, int); |
52 | static void platform_add_uuid(struct smbtable *, const char *, |
53 | const uint8_t *); |
54 | static int platform_dmi_sysctl(SYSCTLFN_PROTO); |
55 | static void platform_print(void); |
56 | |
57 | /* list of private DMI sysctl nodes */ |
58 | static const char *platform_private_nodes[] = { |
59 | "board-serial" , |
60 | "system-serial" , |
61 | "system-uuid" , |
62 | NULL |
63 | }; |
64 | |
65 | void |
66 | platform_init(void) |
67 | { |
68 | struct smbtable smbios; |
69 | struct smbios_sys *psys; |
70 | struct smbios_struct_bios *pbios; |
71 | struct smbios_board *pboard; |
72 | struct smbios_slot *pslot; |
73 | int nisa, nother; |
74 | |
75 | smbios.cookie = 0; |
76 | if (smbios_find_table(SMBIOS_TYPE_SYSTEM, &smbios)) { |
77 | psys = smbios.tblhdr; |
78 | |
79 | platform_add(&smbios, "system-vendor" , psys->vendor); |
80 | platform_add(&smbios, "system-product" , psys->product); |
81 | platform_add(&smbios, "system-version" , psys->version); |
82 | platform_add(&smbios, "system-serial" , psys->serial); |
83 | platform_add_uuid(&smbios, "system-uuid" , psys->uuid); |
84 | } |
85 | |
86 | smbios.cookie = 0; |
87 | if (smbios_find_table(SMBIOS_TYPE_BIOS, &smbios)) { |
88 | pbios = smbios.tblhdr; |
89 | |
90 | platform_add(&smbios, "bios-vendor" , pbios->vendor); |
91 | platform_add(&smbios, "bios-version" , pbios->version); |
92 | platform_add_date(&smbios, "bios-date" , pbios->release); |
93 | } |
94 | |
95 | smbios.cookie = 0; |
96 | if (smbios_find_table(SMBIOS_TYPE_BASEBOARD, &smbios)) { |
97 | pboard = smbios.tblhdr; |
98 | |
99 | platform_add(&smbios, "board-vendor" , pboard->vendor); |
100 | platform_add(&smbios, "board-product" , pboard->product); |
101 | platform_add(&smbios, "board-version" , pboard->version); |
102 | platform_add(&smbios, "board-serial" , pboard->serial); |
103 | platform_add(&smbios, "board-asset-tag" , pboard->asset); |
104 | } |
105 | |
106 | smbios.cookie = 0; |
107 | nisa = 0; |
108 | nother = 0; |
109 | while (smbios_find_table(SMBIOS_TYPE_SLOTS, &smbios)) { |
110 | pslot = smbios.tblhdr; |
111 | switch (pslot->type) { |
112 | case SMBIOS_SLOT_ISA: |
113 | case SMBIOS_SLOT_EISA: |
114 | nisa++; |
115 | break; |
116 | default: |
117 | nother++; |
118 | break; |
119 | } |
120 | } |
121 | |
122 | #if NISA > 0 |
123 | if ((nother | nisa) != 0) { |
124 | /* Only if there seems to be good expansion slot info. */ |
125 | isa_set_slotcount(nisa); |
126 | } |
127 | #endif |
128 | |
129 | platform_print(); |
130 | } |
131 | |
132 | static void |
133 | platform_print(void) |
134 | { |
135 | const char *vend, *prod, *ver; |
136 | |
137 | vend = pmf_get_platform("system-vendor" ); |
138 | prod = pmf_get_platform("system-product" ); |
139 | ver = pmf_get_platform("system-version" ); |
140 | |
141 | if (vend == NULL) |
142 | aprint_verbose("Generic" ); |
143 | else |
144 | aprint_verbose("%s" , vend); |
145 | if (prod == NULL) |
146 | aprint_verbose(" PC" ); |
147 | else |
148 | aprint_verbose(" %s" , prod); |
149 | if (ver != NULL) |
150 | aprint_verbose(" (%s)" , ver); |
151 | aprint_verbose("\n" ); |
152 | } |
153 | |
154 | static bool |
155 | platform_sysctl_is_private(const char *key) |
156 | { |
157 | unsigned int n; |
158 | |
159 | for (n = 0; platform_private_nodes[n] != NULL; n++) { |
160 | if (strcmp(key, platform_private_nodes[n]) == 0) { |
161 | return true; |
162 | } |
163 | } |
164 | |
165 | return false; |
166 | } |
167 | |
168 | static void |
169 | platform_create_sysctl(const char *key) |
170 | { |
171 | int flags = 0, err; |
172 | |
173 | if (pmf_get_platform(key) == NULL) |
174 | return; |
175 | |
176 | /* If the key is marked private, set CTLFLAG_PRIVATE flag */ |
177 | if (platform_sysctl_is_private(key)) |
178 | flags |= CTLFLAG_PRIVATE; |
179 | |
180 | err = sysctl_createv(NULL, 0, NULL, NULL, |
181 | CTLFLAG_READONLY | flags, CTLTYPE_STRING, |
182 | key, NULL, platform_dmi_sysctl, 0, NULL, 0, |
183 | CTL_MACHDEP, platform_dminode, CTL_CREATE, CTL_EOL); |
184 | if (err != 0) |
185 | printf("platform: sysctl_createv " |
186 | "(machdep.dmi.%s) failed, err = %d\n" , |
187 | key, err); |
188 | } |
189 | |
190 | static void |
191 | platform_add(struct smbtable *tbl, const char *key, int idx) |
192 | { |
193 | char tmpbuf[128]; /* XXX is this long enough? */ |
194 | |
195 | if (smbios_get_string(tbl, idx, tmpbuf, 128) != NULL) { |
196 | /* add to platform dictionary */ |
197 | pmf_set_platform(key, tmpbuf); |
198 | |
199 | /* create sysctl node */ |
200 | platform_create_sysctl(key); |
201 | } |
202 | } |
203 | |
204 | static int |
205 | platform_scan_date(char *buf, unsigned int *month, unsigned int *day, |
206 | unsigned int *year) |
207 | { |
208 | char *p, *s; |
209 | |
210 | s = buf; |
211 | p = strchr(s, '/'); |
212 | if (p) *p = '\0'; |
213 | *month = strtoul(s, NULL, 10); |
214 | if (!p) return 1; |
215 | |
216 | s = p + 1; |
217 | p = strchr(s, '/'); |
218 | if (p) *p = '\0'; |
219 | *day = strtoul(s, NULL, 10); |
220 | if (!p) return 2; |
221 | |
222 | s = p + 1; |
223 | *year = strtoul(s, NULL, 10); |
224 | return 3; |
225 | } |
226 | |
227 | static void |
228 | platform_add_date(struct smbtable *tbl, const char *key, int idx) |
229 | { |
230 | unsigned int month, day, year; |
231 | char tmpbuf[128], datestr[9]; |
232 | |
233 | if (smbios_get_string(tbl, idx, tmpbuf, 128) == NULL) |
234 | return; |
235 | if (platform_scan_date(tmpbuf, &month, &day, &year) != 3) |
236 | return; |
237 | if (month == 0 || month > 12 || day == 0 || day > 31) |
238 | return; |
239 | if (year > 9999) |
240 | return; |
241 | if (year < 70) |
242 | year += 2000; |
243 | else if (year < 100) |
244 | year += 1900; |
245 | snprintf(datestr, sizeof(datestr), "%04u%02u%02u" , year, month, day); |
246 | pmf_set_platform(key, datestr); |
247 | platform_create_sysctl(key); |
248 | } |
249 | |
250 | static void |
251 | platform_add_uuid(struct smbtable *tbl, const char *key, const uint8_t *buf) |
252 | { |
253 | struct uuid uuid; |
254 | char tmpbuf[UUID_STR_LEN]; |
255 | |
256 | uuid_dec_le(buf, &uuid); |
257 | uuid_snprintf(tmpbuf, sizeof(tmpbuf), &uuid); |
258 | |
259 | pmf_set_platform(key, tmpbuf); |
260 | platform_create_sysctl(key); |
261 | } |
262 | |
263 | static int |
264 | platform_dmi_sysctl(SYSCTLFN_ARGS) |
265 | { |
266 | struct sysctlnode node; |
267 | const char *v; |
268 | int err = 0; |
269 | |
270 | node = *rnode; |
271 | |
272 | v = pmf_get_platform(node.sysctl_name); |
273 | if (v == NULL) |
274 | return ENOENT; |
275 | |
276 | node.sysctl_data = __UNCONST(v); |
277 | err = sysctl_lookup(SYSCTLFN_CALL(&node)); |
278 | if (err || newp == NULL) |
279 | return err; |
280 | |
281 | return 0; |
282 | } |
283 | |
284 | SYSCTL_SETUP(sysctl_dmi_setup, "sysctl machdep.dmi subtree setup" ) |
285 | { |
286 | const struct sysctlnode *rnode; |
287 | int err; |
288 | |
289 | err = sysctl_createv(clog, 0, NULL, &rnode, |
290 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep" , |
291 | NULL, NULL, 0, NULL, 0, |
292 | CTL_MACHDEP, CTL_EOL); |
293 | if (err) |
294 | return; |
295 | |
296 | err = sysctl_createv(clog, 0, &rnode, &rnode, |
297 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "dmi" , |
298 | SYSCTL_DESCR("DMI table information" ), |
299 | NULL, 0, NULL, 0, |
300 | CTL_CREATE, CTL_EOL); |
301 | if (err) |
302 | return; |
303 | |
304 | platform_dminode = rnode->sysctl_num; |
305 | } |
306 | |