summaryrefslogtreecommitdiffstats
path: root/hw/misc/applesmc.c
diff options
context:
space:
mode:
authorRichard Henderson2021-10-05 20:29:42 +0200
committerRichard Henderson2021-10-05 20:29:42 +0200
commit08a9b68dc033c9826da89f84202e547beadd92f0 (patch)
treeaafcb717250d0cb0648e4d8fee8fe8c6b3489c5b /hw/misc/applesmc.c
parentMerge remote-tracking branch 'remotes/vivier/tags/trivial-branch-for-6.2-pull... (diff)
parentmeson: show library versions in the summary (diff)
downloadqemu-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.c192
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;
}