diff options
author | Peter Grehan <grehan@FreeBSD.org> | 2013-11-26 03:00:54 +0000 |
---|---|---|
committer | Peter Grehan <grehan@FreeBSD.org> | 2013-11-26 03:00:54 +0000 |
commit | 4b48ea6ab2a105d97b07d6c628e1f75d6b9c24ea (patch) | |
tree | c9d6a2e9f6061b806d9d2eaa7424eea4a6ee2c49 /usr.sbin/bhyve/pci_ahci.c | |
parent | 3287361e383779d5a1c7494c21ce28e20ac8a2fc (diff) | |
download | src-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.c | 32 |
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); |