Skip to content

Commit 93ddefb

Browse files
t0rr3sp3dr0bonzini
authored andcommitted
hw/misc: applesmc: use host osk as default on macs
When running on a Mac, QEMU is able to get the host OSK and use it as the default value for the AppleSMC device. The OSK query operation doesn't require administrator privileges and can be executed by any user on the system. This patch is based on open-source code from Apple, just like the implementation from VirtualBox. Apple: https://opensource.apple.com/source/IOKitUser/IOKitUser-647.6.13/pwr_mgt.subproj/IOPMLibPrivate.c https://opensource.apple.com/source/PowerManagement/PowerManagement-637.60.1/pmconfigd/PrivateLib.c VirtualBox: https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Devices/EFI/DevSmc.cpp#L516 Signed-off-by: Pedro Tôrres <[email protected]>
1 parent c0c2d31 commit 93ddefb

File tree

1 file changed

+191
-1
lines changed

1 file changed

+191
-1
lines changed

hw/misc/applesmc.c

Lines changed: 191 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,171 @@
3838
#include "qemu/timer.h"
3939
#include "qom/object.h"
4040

41+
#if defined(__APPLE__) && defined(__MACH__)
42+
#include <IOKit/IOKitLib.h>
43+
44+
enum {
45+
kSMCSuccess = 0x00,
46+
kSMCKeyNotFound = 0x84
47+
};
48+
49+
enum {
50+
kSMCUserClientOpen = 0x00,
51+
kSMCUserClientClose = 0x01,
52+
kSMCHandleYPCEvent = 0x02,
53+
kSMCReadKey = 0x05,
54+
kSMCGetKeyInfo = 0x09
55+
};
56+
57+
typedef struct SMCVersion {
58+
uint8_t major;
59+
uint8_t minor;
60+
uint8_t build;
61+
uint8_t reserved;
62+
uint16_t release;
63+
} SMCVersion;
64+
65+
typedef struct SMCPLimitData {
66+
uint16_t version;
67+
uint16_t length;
68+
uint32_t cpuPLimit;
69+
uint32_t gpuPLimit;
70+
uint32_t memPLimit;
71+
} SMCPLimitData;
72+
73+
typedef struct SMCKeyInfoData {
74+
IOByteCount dataSize;
75+
uint32_t dataType;
76+
uint8_t dataAttributes;
77+
} SMCKeyInfoData;
78+
79+
typedef struct {
80+
uint32_t key;
81+
SMCVersion vers;
82+
SMCPLimitData pLimitData;
83+
SMCKeyInfoData keyInfo;
84+
uint8_t result;
85+
uint8_t status;
86+
uint8_t data8;
87+
uint32_t data32;
88+
uint8_t bytes[32];
89+
} SMCParamStruct;
90+
91+
static IOReturn smc_call_struct_method(uint32_t selector,
92+
SMCParamStruct *inputStruct,
93+
SMCParamStruct *outputStruct)
94+
{
95+
IOReturn ret;
96+
97+
size_t inputStructCnt = sizeof(SMCParamStruct);
98+
size_t outputStructCnt = sizeof(SMCParamStruct);
99+
100+
io_service_t smcService = IO_OBJECT_NULL;
101+
io_connect_t smcConnect = IO_OBJECT_NULL;
102+
103+
smcService = IOServiceGetMatchingService(kIOMasterPortDefault,
104+
IOServiceMatching("AppleSMC"));
105+
if (smcService == IO_OBJECT_NULL) {
106+
ret = kIOReturnNotFound;
107+
goto exit;
108+
}
109+
110+
ret = IOServiceOpen(smcService, mach_task_self(), 1, &smcConnect);
111+
if (ret != kIOReturnSuccess) {
112+
smcConnect = IO_OBJECT_NULL;
113+
goto exit;
114+
}
115+
if (smcConnect == IO_OBJECT_NULL) {
116+
ret = kIOReturnError;
117+
goto exit;
118+
}
119+
120+
ret = IOConnectCallMethod(smcConnect, kSMCUserClientOpen,
121+
NULL, 0, NULL, 0,
122+
NULL, NULL, NULL, NULL);
123+
if (ret != kIOReturnSuccess) {
124+
goto exit;
125+
}
126+
127+
ret = IOConnectCallStructMethod(smcConnect, selector,
128+
inputStruct, inputStructCnt,
129+
outputStruct, &outputStructCnt);
130+
131+
exit:
132+
if (smcConnect != IO_OBJECT_NULL) {
133+
IOConnectCallMethod(smcConnect, kSMCUserClientClose,
134+
NULL, 0, NULL, 0, NULL,
135+
NULL, NULL, NULL);
136+
IOServiceClose(smcConnect);
137+
}
138+
139+
return ret;
140+
}
141+
142+
static IOReturn smc_read_key(uint32_t key,
143+
uint8_t *bytes,
144+
IOByteCount *dataSize)
145+
{
146+
IOReturn ret;
147+
148+
SMCParamStruct inputStruct;
149+
SMCParamStruct outputStruct;
150+
151+
if (key == 0 || bytes == NULL) {
152+
ret = kIOReturnCannotWire;
153+
goto exit;
154+
}
155+
156+
/* determine key's data size */
157+
memset(&inputStruct, 0, sizeof(SMCParamStruct));
158+
inputStruct.data8 = kSMCGetKeyInfo;
159+
inputStruct.key = key;
160+
161+
memset(&outputStruct, 0, sizeof(SMCParamStruct));
162+
ret = smc_call_struct_method(kSMCHandleYPCEvent, &inputStruct, &outputStruct);
163+
if (ret != kIOReturnSuccess) {
164+
goto exit;
165+
}
166+
if (outputStruct.result == kSMCKeyNotFound) {
167+
ret = kIOReturnNotFound;
168+
goto exit;
169+
}
170+
if (outputStruct.result != kSMCSuccess) {
171+
ret = kIOReturnInternalError;
172+
goto exit;
173+
}
174+
175+
/* get key value */
176+
memset(&inputStruct, 0, sizeof(SMCParamStruct));
177+
inputStruct.data8 = kSMCReadKey;
178+
inputStruct.key = key;
179+
inputStruct.keyInfo.dataSize = outputStruct.keyInfo.dataSize;
180+
181+
memset(&outputStruct, 0, sizeof(SMCParamStruct));
182+
ret = smc_call_struct_method(kSMCHandleYPCEvent, &inputStruct, &outputStruct);
183+
if (ret != kIOReturnSuccess) {
184+
goto exit;
185+
}
186+
if (outputStruct.result == kSMCKeyNotFound) {
187+
ret = kIOReturnNotFound;
188+
goto exit;
189+
}
190+
if (outputStruct.result != kSMCSuccess) {
191+
ret = kIOReturnInternalError;
192+
goto exit;
193+
}
194+
195+
memset(bytes, 0, *dataSize);
196+
if (*dataSize > inputStruct.keyInfo.dataSize) {
197+
*dataSize = inputStruct.keyInfo.dataSize;
198+
}
199+
memcpy(bytes, outputStruct.bytes, *dataSize);
200+
201+
exit:
202+
return ret;
203+
}
204+
#endif
205+
41206
/* #define DEBUG_SMC */
42207

