summaryrefslogtreecommitdiff
path: root/hw/ide/atapi.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2018-06-06 15:09:55 -0400
committerJohn Snow <jsnow@redhat.com>2018-06-08 13:36:31 -0400
commitc173723f247c69974a83af1395020d0f01a0d334 (patch)
tree6951a90343b7720974921c64b48dc157f24dd98b /hw/ide/atapi.c
parentd02cea6437b420150915b03aef3691010c7d40df (diff)
downloadqemu-c173723f247c69974a83af1395020d0f01a0d334.zip
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>
Diffstat (limited to 'hw/ide/atapi.c')
-rw-r--r--hw/ide/atapi.c42
1 files changed, 23 insertions, 19 deletions
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 7168ff55a7..39e473f9c2 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -245,15 +245,11 @@ static uint16_t atapi_byte_count_limit(IDEState *s)
void ide_atapi_cmd_reply_end(IDEState *s)
{
int byte_count_limit, size, ret;
- trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size,
- s->elementary_transfer_size,
- s->io_buffer_index);
- if (s->packet_transfer_size <= 0) {
- /* end of transfer */
- ide_atapi_cmd_ok(s);
- ide_set_irq(s->bus);
- trace_ide_atapi_cmd_reply_end_eot(s, s->status);
- } else {
+ while (s->packet_transfer_size > 0) {
+ trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size,
+ s->elementary_transfer_size,
+ s->io_buffer_index);
+
/* see if a new sector must be read */
if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_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;
if (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 {
/* a new transfer is needed */
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);
}
trace_ide_atapi_cmd_reply_end_new(s, s->status);
- 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);
+ }
+ s->packet_transfer_size -= size;
+ s->elementary_transfer_size -= size;
+ s->io_buffer_index += size;
+
+ /* 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 */