Date: Wed, 01 Jul 2026 00:18:46 +0000 From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Abdelkader Boudih <freebsd@seuros.com> Subject: git: 6a1bd5212f29 - main - asmc: add system state and board identity sysctls Message-ID: <6a445ce6.22e46.16a85379@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=6a1bd5212f290933d1429a6d4787394ee53e3181 commit 6a1bd5212f290933d1429a6d4787394ee53e3181 Author: Abdelkader Boudih <freebsd@seuros.com> AuthorDate: 2026-07-01 00:15:24 +0000 Commit: Adrian Chadd <adrian@FreeBSD.org> CommitDate: 2026-07-01 00:18:40 +0000 asmc: add system state and board identity sysctls Add dev.asmc.0.system subtree with read-only sysctls for SMC diagnostic and identity keys: shutdown_cause (MSSD), sleep_cause (MSSP), thermal_status (MSAL), time_of_day (CLKT), power_state (MSPS), board_id (RPlt), and chip_gen (RGEN). Each sysctl is registered only if the key exists on the hardware. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D57853 --- sys/dev/asmc/asmc.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++ sys/dev/asmc/asmcvar.h | 86 +++++++++++++++++++ 2 files changed, 306 insertions(+) diff --git a/sys/dev/asmc/asmc.c b/sys/dev/asmc/asmc.c index 1796867786e5..6513cfed7b4f 100644 --- a/sys/dev/asmc/asmc.c +++ b/sys/dev/asmc/asmc.c @@ -129,6 +129,15 @@ static int asmc_aupo_sysctl(SYSCTL_HANDLER_ARGS); static int asmc_key_getinfo(device_t, const char *, uint8_t *, char *); +/* System state / board identity sysctls */ +static int asmc_mssd_sysctl(SYSCTL_HANDLER_ARGS); +static int asmc_mssp_sysctl(SYSCTL_HANDLER_ARGS); +static int asmc_msal_sysctl(SYSCTL_HANDLER_ARGS); +static int asmc_clkt_sysctl(SYSCTL_HANDLER_ARGS); +static int asmc_msps_sysctl(SYSCTL_HANDLER_ARGS); +static int asmc_rplt_sysctl(SYSCTL_HANDLER_ARGS); +static int asmc_rgen_sysctl(SYSCTL_HANDLER_ARGS); + #ifdef ASMC_DEBUG /* Raw key access */ static int asmc_raw_key_sysctl(SYSCTL_HANDLER_ARGS); @@ -659,6 +668,72 @@ asmc_attach(device_t dev) "Battery charge limit (0-100)"); } + /* System state / board identity subtree. */ + { + struct sysctl_oid *sys_tree; + uint8_t msps_len; + + sys_tree = SYSCTL_ADD_NODE(sysctlctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "system", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, + "System state and board identity"); + if (sys_tree == NULL) { + device_printf(dev, + "failed to create system sysctl node\n"); + goto nosms; + } + + if (asmc_key_getinfo(dev, ASMC_KEY_MSSD, NULL, NULL) == 0) + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(sys_tree), OID_AUTO, "shutdown_cause", + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 0, asmc_mssd_sysctl, "A", + "Last shutdown cause (MSSD)"); + + if (asmc_key_getinfo(dev, ASMC_KEY_MSSP, NULL, NULL) == 0) + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(sys_tree), OID_AUTO, "sleep_cause", + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 0, asmc_mssp_sysctl, "A", + "Last sleep cause (MSSP)"); + + if (asmc_key_getinfo(dev, ASMC_KEY_MSAL, NULL, NULL) == 0) + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(sys_tree), OID_AUTO, "thermal_status", + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 0, asmc_msal_sysctl, "A", + "Thermal subsystem status flags (MSAL)"); + + if (asmc_key_getinfo(dev, ASMC_KEY_CLKT, NULL, NULL) == 0) + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(sys_tree), OID_AUTO, "time_of_day", + CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 0, asmc_clkt_sysctl, "IU", + "Seconds since midnight per SMC clock (CLKT)"); + + if (asmc_key_getinfo(dev, ASMC_KEY_MSPS, &msps_len, NULL) == 0 && + (msps_len == 1 || msps_len == 2)) + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(sys_tree), OID_AUTO, "power_state", + CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 0, asmc_msps_sysctl, "IU", + "SMC power state index (MSPS)"); + + if (asmc_key_getinfo(dev, ASMC_KEY_RPLT, NULL, NULL) == 0) + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(sys_tree), OID_AUTO, "board_id", + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 0, asmc_rplt_sysctl, "A", + "Apple internal board codename (RPlt)"); + + if (asmc_key_getinfo(dev, ASMC_KEY_RGEN, NULL, NULL) == 0) + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(sys_tree), OID_AUTO, "chip_gen", + CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 0, asmc_rgen_sysctl, "IU", + "Apple security chip generation (RGEN; 3=T2)"); + } + if (!sc->sc_has_sms) goto nosms; @@ -2540,3 +2615,148 @@ asmc_backlight_get_info(device_t dev, struct backlight_info *info) return (0); } + +static const char * +asmc_cause_str(int8_t cause, bool is_sleep) +{ + size_t i; + + for (i = 0; i < nitems(asmc_cause_table); i++) { + if (asmc_cause_table[i].code != cause) + continue; + if (is_sleep && asmc_cause_table[i].sleep_desc != NULL) + return (asmc_cause_table[i].sleep_desc); + return (asmc_cause_table[i].desc); + } + return (NULL); +} + +static int +asmc_mssd_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t)arg1; + int8_t cause; + const char *desc; + char buf[ASMC_CAUSE_BUFLEN]; + + /* EIO: SMC I/O bus did not respond to key read. */ + if (asmc_key_read(dev, ASMC_KEY_MSSD, (uint8_t *)&cause, 1) != 0) + return (EIO); + + desc = asmc_cause_str(cause, false); + if (desc != NULL) + snprintf(buf, sizeof(buf), "%d (%s)", (int)cause, desc); + else + snprintf(buf, sizeof(buf), "%d", (int)cause); + + return (sysctl_handle_string(oidp, buf, sizeof(buf), req)); +} + +static int +asmc_mssp_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t)arg1; + int8_t cause; + const char *desc; + char buf[ASMC_CAUSE_BUFLEN]; + + /* EIO: SMC I/O bus did not respond to key read. */ + if (asmc_key_read(dev, ASMC_KEY_MSSP, (uint8_t *)&cause, 1) != 0) + return (EIO); + + desc = asmc_cause_str(cause, true); + if (desc != NULL) + snprintf(buf, sizeof(buf), "%d (%s)", (int)cause, desc); + else + snprintf(buf, sizeof(buf), "%d", (int)cause); + + return (sysctl_handle_string(oidp, buf, sizeof(buf), req)); +} + +static int +asmc_msal_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t)arg1; + uint8_t msal; + char buf[80]; + + /* EIO: SMC I/O bus did not respond to key read. */ + if (asmc_key_read(dev, ASMC_KEY_MSAL, &msal, 1) != 0) + return (EIO); + + snprintf(buf, sizeof(buf), + "0x%02x (tss=%d therm_valid=%d calib_valid=%d prochot=%d plimits=%d)", + msal, + (msal & ASMC_MSAL_TSS) != 0, + (msal & ASMC_MSAL_THERM_VALID) != 0, + (msal & ASMC_MSAL_CALIB_VALID) != 0, + (msal & ASMC_MSAL_PROCHOT) != 0, + (msal & ASMC_MSAL_PLIMITS) != 0); + + return (sysctl_handle_string(oidp, buf, sizeof(buf), req)); +} + +static int +asmc_clkt_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t)arg1; + uint8_t buf[4]; + uint32_t secs; + + if (asmc_key_read(dev, ASMC_KEY_CLKT, buf, 4) != 0) + return (EIO); + + secs = be32dec(buf); + return (sysctl_handle_32(oidp, &secs, 0, req)); +} + +static int +asmc_msps_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t)arg1; + uint8_t buf[2], len; + uint32_t state; + + if (asmc_key_getinfo(dev, ASMC_KEY_MSPS, &len, NULL) != 0) + return (EIO); + if (len != 1 && len != 2) + return (EIO); + + memset(buf, 0, sizeof(buf)); + if (asmc_key_read(dev, ASMC_KEY_MSPS, buf, len) != 0) + return (EIO); + + state = (len == 1) ? buf[0] : be16dec(buf); + return (sysctl_handle_32(oidp, &state, 0, req)); +} + +static int +asmc_rplt_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t)arg1; + uint8_t buf[ASMC_RPLT_MAXLEN + 1]; + char name[ASMC_RPLT_MAXLEN + 1]; + + memset(buf, 0, sizeof(buf)); + if (asmc_key_read(dev, ASMC_KEY_RPLT, buf, ASMC_RPLT_MAXLEN) != 0) + return (EIO); + + memcpy(name, buf, ASMC_RPLT_MAXLEN); + name[ASMC_RPLT_MAXLEN] = '\0'; + + return (sysctl_handle_string(oidp, name, sizeof(name), req)); +} + +static int +asmc_rgen_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t)arg1; + uint8_t gen; + uint32_t val; + + if (asmc_key_read(dev, ASMC_KEY_RGEN, &gen, 1) != 0) + return (EIO); + + val = gen; + return (sysctl_handle_32(oidp, &val, 0, req)); +} diff --git a/sys/dev/asmc/asmcvar.h b/sys/dev/asmc/asmcvar.h index 70485c32ea88..940119e59774 100644 --- a/sys/dev/asmc/asmcvar.h +++ b/sys/dev/asmc/asmcvar.h @@ -190,3 +190,89 @@ struct asmc_softc { * Interrupt keys. */ #define ASMC_KEY_INTOK "NTOK" /* WO; 1 byte */ + +/* + * System State Machine / diagnostics keys. + * + * MSSD - Mac System Shutdown cause (last shutdown reason code) + * MSSP - Mac System SleeP cause (last sleep reason code) + * MSAL - Mac System ALarm (thermal subsystem status bitmap) + * MSPS - Mac System Power State (current power state index) + * CLKT - CLocK Time (seconds since midnight, SMC RTC) + * MSTS - Mac System sTate/Status (SSM state; 0 = S0 awake) + */ +#define ASMC_KEY_CLKT "CLKT" /* RO; 4 bytes ui32 BE */ +#define ASMC_KEY_MSSD "MSSD" /* RO; 1 byte si8 */ +#define ASMC_KEY_MSSP "MSSP" /* RO; 1 byte si8 */ +#define ASMC_KEY_MSAL "MSAL" /* RO; 1 byte hex_ */ +#define ASMC_KEY_MSPS "MSPS" /* RO; 1 or 2 bytes hex_ */ +#define ASMC_KEY_MSTS "MSTS" /* RO; 1 byte ui8 */ + +#define ASMC_MSAL_TSS 0x01 /* TSS running */ +#define ASMC_MSAL_THERM_VALID 0x02 /* thermal calibration valid */ +#define ASMC_MSAL_CALIB_VALID 0x08 /* I/P calibration valid */ +#define ASMC_MSAL_PROCHOT 0x40 /* Prochot enabled */ +#define ASMC_MSAL_PLIMITS 0x80 /* plimits enabled */ + +/* + * Board identity keys. + * + * RPlt - board platform identifier (e.g. "Mac-XXXX") + * RGEN - security chip generation (3 = T2) + */ +#define ASMC_KEY_RPLT "RPlt" /* RO; 8 bytes ch8* */ +#define ASMC_KEY_RGEN "RGEN" /* RO; 1 byte ui8 */ +#define ASMC_RPLT_MAXLEN 8 /* RPlt key data length */ + +/* + * Shutdown/sleep cause codes (MSSD/MSSP values). + * + * Positive values indicate normal operation; negative values indicate + * fault conditions. + * Sources: Apple SMC firmware, VirtualSMC docs, macOS + * pmset/powermetrics output. + */ +struct asmc_cause { + int8_t code; + const char *desc; /* shutdown description */ + const char *sleep_desc; /* sleep description, or NULL if same */ +}; + +#define ASMC_CAUSE_BUFLEN 48 /* "-128 (temperature-overlimit-timeout)\0" */ + +static const struct asmc_cause asmc_cause_table[] = { + { 5, "good-shutdown", "good-sleep" }, + { 3, "power-button", NULL }, + { 2, "low-battery-sleep", NULL }, + { 1, "overtemp-sleep", NULL }, + { 0, "initial", NULL }, + { -1, "health-check", NULL }, + { -2, "power-supply", NULL }, + { -3, "temperature-multisleep", NULL }, + { -4, "sensor-fan", NULL }, + { -30, "temperature-overlimit-timeout",NULL }, + { -40, "pswr-smrst", NULL }, /* power supply watchdog reset */ + { -50, "unmapped", NULL }, + { -60, "low-battery", NULL }, + { -61, "ninja-shutdown", NULL }, /* sudden unexpected power loss */ + { -62, "ninja-restart", NULL }, + { -70, "palm-rest-temperature", NULL }, + { -71, "sodimm-temperature", NULL }, + { -72, "heatpipe-temperature", NULL }, + { -74, "battery-temperature", NULL }, + { -75, "adapter-timeout", NULL }, + { -77, "manual-temperature", NULL }, + { -78, "adapter-current", NULL }, + { -79, "battery-current", NULL }, + { -82, "skin-temperature", NULL }, + { -83, "skin-temperature-sensors", NULL }, + { -84, "backup-temperature", NULL }, + { -86, "cpu-proximity-temperature", NULL }, + { -95, "cpu-temperature", NULL }, + { -100, "power-supply-temperature", NULL }, + { -101, "lcd-temperature", NULL }, + { -102, "rsm-power-fail", NULL }, + { -103, "battery-cuv", NULL }, /* cell under-voltage */ + { -127, "pmu-forced-shutdown", NULL }, + { -128, "unknown", NULL }, +};home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a445ce6.22e46.16a85379>
