336 lines
8.7 KiB
C
336 lines
8.7 KiB
C
/* $NetBSD: smbios_platform.c,v 1.2 2022/11/25 22:17:20 mrg Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "isa.h"
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: smbios_platform.c,v 1.2 2022/11/25 22:17:20 mrg Exp $");
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/uuid.h>
|
|
#include <sys/pmf.h>
|
|
|
|
#if NISA > 0
|
|
#include <dev/isa/isavar.h>
|
|
#endif
|
|
|
|
#include <dev/smbiosvar.h>
|
|
|
|
static int platform_dminode = CTL_EOL;
|
|
|
|
void platform_init(void); /* XXX */
|
|
static void platform_add(struct smbtable *, const char *, int);
|
|
static void platform_add_word(struct smbtable *, const char *, uint16_t,
|
|
const char *);
|
|
static void platform_add_date(struct smbtable *, const char *, int);
|
|
static void platform_add_uuid(struct smbtable *, const char *,
|
|
const uint8_t *);
|
|
static int platform_dmi_sysctl(SYSCTLFN_PROTO);
|
|
|
|
/* list of private DMI sysctl nodes */
|
|
static const char *platform_private_nodes[] = {
|
|
"chassis-serial",
|
|
"board-serial",
|
|
"system-serial",
|
|
"system-uuid",
|
|
NULL
|
|
};
|
|
|
|
void
|
|
platform_init(void)
|
|
{
|
|
struct smbtable smbios;
|
|
struct smbios_sys *psys;
|
|
struct smbios_struct_bios *pbios;
|
|
struct smbios_board *pboard;
|
|
struct smbios_chassis *pchassis;
|
|
struct smbios_processor *pproc;
|
|
struct smbios_slot *pslot;
|
|
int nisa, nother;
|
|
|
|
if (smbios_entry.hdrphys) {
|
|
int err;
|
|
|
|
err = sysctl_createv(NULL, 0, NULL, NULL,
|
|
CTLFLAG_PERMANENT | CTLFLAG_READONLY | CTLFLAG_HEX |
|
|
CTLFLAG_IMMEDIATE, CTLTYPE_QUAD,
|
|
"smbios", SYSCTL_DESCR("SMBIOS table pointer"),
|
|
NULL, smbios_entry.hdrphys, 0, 0,
|
|
CTL_MACHDEP, CTL_CREATE, CTL_EOL);
|
|
if (err != 0 && err != EEXIST)
|
|
printf("platform: sysctl_createv "
|
|
"(machdep.smbios) failed, err = %d\n", err);
|
|
}
|
|
|
|
smbios.cookie = 0;
|
|
if (smbios_find_table(SMBIOS_TYPE_SYSTEM, &smbios)) {
|
|
psys = smbios.tblhdr;
|
|
|
|
platform_add(&smbios, "system-vendor", psys->vendor);
|
|
platform_add(&smbios, "system-product", psys->product);
|
|
platform_add(&smbios, "system-version", psys->version);
|
|
platform_add(&smbios, "system-serial", psys->serial);
|
|
platform_add_uuid(&smbios, "system-uuid", psys->uuid);
|
|
}
|
|
|
|
smbios.cookie = 0;
|
|
if (smbios_find_table(SMBIOS_TYPE_BIOS, &smbios)) {
|
|
pbios = smbios.tblhdr;
|
|
|
|
platform_add(&smbios, "bios-vendor", pbios->vendor);
|
|
platform_add(&smbios, "bios-version", pbios->version);
|
|
platform_add_date(&smbios, "bios-date", pbios->release);
|
|
}
|
|
|
|
smbios.cookie = 0;
|
|
if (smbios_find_table(SMBIOS_TYPE_BASEBOARD, &smbios)) {
|
|
pboard = smbios.tblhdr;
|
|
|
|
platform_add(&smbios, "board-vendor", pboard->vendor);
|
|
platform_add(&smbios, "board-product", pboard->product);
|
|
platform_add(&smbios, "board-version", pboard->version);
|
|
platform_add(&smbios, "board-serial", pboard->serial);
|
|
platform_add(&smbios, "board-asset-tag", pboard->asset);
|
|
}
|
|
|
|
smbios.cookie = 0;
|
|
if (smbios_find_table(SMBIOS_TYPE_ENCLOSURE, &smbios)) {
|
|
pchassis = smbios.tblhdr;
|
|
|
|
platform_add(&smbios, "chassis-vendor", pchassis->vendor);
|
|
platform_add(&smbios, "chassis-type", pchassis->shape);
|
|
platform_add(&smbios, "chassis-version", pchassis->version);
|
|
platform_add(&smbios, "chassis-serial", pchassis->serial);
|
|
platform_add(&smbios, "chassis-asset-tag", pchassis->asset);
|
|
}
|
|
|
|
smbios.cookie = 0;
|
|
if (smbios_find_table(SMBIOS_TYPE_PROCESSOR, &smbios)) {
|
|
pproc = smbios.tblhdr;
|
|
|
|
platform_add(&smbios, "processor-vendor", pproc->vendor);
|
|
platform_add(&smbios, "processor-version", pproc->version);
|
|
platform_add_word(&smbios, "processor-frequency",
|
|
pproc->curspeed, " MHz");
|
|
}
|
|
|
|
smbios.cookie = 0;
|
|
nisa = 0;
|
|
nother = 0;
|
|
while (smbios_find_table(SMBIOS_TYPE_SLOTS, &smbios)) {
|
|
pslot = smbios.tblhdr;
|
|
switch (pslot->type) {
|
|
case SMBIOS_SLOT_ISA:
|
|
case SMBIOS_SLOT_EISA:
|
|
nisa++;
|
|
break;
|
|
default:
|
|
nother++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if NISA > 0
|
|
if ((nother | nisa) != 0) {
|
|
/* Only if there seems to be good expansion slot info. */
|
|
isa_set_slotcount(nisa);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static bool
|
|
platform_sysctl_is_private(const char *key)
|
|
{
|
|
unsigned int n;
|
|
|
|
for (n = 0; platform_private_nodes[n] != NULL; n++) {
|
|
if (strcmp(key, platform_private_nodes[n]) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void
|
|
platform_create_sysctl(const char *key)
|
|
{
|
|
int flags = 0, err;
|
|
|
|
if (pmf_get_platform(key) == NULL)
|
|
return;
|
|
|
|
/* If the key is marked private, set CTLFLAG_PRIVATE flag */
|
|
if (platform_sysctl_is_private(key))
|
|
flags |= CTLFLAG_PRIVATE;
|
|
|
|
err = sysctl_createv(NULL, 0, NULL, NULL,
|
|
CTLFLAG_READONLY | flags, CTLTYPE_STRING,
|
|
key, NULL, platform_dmi_sysctl, 0, NULL, 0,
|
|
CTL_MACHDEP, platform_dminode, CTL_CREATE, CTL_EOL);
|
|
if (err != 0)
|
|
printf("platform: sysctl_createv "
|
|
"(machdep.dmi.%s) failed, err = %d\n",
|
|
key, err);
|
|
}
|
|
|
|
static void
|
|
platform_add(struct smbtable *tbl, const char *key, int idx)
|
|
{
|
|
char tmpbuf[128]; /* XXX is this long enough? */
|
|
|
|
if (smbios_get_string(tbl, idx, tmpbuf, 128) != NULL) {
|
|
/* add to platform dictionary */
|
|
pmf_set_platform(key, tmpbuf);
|
|
|
|
/* create sysctl node */
|
|
platform_create_sysctl(key);
|
|
}
|
|
}
|
|
|
|
static void
|
|
platform_add_word(struct smbtable *tbl, const char *key, uint16_t val,
|
|
const char *suf)
|
|
{
|
|
char tmpbuf[128]; /* XXX is this long enough? */
|
|
|
|
if (snprintf(tmpbuf, sizeof(tmpbuf), "%u%s", val, suf)) {
|
|
/* add to platform dictionary */
|
|
pmf_set_platform(key, tmpbuf);
|
|
|
|
/* create sysctl node */
|
|
platform_create_sysctl(key);
|
|
}
|
|
}
|
|
|
|
static int
|
|
platform_scan_date(char *buf, unsigned int *month, unsigned int *day,
|
|
unsigned int *year)
|
|
{
|
|
char *p, *s;
|
|
|
|
s = buf;
|
|
p = strchr(s, '/');
|
|
if (p) *p = '\0';
|
|
*month = strtoul(s, NULL, 10);
|
|
if (!p) return 1;
|
|
|
|
s = p + 1;
|
|
p = strchr(s, '/');
|
|
if (p) *p = '\0';
|
|
*day = strtoul(s, NULL, 10);
|
|
if (!p) return 2;
|
|
|
|
s = p + 1;
|
|
*year = strtoul(s, NULL, 10);
|
|
return 3;
|
|
}
|
|
|
|
static void
|
|
platform_add_date(struct smbtable *tbl, const char *key, int idx)
|
|
{
|
|
unsigned int month, day, year;
|
|
char tmpbuf[128], datestr[9];
|
|
|
|
if (smbios_get_string(tbl, idx, tmpbuf, 128) == NULL)
|
|
return;
|
|
if (platform_scan_date(tmpbuf, &month, &day, &year) != 3)
|
|
return;
|
|
if (month == 0 || month > 12 || day == 0 || day > 31)
|
|
return;
|
|
if (year > 9999)
|
|
return;
|
|
if (year < 70)
|
|
year += 2000;
|
|
else if (year < 100)
|
|
year += 1900;
|
|
snprintf(datestr, sizeof(datestr), "%04u%02u%02u", year, month, day);
|
|
pmf_set_platform(key, datestr);
|
|
platform_create_sysctl(key);
|
|
}
|
|
|
|
static void
|
|
platform_add_uuid(struct smbtable *tbl, const char *key, const uint8_t *buf)
|
|
{
|
|
struct uuid uuid;
|
|
char tmpbuf[UUID_STR_LEN];
|
|
|
|
uuid_dec_le(buf, &uuid);
|
|
uuid_snprintf(tmpbuf, sizeof(tmpbuf), &uuid);
|
|
|
|
pmf_set_platform(key, tmpbuf);
|
|
platform_create_sysctl(key);
|
|
}
|
|
|
|
static int
|
|
platform_dmi_sysctl(SYSCTLFN_ARGS)
|
|
{
|
|
struct sysctlnode node;
|
|
const char *v;
|
|
int err = 0;
|
|
|
|
node = *rnode;
|
|
|
|
v = pmf_get_platform(node.sysctl_name);
|
|
if (v == NULL)
|
|
return ENOENT;
|
|
|
|
node.sysctl_data = __UNCONST(v);
|
|
err = sysctl_lookup(SYSCTLFN_CALL(&node));
|
|
if (err || newp == NULL)
|
|
return err;
|
|
|
|
return 0;
|
|
}
|
|
|
|
SYSCTL_SETUP(sysctl_dmi_setup, "sysctl machdep.dmi subtree setup")
|
|
{
|
|
const struct sysctlnode *rnode;
|
|
int err;
|
|
|
|
err = sysctl_createv(clog, 0, NULL, &rnode,
|
|
CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep",
|
|
NULL, NULL, 0, NULL, 0,
|
|
CTL_MACHDEP, CTL_EOL);
|
|
if (err)
|
|
return;
|
|
|
|
err = sysctl_createv(clog, 0, &rnode, &rnode,
|
|
CTLFLAG_PERMANENT, CTLTYPE_NODE, "dmi",
|
|
SYSCTL_DESCR("DMI table information"),
|
|
NULL, 0, NULL, 0,
|
|
CTL_CREATE, CTL_EOL);
|
|
if (err)
|
|
return;
|
|
|
|
platform_dminode = rnode->sysctl_num;
|
|
}
|