diff options
author | Richard Henderson | 2021-10-05 20:29:42 +0200 |
---|---|---|
committer | Richard Henderson | 2021-10-05 20:29:42 +0200 |
commit | 08a9b68dc033c9826da89f84202e547beadd92f0 (patch) | |
tree | aafcb717250d0cb0648e4d8fee8fe8c6b3489c5b /hw/misc/applesmc.c | |
parent | Merge remote-tracking branch 'remotes/vivier/tags/trivial-branch-for-6.2-pull... (diff) | |
parent | meson: show library versions in the summary (diff) | |
download | qemu-08a9b68dc033c9826da89f84202e547beadd92f0.tar.gz qemu-08a9b68dc033c9826da89f84202e547beadd92f0.tar.xz qemu-08a9b68dc033c9826da89f84202e547beadd92f0.zip |
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* Meson version update
* fix search path when configuring with --cpu
* support for measured SEV boot with -kernel (Dov)
* fix missing BQL locks (Emanuele)
* retrieve applesmc key from the host (Pedro)
* KVM PV feature documentation (Vitaly)
# gpg: Signature made Tue 05 Oct 2021 04:13:00 AM PDT
# gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg: issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
* remotes/bonzini/tags/for-upstream:
meson: show library versions in the summary
target/xtensa: list cores in a text file
hexagon: use env keyword argument to pass PYTHONPATH
meson: switch minimum meson version to 0.58.2, minimum recommended to 0.59.2
meson: bump submodule to 0.59.2
migration: add missing qemu_mutex_lock_iothread in migration_completion
migration: block-dirty-bitmap: add missing qemu_mutex_lock_iothread
configure, meson: move CPU_CFLAGS out of QEMU_CFLAGS
hw/misc: applesmc: use host osk as default on macs
x86/sev: generate SEV kernel loader hashes in x86_load_linux
sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
i386: docs: Briefly describe KVM PV features
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'hw/misc/applesmc.c')
-rw-r--r-- | hw/misc/applesmc.c | 192 |
1 files changed, 191 insertions, 1 deletions
diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c index 1b9acaf1d3..cec247b5ee 100644 --- a/hw/misc/applesmc.c +++ b/hw/misc/applesmc.c @@ -38,6 +38,171 @@ #include "qemu/timer.h" #include "qom/object.h" +#if defined(__APPLE__) && defined(__MACH__) +#include <IOKit/IOKitLib.h> + +enum { + kSMCSuccess = 0x00, + kSMCKeyNotFound = 0x84 +}; + +enum { + kSMCUserClientOpen = 0x00, + kSMCUserClientClose = 0x01, + kSMCHandleYPCEvent = 0x02, + kSMCReadKey = 0x05, + kSMCGetKeyInfo = 0x09 +}; + +typedef struct SMCVersion { + uint8_t major; + uint8_t minor; + uint8_t build; + uint8_t reserved; + uint16_t release; +} SMCVersion; + +typedef struct SMCPLimitData { + uint16_t version; + uint16_t length; + uint32_t cpuPLimit; + uint32_t gpuPLimit; + uint32_t memPLimit; +} SMCPLimitData; + +typedef struct SMCKeyInfoData { + IOByteCount dataSize; + uint32_t dataType; + uint8_t dataAttributes; +} SMCKeyInfoData; + +typedef struct { + uint32_t key; + SMCVersion vers; + SMCPLimitData pLimitData; + SMCKeyInfoData keyInfo; + uint8_t result; + uint8_t status; + uint8_t data8; + uint32_t data32; + uint8_t bytes[32]; +} SMCParamStruct; + +static IOReturn smc_call_struct_method(uint32_t selector, + SMCParamStruct *inputStruct, + SMCParamStruct *outputStruct) +{ + IOReturn ret; + + size_t inputStructCnt = sizeof(SMCParamStruct); + size_t outputStructCnt = sizeof(SMCParamStruct); + + io_service_t smcService = IO_OBJECT_NULL; + io_connect_t smcConnect = IO_OBJECT_NULL; + + smcService = IOServiceGetMatchingService(kIOMasterPortDefault, + IOServiceMatching("AppleSMC")); + if (smcService == IO_OBJECT_NULL) { + ret = kIOReturnNotFound; + goto exit; + } + + ret = IOServiceOpen(smcService, mach_task_self(), 1, &smcConnect); + if (ret != kIOReturnSuccess) { + smcConnect = IO_OBJECT_NULL; + goto exit; + } + if (smcConnect == IO_OBJECT_NULL) { + ret = kIOReturnError; + goto exit; + } + + ret = IOConnectCallMethod(smcConnect, kSMCUserClientOpen, + NULL, 0, NULL, 0, + NULL, NULL, NULL, NULL); + if (ret != kIOReturnSuccess) { + goto exit; + } + + ret = IOConnectCallStructMethod(smcConnect, selector, + inputStruct, inputStructCnt, + outputStruct, &outputStructCnt); + +exit: + if (smcConnect != IO_OBJECT_NULL) { + IOConnectCallMethod(smcConnect, kSMCUserClientClose, + NULL, 0, NULL, 0, NULL, + NULL, NULL, NULL); + IOServiceClose(smcConnect); + } + + return ret; +} + +static IOReturn smc_read_key(uint32_t key, + uint8_t *bytes, + IOByteCount *dataSize) +{ + IOReturn ret; + + SMCParamStruct inputStruct; + SMCParamStruct outputStruct; + + if (key == 0 || bytes == NULL) { + ret = kIOReturnCannotWire; + goto exit; + } + + /* determine key's data size */ + memset(&inputStruct, 0, sizeof(SMCParamStruct)); + inputStruct.data8 = kSMCGetKeyInfo; + inputStruct.key = key; + + memset(&outputStruct, 0, sizeof(SMCParamStruct)); + ret = smc_call_struct_method(kSMCHandleYPCEvent, &inputStruct, &outputStruct); + if (ret != kIOReturnSuccess) { + goto exit; + } + if (outputStruct.result == kSMCKeyNotFound) { + ret = kIOReturnNotFound; + goto exit; + } + if (outputStruct.result != kSMCSuccess) { + ret = kIOReturnInternalError; + goto exit; + } + + /* get key value */ + memset(&inputStruct, 0, sizeof(SMCParamStruct)); + inputStruct.data8 = kSMCReadKey; + inputStruct.key = key; + inputStruct.keyInfo.dataSize = outputStruct.keyInfo.dataSize; + + memset(&outputStruct, 0, sizeof(SMCParamStruct)); + ret = smc_call_struct_method(kSMCHandleYPCEvent, &inputStruct, &outputStruct); + if (ret != kIOReturnSuccess) { + goto exit; + } + if (outputStruct.result == kSMCKeyNotFound) { + ret = kIOReturnNotFound; + goto exit; + } + if (outputStruct.result != kSMCSuccess) { + ret = kIOReturnInternalError; + goto exit; + } + + memset(bytes, 0, *dataSize); + if (*dataSize > inputStruct.keyInfo.dataSize) { + *dataSize = inputStruct.keyInfo.dataSize; + } + memcpy(bytes, outputStruct.bytes, *dataSize); + +exit: + return ret; +} +#endif + /* #define DEBUG_SMC */ #define APPLESMC_DEFAULT_IOBASE 0x300 @@ -315,6 +480,7 @@ static const MemoryRegionOps applesmc_err_io_ops = { static void applesmc_isa_realize(DeviceState *dev, Error **errp) { AppleSMCState *s = APPLE_SMC(dev); + bool valid_key = false; memory_region_init_io(&s->io_data, OBJECT(s), &applesmc_data_io_ops, s, "applesmc-data", 1); @@ -331,7 +497,31 @@ static void applesmc_isa_realize(DeviceState *dev, Error **errp) isa_register_ioport(&s->parent_obj, &s->io_err, s->iobase + APPLESMC_ERR_PORT); - if (!s->osk || (strlen(s->osk) != 64)) { + if (s->osk) { + valid_key = strlen(s->osk) == 64; + } else { +#if defined(__APPLE__) && defined(__MACH__) + IOReturn ret; + IOByteCount size = 32; + + ret = smc_read_key('OSK0', (uint8_t *) default_osk, &size); + if (ret != kIOReturnSuccess) { + goto failure; + } + + ret = smc_read_key('OSK1', (uint8_t *) default_osk + size, &size); + if (ret != kIOReturnSuccess) { + goto failure; + } + + warn_report("Using AppleSMC with host key"); + valid_key = true; + s->osk = default_osk; +failure:; +#endif + } + + if (!valid_key) { warn_report("Using AppleSMC with invalid key"); s->osk = default_osk; } |