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 }