diff --git a/hw/dma/apple_sio.c b/hw/dma/apple_sio.c index 6d5883c679..4c234f15c2 100644 --- a/hw/dma/apple_sio.c +++ b/hw/dma/apple_sio.c @@ -214,6 +214,8 @@ static void apple_sio_dma_del_buffers(AppleSIODMAEndpoint* ep) QTAILQ_FOREACH_SAFE (buf, &ep->buffers, next, buf_next) { apple_sio_dma_destroy_buffer(ep, buf); } } +static void apple_sio_dma_writeback(AppleSIO* s, AppleSIODMAEndpoint* ep, SIODMABuffer* buf); + // -- internal references -- // Firestorm$Inferno/18A5351d/sio.bndb@000030e4{sio_endpoint::handle_message}+0x64 // -- end internal references -- @@ -224,7 +226,17 @@ static void apple_sio_dma_stop(AppleSIO* s, AppleSIODMAEndpoint* ep) SIOMessage m = {0}; AppleRTKit* rtk = &s->parent_obj; - QTAILQ_FOREACH_SAFE (buf, &ep->buffers, next, buf_next) { apple_sio_dma_destroy_buffer(ep, buf); } + /* + * Every transfer still out comes back completed, however little of it was done. The kernel's stop + * waits, uninterruptibly, for the channel to go idle, and a channel goes idle only once every command + * it handed out has come back. Dropped quietly, they left the audio server's IO thread asleep in + * AppleSmartIODMA::_stopDMA for good — the first time right after the actuator's first vibration — + * and every sound in the system went with it. + */ + QTAILQ_FOREACH_SAFE (buf, &ep->buffers, next, buf_next) { + if (!buf->mapped) { buf->start_timestamp = apple_sio_get_cur_ts(s); } + apple_sio_dma_writeback(s, ep, buf); + } m.op = OP_COMPLETE; m.ep = ep->id; diff --git a/hw/misc/aop.c b/hw/misc/aop.c index a8b7ac17bc..ebb924128e 100644 --- a/hw/misc/aop.c +++ b/hw/misc/aop.c @@ -556,8 +556,12 @@ static void apple_aop_ep_handle_message(void* opaque, uint8_t ep, uint64_t msg) g_free(actual_out_payload); } else { + // Past the result word there are out_len bytes; actual_out_len counts the word as well. + // Given that size, a handler that fills its buffer writes four bytes past the end of the + // allocation, into the next block on the heap, and malloc later spins in the damaged + // freelist with the guest stopped around it. res = s->descr->handle_command(s->opaque, seq, actual_in_payload, actual_in_len, - actual_out_payload, actual_out_len); + actual_out_payload, out_len); } stl_le_p(out_payload, res);