1 /* $NetBSD: smbios_platform.c,v 1.2 2022/11/25 22:17:20 mrg 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: smbios_platform.c,v 1.2 2022/11/25 22:17:20 mrg 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 <dev/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_word(struct smbtable *, const char *, uint16_t, 52 const char *); 53 static void platform_add_date(struct smbtable *, const char *, int); 54 static void platform_add_uuid(struct smbtable *, const char *, 55 const uint8_t *); 56 static int platform_dmi_sysctl(SYSCTLFN_PROTO); 57 58 /* list of private DMI sysctl nodes */ 59 static const char *platform_private_nodes[] = { 60 "chassis-serial", 61 "board-serial", 62 "system-serial", 63 "system-uuid", 64 NULL 65 }; 66 67 void 68 platform_init(void) 69 { 70 struct smbtable smbios; 71 struct smbios_sys *psys; 72 struct smbios_struct_bios *pbios; 73 struct smbios_board *pboard; 74 struct smbios_chassis *pchassis; 75 struct smbios_processor *pproc; 76 struct smbios_slot *pslot; 77 int nisa, nother; 78 79 if (smbios_entry.hdrphys) { 80 int err; 81 82 err = sysctl_createv(NULL, 0, NULL, NULL, 83 CTLFLAG_PERMANENT | CTLFLAG_READONLY | CTLFLAG_HEX | 84 CTLFLAG_IMMEDIATE, CTLTYPE_QUAD, 85 "smbios", SYSCTL_DESCR("SMBIOS table pointer"), 86 NULL, smbios_entry.hdrphys, 0, 0, 87 CTL_MACHDEP, CTL_CREATE, CTL_EOL); 88 if (err != 0 && err != EEXIST) 89 printf("platform: sysctl_createv " 90 "(machdep.smbios) failed, err = %d\n", err); 91 } 92 93 smbios.cookie = 0; 94 if (smbios_find_table(SMBIOS_TYPE_SYSTEM, &smbios)) { 95 psys = smbios.tblhdr; 96 97 platform_add(&smbios, "system-vendor", psys->vendor); 98 platform_add(&smbios, "system-product", psys->product); 99 platform_add(&smbios, "system-version", psys->version); 100 platform_add(&smbios, "system-serial", psys->serial); 101 platform_add_uuid(&smbios, "system-uuid", psys->uuid); 102 } 103 104 smbios.cookie = 0; 105 if (smbios_find_table(SMBIOS_TYPE_BIOS, &smbios)) { 106 pbios = smbios.tblhdr; 107 108 platform_add(&smbios, "bios-vendor", pbios->vendor); 109 platform_add(&smbios, "bios-version", pbios->version); 110 platform_add_date(&smbios, "bios-date", pbios->release); 111 } 112 113 smbios.cookie = 0; 114 if (smbios_find_table(SMBIOS_TYPE_BASEBOARD, &smbios)) { 115 pboard = smbios.tblhdr; 116 117 platform_add(&smbios, "board-vendor", pboard->vendor); 118 platform_add(&smbios, "board-product", pboard->product); 119 platform_add(&smbios, "board-version", pboard->version); 120 platform_add(&smbios, "board-serial", pboard->serial); 121 platform_add(&smbios, "board-asset-tag", pboard->asset); 122 } 123 124 smbios.cookie = 0; 125 if (smbios_find_table(SMBIOS_TYPE_ENCLOSURE, &smbios)) { 126 pchassis = smbios.tblhdr; 127 128 platform_add(&smbios, "chassis-vendor", pchassis->vendor); 129 platform_add(&smbios, "chassis-type", pchassis->shape); 130 platform_add(&smbios, "chassis-version", pchassis->version); 131 platform_add(&smbios, "chassis-serial", pchassis->serial); 132 platform_add(&smbios, "chassis-asset-tag", pchassis->asset); 133 } 134 135 smbios.cookie = 0; 136 if (smbios_find_table(SMBIOS_TYPE_PROCESSOR, &smbios)) { 137 pproc = smbios.tblhdr; 138 139 platform_add(&smbios, "processor-vendor", pproc->vendor); 140 platform_add(&smbios, "processor-version", pproc->version); 141 platform_add_word(&smbios, "processor-frequency", 142 pproc->curspeed, " MHz"); 143 } 144 145 smbios.cookie = 0; 146 nisa = 0; 147 nother = 0; 148 while (smbios_find_table(SMBIOS_TYPE_SLOTS, &smbios)) { 149 pslot = smbios.tblhdr; 150 switch (pslot->type) { 151 case SMBIOS_SLOT_ISA: 152 case SMBIOS_SLOT_EISA: 153 nisa++; 154 break; 155 default: 156 nother++; 157 break; 158 } 159 } 160 161 #if NISA > 0 162 if ((nother | nisa) != 0) { 163 /* Only if there seems to be good expansion slot info. */ 164 isa_set_slotcount(nisa); 165 } 166 #endif 167 } 168 169 static bool 170 platform_sysctl_is_private(const char *key) 171 { 172 unsigned int n; 173 174 for (n = 0; platform_private_nodes[n] != NULL; n++) { 175 if (strcmp(key, platform_private_nodes[n]) == 0) { 176 return true; 177 } 178 } 179 180 return false; 181 } 182 183 static void 184 platform_create_sysctl(const char *key) 185 { 186 int flags = 0, err; 187 188 if (pmf_get_platform(key) == NULL) 189 return; 190 191 /* If the key is marked private, set CTLFLAG_PRIVATE flag */ 192 if (platform_sysctl_is_private(key)) 193 flags |= CTLFLAG_PRIVATE; 194 195 err = sysctl_createv(NULL, 0, NULL, NULL, 196 CTLFLAG_READONLY | flags, CTLTYPE_STRING, 197 key, NULL, platform_dmi_sysctl, 0, NULL, 0, 198 CTL_MACHDEP, platform_dminode, CTL_CREATE, CTL_EOL); 199 if (err != 0) 200 printf("platform: sysctl_createv " 201 "(machdep.dmi.%s) failed, err = %d\n", 202 key, err); 203 } 204 205 static void 206 platform_add(struct smbtable *tbl, const char *key, int idx) 207 { 208 char tmpbuf[128]; /* XXX is this long enough? */ 209 210 if (smbios_get_string(tbl, idx, tmpbuf, 128) != NULL) { 211 /* add to platform dictionary */ 212 pmf_set_platform(key, tmpbuf); 213 214 /* create sysctl node */ 215 platform_create_sysctl(key); 216 } 217 } 218 219 static void 220 platform_add_word(struct smbtable *tbl, const char *key, uint16_t val, 221 const char *suf) 222 { 223 char tmpbuf[128]; /* XXX is this long enough? */ 224 225 if (snprintf(tmpbuf, sizeof(tmpbuf), "%u%s", val, suf)) { 226 /* add to platform dictionary */ 227 pmf_set_platform(key, tmpbuf); 228 229 /* create sysctl node */ 230 platform_create_sysctl(key); 231 } 232 } 233 234 static int 235 platform_scan_date(char *buf, unsigned int *month, unsigned int *day, 236 unsigned int *year) 237 { 238 char *p, *s; 239 240 s = buf; 241 p = strchr(s, '/'); 242 if (p) *p = '\0'; 243 *month = strtoul(s, NULL, 10); 244 if (!p) return 1; 245 246 s = p + 1; 247 p = strchr(s, '/'); 248 if (p) *p = '\0'; 249 *day = strtoul(s, NULL, 10); 250 if (!p) return 2; 251 252 s = p + 1; 253 *year = strtoul(s, NULL, 10); 254 return 3; 255 } 256 257 static void 258 platform_add_date(struct smbtable *tbl, const char *key, int idx) 259 { 260 unsigned int month, day, year; 261 char tmpbuf[128], datestr[9]; 262 263 if (smbios_get_string(tbl, idx, tmpbuf, 128) == NULL) 264 return; 265 if (platform_scan_date(tmpbuf, &month, &day, &year) != 3) 266 return; 267 if (month == 0 || month > 12 || day == 0 || day > 31) 268 return; 269 if (year > 9999) 270 return; 271 if (year < 70) 272 year += 2000; 273 else if (year < 100) 274 year += 1900; 275 snprintf(datestr, sizeof(datestr), "%04u%02u%02u", year, month, day); 276 pmf_set_platform(key, datestr); 277 platform_create_sysctl(key); 278 } 279 280 static void 281 platform_add_uuid(struct smbtable *tbl, const char *key, const uint8_t *buf) 282 { 283 struct uuid uuid; 284 char tmpbuf[UUID_STR_LEN]; 285 286 uuid_dec_le(buf, &uuid); 287 uuid_snprintf(tmpbuf, sizeof(tmpbuf), &uuid); 288 289 pmf_set_platform(key, tmpbuf); 290 platform_create_sysctl(key); 291 } 292 293 static int 294 platform_dmi_sysctl(SYSCTLFN_ARGS) 295 { 296 struct sysctlnode node; 297 const char *v; 298 int err = 0; 299 300 node = *rnode; 301 302 v = pmf_get_platform(node.sysctl_name); 303 if (v == NULL) 304 return ENOENT; 305 306 node.sysctl_data = __UNCONST(v); 307 err = sysctl_lookup(SYSCTLFN_CALL(&node)); 308 if (err || newp == NULL) 309 return err; 310 311 return 0; 312 } 313 314 SYSCTL_SETUP(sysctl_dmi_setup, "sysctl machdep.dmi subtree setup") 315 { 316 const struct sysctlnode *rnode; 317 int err; 318 319 err = sysctl_createv(clog, 0, NULL, &rnode, 320 CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", 321 NULL, NULL, 0, NULL, 0, 322 CTL_MACHDEP, CTL_EOL); 323 if (err) 324 return; 325 326 err = sysctl_createv(clog, 0, &rnode, &rnode, 327 CTLFLAG_PERMANENT, CTLTYPE_NODE, "dmi", 328 SYSCTL_DESCR("DMI table information"), 329 NULL, 0, NULL, 0, 330 CTL_CREATE, CTL_EOL); 331 if (err) 332 return; 333 334 platform_dminode = rnode->sysctl_num; 335 } 336