* [Qemu-devel] [PATCH v2 0/2] AHCI: avoid mapping stale guest memory
@ 2015-03-13 21:50 John Snow
2015-03-13 21:50 ` [Qemu-devel] [PATCH v2 1/2] AHCI: Do not (re)map FB/CLB buffers while not running John Snow
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: John Snow @ 2015-03-13 21:50 UTC (permalink / raw)
To: qemu-block; +Cc: kwolf, pbonzini, John Snow, qemu-devel, stefanha
Currently, the AHCI device tries to re-map guest memory every time
the low or high address registers are written to, whether or not the
AHCI device is currently active. If the other register has stale
information in it, this may lead to runtime failures.
Reconfigure the AHCI device to ignore writes to these registers while
the device is active, and otherwise postpone the dma memory map until
the device becomes active.
If the mappings should for whatever reason fail, do not activate the
bits that tell the user the device has been started successfully.
v2:
- ahci_map_[clb|fis]_address now returns true on success
- PORT_CMD_LIST_ON and PORT_CMD_FIS_ON only turn on if the map succeeds
- Fix compiler warning due to changing context.
John Snow (2):
AHCI: Do not (re)map FB/CLB buffers while not running
AHCI: Protect cmd register
hw/ide/ahci.c | 76 +++++++++++++++++++++++++++++++++++++++++++++--------------
hw/ide/ahci.h | 2 ++
2 files changed, 60 insertions(+), 18 deletions(-)
--
1.9.3
^ permalink raw reply [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH v2 1/2] AHCI: Do not (re)map FB/CLB buffers while not running
2015-03-13 21:50 [Qemu-devel] [PATCH v2 0/2] AHCI: avoid mapping stale guest memory John Snow
@ 2015-03-13 21:50 ` John Snow
2015-03-13 21:50 ` [Qemu-devel] [PATCH v2 2/2] AHCI: Protect cmd register John Snow
2015-03-25 12:57 ` [Qemu-devel] [PATCH v2 0/2] AHCI: avoid mapping stale guest memory Stefan Hajnoczi
2 siblings, 0 replies; 4+ messages in thread
From: John Snow @ 2015-03-13 21:50 UTC (permalink / raw)
To: qemu-block; +Cc: kwolf, pbonzini, John Snow, qemu-devel, stefanha
The FIS Receive Buffer and Command List Buffer pointers
should not be edited while the FIS receive engine or
Command Receive engines are running.
Currently, we attempt to re-map the buffers every time they
are adjusted, but while the AHCI engines are off, these registers
may contain stale values, so we should not attempt to re-map these
values until the engines are reactivated.
Reported-by: Jordan Hargrave <jharg93@gmail.com>
Signed-off-by: John Snow <jsnow@redhat.com>
---
hw/ide/ahci.c | 50 +++++++++++++++++++++++++++++++++-----------------
1 file changed, 33 insertions(+), 17 deletions(-)
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index e1ae36f..3885fa9 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -51,6 +51,8 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
static void ahci_init_d2h(AHCIDevice *ad);
static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write);
static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes);
+static bool ahci_map_clb_address(AHCIDevice *ad);
+static bool ahci_map_fis_address(AHCIDevice *ad);
static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
@@ -202,25 +204,15 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
switch (offset) {
case PORT_LST_ADDR:
pr->lst_addr = val;
- map_page(s->as, &s->dev[port].lst,
- ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
- s->dev[port].cur_cmd = NULL;
break;
case PORT_LST_ADDR_HI:
pr->lst_addr_hi = val;
- map_page(s->as, &s->dev[port].lst,
- ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
- s->dev[port].cur_cmd = NULL;
break;
case PORT_FIS_ADDR:
pr->fis_addr = val;
- map_page(s->as, &s->dev[port].res_fis,
- ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
break;
case PORT_FIS_ADDR_HI:
pr->fis_addr_hi = val;
- map_page(s->as, &s->dev[port].res_fis,
- ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
break;
case PORT_IRQ_STAT:
pr->irq_stat &= ~val;
@@ -234,11 +226,21 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
pr->cmd = val & ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON);
if (pr->cmd & PORT_CMD_START) {
- pr->cmd |= PORT_CMD_LIST_ON;
+ if (ahci_map_clb_address(&s->dev[port])) {
+ pr->cmd |= PORT_CMD_LIST_ON;
+ } else {
+ error_report("AHCI: Failed to start DMA engine: "
+ "bad command list buffer address");
+ }
}
if (pr->cmd & PORT_CMD_FIS_RX) {
- pr->cmd |= PORT_CMD_FIS_ON;
+ if (ahci_map_fis_address(&s->dev[port])) {
+ pr->cmd |= PORT_CMD_FIS_ON;
+ } else {
+ error_report("AHCI: Failed to start FIS receive engine: "
+ "bad FIS receive buffer address");
+ }
}
/* XXX usually the FIS would be pending on the bus here and
@@ -565,6 +567,23 @@ static void debug_print_fis(uint8_t *fis, int cmd_len)
#endif
}
+static bool ahci_map_fis_address(AHCIDevice *ad)
+{
+ AHCIPortRegs *pr = &ad->port_regs;
+ map_page(ad->hba->as, &ad->res_fis,
+ ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
+ return ad->res_fis != NULL;
+}
+
+static bool ahci_map_clb_address(AHCIDevice *ad)
+{
+ AHCIPortRegs *pr = &ad->port_regs;
+ ad->cur_cmd = NULL;
+ map_page(ad->hba->as, &ad->lst,
+ ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
+ return ad->lst != NULL;
+}
+
static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished)
{
AHCIDevice *ad = &s->dev[port];
@@ -1360,12 +1379,9 @@ static int ahci_state_post_load(void *opaque, int version_id)
for (i = 0; i < s->ports; i++) {
ad = &s->dev[i];
- AHCIPortRegs *pr = &ad->port_regs;
- map_page(s->as, &ad->lst,
- ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
- map_page(s->as, &ad->res_fis,
- ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
+ ahci_map_clb_address(ad);
+ ahci_map_fis_address(ad);
/*
* If an error is present, ad->busy_slot will be valid and not -1.
* In this case, an operation is waiting to resume and will re-check
--
1.9.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH v2 2/2] AHCI: Protect cmd register
2015-03-13 21:50 [Qemu-devel] [PATCH v2 0/2] AHCI: avoid mapping stale guest memory John Snow
2015-03-13 21:50 ` [Qemu-devel] [PATCH v2 1/2] AHCI: Do not (re)map FB/CLB buffers while not running John Snow
@ 2015-03-13 21:50 ` John Snow
2015-03-25 12:57 ` [Qemu-devel] [PATCH v2 0/2] AHCI: avoid mapping stale guest memory Stefan Hajnoczi
2 siblings, 0 replies; 4+ messages in thread
From: John Snow @ 2015-03-13 21:50 UTC (permalink / raw)
To: qemu-block; +Cc: kwolf, pbonzini, John Snow, qemu-devel, stefanha
Many bits in the CMD register are supposed to be strictly read-only.
We should not be deleting them on every write.
As a side-effect: pay explicit attention to when a guest marks off
the FIS Receive or Start bits, and disable the status bits ourselves,
instead of letting them implicitly fall off.
Signed-off-by: John Snow <jsnow@redhat.com>
---
hw/ide/ahci.c | 26 +++++++++++++++++++++++++-
hw/ide/ahci.h | 2 ++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 3885fa9..df8c083 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -53,6 +53,8 @@ static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write);
static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes);
static bool ahci_map_clb_address(AHCIDevice *ad);
static bool ahci_map_fis_address(AHCIDevice *ad);
+static void ahci_unmap_clb_address(AHCIDevice *ad);
+static void ahci_unmap_fis_address(AHCIDevice *ad);
static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
@@ -223,7 +225,9 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
ahci_check_irq(s);
break;
case PORT_CMD:
- pr->cmd = val & ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON);
+ /* Block any Read-only fields from being set;
+ * including LIST_ON and FIS_ON. */
+ pr->cmd = (pr->cmd & PORT_CMD_RO_MASK) | (val & ~PORT_CMD_RO_MASK);
if (pr->cmd & PORT_CMD_START) {
if (ahci_map_clb_address(&s->dev[port])) {
@@ -232,6 +236,9 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
error_report("AHCI: Failed to start DMA engine: "
"bad command list buffer address");
}
+ } else if (pr->cmd & PORT_CMD_LIST_ON) {
+ ahci_unmap_clb_address(&s->dev[port]);
+ pr->cmd = pr->cmd & ~(PORT_CMD_LIST_ON);
}
if (pr->cmd & PORT_CMD_FIS_RX) {
@@ -241,6 +248,9 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
error_report("AHCI: Failed to start FIS receive engine: "
"bad FIS receive buffer address");
}
+ } else if (pr->cmd & PORT_CMD_FIS_ON) {
+ ahci_unmap_fis_address(&s->dev[port]);
+ pr->cmd = pr->cmd & ~(PORT_CMD_FIS_ON);
}
/* XXX usually the FIS would be pending on the bus here and
@@ -575,6 +585,13 @@ static bool ahci_map_fis_address(AHCIDevice *ad)
return ad->res_fis != NULL;
}
+static void ahci_unmap_fis_address(AHCIDevice *ad)
+{
+ dma_memory_unmap(ad->hba->as, ad->res_fis, 256,
+ DMA_DIRECTION_FROM_DEVICE, 256);
+ ad->res_fis = NULL;
+}
+
static bool ahci_map_clb_address(AHCIDevice *ad)
{
AHCIPortRegs *pr = &ad->port_regs;
@@ -584,6 +601,13 @@ static bool ahci_map_clb_address(AHCIDevice *ad)
return ad->lst != NULL;
}
+static void ahci_unmap_clb_address(AHCIDevice *ad)
+{
+ dma_memory_unmap(ad->hba->as, ad->lst, 1024,
+ DMA_DIRECTION_FROM_DEVICE, 1024);
+ ad->lst = NULL;
+}
+
static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished)
{
AHCIDevice *ad = &s->dev[port];
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 99aa0c9..501c002 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -132,6 +132,8 @@
#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
+#define PORT_CMD_RO_MASK 0x007dffe0 /* Which CMD bits are read only? */
+
/* ap->flags bits */
#define AHCI_FLAG_NO_NCQ (1 << 24)
#define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */
--
1.9.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH v2 0/2] AHCI: avoid mapping stale guest memory
2015-03-13 21:50 [Qemu-devel] [PATCH v2 0/2] AHCI: avoid mapping stale guest memory John Snow
2015-03-13 21:50 ` [Qemu-devel] [PATCH v2 1/2] AHCI: Do not (re)map FB/CLB buffers while not running John Snow
2015-03-13 21:50 ` [Qemu-devel] [PATCH v2 2/2] AHCI: Protect cmd register John Snow
@ 2015-03-25 12:57 ` Stefan Hajnoczi
2 siblings, 0 replies; 4+ messages in thread
From: Stefan Hajnoczi @ 2015-03-25 12:57 UTC (permalink / raw)
To: John Snow; +Cc: kwolf, pbonzini, qemu-devel, qemu-block
[-- Attachment #1: Type: text/plain, Size: 1211 bytes --]
On Fri, Mar 13, 2015 at 05:50:52PM -0400, John Snow wrote:
> Currently, the AHCI device tries to re-map guest memory every time
> the low or high address registers are written to, whether or not the
> AHCI device is currently active. If the other register has stale
> information in it, this may lead to runtime failures.
>
> Reconfigure the AHCI device to ignore writes to these registers while
> the device is active, and otherwise postpone the dma memory map until
> the device becomes active.
>
> If the mappings should for whatever reason fail, do not activate the
> bits that tell the user the device has been started successfully.
>
> v2:
> - ahci_map_[clb|fis]_address now returns true on success
> - PORT_CMD_LIST_ON and PORT_CMD_FIS_ON only turn on if the map succeeds
> - Fix compiler warning due to changing context.
>
> John Snow (2):
> AHCI: Do not (re)map FB/CLB buffers while not running
> AHCI: Protect cmd register
>
> hw/ide/ahci.c | 76 +++++++++++++++++++++++++++++++++++++++++++++--------------
> hw/ide/ahci.h | 2 ++
> 2 files changed, 60 insertions(+), 18 deletions(-)
>
> --
> 1.9.3
>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2015-03-25 12:58 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-03-13 21:50 [Qemu-devel] [PATCH v2 0/2] AHCI: avoid mapping stale guest memory John Snow
2015-03-13 21:50 ` [Qemu-devel] [PATCH v2 1/2] AHCI: Do not (re)map FB/CLB buffers while not running John Snow
2015-03-13 21:50 ` [Qemu-devel] [PATCH v2 2/2] AHCI: Protect cmd register John Snow
2015-03-25 12:57 ` [Qemu-devel] [PATCH v2 0/2] AHCI: avoid mapping stale guest memory Stefan Hajnoczi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).