The device implemented only the SMC read command (0x10). The write command (0x11) fell through to the default case and returned kSMCBadCommand, so every SMC key write a guest performs failed.
A macOS guest writes keys through this command in normal operation: at boot it writes "NTOK", "MSDW", "QENA" and "HE0N", and retrying those failed writes delays boot; at shutdown it writes "OSWD". All of them showed up as a stream of kSMCBadCommand errors. Accept the write command, collect the key, the declared length and the payload, and return success. The payload is not interpreted yet, so the writes are accepted and discarded, which is enough to remove the boot delay and the shutdown errors; the following patch gives the watchdog keys meaning. Signed-off-by: Daniel Golle <[email protected]> --- hw/misc/applesmc.c | 39 +++++++++++++++++++++++++++++++++++++++ hw/misc/trace-events | 3 +++ 2 files changed, 42 insertions(+) diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c index 6f9d0a590d..bc44b0f1d8 100644 --- a/hw/misc/applesmc.c +++ b/hw/misc/applesmc.c @@ -128,6 +128,7 @@ static void applesmc_io_cmd_write(void *opaque, hwaddr addr, uint64_t val, smc_debug("CMD received: 0x%02x\n", (uint8_t)val); switch (val) { case APPLESMC_READ_CMD: + case APPLESMC_WRITE_CMD: /* did last command run through OK? */ if (status == APPLESMC_ST_CMD_DONE || status == APPLESMC_ST_NEW_CMD) { s->cmd = val; @@ -200,6 +201,44 @@ static void applesmc_io_data_write(void *opaque, hwaddr addr, uint64_t val, } s->read_pos++; break; + case APPLESMC_WRITE_CMD: + if (s->read_pos < 4) { + s->key[s->read_pos] = val; + s->status = APPLESMC_ST_ACK; + if (s->read_pos == 3) { + trace_applesmc_key_selected(s->key[0], s->key[1], + s->key[2], s->key[3]); + } + s->read_pos++; + } else if (s->read_pos == 4) { + s->data_len = val; + s->data_pos = 0; + s->read_pos++; + s->status = APPLESMC_ST_ACK; + trace_applesmc_write_len(s->key[0], s->key[1], s->key[2], + s->key[3], s->data_len); + if (s->data_len == 0) { + s->status = APPLESMC_ST_CMD_DONE; + s->status_1e = APPLESMC_ST_CMD_DONE; + } + } else { + if (s->data_pos < s->data_len) { + s->data[s->data_pos] = val; + trace_applesmc_write_data(s->key[0], s->key[1], s->key[2], + s->key[3], s->data_pos, (uint8_t)val); + s->data_pos++; + } + if (s->data_pos >= s->data_len) { + trace_applesmc_write_complete(s->key[0], s->key[1], + s->key[2], s->key[3], + s->data_len); + s->status = APPLESMC_ST_CMD_DONE; + s->status_1e = APPLESMC_ST_CMD_DONE; + } else { + s->status = APPLESMC_ST_ACK; + } + } + break; default: s->status = APPLESMC_ST_CMD_DONE; s->status_1e = APPLESMC_ST_1E_STILL_BAD_CMD; diff --git a/hw/misc/trace-events b/hw/misc/trace-events index b924b4398e..fc01cc9b7d 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -45,6 +45,9 @@ applesmc_data_write(uint8_t cmd, uint8_t pos, uint8_t val) "cmd 0x%02x pos %u da applesmc_key_selected(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3) "key %c%c%c%c" applesmc_key_not_found(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3) "key %c%c%c%c not found" applesmc_data_read(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3, uint8_t pos, uint8_t val) "read key %c%c%c%c [%u] 0x%02x" +applesmc_write_len(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3, uint8_t len) "write key %c%c%c%c len %u" +applesmc_write_data(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3, uint8_t pos, uint8_t val) "write key %c%c%c%c [%u] 0x%02x" +applesmc_write_complete(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3, uint8_t len) "write key %c%c%c%c complete (%u bytes)" # avr_power.c avr_power_read(uint8_t value) "power_reduc read value:%u" -- 2.55.0
