[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 15/78] ide: Fix incorrect handling of some PRDTs in ide_dma_cb()
From: |
Michael Roth |
Subject: |
[PATCH 15/78] ide: Fix incorrect handling of some PRDTs in ide_dma_cb() |
Date: |
Tue, 16 Jun 2020 09:14:44 -0500 |
From: Alexander Popov <alex.popov@linux.com>
The commit a718978ed58a from July 2015 introduced the assertion which
implies that the size of successful DMA transfers handled in ide_dma_cb()
should be multiple of 512 (the size of a sector). But guest systems can
initiate DMA transfers that don't fit this requirement.
For fixing that let's check the number of bytes prepared for the transfer
by the prepare_buf() handler. The code in ide_dma_cb() must behave
according to the Programming Interface for Bus Master IDE Controller
(Revision 1.0 5/16/94):
1. If PRDs specified a smaller size than the IDE transfer
size, then the Interrupt and Active bits in the Controller
status register are not set (Error Condition).
2. If the size of the physical memory regions was equal to
the IDE device transfer size, the Interrupt bit in the
Controller status register is set to 1, Active bit is set to 0.
3. If PRDs specified a larger size than the IDE transfer size,
the Interrupt and Active bits in the Controller status register
are both set to 1.
Signed-off-by: Alexander Popov <alex.popov@linux.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Message-id: 20191223175117.508990-2-alex.popov@linux.com
Signed-off-by: John Snow <jsnow@redhat.com>
(cherry picked from commit ed78352a59ea7acf7520d4d47a96b9911bae7fc3)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
hw/ide/core.c | 30 ++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 754ff4dc34..80000eb766 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -849,6 +849,7 @@ static void ide_dma_cb(void *opaque, int ret)
int64_t sector_num;
uint64_t offset;
bool stay_active = false;
+ int32_t prep_size = 0;
if (ret == -EINVAL) {
ide_dma_error(s);
@@ -863,13 +864,15 @@ static void ide_dma_cb(void *opaque, int ret)
}
}
- n = s->io_buffer_size >> 9;
- if (n > s->nsector) {
- /* The PRDs were longer than needed for this request. Shorten them so
- * we don't get a negative remainder. The Active bit must remain set
- * after the request completes. */
+ if (s->io_buffer_size > s->nsector * 512) {
+ /*
+ * The PRDs were longer than needed for this request.
+ * The Active bit must remain set after the request completes.
+ */
n = s->nsector;
stay_active = true;
+ } else {
+ n = s->io_buffer_size >> 9;
}
sector_num = ide_get_sector(s);
@@ -892,9 +895,20 @@ static void ide_dma_cb(void *opaque, int ret)
n = s->nsector;
s->io_buffer_index = 0;
s->io_buffer_size = n * 512;
- if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->io_buffer_size) < 512) {
- /* The PRDs were too short. Reset the Active bit, but don't raise an
- * interrupt. */
+ prep_size = s->bus->dma->ops->prepare_buf(s->bus->dma, s->io_buffer_size);
+ /* prepare_buf() must succeed and respect the limit */
+ assert(prep_size >= 0 && prep_size <= n * 512);
+
+ /*
+ * Now prep_size stores the number of bytes in the sglist, and
+ * s->io_buffer_size stores the number of bytes described by the PRDs.
+ */
+
+ if (prep_size < n * 512) {
+ /*
+ * The PRDs are too short for this request. Error condition!
+ * Reset the Active bit and don't raise the interrupt.
+ */
s->status = READY_STAT | SEEK_STAT;
dma_buf_commit(s, 0);
goto eot;
--
2.17.1
- [PATCH 00/78] Patch Round-up for stable 4.2.1, freeze on 2020-06-22, Michael Roth, 2020/06/16
- [PATCH 09/78] numa: properly check if numa is supported, Michael Roth, 2020/06/16
- [PATCH 10/78] backup-top: Begin drain earlier, Michael Roth, 2020/06/16
- [PATCH 11/78] arm/arm-powerctl: set NSACR.{CP11, CP10} bits in arm_set_cpu_on(), Michael Roth, 2020/06/16
- [PATCH 12/78] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on(), Michael Roth, 2020/06/16
- [PATCH 13/78] hw/i386/pc: fix regression in parsing vga cmdline parameter, Michael Roth, 2020/06/16
- [PATCH 14/78] tests/ide-test: Create a single unit-test covering more PRDT cases, Michael Roth, 2020/06/16
- [PATCH 15/78] ide: Fix incorrect handling of some PRDTs in ide_dma_cb(),
Michael Roth <=
- [PATCH 16/78] target/arm: Set ISSIs16Bit in make_issinfo, Michael Roth, 2020/06/16
- [PATCH 17/78] virtio: update queue size on guest write, Michael Roth, 2020/06/16
- [PATCH 18/78] virtio-mmio: update queue size on guest write, Michael Roth, 2020/06/16
- [PATCH 19/78] virtio: add ability to delete vq through a pointer, Michael Roth, 2020/06/16
- [PATCH 20/78] virtio: make virtio_delete_queue idempotent, Michael Roth, 2020/06/16
- [PATCH 01/78] block/nbd: extract the common cleanup code, Michael Roth, 2020/06/16
- [PATCH 21/78] virtio: reset region cache when on queue deletion, Michael Roth, 2020/06/16
- [PATCH 27/78] dp8393x: Mask EOL bit from descriptor addresses, Michael Roth, 2020/06/16
- [PATCH 22/78] virtio-net: delete also control queue when TX/RX deleted, Michael Roth, 2020/06/16
- [PATCH 23/78] intel_iommu: a fix to vtd_find_as_from_bus_num(), Michael Roth, 2020/06/16