Writes to the interrupt registers were not masked, so a guest could set
a reserved bit and read it back. The hardware returns 0 for those.

Mask each one to the bits the datasheet marks read/write:

  UDC_IER         17, 16, 8:6, 4:0
  UDC_ISR         8:6, 4:0
  UDC_EP_ACK_IER  3:0
  UDC_EP_NAK_IER  3:0
  UDC_EP_ACK_ISR  3:0
  UDC_EP_NAK_ISR  3:0

UDC_ISR bits 17 and 16 summarise the endpoint pool. They are read only,
so a write cannot clear them.

Signed-off-by: Jamin Lin <[email protected]>
---
 hw/usb/aspeed-udc.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/hw/usb/aspeed-udc.c b/hw/usb/aspeed-udc.c
index 355512822b..95fe823534 100644
--- a/hw/usb/aspeed-udc.c
+++ b/hw/usb/aspeed-udc.c
@@ -319,14 +319,24 @@ static void aspeed_udc_write(void *opaque, hwaddr offset, 
uint64_t data,
         s->regs[R_UDC_FUNC_CTRL] = val;
         break;
     case R_UDC_IER:
+        val &= 0x000301df;
+        s->regs[reg] = val;
+        aspeed_udc_update_irq(s);
+        break;
+    case R_UDC_ISR:
+        val &= 0x000001df;
+        s->regs[reg] &= ~val;
+        aspeed_udc_update_irq(s);
+        break;
     case R_UDC_EP_ACK_IER:
     case R_UDC_EP_NAK_IER:
+        val &= 0x0000000f;
         s->regs[reg] = val;
         aspeed_udc_update_irq(s);
         break;
-    case R_UDC_ISR:
     case R_UDC_EP_ACK_ISR:
     case R_UDC_EP_NAK_ISR:
+        val &= 0x0000000f;
         s->regs[reg] &= ~val;
         aspeed_udc_update_irq(s);
         break;
-- 
2.53.0

Reply via email to