diff --git a/extra/external/SMC_DumpKey/README b/extra/external/SMC_DumpKey/README new file mode 100644 index 0000000..d7dcbe0 --- /dev/null +++ b/extra/external/SMC_DumpKey/README @@ -0,0 +1,3 @@ +taken with graces to http://www.contrib.andrew.cmu.edu/~somlo/OSXKVM/ + +Needs to be compiled on linux with gcc, and only runs on genuine Apple hardware (as it polls the SMC chip for the given value) diff --git a/extra/external/SMC_DumpKey/SmcDumpKey.c b/extra/external/SMC_DumpKey/SmcDumpKey.c new file mode 100644 index 0000000..ff8672e --- /dev/null +++ b/extra/external/SMC_DumpKey/SmcDumpKey.c @@ -0,0 +1,193 @@ +/* + * prints out 4-character name of the SMC key at given index position; + * + * by Gabriel L. Somlo , Summer 2014 + * + * Compile with: gcc -O2 -o SmcDumpKey SmcDumpKey.c -Wall + * + * You probably want to "modprobe -r applesmc" before running this... + * + * Code bits and pieces shamelessly ripped from the linux kernel driver + * (drivers/hwmon/applesmc.c by N. Boichat and H. Rydberg) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define APPLESMC_START 0x300 +#define APPLESMC_RANGE 0x20 + +#define APPLESMC_DATA_PORT (APPLESMC_START + 0x00) +#define APPLESMC_CMD_PORT (APPLESMC_START + 0x04) + +#define APPLESMC_READ_CMD 0x10 +#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12 +#define APPLESMC_GET_KEY_TYPE_CMD 0x13 + + +/* wait up to 128 ms for a status change. */ +#define APPLESMC_MIN_WAIT 0x0010 +#define APPLESMC_RETRY_WAIT 0x0100 +#define APPLESMC_MAX_WAIT 0x20000 + + +#define APPLESMC_KEY_NAME_LEN 4 +#define APPLESMC_KEY_TYPE_LEN 4 + +typedef struct key_type { + uint8_t data_len; + uint8_t data_type[APPLESMC_KEY_TYPE_LEN]; + uint8_t flags; +} __attribute__((packed)) key_type; + + +/* wait_read - Wait for a byte to appear on SMC port. */ +static int +wait_read(void) +{ + uint8_t status; + int us; + + for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) { + usleep(us); + status = inb(APPLESMC_CMD_PORT); + /* read: wait for smc to settle */ + if (status & 0x01) + return 0; + } + + fprintf(stderr, "wait_read() fail: 0x%02x\n", status); + return -1; +} + +/*send_byte - Write to SMC port, retrying when necessary. */ +static int +send_byte(uint8_t cmd, unsigned short port) +{ + uint8_t status; + int us; + + outb(cmd, port); + for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) { + usleep(us); + status = inb(APPLESMC_CMD_PORT); + /* write: wait for smc to settle */ + if (status & 0x02) + continue; + /* ready: cmd accepted, return */ + if (status & 0x04) + return 0; + /* timeout: give up */ + if (us << 1 == APPLESMC_MAX_WAIT) + break; + /* busy: long wait and resend */ + usleep(APPLESMC_RETRY_WAIT); + outb(cmd, port); + } + + fprintf(stderr, + "send_byte(0x%02x, 0x%04x) fail: 0x%02x\n", cmd, port, status); + return -1; +} + +static int +send_argument(const uint8_t *key) +{ + int i; + + for (i = 0; i < APPLESMC_KEY_NAME_LEN; i++) + if (send_byte(key[i], APPLESMC_DATA_PORT)) + return -1; + return 0; +} + +static int +read_smc(uint8_t cmd, const uint8_t *key, uint8_t *buf, uint8_t len) +{ + int i; + + if (send_byte(cmd, APPLESMC_CMD_PORT) || send_argument(key)) { + fprintf(stderr, "%.4s: read arg fail\n", key); + return -1; + } + + if (send_byte(len, APPLESMC_DATA_PORT)) { + fprintf(stderr, "%.4s: read len fail\n", key); + return -1; + } + + for (i = 0; i < len; i++) { + if (wait_read()) { + fprintf(stderr, "%.4s: read data[%d] fail\n", key, i); + return -1; + } + buf[i] = inb(APPLESMC_DATA_PORT); + } + + return 0; +} + + +int +main(int argc, char **argv) +{ + key_type kt; + uint8_t data_buf[UCHAR_MAX]; + uint8_t i; + + if (argc != 2 || strlen(argv[1]) != APPLESMC_KEY_NAME_LEN) { + fprintf(stderr, "\nUsage: %s <4-char-key-name>\n\n", argv[0]); + return -1; + } + + if (ioperm(APPLESMC_START, APPLESMC_RANGE, 1) != 0) { + perror("ioperm failed"); + return -2; + } + + if (read_smc(APPLESMC_GET_KEY_TYPE_CMD, + (uint8_t *)argv[1], (uint8_t *)&kt, sizeof(kt)) != 0) { + fprintf(stderr, "\nread_smc get_key_type error\n\n"); + return -3; + } + printf(" type=\""); + for (i = 0; i < APPLESMC_KEY_TYPE_LEN; i++) + printf(isprint(kt.data_type[i]) ? "%c" : "\\x%02x", + (uint8_t)kt.data_type[i]); + printf("\" length=%d flags=%x\n", kt.data_len, kt.flags); + + if (read_smc(APPLESMC_READ_CMD, + (uint8_t *)argv[1], data_buf, kt.data_len) != 0) { + fprintf(stderr, "\nread_smc get_key_data error\n\n"); + return -4; + } + printf(" data=\""); + for (i = 0; i < kt.data_len; i++) + printf(isprint(data_buf[i]) ? "%c" : "\\x%02x", + (uint8_t)data_buf[i]); + printf("\"\n"); + + return 0; +}