aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/bhyve/pci_ahci.c
diff options
context:
space:
mode:
authorPeter Grehan <grehan@FreeBSD.org>2013-11-26 03:00:54 +0000
committerPeter Grehan <grehan@FreeBSD.org>2013-11-26 03:00:54 +0000
commit4b48ea6ab2a105d97b07d6c628e1f75d6b9c24ea (patch)
treec9d6a2e9f6061b806d9d2eaa7424eea4a6ee2c49 /usr.sbin/bhyve/pci_ahci.c
parent3287361e383779d5a1c7494c21ce28e20ac8a2fc (diff)
downloadsrc-4b48ea6ab2a105d97b07d6c628e1f75d6b9c24ea.tar.gz
src-4b48ea6ab2a105d97b07d6c628e1f75d6b9c24ea.zip
The Data Byte Count (DBC) field of a Physical Region Descriptor
Table is 22 bits, with the bit 31 being the interrupt-on-completion bit. OpenBSD and UEFI set this bit, resulting in large block i/o lengths being sent to bhyve and coredumping the process. Fix by masking off the relevant 22 bits when using the DBC field as a length. Reviewed by: Zhixiang Yu Discussed with: Tycho Nightingale (tycho.nightingale@pluribusnetworks.com) MFC after: 10.0
Notes
Notes: svn path=/head/; revision=258614
Diffstat (limited to 'usr.sbin/bhyve/pci_ahci.c')
-rw-r--r--usr.sbin/bhyve/pci_ahci.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c
index bc738dcbf527..0109975d2eb8 100644
--- a/usr.sbin/bhyve/pci_ahci.c
+++ b/usr.sbin/bhyve/pci_ahci.c
@@ -165,6 +165,7 @@ struct ahci_cmd_hdr {
struct ahci_prdt_entry {
uint64_t dba;
uint32_t reserved;
+#define DBCMASK 0x3fffff
uint32_t dbc;
};
@@ -461,10 +462,13 @@ ahci_handle_dma(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done,
* Build up the iovec based on the prdt
*/
for (i = 0; i < iovcnt; i++) {
+ uint32_t dbcsz;
+
+ dbcsz = (prdt->dbc & DBCMASK) + 1;
breq->br_iov[i].iov_base = paddr_guest2host(ahci_ctx(sc),
- prdt->dba, prdt->dbc + 1);
- breq->br_iov[i].iov_len = prdt->dbc + 1;
- aior->done += (prdt->dbc + 1);
+ prdt->dba, dbcsz);
+ breq->br_iov[i].iov_len = dbcsz;
+ aior->done += dbcsz;
prdt++;
}
if (readop)
@@ -513,11 +517,14 @@ write_prdt(struct ahci_port *p, int slot, uint8_t *cfis,
from = buf;
prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
for (i = 0; i < hdr->prdtl && len; i++) {
- uint8_t *ptr = paddr_guest2host(ahci_ctx(p->pr_sc),
- prdt->dba, prdt->dbc + 1);
- memcpy(ptr, from, prdt->dbc + 1);
- len -= (prdt->dbc + 1);
- from += (prdt->dbc + 1);
+ uint8_t *ptr;
+ uint32_t dbcsz;
+
+ dbcsz = (prdt->dbc & DBCMASK) + 1;
+ ptr = paddr_guest2host(ahci_ctx(p->pr_sc), prdt->dba, dbcsz);
+ memcpy(ptr, from, dbcsz);
+ len -= dbcsz;
+ from += dbcsz;
prdt++;
}
hdr->prdbc = size - len;
@@ -908,10 +915,13 @@ atapi_read(struct ahci_port *p, int slot, uint8_t *cfis,
* Build up the iovec based on the prdt
*/
for (i = 0; i < iovcnt; i++) {
+ uint32_t dbcsz;
+
+ dbcsz = (prdt->dbc & DBCMASK) + 1;
breq->br_iov[i].iov_base = paddr_guest2host(ahci_ctx(sc),
- prdt->dba, prdt->dbc + 1);
- breq->br_iov[i].iov_len = prdt->dbc + 1;
- aior->done += (prdt->dbc + 1);
+ prdt->dba, dbcsz);
+ breq->br_iov[i].iov_len = dbcsz;
+ aior->done += dbcsz;
prdt++;
}
err = blockif_read(p->bctx, breq);