43208
#define APPLESMC_DEFAULT_IOBASE 0x300
@@ -315,6 +480,7 @@ static const MemoryRegionOps applesmc_err_io_ops = {
315480
static void applesmc_isa_realize(DeviceState *dev, Error **errp)
316481
{
317482
AppleSMCState *s = APPLE_SMC(dev);
483+
bool valid_key = false;
318484

319485
memory_region_init_io(&s->io_data, OBJECT(s), &applesmc_data_io_ops, s,
320486
"applesmc-data", 1);
@@ -331,7 +497,31 @@ static void applesmc_isa_realize(DeviceState *dev, Error **errp)
331497
isa_register_ioport(&s->parent_obj, &s->io_err,
332498
s->iobase + APPLESMC_ERR_PORT);
333499

334-
if (!s->osk || (strlen(s->osk) != 64)) {
500+
if (s->osk) {
501+
valid_key = strlen(s->osk) == 64;
502+
} else {
503+
#if defined(__APPLE__) && defined(__MACH__)
504+
IOReturn ret;
505+
IOByteCount size = 32;
506+
507+
ret = smc_read_key('OSK0', (uint8_t *) default_osk, &size);
508+
if (ret != kIOReturnSuccess) {
509+
goto failure;
510+
}
511+
512+
ret = smc_read_key('OSK1', (uint8_t *) default_osk + size, &size);
513+
if (ret != kIOReturnSuccess) {
514+
goto failure;
515+
}
516+
517+
warn_report("Using AppleSMC with host key");
518+
valid_key = true;
519+
s->osk = default_osk;
520+
failure:;
521+
#endif
522+
}
523+
524+
if (!valid_key) {
335525
warn_report("Using AppleSMC with invalid key");
336526
s->osk = default_osk;
337527
}

0 commit comments

Comments
 (0)