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