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);
 

Reply via email to