Skip to contentSkip to conversation

MIPS: DMA support for RC4030 chipset [v3]

PATCH In review Hervé Poussineau 2 participants 2 messages Dec 13, 2008 – Dec 16, 2008

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 MIPS: DMA support for RC4030 chipset [v3]

Hi,

Attached patch implements DMA support to RC4030 chipset and simplifies jazz IO part (at 0xf0000000), where registers contain 16 bit values. The patch also wires DMA transfers for the SCSI adapter in the Jazz emulation (Mips Magnum 4000 and Acer Pica 61).

Changes since v1:
- Support reuse of esp callback functions up to DMA engine
- Don't keep in memory the DMA table, but read it when needed

Changes since v2:
- Don't use cpu_single_env in the DMA transfer function, as it is NULL in the aio path
- Multiple improvements to the DMA transfer function: report errors to the caller, support for non contiguous physical pages...

Hervé

mips.h +5 -1
Index: hw/mips.h
===================================================================
@@ -27,6 +27,10 @@
 extern void cpu_mips_clock_init(CPUState *);
 
 /* rc4030.c */
-qemu_irq *rc4030_init(qemu_irq timer, qemu_irq jazz_bus);
+typedef struct rc4030DMAState *rc4030_dma;
+typedef void (*rc4030_dma_function)(void *dma, uint8_t *buf, int len);
+qemu_irq *rc4030_init(CPUState *env, qemu_irq timer, qemu_irq jazz_bus,
+                      rc4030_dma **dmas,
+                      rc4030_dma_function *dma_read, rc4030_dma_function *dma_write);
 
 #endif
mips_jazz.c +32 -17

100 lines not on this page · raw message

rc4030.c +221 -81

503 lines not on this page · raw message

#1 lore raw
Quoted 11 lines · Hervé Poussineau

Hi,

Attached patch implements DMA support to RC4030 chipset and simplifies jazz IO part (at 0xf0000000), where registers contain 16 bit values. The patch also wires DMA transfers for the SCSI adapter in the Jazz emulation (Mips Magnum 4000 and Acer Pica 61).

Changes since v1:
- Support reuse of esp callback functions up to DMA engine
- Don't keep in memory the DMA table, but read it when needed

Quoted 5 lines

Changes since v2:
- Don't use cpu_single_env in the DMA transfer function, as it is NULL in the aio path
- Multiple improvements to the DMA transfer function: report errors to the caller, support for non contiguous physical pages...

This patches introduces some new warnings:
/home/aurel32/git/qemu/hw/rc4030.c: In function ‘rc4030_readl’:
/home/aurel32/git/qemu/hw/rc4030.c:229: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 4 has type ‘target_phys_addr_t’ /home/aurel32/git/qemu/hw/rc4030.c: In function ‘rc4030_writel’:
/home/aurel32/git/qemu/hw/rc4030.c:376: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 5 has type ‘target_phys_addr_t’ /home/aurel32/git/qemu/hw/rc4030.c: In function ‘jazzio_readw’:
/home/aurel32/git/qemu/hw/rc4030.c:503: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 4 has type ‘target_phys_addr_t’ /home/aurel32/git/qemu/hw/rc4030.c: In function ‘jazzio_writew’:
/home/aurel32/git/qemu/hw/rc4030.c:541: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 5 has type ‘target_phys_addr_t’

Also, please include a Signed-off.

Please find my other comments inline.

Quoted 91 lines

Index: hw/mips.h
===================================================================

mips.h +5 -1
@@ -27,6 +27,10 @@
 extern void cpu_mips_clock_init(CPUState *);
 
 /* rc4030.c */
-qemu_irq *rc4030_init(qemu_irq timer, qemu_irq jazz_bus);
+typedef struct rc4030DMAState *rc4030_dma;
+typedef void (*rc4030_dma_function)(void *dma, uint8_t *buf, int len);
+qemu_irq *rc4030_init(CPUState *env, qemu_irq timer, qemu_irq jazz_bus,
+                      rc4030_dma **dmas,
+                      rc4030_dma_function *dma_read, rc4030_dma_function *dma_write);
 
 #endif

Index: hw/mips_jazz.c
===================================================================

mips_jazz.c +24 -13
@@ -75,6 +75,24 @@
     rtc_writeb,
 };
 
