On Sun, 10 Jan 2016 21:28:31 +0100 Joerg Jung wrote: > On Sun, Jan 10, 2016 at 04:59:22AM +0200, Sviatoslav Chagaev wrote: > > So below is a driver for TI LP8550. ... > > If there's any chance for it to be commited, please tell me what I need to > > fix/improve to get it commited (so I don't have to reapply it every time I > > upgrade). > > IMHO, instead of adding another driver to the mix, I would prefer this > to be handled through the associated asmc(4) keys instead of accessing > the chip directly. The SMC is supposed to be the central point for such > manipulations. Unfortunately, the keys are not documented and need some > non-trivial effort to be figured out. > > If this is not possible through asmc(4) and if your new driver improves > the situation then I'm fine with importing it, but for now it is just > worse. >
Using knowledge acquired from [1] and [2] made a diff, posted below for reference, which adds: * ioctl interface to asmc(4) to allow reading/writing of ``keys'' from userspace; * companion smcprobe(1) which reads/writes ``keys'' using the ioctl; * smcdumpkeys(1): scans an SMC textual firmware file and dumps the ``key'' table that it contains. Downloaded SMC FW [3], unpacked it using Google Drive and used smcdumpkeys(1) + smcprobe(1) to create the table of keys and their current values before suspend [4] and after wake up [5]. Diffed them [6], filtering out keys which change over time as they are probably sensors (some might have gotten through). Tried modifying all keys whose names start with 'B': no effect. Tried modifying keys which are different after wake up: no effect. [1] https://reverse.put.as/wp-content/uploads/2015/12/D1_02_Alex_Ninjas_and_Harry_Potter.pdf [2] https://dev.inversepath.com/download/public/embedded_systems_exploitation.pdf [3] https://support.apple.com/kb/DL1748?locale=en_US [4] https://gist.github.com/S010/26145f4446fcc0b8a0d6#file-before_suspend-txt [5] https://gist.github.com/S010/26145f4446fcc0b8a0d6#file-after_wakeup-txt [6] https://gist.github.com/S010/26145f4446fcc0b8a0d6#file-suspend_wakeup_key-diff Index: sys/dev/isa/asmc.c =================================================================== RCS file: /cvs/src/sys/dev/isa/asmc.c,v retrieving revision 1.28 diff -u -p -r1.28 asmc.c --- sys/dev/isa/asmc.c 27 Dec 2015 20:54:53 -0000 1.28 +++ sys/dev/isa/asmc.c 27 Jan 2016 02:43:15 -0000 @@ -26,6 +26,8 @@ #include <sys/rwlock.h> #include <sys/task.h> #include <sys/sensors.h> +#include <sys/ioctl.h> +#include <dev/isa/asmc.h> #include <machine/bus.h> @@ -705,4 +707,47 @@ asmc_update(void *arg) if (!(sc->sc_sensor_motion[i].flags & SENSOR_FINVALID)) asmc_motion(sc, i, 0); #endif +} + +int +asmcopen(dev_t dev, int flag, int mode, struct proc *p) +{ + /* FIXME */ + return 0; +} + +int +asmcclose(dev_t dev, int flag, int mode, struct proc *p) +{ + /* FIXME */ + return 0; +} + +/* + * An ioctl interface to poke SMC ``keys'' from userspace. + */ +int +asmcioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) +{ + struct asmc_softc *sc; + struct asmc_key_buf *buf = (struct asmc_key_buf *)addr; + int error; + + sc = asmc_cd.cd_devs[minor(dev)]; + + switch (cmd) { + case ASMC_READ_KEY: + error = asmc_try(sc, ASMC_READ, buf->key, buf->data, buf->len); + break; + case ASMC_WRITE_KEY: + error = asmc_try(sc, ASMC_WRITE, buf->key, buf->data, buf->len); + break; + default: + return ENOTTY; + } + + if (error) + return EIO; + else + return 0; } Index: sys/dev/isa/asmc.h =================================================================== RCS file: sys/dev/isa/asmc.h diff -N sys/dev/isa/asmc.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/dev/isa/asmc.h 27 Jan 2016 02:43:15 -0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016 Sviatoslav Chagaev <sviatoslav.chag...@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _ASMC_H_ +#define _ASMC_H_ + +#include <sys/types.h> +#include <sys/ioctl.h> + +struct asmc_key_buf { + char key[4]; + size_t len; + uint8_t data[32]; +}; + +#define ASMC_READ_KEY _IOWR('a', 1, struct asmc_key_buf) +#define ASMC_WRITE_KEY _IOWR('a', 2, struct asmc_key_buf) + +#endif Index: etc/etc.amd64/MAKEDEV =================================================================== RCS file: /cvs/src/etc/etc.amd64/MAKEDEV,v retrieving revision 1.103 diff -u -p -r1.103 MAKEDEV --- etc/etc.amd64/MAKEDEV 21 Dec 2015 22:23:24 -0000 1.103 +++ etc/etc.amd64/MAKEDEV 27 Jan 2016 02:43:16 -0000 @@ -94,6 +94,7 @@ # video* Video V4L2 devices # vmm Virtual Machine Monitor # vscsi* Virtual SCSI controller +# asmc* Apple SMC PATH=/sbin:/usr/sbin:/bin:/usr/bin T=$0 @@ -242,6 +243,10 @@ std) ttyc*) M ttyc$U c 38 $U 660 dialer uucp M cuac$U c 38 $(($U+128)) 660 dialer uucp + ;; + +asmc) + M asmc$U c 95 $U ;; vscsi*) Index: etc/etc.amd64/MAKEDEV.md =================================================================== RCS file: /cvs/src/etc/etc.amd64/MAKEDEV.md,v retrieving revision 1.62 diff -u -p -r1.62 MAKEDEV.md --- etc/etc.amd64/MAKEDEV.md 21 Dec 2015 22:15:53 -0000 1.62 +++ etc/etc.amd64/MAKEDEV.md 27 Jan 2016 02:43:16 -0000 @@ -20,7 +20,9 @@ dnl dnl __devitem(apm, apm, Power Management Interface)dnl __devitem(nvram, nvram, NVRAM access)dnl +__devitem(asmc, asmc*, Apple SMC)dnl _mkdev(nvram, nvram, {-M nvram c major_nvram_c 0 440 kmem-})dnl +_mkdev(asmc, asmc, {-M asmc$U c major_asmc_c $U-})dnl _TITLE(make) _DEV(all) _DEV(ramdisk) @@ -92,6 +94,7 @@ _DEV(uk, 20) _DEV(vi, 44) _DEV(vmm, 10) _DEV(vscsi, 89) +_DEV(asmc, 95) dnl divert(__mddivert)dnl dnl Index: usr.sbin/smcdumpkeys/Makefile =================================================================== RCS file: usr.sbin/smcdumpkeys/Makefile diff -N usr.sbin/smcdumpkeys/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.sbin/smcdumpkeys/Makefile 27 Jan 2016 02:43:22 -0000 @@ -0,0 +1,5 @@ +PROG= smcdumpkeys +MAN= +CFLAGS+= -Wall + +.include <bsd.prog.mk> Index: usr.sbin/smcdumpkeys/smcdumpkeys.c =================================================================== RCS file: usr.sbin/smcdumpkeys/smcdumpkeys.c diff -N usr.sbin/smcdumpkeys/smcdumpkeys.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.sbin/smcdumpkeys/smcdumpkeys.c 27 Jan 2016 02:43:22 -0000 @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2016 Sviatoslav Chagaev <sviatoslav.chag...@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Dump the ``key'' table in an Apple System Management Controller (SMC) + * firmware to standard output. + */ + +#include <unistd.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> +#include <stdbool.h> + +#define _STR(x) #x +#define STR(x) _STR(x) + +#define FIRST_KEY "#KEY" + +struct key_record { + uint8_t name[4]; + uint8_t unknown1[4]; + uint8_t type[4]; + uint8_t unknown2[4]; +}; +#define FIELD_LEN 4 +#define KEY_NAME_FMT "%-" STR(FIELD_LEN) "." STR(FIELD_LEN) "s" +#define KEY_TYPE_FMT KEY_NAME_FMT + +void smcdumpkeys(const char *); +void parse(const char *, uint8_t **, size_t *); +void *xrealloc(void *, size_t); +bool is_key(const uint8_t *, const uint8_t *); + +int +main(int argc, char **argv) +{ + while (++argv, --argc) + smcdumpkeys(*argv); + + return 0; +} + +void * +find_first_key_record(uint8_t *p, uint8_t *end) +{ + /* Find the first key's record. */ + while (p < end) { + p = memchr(p, FIRST_KEY[0], end - p); + if (p == NULL || end - p < FIELD_LEN) + errx(1, "first key record not found"); + if (memcmp(p, FIRST_KEY, FIELD_LEN) == 0) + break; + ++p; + } + + return p; +} + +bool +is_key_record(struct key_record *r) +{ + unsigned i; + + for (i = 0; i < FIELD_LEN; i++) + if (!isprint(r->name[i])) + return false; + return true; +} + +void +print_unknown_field(uint8_t *p) +{ + unsigned i; + + for (i = 0; i < FIELD_LEN; i++) + printf("%02x", (unsigned)*p++); +} + +void +smcdumpkeys(const char *path) +{ + uint8_t *fwdata = NULL; + size_t fwdata_size = 0; + uint8_t *p; + size_t n_records; + struct key_record *r; + struct key_record *end; + + /* Parse SMC firmware file into binary form. */ + parse(path, &fwdata, &fwdata_size); + + p = find_first_key_record(fwdata, fwdata + fwdata_size); + n_records = (p - fwdata) / sizeof(*r); + + r = (struct key_record *)p; + end = r + n_records; + + /* Keep dumping records as long as they look like key records. */ + while (r < end && is_key_record(r)) { + printf(KEY_NAME_FMT " ", r->name); + print_unknown_field(r->unknown1); + printf(" " KEY_TYPE_FMT " ", r->type); + print_unknown_field(r->unknown2); + printf("\n"); + r++; + } +} + +void +parse(const char *path, uint8_t **fwdatap, size_t *fwdata_sizep) +{ + FILE *fp; + char line[1024]; + char *linep; + unsigned line_no = 0; + unsigned byte; + uint8_t *fwdata = NULL; + size_t fwdata_size = 0; + + fp = fopen(path, "r"); + if (fp == NULL) + err(1, "%s: failed to open", path); + + while (fgets(line, sizeof line, fp) != NULL) { + line_no++; + + if (line[0] != 'D' && line[0] != '+') + continue; + + if (strchr(line, '\n') == NULL + && strlen(line) == sizeof(line) - 1) { + warnx("%s: line %u: line possibly truncated", + path, line_no); + } + + linep = strrchr(line, ':'); + if (linep == NULL) { + errx(1, + "%s: line %u: second ``:'' data separator not found", + path, line_no); + } + *linep = '\0'; + + linep = strrchr(line, ':'); + if (linep == NULL) { + errx(1, + "%s: line %u: first ``:'' data separator not found", + path, line_no); + } + ++linep; + + + if (strlen(linep) % 2 != 0) { + errx(1, "%s: line %u: data string is not of even length", + path, line_no); + } + + while (*linep != '\0') { + if (sscanf(linep, "%2X", &byte) != 1) { + errx(1, "%s: line %u: non-hex characters", + path, line_no); + } + fwdata = xrealloc(fwdata, fwdata_size + 1); + fwdata[fwdata_size++] = byte; + linep += 2; + } + } + if (!feof(fp)) + err(1, "%s: read error", path); + + *fwdatap = fwdata; + *fwdata_sizep = fwdata_size; + + fclose(fp); +} + +void * +xrealloc(void *ptr, size_t size) +{ + void *tmp; + + tmp = realloc(ptr, size); + if (tmp == NULL) + err(1, "failed to allocate %lu bytes", (unsigned long)size); + return tmp; +} Index: usr.sbin/smcprobe/Makefile =================================================================== RCS file: usr.sbin/smcprobe/Makefile diff -N usr.sbin/smcprobe/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.sbin/smcprobe/Makefile 27 Jan 2016 02:43:22 -0000 @@ -0,0 +1,5 @@ +PROG= smcprobe +MAN= +CFLAGS+= -Wall + +.include <bsd.prog.mk> Index: usr.sbin/smcprobe/smcprobe.c =================================================================== RCS file: usr.sbin/smcprobe/smcprobe.c diff -N usr.sbin/smcprobe/smcprobe.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.sbin/smcprobe/smcprobe.c 27 Jan 2016 02:43:22 -0000 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 Sviatoslav Chagaev <sviatoslav.chag...@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Read/write Apple System Management Cotroller (SMC) ``keys''. + */ + +#include <dev/isa/asmc.h> +#include <unistd.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int +main(int argc, char **argv) +{ + struct asmc_key_buf buf; + unsigned i; + unsigned len; + unsigned byte; + int fd; + + if (argc < 4) { + printf("usage: smcprobe <dev> <key> <len> [<value>]\n"); + return 0; + } + + fd = open(argv[1], O_RDWR); + if (fd < 0) + err(1, "%s", argv[1]); + + strncpy(buf.key, argv[2], sizeof buf.key); + sscanf(argv[3], "%u", &len); + buf.len = len; + + if (argc > 4) { + for (i = 0; i < len; i++) { + if (sscanf(argv[4] + i * 2, "%2x", &byte) != 1) + errx(1, "failed to parse value"); + buf.data[i] = byte; + } + if (ioctl(fd, ASMC_WRITE_KEY, &buf) < 0) + err(1, "ioctl ASMC_WRITE_KEY"); + } else { + if (ioctl(fd, ASMC_READ_KEY, &buf) < 0) + err(1, "ioctl ASMC_READ_KEY"); + + if (buf.len == 0) + printf("buf empty\n"); + else { + for (len = 0; len < buf.len; len++) + printf("%02x ", buf.data[len]); + printf("\n"); + } + } + + close(fd); + + return 0; +} Index: sys/arch/amd64/amd64/conf.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/conf.c,v retrieving revision 1.54 diff -u -p -r1.54 conf.c --- sys/arch/amd64/amd64/conf.c 8 Jan 2016 11:20:58 -0000 1.54 +++ sys/arch/amd64/amd64/conf.c 27 Jan 2016 02:43:23 -0000 @@ -113,6 +113,21 @@ int nblkdev = nitems(bdevsw); (dev_type_mmap((*))) enodev } +int asmcopen(dev_t, int, int, struct proc *); +int asmcclose(dev_t, int, int, struct proc *); +int asmcioctl(dev_t, u_long, caddr_t, int, struct proc *); + +/* open, close, ioctl */ +#define cdev_asmc_init(c,n) { \ + dev_init(c,n,open), \ + dev_init(c,n,close), \ + (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, \ + dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, seltrue, \ + (dev_type_mmap((*))) enodev } + + #define mmread mmrw #define mmwrite mmrw cdev_decl(mm); @@ -292,6 +307,7 @@ struct cdevsw cdevsw[] = cdev_fuse_init(NFUSE,fuse), /* 92: fuse */ cdev_tun_init(NTUN,tap), /* 93: Ethernet network tunnel */ cdev_tty_init(NVIOCON,viocon), /* 94: virtio console */ + cdev_asmc_init(1,asmc), /* 95: Apple SMC */ }; int nchrdev = nitems(cdevsw);