diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/fdc.c | 35 | ||||
-rw-r--r-- | hw/iommu.c | 54 | ||||
-rw-r--r-- | hw/lance.c | 127 | ||||
-rw-r--r-- | hw/m48t08.c | 161 | ||||
-rw-r--r-- | hw/m48t08.h | 8 | ||||
-rw-r--r-- | hw/magic-load.c | 179 | ||||
-rw-r--r-- | hw/sched.c | 268 | ||||
-rw-r--r-- | hw/slavio_intctl.c | 299 | ||||
-rw-r--r-- | hw/slavio_serial.c | 364 | ||||
-rw-r--r-- | hw/slavio_timer.c | 289 | ||||
-rw-r--r-- | hw/sun4m.c | 163 | ||||
-rw-r--r-- | hw/tcx.c | 297 | ||||
-rw-r--r-- | hw/timer.c | 97 |
13 files changed, 1567 insertions, 774 deletions
@@ -21,6 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +/* + * The controller is used in Sun4m systems in a slightly different + * way. There are changes in DOR register and DMA is not available. + */ #include "vl.h" /********************************************************/ @@ -90,6 +94,16 @@ typedef struct fdrive_t { uint8_t ro; /* Is read-only */ } fdrive_t; +#ifdef TARGET_SPARC +#define DMA_read_memory(a,b,c,d) +#define DMA_write_memory(a,b,c,d) +#define DMA_register_channel(a,b,c) +#define DMA_hold_DREQ(a) +#define DMA_release_DREQ(a) +#define DMA_get_channel_mode(a) (0) +#define DMA_schedule(a) +#endif + static void fd_init (fdrive_t *drv, BlockDriverState *bs) { /* Drive */ @@ -455,6 +469,18 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) } } +static CPUReadMemoryFunc *fdctrl_mem_read[3] = { + fdctrl_read, + fdctrl_read, + fdctrl_read, +}; + +static CPUWriteMemoryFunc *fdctrl_mem_write[3] = { + fdctrl_write, + fdctrl_write, + fdctrl_write, +}; + static void fd_change_cb (void *opaque) { fdrive_t *drv = opaque; @@ -473,7 +499,7 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, BlockDriverState **fds) { fdctrl_t *fdctrl; -// int io_mem; + int io_mem; int i; FLOPPY_DPRINTF("init controller\n"); @@ -504,11 +530,8 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, fdctrl_reset(fdctrl, 0); fdctrl->state = FD_CTRL_ACTIVE; if (mem_mapped) { - FLOPPY_ERROR("memory mapped floppy not supported by now !\n"); -#if 0 - io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write); - cpu_register_physical_memory(base, 0x08, io_mem); -#endif + io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl); + cpu_register_physical_memory(io_base, 0x08, io_mem); } else { register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl); register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl); diff --git a/hw/iommu.c b/hw/iommu.c index a9249c4ba7..62927acd54 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -117,8 +117,6 @@ typedef struct IOMMUState { uint32_t iostart; } IOMMUState; -static IOMMUState *ps; - static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) { IOMMUState *s = opaque; @@ -187,25 +185,61 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = { iommu_mem_writew, }; -uint32_t iommu_translate(uint32_t addr) +uint32_t iommu_translate_local(void *opaque, uint32_t addr) { - uint32_t *iopte = (void *)(ps->regs[1] << 4), pa; + IOMMUState *s = opaque; + uint32_t *iopte = (void *)(s->regs[1] << 4), pa; - iopte += ((addr - ps->iostart) >> PAGE_SHIFT); - cpu_physical_memory_rw((uint32_t)iopte, (void *) &pa, 4, 0); + iopte += ((addr - s->iostart) >> PAGE_SHIFT); + cpu_physical_memory_read((uint32_t)iopte, (void *) &pa, 4); bswap32s(&pa); pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */ return pa + (addr & PAGE_MASK); } -void iommu_init(uint32_t addr) +static void iommu_save(QEMUFile *f, void *opaque) +{ + IOMMUState *s = opaque; + int i; + + qemu_put_be32s(f, &s->addr); + for (i = 0; i < sizeof(struct iommu_regs); i += 4) + qemu_put_be32s(f, &s->regs[i]); + qemu_put_be32s(f, &s->iostart); +} + +static int iommu_load(QEMUFile *f, void *opaque, int version_id) +{ + IOMMUState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->addr); + for (i = 0; i < sizeof(struct iommu_regs); i += 4) + qemu_put_be32s(f, &s->regs[i]); + qemu_get_be32s(f, &s->iostart); + + return 0; +} + +static void iommu_reset(void *opaque) +{ + IOMMUState *s = opaque; + + memset(s->regs, 0, sizeof(struct iommu_regs)); + s->iostart = 0; +} + +void *iommu_init(uint32_t addr) { IOMMUState *s; int iommu_io_memory; s = qemu_mallocz(sizeof(IOMMUState)); if (!s) - return; + return NULL; s->addr = addr; @@ -213,6 +247,8 @@ void iommu_init(uint32_t addr) cpu_register_physical_memory(addr, sizeof(struct iommu_regs), iommu_io_memory); - ps = s; + register_savevm("iommu", addr, 1, iommu_save, iommu_load, s); + qemu_register_reset(iommu_reset, s); + return s; } diff --git a/hw/lance.c b/hw/lance.c index 25ad8c45b2..c594c52e83 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -147,6 +147,7 @@ struct lance_init_block { }; #define LEDMA_REGS 4 +#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1) #if 0 /* Structure to describe the current status of DMA registers on the Sparc */ struct sparc_dma_registers { @@ -157,32 +158,28 @@ struct sparc_dma_registers { }; #endif -typedef struct LEDMAState { - uint32_t addr; - uint32_t regs[LEDMA_REGS]; -} LEDMAState; - typedef struct LANCEState { - uint32_t paddr; NetDriverState *nd; uint32_t leptr; uint16_t addr; uint16_t regs[LE_MAXREG]; uint8_t phys[6]; /* mac address */ int irq; - LEDMAState *ledma; + unsigned int rxptr, txptr; + uint32_t ledmaregs[LEDMA_REGS]; } LANCEState; -static unsigned int rxptr, txptr; - static void lance_send(void *opaque); -static void lance_reset(LANCEState *s) +static void lance_reset(void *opaque) { + LANCEState *s = opaque; memcpy(s->phys, s->nd->macaddr, 6); - rxptr = 0; - txptr = 0; + s->rxptr = 0; + s->txptr = 0; + memset(s->regs, 0, LE_MAXREG * 2); s->regs[LE_CSR0] = LE_C0_STOP; + memset(s->ledmaregs, 0, LEDMA_REGS * 4); } static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) @@ -190,7 +187,7 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) LANCEState *s = opaque; uint32_t saddr; - saddr = addr - s->paddr; + saddr = addr & LE_MAXREG; switch (saddr >> 1) { case LE_RDP: return s->regs[s->addr]; @@ -208,7 +205,7 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val uint32_t saddr; uint16_t reg; - saddr = addr - s->paddr; + saddr = addr & LE_MAXREG; switch (saddr >> 1) { case LE_RDP: switch(s->addr) { @@ -292,7 +289,7 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { static int lance_can_receive(void *opaque) { LANCEState *s = opaque; - void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; int i; uint16_t temp; @@ -303,7 +300,7 @@ static int lance_can_receive(void *opaque) ib = (void *) iommu_translate(dmaptr); for (i = 0; i < RX_RING_SIZE; i++) { - cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); temp &= 0xff; if (temp == (LE_R1_OWN)) { #ifdef DEBUG_LANCE @@ -323,7 +320,7 @@ static int lance_can_receive(void *opaque) static void lance_receive(void *opaque, const uint8_t *buf, int size) { LANCEState *s = opaque; - void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; unsigned int i, old_rxptr, j; uint16_t temp; @@ -333,23 +330,23 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size) ib = (void *) iommu_translate(dmaptr); - old_rxptr = rxptr; - for (i = rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { - cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + old_rxptr = s->rxptr; + for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { + cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); if (temp == (LE_R1_OWN)) { - rxptr = (rxptr + 1) & RX_RING_MOD_MASK; + s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK; temp = size; bswap16s(&temp); - cpu_physical_memory_write(&ib->brx_ring[i].mblength, (void *) &temp, 2); + cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp, 2); #if 0 - cpu_physical_memory_write(&ib->rx_buf[i], buf, size); + cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size); #else for (j = 0; j < size; j++) { - cpu_physical_memory_write(((void *)&ib->rx_buf[i]) + j, &buf[j], 1); + cpu_physical_memory_write(((uint32_t)&ib->rx_buf[i]) + j, &buf[j], 1); } #endif temp = LE_R1_POK; - cpu_physical_memory_write(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) pic_set_irq(s->irq, 1); @@ -364,7 +361,7 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size) static void lance_send(void *opaque) { LANCEState *s = opaque; - void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; unsigned int i, old_txptr, j; uint16_t temp; @@ -375,18 +372,18 @@ static void lance_send(void *opaque) ib = (void *) iommu_translate(dmaptr); - old_txptr = txptr; - for (i = txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { - cpu_physical_memory_read(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); + old_txptr = s->txptr; + for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { + cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); if (temp == (LE_T1_POK|LE_T1_OWN)) { - cpu_physical_memory_read(&ib->btx_ring[i].length, (void *) &temp, 2); + cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp, 2); bswap16s(&temp); temp = (~temp) + 1; #if 0 - cpu_physical_memory_read(&ib->tx_buf[i], pkt_buf, temp); + cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp); #else for (j = 0; j < temp; j++) { - cpu_physical_memory_read(((void *)&ib->tx_buf[i]) + j, &pkt_buf[j], 1); + cpu_physical_memory_read((uint32_t)&ib->tx_buf[i] + j, &pkt_buf[j], 1); } #endif @@ -395,8 +392,8 @@ static void lance_send(void *opaque) #endif qemu_send_packet(s->nd, pkt_buf, temp); temp = LE_T1_POK; - cpu_physical_memory_write(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); - txptr = (txptr + 1) & TX_RING_MOD_MASK; + cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); + s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK; s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; } } @@ -404,24 +401,20 @@ static void lance_send(void *opaque) static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) { - LEDMAState *s = opaque; + LANCEState *s = opaque; uint32_t saddr; - saddr = (addr - s->addr) >> 2; - if (saddr < LEDMA_REGS) - return s->regs[saddr]; - else - return 0; + saddr = (addr & LEDMA_MAXADDR) >> 2; + return s->ledmaregs[saddr]; } static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { - LEDMAState *s = opaque; + LANCEState *s = opaque; uint32_t saddr; - saddr = (addr - s->addr) >> 2; - if (saddr < LEDMA_REGS) - s->regs[saddr] = val; + saddr = (addr & LEDMA_MAXADDR) >> 2; + s->ledmaregs[saddr] = val; } static CPUReadMemoryFunc *ledma_mem_read[3] = { @@ -436,33 +429,61 @@ static CPUWriteMemoryFunc *ledma_mem_write[3] = { ledma_mem_writel, }; +static void lance_save(QEMUFile *f, void *opaque) +{ + LANCEState *s = opaque; + int i; + + qemu_put_be32s(f, &s->leptr); + qemu_put_be16s(f, &s->addr); + for (i = 0; i < LE_MAXREG; i ++) + qemu_put_be16s(f, &s->regs[i]); + qemu_put_buffer(f, s->phys, 6); + qemu_put_be32s(f, &s->irq); + for (i = 0; i < LEDMA_REGS; i ++) + qemu_put_be32s(f, &s->ledmaregs[i]); +} + +static int lance_load(QEMUFile *f, void *opaque, int version_id) +{ + LANCEState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->leptr); + qemu_get_be16s(f, &s->addr); + for (i = 0; i < LE_MAXREG; i ++) + qemu_get_be16s(f, &s->regs[i]); + qemu_get_buffer(f, s->phys, 6); + qemu_get_be32s(f, &s->irq); + for (i = 0; i < LEDMA_REGS; i ++) + qemu_get_be32s(f, &s->ledmaregs[i]); + return 0; +} + void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr) { LANCEState *s; - LEDMAState *led; int lance_io_memory, ledma_io_memory; s = qemu_mallocz(sizeof(LANCEState)); if (!s) return; - s->paddr = leaddr; s->nd = nd; s->irq = irq; lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); cpu_register_physical_memory(leaddr, 8, lance_io_memory); - led = qemu_mallocz(sizeof(LEDMAState)); - if (!led) - return; - - s->ledma = led; - led->addr = ledaddr; - ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led); + ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); cpu_register_physical_memory(ledaddr, 16, ledma_io_memory); lance_reset(s); qemu_add_read_packet(nd, lance_can_receive, lance_receive, s); + register_savevm("lance", leaddr, 1, lance_save, lance_load, s); + qemu_register_reset(lance_reset, s); } diff --git a/hw/m48t08.c b/hw/m48t08.c index 46ec665570..0945879532 100644 --- a/hw/m48t08.c +++ b/hw/m48t08.c @@ -32,19 +32,14 @@ #define NVRAM_PRINTF(fmt, args...) do { } while (0) #endif -#define NVRAM_MAX_MEM 0xfff0 +#define NVRAM_MAX_MEM 0x1ff0 +#define NVRAM_MAXADDR 0x1fff struct m48t08_t { - /* Hardware parameters */ - int mem_index; - uint32_t mem_base; - uint16_t size; /* RTC management */ time_t time_offset; time_t stop_time; /* NVRAM storage */ - uint8_t lock; - uint16_t addr; uint8_t *buffer; }; @@ -83,14 +78,13 @@ static void set_time (m48t08_t *NVRAM, struct tm *tm) } /* Direct access to NVRAM */ -void m48t08_write (m48t08_t *NVRAM, uint32_t val) +void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val) { struct tm tm; int tmp; - if (NVRAM->addr > NVRAM_MAX_MEM && NVRAM->addr < 0x2000) - NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); - switch (NVRAM->addr) { + addr &= NVRAM_MAXADDR; + switch (addr) { case 0x1FF8: /* control */ NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; @@ -167,25 +161,18 @@ void m48t08_write (m48t08_t *NVRAM, uint32_t val) } break; default: - /* Check lock registers state */ - if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) - break; - if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) - break; - if (NVRAM->addr < NVRAM_MAX_MEM || - (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { - NVRAM->buffer[NVRAM->addr] = val & 0xFF; - } + NVRAM->buffer[addr] = val & 0xFF; break; } } -uint32_t m48t08_read (m48t08_t *NVRAM) +uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr) { struct tm tm; - uint32_t retval = 0xFF; + uint8_t retval = 0xFF; - switch (NVRAM->addr) { + addr &= NVRAM_MAXADDR; + switch (addr) { case 0x1FF8: /* control */ goto do_read; @@ -225,65 +212,36 @@ uint32_t m48t08_read (m48t08_t *NVRAM) retval = toBCD(tm.tm_year); break; default: - /* Check lock registers state */ - if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) - break; - if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) - break; - if (NVRAM->addr < NVRAM_MAX_MEM || - (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { - do_read: - retval = NVRAM->buffer[NVRAM->addr]; - } + do_read: + retval = NVRAM->buffer[addr]; break; } - if (NVRAM->addr > NVRAM_MAX_MEM + 1 && NVRAM->addr < 0x2000) - NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); - return retval; } -void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr) -{ - NVRAM->addr = addr; -} - -void m48t08_toggle_lock (m48t08_t *NVRAM, int lock) -{ - NVRAM->lock ^= 1 << lock; -} - static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t08_t *NVRAM = opaque; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) - NVRAM->buffer[addr] = value; + m48t08_write(NVRAM, addr, value); } static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t08_t *NVRAM = opaque; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - NVRAM->buffer[addr] = value >> 8; - NVRAM->buffer[addr + 1] = value; - } + m48t08_write(NVRAM, addr, value); + m48t08_write(NVRAM, addr + 1, value >> 8); } static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t08_t *NVRAM = opaque; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - NVRAM->buffer[addr] = value >> 24; - NVRAM->buffer[addr + 1] = value >> 16; - NVRAM->buffer[addr + 2] = value >> 8; - NVRAM->buffer[addr + 3] = value; - } + m48t08_write(NVRAM, addr, value); + m48t08_write(NVRAM, addr + 1, value >> 8); + m48t08_write(NVRAM, addr + 2, value >> 16); + m48t08_write(NVRAM, addr + 3, value >> 24); } static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) @@ -291,10 +249,7 @@ static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) m48t08_t *NVRAM = opaque; uint32_t retval = 0; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) - retval = NVRAM->buffer[addr]; - + retval = m48t08_read(NVRAM, addr); return retval; } @@ -303,12 +258,8 @@ static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) m48t08_t *NVRAM = opaque; uint32_t retval = 0; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - retval = NVRAM->buffer[addr] << 8; - retval |= NVRAM->buffer[addr + 1]; - } - + retval = m48t08_read(NVRAM, addr) << 8; + retval |= m48t08_read(NVRAM, addr + 1); return retval; } @@ -317,14 +268,10 @@ static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) m48t08_t *NVRAM = opaque; uint32_t retval = 0; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - retval = NVRAM->buffer[addr] << 24; - retval |= NVRAM->buffer[addr + 1] << 16; - retval |= NVRAM->buffer[addr + 2] << 8; - retval |= NVRAM->buffer[addr + 3]; - } - + retval = m48t08_read(NVRAM, addr) << 24; + retval |= m48t08_read(NVRAM, addr + 1) << 16; + retval |= m48t08_read(NVRAM, addr + 2) << 8; + retval |= m48t08_read(NVRAM, addr + 3); return retval; } @@ -340,12 +287,42 @@ static CPUReadMemoryFunc *nvram_read[] = { &nvram_readl, }; +static void nvram_save(QEMUFile *f, void *opaque) +{ + m48t08_t *s = opaque; + + qemu_put_be32s(f, (uint32_t *)&s->time_offset); + qemu_put_be32s(f, (uint32_t *)&s->stop_time); + qemu_put_buffer(f, s->buffer, 0x2000); +} + +static int nvram_load(QEMUFile *f, void *opaque, int version_id) +{ + m48t08_t *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, (uint32_t *)&s->time_offset); + qemu_get_be32s(f, (uint32_t *)&s->stop_time); + qemu_get_buffer(f, s->buffer, 0x2000); + return 0; +} + +static void m48t08_reset(void *opaque) +{ + m48t08_t *s = opaque; + + s->time_offset = 0; + s->stop_time = 0; +} + + /* Initialisation routine */ -m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr) +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size) { m48t08_t *s; - int i; - unsigned char tmp = 0; + int mem_index; s = qemu_mallocz(sizeof(m48t08_t)); if (!s) @@ -355,25 +332,13 @@ m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr) qemu_free(s); return NULL; } - s->size = size; - s->mem_base = mem_base; - s->addr = 0; if (mem_base != 0) { - s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); - cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); + mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); + cpu_register_physical_memory(mem_base, 0x2000, mem_index); } - s->lock = 0; - i = 0x1fd8; - s->buffer[i++] = 0x01; - s->buffer[i++] = 0x80; /* Sun4m OBP */ - memcpy(&s->buffer[i], macaddr, 6); - - /* Calculate checksum */ - for (i = 0x1fd8; i < 0x1fe7; i++) { - tmp ^= s->buffer[i]; - } - s->buffer[0x1fe7] = tmp; + register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s); + qemu_register_reset(m48t08_reset, s); return s; } diff --git a/hw/m48t08.h b/hw/m48t08.h index 9b44bc0d16..985116a099 100644 --- a/hw/m48t08.h +++ b/hw/m48t08.h @@ -3,10 +3,8 @@ typedef struct m48t08_t m48t08_t; -void m48t08_write (m48t08_t *NVRAM, uint32_t val); -uint32_t m48t08_read (m48t08_t *NVRAM); -void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr); -void m48t08_toggle_lock (m48t08_t *NVRAM, int lock); -m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr); +void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val); +uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr); +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size); #endif /* !defined (__M48T08_H__) */ diff --git a/hw/magic-load.c b/hw/magic-load.c index 06a5f743af..713343a758 100644 --- a/hw/magic-load.c +++ b/hw/magic-load.c @@ -1,5 +1,54 @@ #include "vl.h" #include "disas.h" +#include "exec-all.h" + +struct exec +{ + uint32_t a_info; /* Use macros N_MAGIC, etc for access */ + uint32_t a_text; /* length of text, in bytes */ + uint32_t a_data; /* length of data, in bytes */ + uint32_t a_bss; /* length of uninitialized data area, in bytes */ + uint32_t a_syms; /* length of symbol table data in file, in bytes */ + uint32_t a_entry; /* start address */ + uint32_t a_trsize; /* length of relocation info for text, in bytes */ + uint32_t a_drsize; /* length of relocation info for data, in bytes */ +}; + +#ifdef BSWAP_NEEDED +static void bswap_ahdr(struct exec *e) +{ + bswap32s(&e->a_info); + bswap32s(&e->a_text); + bswap32s(&e->a_data); + bswap32s(&e->a_bss); + bswap32s(&e->a_syms); + bswap32s(&e->a_entry); + bswap32s(&e->a_trsize); + bswap32s(&e->a_drsize); +} +#else +#define bswap_ahdr(x) do { } while (0) +#endif + +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define QMAGIC 0314 +#define _N_HDROFF(x) (1024 - sizeof (struct exec)) +#define N_TXTOFF(x) \ + (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ + (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) +#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0) +#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) +#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1)) + +#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) + +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ + : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) + #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB @@ -103,27 +152,27 @@ static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint3 return NULL; } -static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) +static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) { int retval; retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); if (retval < 0) - return -1; + return NULL; retval = read(fd, shdr, sizeof(*shdr)); if (retval < 0) - return -1; + return NULL; bswap_shdr(shdr); if (shdr->sh_type == SHT_STRTAB) return qemu_malloc(shdr->sh_size);; - return 0; + return NULL; } -static int read_program(int fd, struct elf_phdr *phdr, void *dst) +static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry) { int retval; - retval = lseek(fd, 0x4000, SEEK_SET); + retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET); if (retval < 0) return -1; return read(fd, dst, phdr->p_filesz); @@ -178,6 +227,7 @@ static void load_symbols(struct elfhdr *ehdr, int fd) { struct elf_shdr symtab, strtab; struct elf_sym *syms; + struct syminfo *s; int nsyms, i; char *str; @@ -196,20 +246,19 @@ static void load_symbols(struct elfhdr *ehdr, int fd) goto error_freesyms; /* Commit */ - if (disas_symtab) - qemu_free(disas_symtab); /* XXX Merge with old symbols? */ - if (disas_strtab) - qemu_free(disas_strtab); - disas_symtab = syms; - disas_num_syms = nsyms; - disas_strtab = str; + s = qemu_mallocz(sizeof(*s)); + s->disas_symtab = syms; + s->disas_num_syms = nsyms; + s->disas_strtab = str; + s->next = syminfos; + syminfos = s; return; error_freesyms: qemu_free(syms); return; } -int load_elf(const char * filename, uint8_t *addr) +int load_elf(const char *filename, uint8_t *addr) { struct elfhdr ehdr; struct elf_phdr phdr; @@ -227,12 +276,13 @@ int load_elf(const char * filename, uint8_t *addr) if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F' - || ehdr.e_machine != EM_SPARC) + || (ehdr.e_machine != EM_SPARC + && ehdr.e_machine != EM_SPARC32PLUS)) goto error; if (find_phdr(&ehdr, fd, &phdr, PT_LOAD)) goto error; - retval = read_program(fd, &phdr, addr); + retval = read_program(fd, &phdr, addr, ehdr.e_entry); if (retval < 0) goto error; @@ -245,17 +295,45 @@ int load_elf(const char * filename, uint8_t *addr) return -1; } -int load_kernel(const char *filename, uint8_t *addr) +int load_aout(const char *filename, uint8_t *addr) { - int fd, size; + int fd, size, ret; + struct exec e; + uint32_t magic; fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return -1; - /* load 32 bit code */ - size = read(fd, addr, 16 * 1024 * 1024); + + size = read(fd, &e, sizeof(e)); if (size < 0) goto fail; + + bswap_ahdr(&e); + + magic = N_MAGIC(e); + switch (magic) { + case ZMAGIC: + case QMAGIC: + case OMAGIC: + lseek(fd, N_TXTOFF(e), SEEK_SET); + size = read(fd, addr, e.a_text + e.a_data); + if (size < 0) + goto fail; + break; + case NMAGIC: + lseek(fd, N_TXTOFF(e), SEEK_SET); + size = read(fd, addr, e.a_text); + if (size < 0) + goto fail; + ret = read(fd, addr + N_DATADDR(e), e.a_data); + if (ret < 0) + goto fail; + size += ret; + break; + default: + goto fail; + } close(fd); return size; fail: @@ -263,64 +341,3 @@ int load_kernel(const char *filename, uint8_t *addr) return -1; } -typedef struct MAGICState { - uint32_t addr; - uint32_t saved_addr; - int magic_state; - char saved_kfn[1024]; -} MAGICState; - -static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr) -{ - int ret; - MAGICState *s = opaque; - - if (s->magic_state == 0) { - ret = load_elf(s->saved_kfn, (uint8_t *)s->saved_addr); - if (ret < 0) - ret = load_kernel(s->saved_kfn, (uint8_t *)s->saved_addr); - if (ret < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - s->saved_kfn); - } - s->magic_state = 1; /* No more magic */ - tb_flush(); - return bswap32(ret); - } - return 0; -} - -static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -} - - -static CPUReadMemoryFunc *magic_mem_read[3] = { - magic_mem_readl, - magic_mem_readl, - magic_mem_readl, -}; - -static CPUWriteMemoryFunc *magic_mem_write[3] = { - magic_mem_writel, - magic_mem_writel, - magic_mem_writel, -}; - -void magic_init(const char *kfn, int kloadaddr, uint32_t addr) -{ - int magic_io_memory; - MAGICState *s; - - s = qemu_mallocz(sizeof(MAGICState)); - if (!s) - return; - - strcpy(s->saved_kfn, kfn); - s->saved_addr = kloadaddr; - s->magic_state = 0; - s->addr = addr; - magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, s); - cpu_register_physical_memory(addr, 4, magic_io_memory); -} - diff --git a/hw/sched.c b/hw/sched.c deleted file mode 100644 index 2ab966de4c..0000000000 --- a/hw/sched.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * QEMU interrupt controller emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -//#define DEBUG_IRQ_COUNT - -/* These registers are used for sending/receiving irqs from/to - * different cpu's. - */ -struct sun4m_intreg_percpu { - unsigned int tbt; /* Intrs pending for this cpu, by PIL. */ - /* These next two registers are WRITE-ONLY and are only - * "on bit" sensitive, "off bits" written have NO affect. - */ - unsigned int clear; /* Clear this cpus irqs here. */ - unsigned int set; /* Set this cpus irqs here. */ -}; -/* - * djhr - * Actually the clear and set fields in this struct are misleading.. - * according to the SLAVIO manual (and the same applies for the SEC) - * the clear field clears bits in the mask which will ENABLE that IRQ - * the set field sets bits in the mask to DISABLE the IRQ. - * - * Also the undirected_xx address in the SLAVIO is defined as - * RESERVED and write only.. - * - * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor - * sun4m machines, for MP the layout makes more sense. - */ -struct sun4m_intreg_master { - unsigned int tbt; /* IRQ's that are pending, see sun4m masks. */ - unsigned int irqs; /* Master IRQ bits. */ - - /* Again, like the above, two these registers are WRITE-ONLY. */ - unsigned int clear; /* Clear master IRQ's by setting bits here. */ - unsigned int set; /* Set master IRQ's by setting bits here. */ - - /* This register is both READ and WRITE. */ - unsigned int undirected_target; /* Which cpu gets undirected irqs. */ -}; - -#define SUN4M_INT_ENABLE 0x80000000 -#define SUN4M_INT_E14 0x00000080 -#define SUN4M_INT_E10 0x00080000 - -#define SUN4M_HARD_INT(x) (0x000000001 << (x)) -#define SUN4M_SOFT_INT(x) (0x000010000 << (x)) - -#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ -#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ -#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ -#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ -#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ -#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ -#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ -#define SUN4M_INT_REALTIME 0x00080000 /* system timer */ -#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */ -#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */ -#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */ -#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ -#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ - -#define SUN4M_INT_SBUS(x) (1 << (x+7)) -#define SUN4M_INT_VME(x) (1 << (x)) - -typedef struct SCHEDState { - uint32_t addr, addrg; - uint32_t intreg_pending; - uint32_t intreg_enabled; - uint32_t intregm_pending; - uint32_t intregm_enabled; -} SCHEDState; - -static SCHEDState *ps; - -#ifdef DEBUG_IRQ_COUNT -static uint64_t irq_count[32]; -#endif - -static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - case 0: - return s->intreg_pending; - break; - default: - break; - } - return 0; -} - -static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - case 0: - s->intreg_pending = val; - break; - case 1: // clear - s->intreg_enabled &= ~val; - break; - case 2: // set - s->intreg_enabled |= val; - break; - default: - break; - } -} - -static CPUReadMemoryFunc *intreg_mem_read[3] = { - intreg_mem_readl, - intreg_mem_readl, - intreg_mem_readl, -}; - -static CPUWriteMemoryFunc *intreg_mem_write[3] = { - intreg_mem_writel, - intreg_mem_writel, - intreg_mem_writel, -}; - -static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addrg) >> 2; - switch (saddr) { - case 0: - return s->intregm_pending; - break; - case 1: - return s->intregm_enabled; - break; - default: - break; - } - return 0; -} - -static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addrg) >> 2; - switch (saddr) { - case 0: - s->intregm_pending = val; - break; - case 1: - s->intregm_enabled = val; - break; - case 2: // clear - s->intregm_enabled &= ~val; - break; - case 3: // set - s->intregm_enabled |= val; - break; - default: - break; - } -} - -static CPUReadMemoryFunc *intregm_mem_read[3] = { - intregm_mem_readl, - intregm_mem_readl, - intregm_mem_readl, -}; - -static CPUWriteMemoryFunc *intregm_mem_write[3] = { - intregm_mem_writel, - intregm_mem_writel, - intregm_mem_writel, -}; - -void pic_info(void) -{ - term_printf("per-cpu: pending 0x%08x, enabled 0x%08x\n", ps->intreg_pending, ps->intreg_enabled); - term_printf("master: pending 0x%08x, enabled 0x%08x\n", ps->intregm_pending, ps->intregm_enabled); -} - -void irq_info(void) -{ -#ifndef DEBUG_IRQ_COUNT - term_printf("irq statistic code not compiled.\n"); -#else - int i; - int64_t count; - - term_printf("IRQ statistics:\n"); - for (i = 0; i < 32; i++) { - count = irq_count[i]; - if (count > 0) - term_printf("%2d: %lld\n", i, count); - } -#endif -} - -static const unsigned int intr_to_mask[16] = { - 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -void pic_set_irq(int irq, int level) -{ - if (irq < 16) { - unsigned int mask = intr_to_mask[irq]; - ps->intreg_pending |= 1 << irq; - if (ps->intregm_enabled & mask) { - cpu_single_env->interrupt_index = irq; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); - } - } -#ifdef DEBUG_IRQ_COUNT - if (level == 1) - irq_count[irq]++; -#endif -} - -void sched_init(uint32_t addr, uint32_t addrg) -{ - int intreg_io_memory, intregm_io_memory; - SCHEDState *s; - - s = qemu_mallocz(sizeof(SCHEDState)); - if (!s) - return; - s->addr = addr; - s->addrg = addrg; - - intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s); - cpu_register_physical_memory(addr, 3, intreg_io_memory); - - intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s); - cpu_register_physical_memory(addrg, 5, intregm_io_memory); - - ps = s; -} - diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c new file mode 100644 index 0000000000..745467214b --- /dev/null +++ b/hw/slavio_intctl.c @@ -0,0 +1,299 @@ +/* + * QEMU Sparc SLAVIO interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +//#define DEBUG_IRQ_COUNT + +/* + * Registers of interrupt controller in sun4m. + * + * This is the interrupt controller part of chip STP2001 (Slave I/O), also + * produced as NCR89C105. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt + * + * There is a system master controller and one for each cpu. + * + */ + +#define MAX_CPUS 16 + +typedef struct SLAVIO_INTCTLState { + uint32_t intreg_pending[MAX_CPUS]; + uint32_t intregm_pending; + uint32_t intregm_disabled; + uint32_t target_cpu; +#ifdef DEBUG_IRQ_COUNT + uint64_t irq_count[32]; +#endif +} SLAVIO_INTCTLState; + +#define INTCTL_MAXADDR 0xf +#define INTCTLM_MAXADDR 0xf + +// per-cpu interrupt controller +static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + int cpu; + + cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; + saddr = (addr & INTCTL_MAXADDR) >> 2; + switch (saddr) { + case 0: + return s->intreg_pending[cpu]; + default: + break; + } + return 0; +} + +static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + int cpu; + + cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; + saddr = (addr & INTCTL_MAXADDR) >> 2; + switch (saddr) { + case 1: // clear pending softints + if (val & 0x4000) + val |= 80000000; + val &= 0xfffe0000; + s->intreg_pending[cpu] &= ~val; + break; + case 2: // set softint + val &= 0xfffe0000; + s->intreg_pending[cpu] |= val; + break; + default: + break; + } +} + +static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = { + slavio_intctl_mem_readl, + slavio_intctl_mem_readl, + slavio_intctl_mem_readl, +}; + +static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = { + slavio_intctl_mem_writel, + slavio_intctl_mem_writel, + slavio_intctl_mem_writel, +}; + +// master system interrupt controller +static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + + saddr = (addr & INTCTLM_MAXADDR) >> 2; + switch (saddr) { + case 0: + return s->intregm_pending; + case 1: + return s->intregm_disabled; + case 4: + return s->target_cpu; + default: + break; + } + return 0; +} + +static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + + saddr = (addr & INTCTLM_MAXADDR) >> 2; + switch (saddr) { + case 2: // clear (enable) + // Force unused bits + val |= 0x7fb2007f; + s->intregm_disabled &= ~val; + break; + case 3: // set (disable, clear pending) + // Force unused bits + val &= ~0x7fb2007f; + s->intregm_disabled |= val; + s->intregm_pending &= ~val; + break; + case 4: + s->target_cpu = val & (MAX_CPUS - 1); + break; + default: + break; + } +} + +static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = { + slavio_intctlm_mem_readl, + slavio_intctlm_mem_readl, + slavio_intctlm_mem_readl, +}; + +static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = { + slavio_intctlm_mem_writel, + slavio_intctlm_mem_writel, + slavio_intctlm_mem_writel, +}; + +void slavio_pic_info(void *opaque) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + for (i = 0; i < MAX_CPUS; i++) { + term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]); + } + term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled); +} + +void slavio_irq_info(void *opaque) +{ +#ifndef DEBUG_IRQ_COUNT + term_printf("irq statistic code not compiled.\n"); +#else + SLAVIO_INTCTLState *s = opaque; + int i; + int64_t count; + + term_printf("IRQ statistics:\n"); + for (i = 0; i < 32; i++) { + count = s->irq_count[i]; + if (count > 0) + term_printf("%2d: %lld\n", i, count); + } +#endif +} + +static const uint32_t intbit_to_level[32] = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0, +}; + +/* + * "irq" here is the bit number in the system interrupt register to + * separate serial and keyboard interrupts sharing a level. + */ +void slavio_pic_set_irq(void *opaque, int irq, int level) +{ + SLAVIO_INTCTLState *s = opaque; + + if (irq < 32) { + uint32_t mask = 1 << irq; + uint32_t pil = intbit_to_level[irq]; + if (pil > 0) { + if (level) { + s->intregm_pending |= mask; + s->intreg_pending[s->target_cpu] |= 1 << pil; + } + else { + s->intregm_pending &= ~mask; + s->intreg_pending[s->target_cpu] &= ~(1 << pil); + } + if (level && + !(s->intregm_disabled & mask) && + !(s->intregm_disabled & 0x80000000) && + (pil == 15 || (pil > cpu_single_env->psrpil && cpu_single_env->psret == 1))) { +#ifdef DEBUG_IRQ_COUNT + if (level == 1) + s->irq_count[pil]++; +#endif + cpu_single_env->interrupt_index = TT_EXTINT | pil; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } + } + } +} + +static void slavio_intctl_save(QEMUFile *f, void *opaque) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + for (i = 0; i < MAX_CPUS; i++) { + qemu_put_be32s(f, &s->intreg_pending[i]); + } + qemu_put_be32s(f, &s->intregm_pending); + qemu_put_be32s(f, &s->intregm_disabled); + qemu_put_be32s(f, &s->target_cpu); +} + +static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + for (i = 0; i < MAX_CPUS; i++) { + qemu_get_be32s(f, &s->intreg_pending[i]); + } + qemu_get_be32s(f, &s->intregm_pending); + qemu_get_be32s(f, &s->intregm_disabled); + qemu_get_be32s(f, &s->target_cpu); + return 0; +} + +static void slavio_intctl_reset(void *opaque) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + for (i = 0; i < MAX_CPUS; i++) { + s->intreg_pending[i] = 0; + } + s->intregm_disabled = 0xffffffff; + s->intregm_pending = 0; + s->target_cpu = 0; +} + +void *slavio_intctl_init(uint32_t addr, uint32_t addrg) +{ + int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; + SLAVIO_INTCTLState *s; + + s = qemu_mallocz(sizeof(SLAVIO_INTCTLState)); + if (!s) + return NULL; + + for (i = 0; i < MAX_CPUS; i++) { + slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); + cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory); + } + + slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); + cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory); + + register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s); + qemu_register_reset(slavio_intctl_reset, s); + slavio_intctl_reset(s); + return s; +} + diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c new file mode 100644 index 0000000000..348f328f5a --- /dev/null +++ b/hw/slavio_serial.c @@ -0,0 +1,364 @@ +/* + * QEMU Sparc SLAVIO serial port emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG_SERIAL + +/* debug keyboard */ +//#define DEBUG_KBD + +/* debug keyboard : only mouse */ +//#define DEBUG_MOUSE + +/* + * This is the serial port, mouse and keyboard part of chip STP2001 + * (Slave I/O), also produced as NCR89C105. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt + * + * The serial ports implement full AMD AM8530 or Zilog Z8530 chips, + * mouse and keyboard ports don't implement all functions and they are + * only asynchronous. There is no DMA. + * + */ + +typedef struct ChannelState { + int irq; + int reg; + int rxint, txint; + uint8_t rx, tx, wregs[16], rregs[16]; + CharDriverState *chr; +} ChannelState; + +struct SerialState { + struct ChannelState chn[2]; +}; + +#define SERIAL_MAXADDR 7 + +static void slavio_serial_update_irq(ChannelState *s) +{ + if ((s->wregs[1] & 1) && // interrupts enabled + (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending + ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && + s->rxint == 1) || // rx ints enabled, pending + ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p + pic_set_irq(s->irq, 1); + } else { + pic_set_irq(s->irq, 0); + } +} + +static void slavio_serial_reset_chn(ChannelState *s) +{ + int i; + + s->reg = 0; + for (i = 0; i < SERIAL_MAXADDR; i++) { + s->rregs[i] = 0; + s->wregs[i] = 0; + } + s->wregs[4] = 4; + s->wregs[9] = 0xc0; + s->wregs[11] = 8; + s->wregs[14] = 0x30; + s->wregs[15] = 0xf8; + s->rregs[0] = 0x44; + s->rregs[1] = 6; + + s->rx = s->tx = 0; + s->rxint = s->txint = 0; +} + +static void slavio_serial_reset(void *opaque) +{ + SerialState *s = opaque; + slavio_serial_reset_chn(&s->chn[0]); + slavio_serial_reset_chn(&s->chn[1]); +} + +static void slavio_serial_mem_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + SerialState *ser = opaque; + ChannelState *s; + uint32_t saddr; + int newreg, channel; + + val &= 0xff; + saddr = (addr & 3) >> 1; + channel = (addr & SERIAL_MAXADDR) >> 2; + s = &ser->chn[channel]; + switch (saddr) { + case 0: + newreg = 0; + switch (s->reg) { + case 0: + newreg = val & 7; + val &= 0x38; + switch (val) { + case 8: + s->reg |= 0x8; + break; + case 0x20: + s->rxint = 0; + break; + case 0x28: + s->txint = 0; + break; + default: + break; + } + break; + case 1 ... 8: + case 10 ... 15: + s->wregs[s->reg] = val; + break; + case 9: + switch (val & 0xc0) { + case 0: + default: + break; + case 0x40: + slavio_serial_reset_chn(&ser->chn[1]); + return; + case 0x80: + slavio_serial_reset_chn(&ser->chn[0]); + return; + case 0xc0: + slavio_serial_reset(ser); + return; + } + break; + default: + break; + } + if (s->reg == 0) + s->reg = newreg; + else + s->reg = 0; + break; + case 1: + if (s->wregs[5] & 8) { // tx enabled + s->tx = val; + if (s->chr) + qemu_chr_write(s->chr, &s->tx, 1); + s->txint = 1; + } + break; + default: + break; + } +} + +static uint32_t slavio_serial_mem_readb(void *opaque, uint32_t addr) +{ + SerialState *ser = opaque; + ChannelState *s; + uint32_t saddr; + uint32_t ret; + int channel; + + saddr = (addr & 3) >> 1; + channel = (addr & SERIAL_MAXADDR) >> 2; + s = &ser->chn[channel]; + switch (saddr) { + case 0: + ret = s->rregs[s->reg]; + s->reg = 0; + return ret; + case 1: + s->rregs[0] &= ~1; + return s->rx; + default: + break; + } + return 0; +} + +static int serial_can_receive(void *opaque) +{ + ChannelState *s = opaque; + if (((s->wregs[3] & 1) == 0) // Rx not enabled + || ((s->rregs[0] & 1) == 1)) // char already available + return 0; + else + return 1; +} + +static void serial_receive_byte(ChannelState *s, int ch) +{ + s->rregs[0] |= 1; + s->rx = ch; + s->rxint = 1; + slavio_serial_update_irq(s); +} + +static void serial_receive_break(ChannelState *s) +{ + s->rregs[0] |= 0x80; + slavio_serial_update_irq(s); +} + +static void serial_receive1(void *opaque, const uint8_t *buf, int size) +{ + ChannelState *s = opaque; + serial_receive_byte(s, buf[0]); +} + +static void serial_event(void *opaque, int event) +{ + ChannelState *s = opaque; + if (event == CHR_EVENT_BREAK) + serial_receive_break(s); +} + +static CPUReadMemoryFunc *slavio_serial_mem_read[3] = { + slavio_serial_mem_readb, + slavio_serial_mem_readb, + slavio_serial_mem_readb, +}; + +static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = { + slavio_serial_mem_writeb, + slavio_serial_mem_writeb, + slavio_serial_mem_writeb, +}; + +static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) +{ + qemu_put_be32s(f, &s->irq); + qemu_put_be32s(f, &s->reg); + qemu_put_be32s(f, &s->rxint); + qemu_put_be32s(f, &s->txint); + qemu_put_8s(f, &s->rx); + qemu_put_8s(f, &s->tx); + qemu_put_buffer(f, s->wregs, 16); + qemu_put_buffer(f, s->rregs, 16); +} + +static void slavio_serial_save(QEMUFile *f, void *opaque) +{ + SerialState *s = opaque; + + slavio_serial_save_chn(f, &s->chn[0]); + slavio_serial_save_chn(f, &s->chn[1]); +} + +static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) +{ + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->irq); + qemu_get_be32s(f, &s->reg); + qemu_get_be32s(f, &s->rxint); + qemu_get_be32s(f, &s->txint); + qemu_get_8s(f, &s->rx); + qemu_get_8s(f, &s->tx); + qemu_get_buffer(f, s->wregs, 16); + qemu_get_buffer(f, s->rregs, 16); + return 0; +} + +static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) +{ + SerialState *s = opaque; + int ret; + + ret = slavio_serial_load_chn(f, &s->chn[0], version_id); + if (ret != 0) + return ret; + ret = slavio_serial_load_chn(f, &s->chn[1], version_id); + return ret; + +} + +SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2) +{ + int slavio_serial_io_memory; + SerialState *s; + + s = qemu_mallocz(sizeof(SerialState)); + if (!s) + return NULL; + s->chn[0].irq = irq; + s->chn[1].irq = irq; + s->chn[0].chr = chr1; + s->chn[1].chr = chr2; + + slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); + cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); + + if (chr1) { + qemu_chr_add_read_handler(chr1, serial_can_receive, serial_receive1, &s->chn[0]); + qemu_chr_add_event_handler(chr1, serial_event); + } + if (chr2) { + qemu_chr_add_read_handler(chr2, serial_can_receive, serial_receive1, &s->chn[1]); + qemu_chr_add_event_handler(chr2, serial_event); + } + register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s); + qemu_register_reset(slavio_serial_reset, s); + slavio_serial_reset(s); + return s; +} + +static void sunkbd_event(void *opaque, int ch) +{ + ChannelState *s = opaque; + // XXX: PC -> Sun Type 5 translation? + serial_receive_byte(s, ch); +} + +static void sunmouse_event(void *opaque, + int dx, int dy, int dz, int buttons_state) +{ + ChannelState *s = opaque; + int ch; + + // XXX + ch = 0x42; + serial_receive_byte(s, ch); +} + +void slavio_serial_ms_kbd_init(int base, int irq) +{ + int slavio_serial_io_memory; + SerialState *s; + + s = qemu_mallocz(sizeof(SerialState)); + if (!s) + return; + s->chn[0].irq = irq; + s->chn[1].irq = irq; + s->chn[0].chr = NULL; + s->chn[1].chr = NULL; + + slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); + cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); + + qemu_add_kbd_event_handler(sunkbd_event, &s->chn[0]); + qemu_add_mouse_event_handler(sunmouse_event, &s->chn[1]); + qemu_register_reset(slavio_serial_reset, s); + slavio_serial_reset(s); +} diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c new file mode 100644 index 0000000000..43f59d2750 --- /dev/null +++ b/hw/slavio_timer.c @@ -0,0 +1,289 @@ +/* + * QEMU Sparc SLAVIO timer controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG_TIMER + +/* + * Registers of hardware timer in sun4m. + * + * This is the timer/counter part of chip STP2001 (Slave I/O), also + * produced as NCR89C105. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt + * + * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 + * are zero. Bit 31 is 1 when count has been reached. + * + */ + +typedef struct SLAVIO_TIMERState { + uint32_t limit, count, counthigh; + int64_t count_load_time; + int64_t expire_time; + int64_t stop_time, tick_offset; + QEMUTimer *irq_timer; + int irq; + int reached, stopped; + int mode; // 0 = processor, 1 = user, 2 = system +} SLAVIO_TIMERState; + +#define TIMER_MAXADDR 0x1f +#define CNT_FREQ 2000000 +#define MAX_CPUS 16 + +// Update count, set irq, update expire_time +static void slavio_timer_get_out(SLAVIO_TIMERState *s) +{ + int out; + int64_t diff, ticks, count; + uint32_t limit; + + // There are three clock tick units: CPU ticks, register units + // (nanoseconds), and counter ticks (500 ns). + if (s->mode == 1 && s->stopped) + ticks = s->stop_time; + else + ticks = qemu_get_clock(vm_clock) - s->tick_offset; + + out = (ticks >= s->expire_time); + if (out) + s->reached = 0x80000000; + if (!s->limit) + limit = 0x7fffffff; + else + limit = s->limit; + + // Convert register units to counter ticks + limit = limit >> 9; + + // Convert cpu ticks to counter ticks + diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec); + + // Calculate what the counter should be, convert to register + // units + count = diff % limit; + s->count = count << 9; + s->counthigh = count >> 22; + + // Expire time: CPU ticks left to next interrupt + // Convert remaining counter ticks to CPU ticks + s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ); + +#ifdef DEBUG_TIMER + term_printf("timer: irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); +#endif + if (s->mode != 1) + pic_set_irq(s->irq, out); +} + +// timer callback +static void slavio_timer_irq(void *opaque) +{ + SLAVIO_TIMERState *s = opaque; + + if (!s->irq_timer) + return; + slavio_timer_get_out(s); + if (s->mode != 1) + qemu_mod_timer(s->irq_timer, s->expire_time); +} + +static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SLAVIO_TIMERState *s = opaque; + uint32_t saddr; + + saddr = (addr & TIMER_MAXADDR) >> 2; + switch (saddr) { + case 0: + // read limit (system counter mode) or read most signifying + // part of counter (user mode) + if (s->mode != 1) { + // clear irq + pic_set_irq(s->irq, 0); + s->count_load_time = qemu_get_clock(vm_clock); + s->reached = 0; + return s->limit; + } + else { + slavio_timer_get_out(s); + return s->counthigh & 0x7fffffff; + } + case 1: + // read counter and reached bit (system mode) or read lsbits + // of counter (user mode) + slavio_timer_get_out(s); + if (s->mode != 1) + return (s->count & 0x7fffffff) | s->reached; + else + return s->count; + case 3: + // read start/stop status + return s->stopped; + case 4: + // read user/system mode + return s->mode & 1; + default: + return 0; + } +} + +static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SLAVIO_TIMERState *s = opaque; + uint32_t saddr; + + saddr = (addr & TIMER_MAXADDR) >> 2; + switch (saddr) { + case 0: + // set limit, reset counter + s->count_load_time = qemu_get_clock(vm_clock); + // fall through + case 2: + // set limit without resetting counter + if (!val) + s->limit = 0x7fffffff; + else + s->limit = val & 0x7fffffff; + slavio_timer_irq(s); + break; + case 3: + // start/stop user counter + if (s->mode == 1) { + if (val & 1) { + s->stop_time = qemu_get_clock(vm_clock); + s->stopped = 1; + } + else { + if (s->stopped) + s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time; + s->stopped = 0; + } + } + break; + case 4: + // bit 0: user (1) or system (0) counter mode + if (s->mode == 0 || s->mode == 1) + s->mode = val & 1; + break; + default: + break; + } +} + +static CPUReadMemoryFunc *slavio_timer_mem_read[3] = { + slavio_timer_mem_readl, + slavio_timer_mem_readl, + slavio_timer_mem_readl, +}; + +static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = { + slavio_timer_mem_writel, + slavio_timer_mem_writel, + slavio_timer_mem_writel, +}; + +static void slavio_timer_save(QEMUFile *f, void *opaque) +{ + SLAVIO_TIMERState *s = opaque; + + qemu_put_be32s(f, &s->limit); + qemu_put_be32s(f, &s->count); + qemu_put_be32s(f, &s->counthigh); + qemu_put_be64s(f, &s->count_load_time); + qemu_put_be64s(f, &s->expire_time); + qemu_put_be64s(f, &s->stop_time); + qemu_put_be64s(f, &s->tick_offset); + qemu_put_be32s(f, &s->irq); + qemu_put_be32s(f, &s->reached); + qemu_put_be32s(f, &s->stopped); + qemu_put_be32s(f, &s->mode); +} + +static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) +{ + SLAVIO_TIMERState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->limit); + qemu_get_be32s(f, &s->count); + qemu_get_be32s(f, &s->counthigh); + qemu_get_be64s(f, &s->count_load_time); + qemu_get_be64s(f, &s->expire_time); + qemu_get_be64s(f, &s->stop_time); + qemu_get_be64s(f, &s->tick_offset); + qemu_get_be32s(f, &s->irq); + qemu_get_be32s(f, &s->reached); + qemu_get_be32s(f, &s->stopped); + qemu_get_be32s(f, &s->mode); + return 0; +} + +static void slavio_timer_reset(void *opaque) +{ + SLAVIO_TIMERState *s = opaque; + + s->limit = 0; + s->count = 0; + s->count_load_time = qemu_get_clock(vm_clock);; + s->stop_time = s->count_load_time; + s->tick_offset = 0; + s->reached = 0; + s->mode &= 2; + s->stopped = 1; + slavio_timer_get_out(s); +} + +static void slavio_timer_init_internal(uint32_t addr, int irq, int mode) +{ + int slavio_timer_io_memory; + SLAVIO_TIMERState *s; + + s = qemu_mallocz(sizeof(SLAVIO_TIMERState)); + if (!s) + return; + s->irq = irq; + s->mode = mode; + s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s); + + slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, + slavio_timer_mem_write, s); + cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory); + register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s); + qemu_register_reset(slavio_timer_reset, s); + slavio_timer_reset(s); +} + +void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2) +{ + int i; + + for (i = 0; i < MAX_CPUS; i++) { + slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0); + } + + slavio_timer_init_internal(addr2, irq2, 2); +} diff --git a/hw/sun4m.c b/hw/sun4m.c index 80305e09c3..7cc5bd8d9c 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -25,29 +25,32 @@ #include "m48t08.h" #define KERNEL_LOAD_ADDR 0x00004000 -#define MMU_CONTEXT_TBL 0x00003000 -#define MMU_L1PTP (MMU_CONTEXT_TBL + 0x0400) -#define MMU_L2PTP (MMU_CONTEXT_TBL + 0x0800) -#define PROM_ADDR 0xffd04000 +#define PROM_ADDR 0xffd00000 #define PROM_FILENAMEB "proll.bin" #define PROM_FILENAMEE "proll.elf" -#define PROLL_MAGIC_ADDR 0x20000000 -#define PHYS_JJ_EEPROM 0x71200000 /* [2000] MK48T08 */ +#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */ #define PHYS_JJ_IDPROM_OFF 0x1FD8 #define PHYS_JJ_EEPROM_SIZE 0x2000 -#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ +// IRQs are not PIL ones, but master interrupt controller register +// bits +#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */ #define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */ -#define PHYS_JJ_TCX_0E 0x5E000000 /* Top address, one byte used. */ -#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ -#define PHYS_JJ_LEDMA 0x78400010 /* ledma, off by 10 from unused SCSI */ -#define PHYS_JJ_LE 0x78C00000 /* LANCE, typical sun4m */ -#define PHYS_JJ_LE_IRQ 6 -#define PHYS_JJ_CLOCK 0x71D00000 -#define PHYS_JJ_CLOCK_IRQ 10 -#define PHYS_JJ_CLOCK1 0x71D10000 -#define PHYS_JJ_CLOCK1_IRQ 14 -#define PHYS_JJ_INTR0 0x71E00000 /* CPU0 interrupt control registers */ +#define PHYS_JJ_LEDMA 0x78400010 /* Lance DMA controller */ +#define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */ +#define PHYS_JJ_LE_IRQ 16 +#define PHYS_JJ_CLOCK 0x71D00000 /* Per-CPU timer/counter, L14 */ +#define PHYS_JJ_CLOCK_IRQ 7 +#define PHYS_JJ_CLOCK1 0x71D10000 /* System timer/counter, L10 */ +#define PHYS_JJ_CLOCK1_IRQ 19 +#define PHYS_JJ_INTR0 0x71E00000 /* Per-CPU interrupt control registers */ #define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */ +#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */ +#define PHYS_JJ_MS_KBD_IRQ 14 +#define PHYS_JJ_SER 0x71100000 /* Serial */ +#define PHYS_JJ_SER_IRQ 15 +#define PHYS_JJ_SCSI_IRQ 18 +#define PHYS_JJ_FDC 0x71400000 /* Floppy */ +#define PHYS_JJ_FLOPPY_IRQ 22 /* TSC handling */ @@ -57,13 +60,73 @@ uint64_t cpu_get_tsc() } void DMA_run() {} -void SB16_run() {} -int serial_can_receive(SerialState *s) { return 0; } -void serial_receive_byte(SerialState *s, int ch) {} -void serial_receive_break(SerialState *s) {} static m48t08_t *nvram; +static void nvram_init(m48t08_t *nvram, uint8_t *macaddr) +{ + unsigned char tmp = 0; + int i, j; + + i = 0x1fd8; + m48t08_write(nvram, i++, 0x01); + m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */ + j = 0; + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i, macaddr[j]); + + /* Calculate checksum */ + for (i = 0x1fd8; i < 0x1fe7; i++) { + tmp ^= m48t08_read(nvram, i); + } + m48t08_write(nvram, 0x1fe7, tmp); +} + +static void *slavio_intctl; + +void pic_info() +{ + slavio_pic_info(slavio_intctl); +} + +void irq_info() +{ + slavio_irq_info(slavio_intctl); +} + +void pic_set_irq(int irq, int level) +{ + slavio_pic_set_irq(slavio_intctl, irq, level); +} + +static void *tcx; + +void vga_update_display() +{ + tcx_update_display(tcx); +} + +void vga_invalidate_display() +{ + tcx_invalidate_display(tcx); +} + +void vga_screen_dump(const char *filename) +{ + tcx_screen_dump(tcx, filename); +} + +static void *iommu; + +uint32_t iommu_translate(uint32_t addr) +{ + return iommu_translate_local(iommu, addr); +} + /* Sun4m hardware initialisation */ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -72,42 +135,50 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, { char buf[1024]; int ret, linux_boot; - unsigned long bios_offset; + unsigned long vram_size = 0x100000, prom_offset; linux_boot = (kernel_filename != NULL); /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); - bios_offset = ram_size; - iommu_init(PHYS_JJ_IOMMU); - sched_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); - tcx_init(ds, PHYS_JJ_TCX_FB); + iommu = iommu_init(PHYS_JJ_IOMMU); + slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); + tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size); lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); - nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE, &nd_table[0].macaddr); - timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ); - timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); - magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR, PROLL_MAGIC_ADDR); + nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr); + slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); + slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ); + slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[0], serial_hds[1]); + fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); - /* We load Proll as the kernel and start it. It will issue a magic - IO to load the real kernel */ - if (linux_boot) { + prom_offset = ram_size + vram_size; + + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); + ret = load_elf(buf, phys_ram_base + prom_offset); + if (ret < 0) { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); - ret = load_kernel(buf, - phys_ram_base + KERNEL_LOAD_ADDR); + ret = load_image(buf, phys_ram_base + prom_offset); + } + if (ret < 0) { + fprintf(stderr, "qemu: could not load prom '%s'\n", + buf); + exit(1); + } + cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, + prom_offset | IO_MEM_ROM); + + if (linux_boot) { + ret = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (ret < 0) + ret = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (ret < 0) + ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (ret < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", - buf); - exit(1); + kernel_filename); + exit(1); } } - /* Setup a MMU entry for entire address space */ - stl_raw(phys_ram_base + MMU_CONTEXT_TBL, (MMU_L1PTP >> 4) | 1); - stl_raw(phys_ram_base + MMU_L1PTP, (MMU_L2PTP >> 4) | 1); - stl_raw(phys_ram_base + MMU_L1PTP + (0x01 << 2), (MMU_L2PTP >> 4) | 1); // 01.. == 00.. - stl_raw(phys_ram_base + MMU_L1PTP + (0xff << 2), (MMU_L2PTP >> 4) | 1); // ff.. == 00.. - stl_raw(phys_ram_base + MMU_L1PTP + (0xf0 << 2), (MMU_L2PTP >> 4) | 1); // f0.. == 00.. - /* 3 = U:RWX S:RWX */ - stl_raw(phys_ram_base + MMU_L2PTP, (3 << PTE_ACCESS_SHIFT) | 2); - stl_raw(phys_ram_base + MMU_L2PTP, ((0x01 << PTE_PPN_SHIFT) >> 4 ) | (3 << PTE_ACCESS_SHIFT) | 2); } @@ -25,179 +25,254 @@ #define MAXX 1024 #define MAXY 768 +/* + * Proll uses only small part of display, we need to switch to full + * display when we get linux framebuffer console or X11 running. For + * now it's just slower and awkward. +*/ +#if 1 #define XSZ (8*80) #define YSZ (24*11) #define XOFF (MAXX-XSZ) #define YOFF (MAXY-YSZ) +#else +#define XSZ MAXX +#define YSZ MAXY +#define XOFF 0 +#define YOFF 0 +#endif typedef struct TCXState { uint32_t addr; DisplayState *ds; uint8_t *vram; + unsigned long vram_offset; + uint8_t r[256], g[256], b[256]; } TCXState; -static TCXState *ts; - -void vga_update_display() +static void tcx_draw_line32(TCXState *s1, uint8_t *d, + const uint8_t *s, int width) { - dpy_update(ts->ds, 0, 0, XSZ, YSZ); + int x; + uint8_t val; + + for(x = 0; x < width; x++) { + val = *s++; + *d++ = s1->r[val]; + *d++ = s1->g[val]; + *d++ = s1->b[val]; + d++; + } } -void vga_invalidate_display() {} +static void tcx_draw_line24(TCXState *s1, uint8_t *d, + const uint8_t *s, int width) +{ + int x; + uint8_t val; -static uint32_t tcx_mem_readb(void *opaque, target_phys_addr_t addr) + for(x = 0; x < width; x++) { + val = *s++; + *d++ = s1->r[val]; + *d++ = s1->g[val]; + *d++ = s1->b[val]; + } +} + +static void tcx_draw_line8(TCXState *s1, uint8_t *d, + const uint8_t *s, int width) { - TCXState *s = opaque; - uint32_t saddr; - unsigned int x, y; - - saddr = addr - s->addr - YOFF*MAXX - XOFF; - y = saddr / MAXX; - x = saddr - y * MAXX; - if (x < XSZ && y < YSZ) { - return s->vram[y * XSZ + x]; + int x; + uint8_t val; + + for(x = 0; x < width; x++) { + val = *s++; + /* XXX translate between palettes? */ + *d++ = val; } - return 0; } -static uint32_t tcx_mem_readw(void *opaque, target_phys_addr_t addr) +/* Fixed line length 1024 allows us to do nice tricks not possible on + VGA... */ +void tcx_update_display(void *opaque) { - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = tcx_mem_readb(opaque, addr) << 8; - v |= tcx_mem_readb(opaque, addr + 1); + TCXState *ts = opaque; + uint32_t page; + int y, page_min, page_max, y_start, dd, ds; + uint8_t *d, *s; + void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width); + + if (ts->ds->depth == 0) + return; +#ifdef LD_BYPASS_OK + page = ts->vram_offset + YOFF*MAXX; #else - v = tcx_mem_readb(opaque, addr); - v |= tcx_mem_readb(opaque, addr + 1) << 8; + page = ts->addr + YOFF*MAXX; #endif - return v; + y_start = -1; + page_min = 0x7fffffff; + page_max = -1; + d = ts->ds->data; + s = ts->vram + YOFF*MAXX + XOFF; + dd = ts->ds->linesize; + ds = 1024; + + switch (ts->ds->depth) { + case 32: + f = tcx_draw_line32; + break; + case 24: + f = tcx_draw_line24; + break; + default: + case 8: + f = tcx_draw_line8; + break; + case 0: + return; + } + + for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) { + if (cpu_physical_memory_is_dirty(page)) { + if (y_start < 0) + y_start = y; + if (page < page_min) + page_min = page; + if (page > page_max) + page_max = page; + f(ts, d, s, XSZ); + d += dd; + s += ds; + f(ts, d, s, XSZ); + d += dd; + s += ds; + f(ts, d, s, XSZ); + d += dd; + s += ds; + f(ts, d, s, XSZ); + d += dd; + s += ds; + } else { + if (y_start >= 0) { + /* flush to display */ + dpy_update(ts->ds, 0, y_start, + XSZ, y - y_start); + y_start = -1; + } + d += dd * 4; + s += ds * 4; + } + } + if (y_start >= 0) { + /* flush to display */ + dpy_update(ts->ds, 0, y_start, + XSZ, y - y_start); + } + /* reset modified pages */ + if (page_max != -1) { + cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE); + } } -static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr) +void tcx_invalidate_display(void *opaque) { - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = tcx_mem_readb(opaque, addr) << 24; - v |= tcx_mem_readb(opaque, addr + 1) << 16; - v |= tcx_mem_readb(opaque, addr + 2) << 8; - v |= tcx_mem_readb(opaque, addr + 3); + TCXState *s = opaque; + int i; + + for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) { +#ifdef LD_BYPASS_OK + cpu_physical_memory_set_dirty(s->vram_offset + i); #else - v = tcx_mem_readb(opaque, addr); - v |= tcx_mem_readb(opaque, addr + 1) << 8; - v |= tcx_mem_readb(opaque, addr + 2) << 16; - v |= tcx_mem_readb(opaque, addr + 3) << 24; + cpu_physical_memory_set_dirty(s->addr + i); #endif - return v; + } } -static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void tcx_save(QEMUFile *f, void *opaque) { TCXState *s = opaque; - uint32_t saddr; - unsigned int x, y; - char *sptr; - - saddr = addr - s->addr - YOFF*MAXX - XOFF; - y = saddr / MAXX; - x = saddr - y * MAXX; - if (x < XSZ && y < YSZ) { - sptr = s->ds->data; - if (sptr) { - if (s->ds->depth == 24 || s->ds->depth == 32) { - /* XXX need to do CLUT translation */ - sptr[y * s->ds->linesize + x*4] = val & 0xff; - sptr[y * s->ds->linesize + x*4+1] = val & 0xff; - sptr[y * s->ds->linesize + x*4+2] = val & 0xff; - } - else if (s->ds->depth == 8) { - sptr[y * s->ds->linesize + x] = val & 0xff; - } - } - cpu_physical_memory_set_dirty(addr); - s->vram[y * XSZ + x] = val & 0xff; - } + + qemu_put_be32s(f, (uint32_t *)&s->addr); + qemu_put_be32s(f, (uint32_t *)&s->vram); + qemu_put_buffer(f, s->r, 256); + qemu_put_buffer(f, s->g, 256); + qemu_put_buffer(f, s->b, 256); } -static void tcx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static int tcx_load(QEMUFile *f, void *opaque, int version_id) { -#ifdef TARGET_WORDS_BIGENDIAN - tcx_mem_writeb(opaque, addr, (val >> 8) & 0xff); - tcx_mem_writeb(opaque, addr + 1, val & 0xff); -#else - tcx_mem_writeb(opaque, addr, val & 0xff); - tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif + TCXState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, (uint32_t *)&s->addr); + qemu_get_be32s(f, (uint32_t *)&s->vram); + qemu_get_buffer(f, s->r, 256); + qemu_get_buffer(f, s->g, 256); + qemu_get_buffer(f, s->b, 256); + return 0; } -static void tcx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void tcx_reset(void *opaque) { -#ifdef TARGET_WORDS_BIGENDIAN - tcx_mem_writeb(opaque, addr, (val >> 24) & 0xff); - tcx_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff); - tcx_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff); - tcx_mem_writeb(opaque, addr + 3, val & 0xff); -#else - tcx_mem_writeb(opaque, addr, val & 0xff); - tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); - tcx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); - tcx_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); + TCXState *s = opaque; + + /* Initialize palette */ + memset(s->r, 0, 256); + memset(s->g, 0, 256); + memset(s->b, 0, 256); + s->r[255] = s->g[255] = s->b[255] = 255; + memset(s->vram, 0, MAXX*MAXY); +#ifdef LD_BYPASS_OK + cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY - 1); #endif } -static CPUReadMemoryFunc *tcx_mem_read[3] = { - tcx_mem_readb, - tcx_mem_readw, - tcx_mem_readl, -}; - -static CPUWriteMemoryFunc *tcx_mem_write[3] = { - tcx_mem_writeb, - tcx_mem_writew, - tcx_mem_writel, -}; - -void tcx_init(DisplayState *ds, uint32_t addr) +void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, + unsigned long vram_offset, int vram_size) { TCXState *s; - int tcx_io_memory; s = qemu_mallocz(sizeof(TCXState)); if (!s) - return; + return NULL; s->ds = ds; s->addr = addr; - ts = s; - tcx_io_memory = cpu_register_io_memory(0, tcx_mem_read, tcx_mem_write, s); - cpu_register_physical_memory(addr, 0x100000, - tcx_io_memory); - s->vram = qemu_mallocz(XSZ*YSZ); + s->vram = vram_base; + s->vram_offset = vram_offset; + + cpu_register_physical_memory(addr, vram_size, vram_offset); + + register_savevm("tcx", addr, 1, tcx_save, tcx_load, s); + qemu_register_reset(tcx_reset, s); + tcx_reset(s); dpy_resize(s->ds, XSZ, YSZ); + return s; } -void vga_screen_dump(const char *filename) +void tcx_screen_dump(void *opaque, const char *filename) { - TCXState *s = ts; + TCXState *s = opaque; FILE *f; - uint8_t *d, *d1; - unsigned int v; + uint8_t *d, *d1, v; int y, x; f = fopen(filename, "wb"); if (!f) - return -1; - fprintf(f, "P6\n%d %d\n%d\n", - XSZ, YSZ, 255); - d1 = s->vram; + return; + fprintf(f, "P6\n%d %d\n%d\n", XSZ, YSZ, 255); + d1 = s->vram + YOFF*MAXX + XOFF; for(y = 0; y < YSZ; y++) { d = d1; for(x = 0; x < XSZ; x++) { v = *d; - fputc((v) & 0xff, f); - fputc((v) & 0xff, f); - fputc((v) & 0xff, f); + fputc(s->r[v], f); + fputc(s->g[v], f); + fputc(s->b[v], f); d++; } - d1 += XSZ; + d1 += MAXX; } fclose(f); return; diff --git a/hw/timer.c b/hw/timer.c deleted file mode 100644 index e393fa36fd..0000000000 --- a/hw/timer.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * QEMU Sparc timer controller emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* - * Registers of hardware timer in sun4m. - */ -struct sun4m_timer_percpu { - volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */ - volatile unsigned int l14_cur_count; -}; - -struct sun4m_timer_global { - volatile unsigned int l10_timer_limit; - volatile unsigned int l10_cur_count; -}; - -typedef struct TIMERState { - uint32_t addr; - uint32_t timer_regs[2]; - int irq; -} TIMERState; - -static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr) -{ - TIMERState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - default: - return s->timer_regs[saddr]; - break; - } - return 0; -} - -static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - TIMERState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - default: - s->timer_regs[saddr] = val; - break; - } -} - -static CPUReadMemoryFunc *timer_mem_read[3] = { - timer_mem_readl, - timer_mem_readl, - timer_mem_readl, -}; - -static CPUWriteMemoryFunc *timer_mem_write[3] = { - timer_mem_writel, - timer_mem_writel, - timer_mem_writel, -}; - -void timer_init(uint32_t addr, int irq) -{ - int timer_io_memory; - TIMERState *s; - - s = qemu_mallocz(sizeof(TIMERState)); - if (!s) - return; - s->addr = addr; - s->irq = irq; - - timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s); - cpu_register_physical_memory(addr, 2, timer_io_memory); -} |