+static void dma_dummy_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    /* Nothing to do. That is only to ensure that
+     * the current DMA acknowledge cycle is completed. */
+}
+
+static CPUReadMemoryFunc *dma_dummy_read[3] = {
+    NULL,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc *dma_dummy_write[3] = {
+    dma_dummy_writeb,
+    dma_dummy_writeb,
+    dma_dummy_writeb,
+};
+
 #ifdef HAS_AUDIO
 static void audio_init(qemu_irq *pic)
 {
@@ -102,16 +120,6 @@
 }
 #endif
 
-static void espdma_memory_read(void *opaque, uint8_t *buf, int len)
-{
-    printf("espdma_memory_read(buf %p, len %d) not implemented\n", buf, len);
-}
-
-static void espdma_memory_write(void *opaque, uint8_t *buf, int len)
-{
-    printf("espdma_memory_write(buf %p, len %d) not implemented\n", buf, len);
-}
-
 #define MAGNUM_BIOS_SIZE_MAX 0x7e000
 #define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX)
 
@@ -125,10 +133,11 @@
     int bios_size, n;
     CPUState *env;
     qemu_irq *rc4030, *i8259;
+    rc4030_dma *dmas;
+    rc4030_dma_function dma_read, dma_write;
     void *scsi_hba;
     int hd;
-    int s_rtc;
-    PITState *pit;
+    int s_rtc, s_dma_dummy;
     BlockDriverState *fds[MAX_FD];
     qemu_irq esp_reset;
 
@@ -153,7 +162,9 @@
 
     /* load the BIOS image. */
     bios_offset = ram_size + vga_ram_size;
-    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+    if (bios_name == NULL)
+        bios_name = BIOS_FILENAME;
+    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
     bios_size = load_image(buf, phys_ram_base + bios_offset);
     if (bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) {
         fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n",
@@ -171,12 +182,14 @@
     cpu_mips_clock_init(env);
 
     /* Chipset */

mips_jazz.c line 179

Quoted 10 lines
mips_jazz.c +4 -3
-    rc4030 = rc4030_init(env->irq[6], env->irq[3]);
+    rc4030 = rc4030_init(env, env->irq[6], env->irq[3],
+                         &dmas, &dma_read, &dma_write);
+    s_dma_dummy = cpu_register_io_memory(0, dma_dummy_read, dma_dummy_write, NULL);
+    cpu_register_physical_memory(0x8000d000, 0x00001000, s_dma_dummy);
 
     /* ISA devices */
     i8259 = i8259_init(env->irq[4]);
-    pit = pit_init(0x40, i8259[0]);
-    pcspk_init(pit);

Is this wanted? This does not appear in the description and seems unrelated.

Quoted 377 lines
mips_jazz.c +4 -1
+    DMA_init(0);
 
     /* ISA IO space at 0x90000000 */
     isa_mmio_init(0x90000000, 0x01000000);
@@ -200,7 +213,7 @@
 
     /* SCSI adapter */
     scsi_hba = esp_init(0x80002000, 0,
-                        espdma_memory_read, espdma_memory_write, NULL,
+                        dma_read, dma_write, dmas[0],
                         rc4030[5], &esp_reset);
     for (n = 0; n < ESP_MAX_DEVS; n++) {
         hd = drive_get_index(IF_SCSI, 0, n);
@@ -278,6 +291,7 @@
     .init = mips_magnum_init,
     .ram_require = MAGNUM_BIOS_SIZE + VGA_RAM_SIZE,
     .nodisk_ok = 1,
+    .use_scsi = 1,
 };
 
 QEMUMachine mips_pica61_machine = {
@@ -286,4 +300,5 @@
     .init = mips_pica61_init,
     .ram_require = MAGNUM_BIOS_SIZE + VGA_RAM_SIZE,
     .nodisk_ok = 1,
+    .use_scsi = 1,
 };

Index: hw/rc4030.c
===================================================================

rc4030.c +96 -71
@@ -26,21 +26,53 @@
 #include "mips.h"
 #include "qemu-timer.h"
 
+/********************************************************/
+/* debug rc4030 */
+
 //#define DEBUG_RC4030
+//#define DEBUG_RC4030_DMA
 
 #ifdef DEBUG_RC4030
+#define DPRINTF(fmt, args...) \
+do { printf("rc4030: " fmt , ##args); } while (0)
 static const char* irq_names[] = { "parallel", "floppy", "sound", "video",
             "network", "scsi", "keyboard", "mouse", "serial0", "serial1" };
+#else
+#define DPRINTF(fmt, args...)
 #endif
 
+#define RC4030_ERROR(fmt, args...) \
+do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ##args); } while (0)
+
+/********************************************************/
+/* rc4030 emulation                                     */
+
+typedef struct dma_pagetable_entry {
+    int32_t frame;
+    int32_t owner;
+} __attribute__((packed)) dma_pagetable_entry;
+
+#define DMA_PAGESIZE    4096
+#define DMA_REG_ENABLE  1
+#define DMA_REG_COUNT   2
+#define DMA_REG_ADDRESS 3
+
+#define DMA_FLAG_ENABLE     0x0001
+#define DMA_FLAG_MEM_TO_DEV 0x0002
+#define DMA_FLAG_TC_INTR    0x0100
+#define DMA_FLAG_MEM_INTR   0x0200
+#define DMA_FLAG_ADDR_INTR  0x0400
+
 typedef struct rc4030State
 {
+    CPUState *env;
+
     uint32_t config; /* 0x0000: RC4030 config register */
     uint32_t invalid_address_register; /* 0x0010: Invalid Address register */
 
     /* DMA */
     uint32_t dma_regs[8][4];
-    uint32_t dma_tl_base; /* 0x0018: DMA transl. table base */
+    target_phys_addr_t dma_tl_base; /* 0x0018: DMA transl. table base */
     uint32_t dma_tl_limit; /* 0x0020: DMA transl. table limit */
 
     /* cache */
@@ -51,7 +83,6 @@
     uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */
     uint32_t cache_bwin; /* 0x0060: I/O Cache Buffer Window */
 
-    uint32_t offset208;
     uint32_t offset210;
     uint32_t nvram_protect; /* 0x0220: NV ram protect register */
     uint32_t offset238;
@@ -63,7 +94,6 @@
     QEMUTimer *periodic_timer;
     uint32_t itr; /* Interval timer reload */
 
-    uint32_t dummy32;
     qemu_irq timer_irq;
     qemu_irq jazz_bus_irq;
 } rc4030State;
@@ -165,7 +195,7 @@
     case 0x01d0:
     case 0x01d8:
     case 0x01e0:
-    case 0x1e8:
+    case 0x01e8:
     case 0x01f0:
     case 0x01f8:
         {
@@ -176,7 +206,7 @@
         break;
     /* Offset 0x0208 */
     case 0x0208:
-        val = s->offset208;
+        val = 0;
         break;
     /* Offset 0x0210 */
     case 0x0210:
@@ -188,7 +218,7 @@
         break;
     /* Interval timer count */
     case 0x0230:
-        val = s->dummy32;
+        val = 0;
         qemu_irq_lower(s->timer_irq);
         break;
     /* Offset 0x0238 */
@@ -196,17 +226,13 @@
         val = s->offset238;
         break;
     default:
-#ifdef DEBUG_RC4030
-        printf("rc4030: invalid read [" TARGET_FMT_lx "]\n", addr);
-#endif
+        RC4030_ERROR("invalid read [" TARGET_FMT_lx "]\n", addr);
         val = 0;
         break;
     }
 
-#ifdef DEBUG_RC4030
     if ((addr & ~3) != 0x230)
-        printf("rc4030: read 0x%02x at " TARGET_FMT_lx "\n", val, addr);
-#endif
+        DPRINTF("read 0x%02x at " TARGET_FMT_lx "\n", val, addr);
 
     return val;
 }
@@ -231,9 +257,7 @@
     rc4030State *s = opaque;
     addr &= 0x3fff;
 
-#ifdef DEBUG_RC4030
-    printf("rc4030: write 0x%02x at " TARGET_FMT_lx "\n", val, addr);
-#endif
+    DPRINTF("write 0x%02x at " TARGET_FMT_lx "\n", val, addr);
 
     switch (addr & ~0x3) {
     /* Global config register */
@@ -242,12 +266,19 @@
         break;
     /* DMA transl. table base */
     case 0x0018:
-        s->dma_tl_base = val;
+        s->dma_tl_base = (int32_t)val;
         break;
     /* DMA transl. table limit */
     case 0x0020:
         s->dma_tl_limit = val;
         break;
+    /* DMA transl. table invalidated */
+    case 0x0028:
+        break;
+    /* Cache Maintenance */
+    case 0x0030:
+        RC4030_ERROR("Cache maintenance not handled yet (val 0x%02x)\n", val);
+        break;
     /* I/O Cache Physical Tag */
     case 0x0048:
         s->cache_ptag = val;
@@ -269,7 +300,7 @@
             static int current = 0;
             target_phys_addr_t dest = 0 + dests[current];
             uint8_t buf;
-            current = (current + 1) % (sizeof(dests)/sizeof(dests[0]));
+            current = (current + 1) % ARRAY_SIZE(dests);
             buf = s->cache_bwin - 1;
             cpu_physical_memory_rw(dest, &buf, 1, 1);
         }
@@ -322,7 +353,7 @@
     case 0x01d0:
     case 0x01d8:
     case 0x01e0:
-    case 0x1e8:
+    case 0x01e8:
     case 0x01f0:
     case 0x01f8:
         {
@@ -342,9 +373,7 @@
         set_next_tick(s);
         break;
     default:
-#ifdef DEBUG_RC4030
-        printf("rc4030: invalid write of 0x%02x at [" TARGET_FMT_lx "]\n", val, addr);
-#endif
+        RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_lx "]\n", val, addr);
         break;
     }
 }
@@ -402,8 +431,8 @@
 #ifdef DEBUG_RC4030
     if (s->isr_jazz != 0) {
         uint32_t irq = 0;
-        printf("jazz pending:");
-        for (irq = 0; irq < sizeof(irq_names)/sizeof(irq_names[0]); irq++) {
+        DPRINTF("pending irqs:");
+        for (irq = 0; irq < ARRAY_SIZE(irq_names); irq++) {
             if (s->isr_jazz & (1 << irq)) {
                 printf(" %s", irq_names[irq]);
                 if (!(s->imr_jazz & (1 << irq))) {
@@ -442,7 +471,7 @@
     qemu_irq_raise(s->timer_irq);
 }
 
-static uint32_t int_readb(void *opaque, target_phys_addr_t addr)
+static uint32_t jazzio_readw(void *opaque, target_phys_addr_t addr)
 {
     rc4030State *s = opaque;
     uint32_t val;
@@ -450,14 +479,14 @@
     addr &= 0xfff;
 
     switch (addr) {
+    /* Local bus int source */
     case 0x00: {
-        /* Local bus int source */
         uint32_t pending = s->isr_jazz & s->imr_jazz;
         val = 0;
         irq = 0;
         while (pending) {
             if (pending & 1) {
-                //printf("returning irq %s\n", irq_names[irq]);
+                DPRINTF("returning irq %s\n", irq_names[irq]);
                 val = (irq + 1) << 2;
                 break;
             }
@@ -466,100 +495,93 @@
         }
         break;
     }
+    /* Local bus int enable mask */
+    case 0x02:
+        val = s->imr_jazz;
+        break;
     default:
-#ifdef DEBUG_RC4030
-            printf("rc4030: (interrupt controller) invalid read [" TARGET_FMT_lx "]\n", addr);
-#endif
-            val = 0;
+        RC4030_ERROR("(jazz io controller) invalid read [" TARGET_FMT_lx "]\n", addr);
+        val = 0;
     }
 
-#ifdef DEBUG_RC4030
-    printf("rc4030: (interrupt controller) read 0x%02x at " TARGET_FMT_lx "\n", val, addr);
-#endif
+    DPRINTF("(jazz io controller) read 0x%04x at " TARGET_FMT_lx "\n", val, addr);
 
     return val;
 }
 
-static uint32_t int_readw(void *opaque, target_phys_addr_t addr)
+static uint32_t jazzio_readb(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-    v = int_readb(opaque, addr);
-    v |= int_readb(opaque, addr + 1) << 8;
-    return v;
+    v = jazzio_readw(opaque, addr & ~0x1);
+    return (v >> (8 * (addr & 0x1))) & 0xff;
 }
 
-static uint32_t int_readl(void *opaque, target_phys_addr_t addr)
+static uint32_t jazzio_readl(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-    v = int_readb(opaque, addr);
-    v |= int_readb(opaque, addr + 1) << 8;
-    v |= int_readb(opaque, addr + 2) << 16;
-    v |= int_readb(opaque, addr + 3) << 24;
+    v = jazzio_readw(opaque, addr);
+    v |= jazzio_readw(opaque, addr + 2) << 16;
     return v;
 }
 
-static void int_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void jazzio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     rc4030State *s = opaque;
     addr &= 0xfff;
 
-#ifdef DEBUG_RC4030
-    printf("rc4030: (interrupt controller) write 0x%02x at " TARGET_FMT_lx "\n", val, addr);
-#endif
+    DPRINTF("(jazz io controller) write 0x%04x at " TARGET_FMT_lx "\n", val, addr);
 
     switch (addr) {
     /* Local bus int enable mask */
     case 0x02:
-        s->imr_jazz = (s->imr_jazz & 0xff00) | (val << 0); update_jazz_irq(s);
+        s->imr_jazz = val;
+        update_jazz_irq(s);
         break;
-    case 0x03:
-        s->imr_jazz = (s->imr_jazz & 0x00ff) | (val << 8); update_jazz_irq(s);
-        break;
     default:
-#ifdef DEBUG_RC4030
-        printf("rc4030: (interrupt controller) invalid write of 0x%02x at [" TARGET_FMT_lx "]\n", val, addr);
-#endif
+        RC4030_ERROR("(jazz io controller) invalid write of 0x%04x at [" TARGET_FMT_lx "]\n", val, addr);
         break;
     }
 }
 
-static void int_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void jazzio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-    int_writeb(opaque, addr, val & 0xff);
-    int_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+    uint32_t old_val = jazzio_readw(opaque, addr & ~0x1);
+
+    switch (addr & 1) {
+    case 0:
+        val = val | (old_val & 0xff00);
+        break;
+    case 1:
+        val = (val << 8) | (old_val & 0x00ff);
+        break;
+    }
+    jazzio_writew(opaque, addr & ~0x1, val);
 }
 
-static void int_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void jazzio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-    int_writeb(opaque, addr, val & 0xff);
-    int_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    int_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    int_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+    jazzio_writew(opaque, addr, val & 0xffff);
+    jazzio_writew(opaque, addr + 2, (val >> 16) & 0xffff);
 }
 
-static CPUReadMemoryFunc *int_read[3] = {
-    int_readb,
-    int_readw,
-    int_readl,
+static CPUReadMemoryFunc *jazzio_read[3] = {
+    jazzio_readb,
+    jazzio_readw,
+    jazzio_readl,
 };
 
-static CPUWriteMemoryFunc *int_write[3] = {
-    int_writeb,
-    int_writew,
-    int_writel,
+static CPUWriteMemoryFunc *jazzio_write[3] = {
+    jazzio_writeb,
+    jazzio_writew,
+    jazzio_writel,
 };
 
-#define G364_512KB_RAM (0x0)
-#define G364_2MB_RAM   (0x1)

rc4030.c line 584

Quoted 10 lines
rc4030.c +1 -4
-#define G364_8MB_RAM   (0x2)
-#define G364_32MB_RAM  (0x3)
-
 static void rc4030_reset(void *opaque)
 {
     rc4030State *s = opaque;
     int i;
 
-    s->config = (G364_2MB_RAM << 8) | 0x04;
+    s->config = 0x104;

Why this change? This make the resultint code less readable.

Quoted 54 lines
rc4030.c +31 -3
     s->invalid_address_register = 0;
 
     memset(s->dma_regs, 0, sizeof(s->dma_regs));
@@ -569,7 +591,6 @@
     s->cache_ptag = s->cache_ltag = 0;
     s->cache_bmask = s->cache_bwin = 0;
 
-    s->offset208 = 0;
     s->offset210 = 0x18186;
     s->nvram_protect = 7;
     s->offset238 = 7;
@@ -578,21 +599,140 @@
     s->imr_jazz = s->isr_jazz = 0;
 
     s->itr = 0;
-    s->dummy32 = 0;
 
     qemu_irq_lower(s->timer_irq);
     qemu_irq_lower(s->jazz_bus_irq);
 }
 
-qemu_irq *rc4030_init(qemu_irq timer, qemu_irq jazz_bus)
+static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
 {
+    rc4030State *s = opaque;
+    target_phys_addr_t entry_addr;
+    target_phys_addr_t dma_addr, phys_addr;
+    dma_pagetable_entry entry;
+    int index, dev_to_mem;
+    int ncpy, i;
+
+    s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR);
+
+    /* Check DMA channel consistency */
+    dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1;
+    if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) ||
+        (is_write != dev_to_mem)) {
+        s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR;
+        return;
+    }
+
+    if (len > s->dma_regs[n][DMA_REG_COUNT])
+        len = s->dma_regs[n][DMA_REG_COUNT];
+
+    dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
+    i = 0;
+    for (;;) {
+        if (i == len) {
+            s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR;
+            break;
+        }
+
+        ncpy = DMA_PAGESIZE - (dma_addr & (DMA_PAGESIZE - 1));
+        if (ncpy > len - i)

rc4030.c line 648

Quoted 10 lines
rc4030.c +10 -0
+            ncpy = len - i;
+
+        /* Get DMA translation table entry */
+        index = dma_addr / DMA_PAGESIZE;
+        if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) {
+            s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR;
+            break;
+        }
+        entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry);
+        /* HACK: Qemu has no function to read from a virtual or physical address */

cpu_physical_memory_rw is able to read/write from a physical address.

rc4030.c line 649

Quoted 1 line
rc4030.c +1 -0
+        if (entry_addr > ram_size) {

Where does this condition come from?

rc4030.c line 650

Quoted 1 line
rc4030.c +1 -0
+            if (cpu_memory_rw_debug(s->env, entry_addr, (uint8_t *)&entry, sizeof(entry), 0) < 0) {

This looks very hackish especially given this function use the current mode of the CPU (supervisor/kernel/user) to do the memory access. You can use env->tlb->map_address() to do virtual->physical address translation.

Quoted 102 lines
rc4030.c +81 -3
+                s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR;
+                break;
+            }
+        } else
+            cpu_physical_memory_rw(entry_addr, (uint8_t *)&entry, sizeof(entry), 0);
+
+        /* Read/write data at right place */
+        phys_addr = entry.frame + (dma_addr & (DMA_PAGESIZE - 1));
+        cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write);
+
+        i += ncpy;
+        dma_addr += ncpy;
+        s->dma_regs[n][DMA_REG_COUNT] -= ncpy;
+    }
+
+#ifdef DEBUG_RC4030_DMA
+    {
+        int i, j;
+        printf("rc4030 dma: Copying %d bytes %s host %p\n",
+            len, is_write ? "from" : "to", buf);
+        for (i = 0; i < len; i += 16) {
+            int n = min(16, len - i);
+            for (j = 0; j < n; j++)
+                printf("%02x ", buf[i + j]);
+            while (j++ < 16)
+                printf("   ");
+            printf("| ");
+            for (j = 0; j < n; j++)
+                printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.');
+            printf("\n");
+        }
+    }
+#endif
+}
+
+struct rc4030DMAState {
+    void *opaque;
+    int n;
+};
+
+static void rc4030_dma_read(void *dma, uint8_t *buf, int len)
+{
+    rc4030_dma s = dma;
+    rc4030_do_dma(s->opaque, s->n, buf, len, 0);
+}
+
+static void rc4030_dma_write(void *dma, uint8_t *buf, int len)
+{
+    rc4030_dma s = dma;
+    rc4030_do_dma(s->opaque, s->n, buf, len, 1);
+}
+
+static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n)
+{
+    rc4030_dma *s;
+    struct rc4030DMAState *p;
+    int i;
+
+    s = (rc4030_dma *)qemu_mallocz(sizeof(rc4030_dma) * n);
+    p = (struct rc4030DMAState *)qemu_mallocz(sizeof(struct rc4030DMAState) * n);
+    for (i = 0; i < n; i++) {
+        p->opaque = opaque;
+        p->n = i;
+        s[i] = p;
+        p++;
+    }
+    return s;
+}
+
+qemu_irq *rc4030_init(CPUState *env, qemu_irq timer, qemu_irq jazz_bus,
+                      rc4030_dma **dmas,
+                      rc4030_dma_function *dma_read, rc4030_dma_function *dma_write)
+{
     rc4030State *s;
-    int s_chipset, s_int;
+    int s_chipset, s_jazzio;
 
     s = qemu_mallocz(sizeof(rc4030State));
     if (!s)
         return NULL;
 
+    *dmas = rc4030_allocate_dmas(s, 4);
+    *dma_read = rc4030_dma_read;
+    *dma_write = rc4030_dma_write;
+
+    s->env = env;
     s->periodic_timer = qemu_new_timer(vm_clock, rc4030_periodic_timer, s);
     s->timer_irq = timer;
     s->jazz_bus_irq = jazz_bus;
@@ -602,8 +742,8 @@
 
     s_chipset = cpu_register_io_memory(0, rc4030_read, rc4030_write, s);
     cpu_register_physical_memory(0x80000000, 0x300, s_chipset);
-    s_int = cpu_register_io_memory(0, int_read, int_write, s);
-    cpu_register_physical_memory(0xf0000000, 0x00001000, s_int);
+    s_jazzio = cpu_register_io_memory(0, jazzio_read, jazzio_write, s);
+    cpu_register_physical_memory(0xf0000000, 0x00001000, s_jazzio);
 
     return qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16);
 }
Signature · 4 lines
  .''`.  Aurelien Jarno	            | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   [email protected]         | [email protected]
   `-    people.debian.org/~aurel32 | www.aurel32.net