smc_darwin.c 3.8 KB

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