github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/lib/darwin/include/smc.c (about)

     1  #include "smc.h"
     2  
     3  #define IOSERVICE_SMC "AppleSMC"
     4  #define IOSERVICE_MODEL "IOPlatformExpertDevice"
     5  
     6  #define DATA_TYPE_SP78 "sp78"
     7  
     8  typedef enum {
     9    kSMCUserClientOpen = 0,
    10    kSMCUserClientClose = 1,
    11    kSMCHandleYPCEvent = 2,
    12    kSMCReadKey = 5,
    13    kSMCWriteKey = 6,
    14    kSMCGetKeyCount = 7,
    15    kSMCGetKeyFromIndex = 8,
    16    kSMCGetKeyInfo = 9,
    17  } selector_t;
    18  
    19  typedef struct {
    20    unsigned char major;
    21    unsigned char minor;
    22    unsigned char build;
    23    unsigned char reserved;
    24    unsigned short release;
    25  } SMCVersion;
    26  
    27  typedef struct {
    28    uint16_t version;
    29    uint16_t length;
    30    uint32_t cpuPLimit;
    31    uint32_t gpuPLimit;
    32    uint32_t memPLimit;
    33  } SMCPLimitData;
    34  
    35  typedef struct {
    36    IOByteCount data_size;
    37    uint32_t data_type;
    38    uint8_t data_attributes;
    39  } SMCKeyInfoData;
    40  
    41  typedef struct {
    42    uint32_t key;
    43    SMCVersion vers;
    44    SMCPLimitData p_limit_data;
    45    SMCKeyInfoData key_info;
    46    uint8_t result;
    47    uint8_t status;
    48    uint8_t data8;
    49    uint32_t data32;
    50    uint8_t bytes[32];
    51  } SMCParamStruct;
    52  
    53  typedef enum {
    54    kSMCSuccess = 0,
    55    kSMCError = 1,
    56    kSMCKeyNotFound = 0x84,
    57  } kSMC_t;
    58  
    59  typedef struct {
    60    uint8_t data[32];
    61    uint32_t data_type;
    62    uint32_t data_size;
    63    kSMC_t kSMC;
    64  } smc_return_t;
    65  
    66  static const int SMC_KEY_SIZE = 4; // number of characters in an SMC key.
    67  static io_connect_t conn;          // our connection to the SMC.
    68  
    69  kern_return_t open_smc(void) {
    70    kern_return_t result;
    71    io_service_t service;
    72  
    73    service = IOServiceGetMatchingService(kIOMasterPortDefault,
    74                                          IOServiceMatching(IOSERVICE_SMC));
    75    if (service == 0) {
    76      // Note: IOServiceMatching documents 0 on failure
    77      printf("ERROR: %s NOT FOUND\n", IOSERVICE_SMC);
    78      return kIOReturnError;
    79    }
    80  
    81    result = IOServiceOpen(service, mach_task_self(), 0, &conn);
    82    IOObjectRelease(service);
    83  
    84    return result;
    85  }
    86  
    87  kern_return_t close_smc(void) { return IOServiceClose(conn); }
    88  
    89  static uint32_t to_uint32(char *key) {
    90    uint32_t ans = 0;
    91    uint32_t shift = 24;
    92  
    93    if (strlen(key) != SMC_KEY_SIZE) {
    94      return 0;
    95    }
    96  
    97    for (int i = 0; i < SMC_KEY_SIZE; i++) {
    98      ans += key[i] << shift;
    99      shift -= 8;
   100    }
   101  
   102    return ans;
   103  }
   104  
   105  static kern_return_t call_smc(SMCParamStruct *input, SMCParamStruct *output) {
   106    kern_return_t result;
   107    size_t input_cnt = sizeof(SMCParamStruct);
   108    size_t output_cnt = sizeof(SMCParamStruct);
   109  
   110    result = IOConnectCallStructMethod(conn, kSMCHandleYPCEvent, input, input_cnt,
   111                                       output, &output_cnt);
   112  
   113    if (result != kIOReturnSuccess) {
   114      result = err_get_code(result);
   115    }
   116    return result;
   117  }
   118  
   119  static kern_return_t read_smc(char *key, smc_return_t *result_smc) {
   120    kern_return_t result;
   121    SMCParamStruct input;
   122    SMCParamStruct output;
   123  
   124    memset(&input, 0, sizeof(SMCParamStruct));
   125    memset(&output, 0, sizeof(SMCParamStruct));
   126    memset(result_smc, 0, sizeof(smc_return_t));
   127  
   128    input.key = to_uint32(key);
   129    input.data8 = kSMCGetKeyInfo;
   130  
   131    result = call_smc(&input, &output);
   132    result_smc->kSMC = output.result;
   133  
   134    if (result != kIOReturnSuccess || output.result != kSMCSuccess) {
   135      return result;
   136    }
   137  
   138    result_smc->data_size = output.key_info.data_size;
   139    result_smc->data_type = output.key_info.data_type;
   140  
   141    input.key_info.data_size = output.key_info.data_size;
   142    input.data8 = kSMCReadKey;
   143  
   144    result = call_smc(&input, &output);
   145    result_smc->kSMC = output.result;
   146  
   147    if (result != kIOReturnSuccess || output.result != kSMCSuccess) {
   148      return result;
   149    }
   150  
   151    memcpy(result_smc->data, output.bytes, sizeof(output.bytes));
   152  
   153    return result;
   154  }
   155  
   156  double get_temperature(char *key) {
   157    kern_return_t result;
   158    smc_return_t result_smc;
   159  
   160    result = read_smc(key, &result_smc);
   161  
   162    if (!(result == kIOReturnSuccess) && result_smc.data_size == 2 &&
   163        result_smc.data_type == to_uint32(DATA_TYPE_SP78)) {
   164      return 0.0;
   165    }
   166  
   167    return (double)result_smc.data[0];
   168  }