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