Commit 6c16381150 for qemu.org

commit 6c163811500834f8fa810e240d105468d464cd07
Author: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Date:   Mon Sep 14 13:52:17 2026 +0100

    hw/macio/mac_dbdma: ensure only implemented DBDMA registers are accessed

    Whilst the DBDMA memory region is 4K in size, only the bottom 16 registers are
    implemented in the Power Macintosh DBDMA controller. If an attempt is made to
    access any unimplemented registers then an out-of-bounds array access occurs.

    Rework the switch() statements in dbdma_read() and dbdma_write() to handle each
    individual register access, as well as providing a safe default for all other
    unimplemented registers.

    Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
    Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
    Message-ID: <20260914125236.820155-1-mark.cave-ayland@ilande.co.uk>
    Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c
index a55c9c9982..d00181b978 100644
--- a/hw/misc/macio/mac_dbdma.c
+++ b/hw/misc/macio/mac_dbdma.c
@@ -715,22 +715,25 @@ static void dbdma_write(void *opaque, hwaddr addr,
         return;
     }

-    ch->regs[reg] = value;
-
     switch(reg) {
     case DBDMA_CONTROL:
+        ch->regs[DBDMA_CONTROL] = value;
         dbdma_control_write(ch);
         break;
     case DBDMA_CMDPTR_LO:
         /* 16-byte aligned */
-        ch->regs[DBDMA_CMDPTR_LO] &= ~0xf;
+        ch->regs[DBDMA_CMDPTR_LO] = value & ~0xf;
         dbdma_cmdptr_load(ch);
         break;
     case DBDMA_STATUS:
     case DBDMA_INTR_SEL:
     case DBDMA_BRANCH_SEL:
     case DBDMA_WAIT_SEL:
-        /* nothing to do */
+    case DBDMA_RES1:
+    case DBDMA_RES2:
+    case DBDMA_RES3:
+    case DBDMA_RES4:
+        ch->regs[reg] = value;
         break;
     case DBDMA_XFER_MODE:
     case DBDMA_CMDPTR_HI:
@@ -738,12 +741,11 @@ static void dbdma_write(void *opaque, hwaddr addr,
     case DBDMA_DATA2PTR_LO:
     case DBDMA_ADDRESS_HI:
     case DBDMA_BRANCH_ADDR_HI:
-    case DBDMA_RES1:
-    case DBDMA_RES2:
-    case DBDMA_RES3:
-    case DBDMA_RES4:
         /* unused */
         break;
+    default:
+        /* do nothing */
+        break;
     }
 }

@@ -756,8 +758,6 @@ static uint64_t dbdma_read(void *opaque, hwaddr addr,
     DBDMA_channel *ch = &s->channels[channel];
     int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;

-    value = ch->regs[reg];
-
     switch(reg) {
     case DBDMA_CONTROL:
         value = ch->regs[DBDMA_STATUS];
@@ -767,7 +767,11 @@ static uint64_t dbdma_read(void *opaque, hwaddr addr,
     case DBDMA_INTR_SEL:
     case DBDMA_BRANCH_SEL:
     case DBDMA_WAIT_SEL:
-        /* nothing to do */
+    case DBDMA_RES1:
+    case DBDMA_RES2:
+    case DBDMA_RES3:
+    case DBDMA_RES4:
+        value = ch->regs[reg];
         break;
     case DBDMA_XFER_MODE:
     case DBDMA_CMDPTR_HI:
@@ -778,11 +782,9 @@ static uint64_t dbdma_read(void *opaque, hwaddr addr,
         /* unused */
         value = 0;
         break;
-    case DBDMA_RES1:
-    case DBDMA_RES2:
-    case DBDMA_RES3:
-    case DBDMA_RES4:
-        /* reserved */
+    default:
+        /* unimplemented */
+        value = 0;
         break;
     }