ide: introduce ide_transfer_start_norecurse

For the case where the end_transfer_func is also the caller of
ide_transfer_start, the mutual recursion can lead to unlimited
stack usage.  Introduce a new version that can be used to change
tail recursion into a loop, and use it in trace_ide_atapi_cmd_reply_end.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-id: 20180606190955.20845-8-jsnow@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
This commit is contained in:
Paolo Bonzini 2018-06-06 15:09:55 -04:00 committed by John Snow
parent d02cea6437
commit c173723f24
3 changed files with 37 additions and 23 deletions

View File

@ -245,15 +245,11 @@ static uint16_t atapi_byte_count_limit(IDEState *s)
void ide_atapi_cmd_reply_end(IDEState *s) void ide_atapi_cmd_reply_end(IDEState *s)
{ {
int byte_count_limit, size, ret; int byte_count_limit, size, ret;
trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size, while (s->packet_transfer_size > 0) {
s->elementary_transfer_size, trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size,
s->io_buffer_index); s->elementary_transfer_size,
if (s->packet_transfer_size <= 0) { s->io_buffer_index);
/* end of transfer */
ide_atapi_cmd_ok(s);
ide_set_irq(s->bus);
trace_ide_atapi_cmd_reply_end_eot(s, s->status);
} else {
/* see if a new sector must be read */ /* see if a new sector must be read */
if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) {
if (!s->elementary_transfer_size) { if (!s->elementary_transfer_size) {
@ -279,11 +275,6 @@ void ide_atapi_cmd_reply_end(IDEState *s)
size = s->cd_sector_size - s->io_buffer_index; size = s->cd_sector_size - s->io_buffer_index;
if (size > s->elementary_transfer_size) if (size > s->elementary_transfer_size)
size = s->elementary_transfer_size; size = s->elementary_transfer_size;
s->packet_transfer_size -= size;
s->elementary_transfer_size -= size;
s->io_buffer_index += size;
ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
size, ide_atapi_cmd_reply_end);
} else { } else {
/* a new transfer is needed */ /* a new transfer is needed */
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
@ -306,13 +297,26 @@ void ide_atapi_cmd_reply_end(IDEState *s)
size = (s->cd_sector_size - s->io_buffer_index); size = (s->cd_sector_size - s->io_buffer_index);
} }
trace_ide_atapi_cmd_reply_end_new(s, s->status); trace_ide_atapi_cmd_reply_end_new(s, s->status);
s->packet_transfer_size -= size; }
s->elementary_transfer_size -= size; s->packet_transfer_size -= size;
s->io_buffer_index += size; s->elementary_transfer_size -= size;
ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size, s->io_buffer_index += size;
size, ide_atapi_cmd_reply_end);
/* Some adapters process PIO data right away. In that case, we need
* to avoid mutual recursion between ide_transfer_start
* and ide_atapi_cmd_reply_end.
*/
if (!ide_transfer_start_norecurse(s,
s->io_buffer + s->io_buffer_index - size,
size, ide_atapi_cmd_reply_end)) {
return;
} }
} }
/* end of transfer */
trace_ide_atapi_cmd_reply_end_eot(s, s->status);
ide_atapi_cmd_ok(s);
ide_set_irq(s->bus);
} }
/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */ /* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */

View File

@ -523,8 +523,8 @@ static void ide_clear_retry(IDEState *s)
} }
/* prepare data transfer and tell what to do after */ /* prepare data transfer and tell what to do after */
void ide_transfer_start(IDEState *s, uint8_t *buf, int size, bool ide_transfer_start_norecurse(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func) EndTransferFunc *end_transfer_func)
{ {
s->data_ptr = buf; s->data_ptr = buf;
s->data_end = buf + size; s->data_end = buf + size;
@ -534,10 +534,18 @@ void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
} }
if (!s->bus->dma->ops->pio_transfer) { if (!s->bus->dma->ops->pio_transfer) {
s->end_transfer_func = end_transfer_func; s->end_transfer_func = end_transfer_func;
return; return false;
} }
s->bus->dma->ops->pio_transfer(s->bus->dma); s->bus->dma->ops->pio_transfer(s->bus->dma);
end_transfer_func(s); return true;
}
void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func)
{
if (ide_transfer_start_norecurse(s, buf, size, end_transfer_func)) {
end_transfer_func(s);
}
} }
static void ide_cmd_done(IDEState *s) static void ide_cmd_done(IDEState *s)

View File

@ -623,6 +623,8 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val);
void ide_transfer_start(IDEState *s, uint8_t *buf, int size, void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func); EndTransferFunc *end_transfer_func);
bool ide_transfer_start_norecurse(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func);
void ide_transfer_stop(IDEState *s); void ide_transfer_stop(IDEState *s);
void ide_set_inactive(IDEState *s, bool more); void ide_set_inactive(IDEState *s, bool more);
BlockAIOCB *ide_issue_trim( BlockAIOCB *ide_issue_trim(