From e80cfcfc8884400e826328b772971913a14d0f44 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 19 Dec 2004 23:18:01 +0000 Subject: [PATCH] SPARC merge git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1179 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 +- Makefile.target | 3 +- cpu-exec.c | 2 +- disas.c | 34 +- disas.h | 10 +- gdbstub.c | 19 +- hw/fdc.c | 35 +- hw/iommu.c | 54 +- hw/lance.c | 127 ++- hw/m48t08.c | 161 ++- hw/m48t08.h | 8 +- hw/magic-load.c | 179 +-- hw/sched.c | 268 ----- hw/slavio_intctl.c | 299 +++++ hw/slavio_serial.c | 364 ++++++ hw/slavio_timer.c | 289 +++++ hw/sun4m.c | 163 ++- hw/tcx.c | 297 +++-- hw/timer.c | 97 -- linux-user/elfload.c | 16 +- linux-user/main.c | 2 + linux-user/signal.c | 79 +- pc-bios/proll.bin | Bin 56856 -> 0 bytes pc-bios/proll.elf | Bin 0 -> 133338 bytes pc-bios/proll.patch | 2088 ++++++++++++++++++++++++++++++++++- qemu-doc.texi | 23 + qemu-tech.texi | 5 +- target-sparc/cpu.h | 28 +- target-sparc/exec.h | 3 + target-sparc/fop_template.h | 12 - target-sparc/helper.c | 255 +++-- target-sparc/op.c | 29 +- target-sparc/op_helper.c | 176 ++- target-sparc/op_mem.h | 4 - target-sparc/translate.c | 396 +++++-- vl.c | 66 +- vl.h | 33 +- 37 files changed, 4490 insertions(+), 1138 deletions(-) delete mode 100644 hw/sched.c create mode 100644 hw/slavio_intctl.c create mode 100644 hw/slavio_serial.c create mode 100644 hw/slavio_timer.c delete mode 100644 hw/timer.c delete mode 100644 pc-bios/proll.bin create mode 100644 pc-bios/proll.elf diff --git a/Makefile b/Makefile index 3659819fbe..3cf7e504cd 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ install: all install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ pc-bios/vgabios-cirrus.bin \ pc-bios/ppc_rom.bin \ - pc-bios/proll.bin \ + pc-bios/proll.elf \ pc-bios/linux_boot.bin "$(datadir)" mkdir -p "$(docdir)" install -m 644 qemu-doc.html qemu-tech.html "$(docdir)" @@ -107,7 +107,7 @@ tarbin: $(datadir)/vgabios.bin \ $(datadir)/vgabios-cirrus.bin \ $(datadir)/ppc_rom.bin \ - $(datadir)/proll.bin \ + $(datadir)/proll.elf \ $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ diff --git a/Makefile.target b/Makefile.target index a5c697ddc9..edf76cffbe 100644 --- a/Makefile.target +++ b/Makefile.target @@ -175,6 +175,7 @@ endif ifeq ($(CONFIG_DARWIN),yes) OP_CFLAGS+= -mdynamic-no-pic +LIBS+=-lmx endif ######################################################### @@ -300,7 +301,7 @@ VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o endif ifeq ($(TARGET_ARCH), sparc) -VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o timer.o +VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o diff --git a/cpu-exec.c b/cpu-exec.c index b98c22c58e..cc6324ca10 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -261,7 +261,7 @@ int cpu_exec(CPUState *env1) } #elif defined(TARGET_SPARC) if (interrupt_request & CPU_INTERRUPT_HARD) { - do_interrupt(0, 0, 0, 0, 0); + do_interrupt(env->interrupt_index, 0, 0, 0, 0); env->interrupt_request &= ~CPU_INTERRUPT_HARD; } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); diff --git a/disas.c b/disas.c index 86f29d2458..bfab8c3bb7 100644 --- a/disas.c +++ b/disas.c @@ -9,9 +9,7 @@ #include "disas.h" /* Filled in by elfload.c. Simplistic, but will do for now. */ -unsigned int disas_num_syms; -void *disas_symtab; -const char *disas_strtab; +struct syminfo *syminfos = NULL; /* Get LENGTH bytes from info's buffer, at target address memaddr. Transfer them to myaddr. */ @@ -203,19 +201,23 @@ const char *lookup_symbol(void *orig_addr) { unsigned int i; /* Hack, because we know this is x86. */ - Elf32_Sym *sym = disas_symtab; - - for (i = 0; i < disas_num_syms; i++) { - if (sym[i].st_shndx == SHN_UNDEF - || sym[i].st_shndx >= SHN_LORESERVE) - continue; - - if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC) - continue; - - if ((long)orig_addr >= sym[i].st_value - && (long)orig_addr < sym[i].st_value + sym[i].st_size) - return disas_strtab + sym[i].st_name; + Elf32_Sym *sym; + struct syminfo *s; + + for (s = syminfos; s; s = s->next) { + sym = s->disas_symtab; + for (i = 0; i < s->disas_num_syms; i++) { + if (sym[i].st_shndx == SHN_UNDEF + || sym[i].st_shndx >= SHN_LORESERVE) + continue; + + if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC) + continue; + + if ((long)orig_addr >= sym[i].st_value + && (long)orig_addr < sym[i].st_value + sym[i].st_size) + return s->disas_strtab + sym[i].st_name; + } } return ""; } diff --git a/disas.h b/disas.h index c4a251ff8f..5d383faab6 100644 --- a/disas.h +++ b/disas.h @@ -9,7 +9,11 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags); const char *lookup_symbol(void *orig_addr); /* Filled in by elfload.c. Simplistic, but will do for now. */ -extern unsigned int disas_num_syms; -extern void *disas_symtab; /* FIXME: includes are a mess --RR */ -extern const char *disas_strtab; +extern struct syminfo { + unsigned int disas_num_syms; + void *disas_symtab; + const char *disas_strtab; + struct syminfo *next; +} *syminfos; + #endif /* _QEMU_DISAS_H */ diff --git a/gdbstub.c b/gdbstub.c index 2491c2cd77..e2c8b2dfa8 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -298,11 +298,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) } /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ registers[64] = tswapl(env->y); - tmp = (0<<28) | (4<<24) | env->psr \ - | (env->psrs? PSR_S : 0) \ - | (env->psrs? PSR_PS : 0) \ - | (env->psret? PSR_ET : 0) \ - | env->cwp; + tmp = GET_PSR(env); registers[65] = tswapl(tmp); registers[66] = tswapl(env->wim); registers[67] = tswapl(env->tbr); @@ -317,7 +313,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) { - uint32_t *registers = (uint32_t *)mem_buf, tmp; + uint32_t *registers = (uint32_t *)mem_buf; int i; /* fill in g0..g7 */ @@ -334,12 +330,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ env->y = tswapl(registers[64]); - tmp = tswapl(registers[65]); - env->psr = tmp & ~PSR_ICC; - env->psrs = (tmp & PSR_S)? 1 : 0; - env->psrps = (tmp & PSR_PS)? 1 : 0; - env->psret = (tmp & PSR_ET)? 1 : 0; - env->cwp = (tmp & PSR_CWP); + PUT_PSR(env, tswapl(registers[65])); env->wim = tswapl(registers[66]); env->tbr = tswapl(registers[67]); env->pc = tswapl(registers[68]); @@ -495,8 +486,10 @@ static void gdb_vm_stopped(void *opaque, int reason) /* disable single step if it was enable */ cpu_single_step(cpu_single_env, 0); - if (reason == EXCP_DEBUG) + if (reason == EXCP_DEBUG) { + tb_flush(cpu_single_env); ret = SIGTRAP; + } else ret = 0; snprintf(buf, sizeof(buf), "S%02x", ret); diff --git a/hw/fdc.c b/hw/fdc.c index d512b1ca98..ee07328481 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -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); } diff --git a/hw/tcx.c b/hw/tcx.c index 7f979946fc..ccac0bffa6 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -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); -} diff --git a/linux-user/elfload.c b/linux-user/elfload.c index cfc4256974..09c33aa90b 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -841,6 +841,7 @@ static void load_symbols(struct elfhdr *hdr, int fd) unsigned int i; struct elf_shdr sechdr, symtab, strtab; char *strings; + struct syminfo *s; lseek(fd, hdr->e_shoff, SEEK_SET); for (i = 0; i < hdr->e_shnum; i++) { @@ -866,24 +867,27 @@ static void load_symbols(struct elfhdr *hdr, int fd) found: /* Now know where the strtab and symtab are. Snarf them. */ - disas_symtab = malloc(symtab.sh_size); - disas_strtab = strings = malloc(strtab.sh_size); - if (!disas_symtab || !disas_strtab) + s = malloc(sizeof(*s)); + s->disas_symtab = malloc(symtab.sh_size); + s->disas_strtab = strings = malloc(strtab.sh_size); + if (!s->disas_symtab || !s->disas_strtab) return; lseek(fd, symtab.sh_offset, SEEK_SET); - if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size) + if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size) return; #ifdef BSWAP_NEEDED for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) - bswap_sym(disas_symtab + sizeof(struct elf_sym)*i); + bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i); #endif lseek(fd, strtab.sh_offset, SEEK_SET); if (read(fd, strings, strtab.sh_size) != strtab.sh_size) return; - disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + s->next = syminfos; + syminfos = s; } static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, diff --git a/linux-user/main.c b/linux-user/main.c index 6ab024e0bf..3d99dda1ad 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -497,6 +497,8 @@ void cpu_loop (CPUSPARCState *env) case TT_WIN_UNF: /* window underflow */ restore_window(env); break; + case 0x100: // XXX, why do we get these? + break; default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); diff --git a/linux-user/signal.c b/linux-user/signal.c index 50f2ba10a0..49278208c5 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1354,13 +1354,14 @@ struct target_rt_signal_frame { __siginfo_fpu_t fpu_state; }; -#define UREG_O0 0 -#define UREG_O6 6 -#define UREG_I0 16 -#define UREG_I1 17 -#define UREG_I2 18 -#define UREG_I6 22 -#define UREG_I7 23 +#define UREG_O0 16 +#define UREG_O6 22 +#define UREG_I0 0 +#define UREG_I1 1 +#define UREG_I2 2 +#define UREG_I6 6 +#define UREG_I7 7 +#define UREG_L0 8 #define UREG_FP UREG_I6 #define UREG_SP UREG_O6 @@ -1385,23 +1386,20 @@ setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask) { int err = 0, i; - fprintf(stderr, "2.a %lx psr: %lx regs: %lx\n", si, env->psr, si->si_regs.psr); err |= __put_user(env->psr, &si->si_regs.psr); - fprintf(stderr, "2.a1 pc:%lx\n", si->si_regs.pc); err |= __put_user(env->pc, &si->si_regs.pc); err |= __put_user(env->npc, &si->si_regs.npc); err |= __put_user(env->y, &si->si_regs.y); - fprintf(stderr, "2.b\n"); for (i=0; i < 7; i++) { err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]); } for (i=0; i < 7; i++) { - err |= __put_user(env->regwptr[i+16], &si->si_regs.u_regs[i+8]); + err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]); } - fprintf(stderr, "2.c\n"); err |= __put_user(mask, &si->si_mask); return err; } + static int setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ CPUState *env, unsigned long mask) @@ -1434,6 +1432,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, sf = (struct target_signal_frame *) get_sigframe(ka, env, sigframe_size); + //fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); #if 0 if (invalid_frame_pointer(sf, sigframe_size)) goto sigill_and_return; @@ -1451,13 +1450,11 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, } for (i = 0; i < 7; i++) { - err |= __put_user(env->regwptr[i + 8], &sf->ss.locals[i]); + err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]); } for (i = 0; i < 7; i++) { - err |= __put_user(env->regwptr[i + 16], &sf->ss.ins[i]); + err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]); } - //err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], - // sizeof(struct reg_window)); if (err) goto sigsegv; @@ -1486,13 +1483,15 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, /* Flush instruction space. */ //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); - //tb_flush(env); + tb_flush(env); } + //cpu_dump_state(env, stderr, fprintf, 0); return; sigill_and_return: force_sig(TARGET_SIGILL); sigsegv: + //fprintf(stderr, "force_sig\n"); force_sig(TARGET_SIGSEGV); } static inline int @@ -1542,13 +1541,16 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, long do_sigreturn(CPUState *env) { struct target_signal_frame *sf; - unsigned long up_psr, pc, npc; + uint32_t up_psr, pc, npc; target_sigset_t set; + sigset_t host_set; __siginfo_fpu_t *fpu_save; - int err; + int err, i; - sf = (struct new_signal_frame *) env->regwptr[UREG_FP]; - fprintf(stderr, "sigreturn sf: %lx\n", &sf); + sf = (struct target_signal_frame *) env->regwptr[UREG_FP]; + fprintf(stderr, "sigreturn\n"); + fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); + //cpu_dump_state(env, stderr, fprintf, 0); /* 1. Make sure we are not getting garbage from the user */ #if 0 @@ -1567,36 +1569,41 @@ long do_sigreturn(CPUState *env) goto segv_and_exit; /* 2. Restore the state */ - up_psr = env->psr; - //err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs) - //); + err |= __get_user(up_psr, &sf->info.si_regs.psr); + /* User can only change condition codes and FPU enabling in %psr. */ env->psr = (up_psr & ~(PSR_ICC /* | PSR_EF */)) | (env->psr & (PSR_ICC /* | PSR_EF */)); - fprintf(stderr, "psr: %lx\n", env->psr); + fprintf(stderr, "psr: %x\n", env->psr); + env->pc = pc-4; + env->npc = pc; + err |= __get_user(env->y, &sf->info.si_regs.y); + for (i=0; i < 7; i++) { + err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]); + } + for (i=0; i < 7; i++) { + err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); + } err |= __get_user(fpu_save, &sf->fpu_save); - if (fpu_save) - err |= restore_fpu_state(env, fpu_save); + //if (fpu_save) + // err |= restore_fpu_state(env, fpu_save); /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. */ err |= __get_user(set.sig[0], &sf->info.si_mask); - //err |= __copy_from_user(&set.sig[1], &sf->extramask, - // (_NSIG_WORDS-1) * sizeof(unsigned int)); + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + err |= (__get_user(set.sig[i], &sf->extramask[i - 1])); + } + + target_to_host_sigset_internal(&host_set, &set); + sigprocmask(SIG_SETMASK, &host_set, NULL); if (err) goto segv_and_exit; -#if 0 - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); - current->blocked = set; - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); -#endif fprintf(stderr, "returning %lx\n", env->regwptr[0]); return env->regwptr[0]; diff --git a/pc-bios/proll.bin b/pc-bios/proll.bin deleted file mode 100644 index 0489cc245fc524bb89eb36582304617ec4ca5b59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56856 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∨KO=X!-RtFV^C-f>P$&Zau3 zJ^K%LP$ zvna*wzPOJxEHBR|lCdv;XcQs&E1HYiFAdZ*USP1L$Oi|){zhZ@S+*6#C696pIRszvk3WS*u< z;`&KFHbuu$>RyOsf~zD^iZBHSM^qAaoNBC6F@zL73z6lC;8v(KqyB`%#SO8!HyLvy z<33}!O&<#Wc%$n6DvyF@F0f0&ZHY4ENHUH!HM$3XkoWP*pd+TBG@K` zlJ7n!EsA|?N%tE-(TxTr-(f&Ak&}l@x~D)qN7!Zp>INqbm%{de@WYMv6FFpafXPy9 z04Np4{2@T`p!Hsjoi~1tH8T zJ6c|A#S3=A3e-SYf4OC_{&tgK{q5Gj`a78Y(uG9JZ6$!iy^@$?TLj`|ApD}OmkNXH zU>oZOu+hrZty|5imH*Y6wd7W;8dcmD@5pz;R~u0)&FqTxr*2QzUt&9~KipGH}^|-|x zdqI^nfB^&oZ^&`;lmuIqW-a<|9J4L zoPj(V^J3ENSr$`XZKzg}AO?58 z?%Y3m*DP`_C%#AIUjRE`}}ts@LdQwMrUe(3vJ1y>Fb9@+l2Z zs+BHHV?rB-ZcOp>VA4~%Wg@D@Z7QHg(em*Q%+H2*=f~7fsW4LRc7%oYJM1OlEQZ8S z8Kvqca%fxE`LcFD)}Uolu0?&YGK}wA+yg8yFSO*D#p literal 0 HcmV?d00001 diff --git a/pc-bios/proll.patch b/pc-bios/proll.patch index b0860e26f4..18a157512a 100644 --- a/pc-bios/proll.patch +++ b/pc-bios/proll.patch @@ -1,50 +1,2064 @@ -diff -ru proll_18.orig/mrcoffee/main.c proll_18/mrcoffee/main.c ---- proll_18.orig/mrcoffee/main.c 2002-09-13 16:16:59.000000000 +0200 -+++ proll_18/mrcoffee/main.c 2004-09-26 11:52:23.000000000 +0200 -@@ -101,6 +101,7 @@ - le_probe(); - init_net(); +diff -ruN proll_18.orig/Makefile proll-patch4/Makefile +--- proll_18.orig/Makefile 2002-09-13 14:16:59.000000000 +0000 ++++ proll-patch4/Makefile 2004-11-13 15:50:49.000000000 +0000 +@@ -4,6 +4,7 @@ + make -C krups-ser all + make -C espresso all + make -C espresso-ser all ++ make -C qemu all + clean: + make -C mrcoffee clean +@@ -11,3 +12,4 @@ + make -C krups-ser clean + make -C espresso clean + make -C espresso-ser clean ++ make -C qemu clean +diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S +--- proll_18.orig/qemu/head.S 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/qemu/head.S 2004-11-13 15:50:49.000000000 +0000 +@@ -0,0 +1,515 @@ ++/** ++ ** Standalone startup code for Linux PROM emulator. ++ ** Copyright 1999 Pete A. Zaitcev ++ ** This code is licensed under GNU General Public License. ++ **/ ++/* ++ * $Id: proll.patch,v 1.2 2004-12-19 23:18:01 bellard Exp $ ++ */ ++ ++#include ++#include ++#include ++/* #include */ /* Trap entries. Do not use. */ ++#include "phys_jj.h" ++ ++#define C_LABEL(name) name ++#define REGWIN_SZ 0x40 ++ ++#define WRITE_PAUSE nop; nop; nop; /* Have to do this after %wim/%psr chg */ ++ ++ /* 22 is 24-2, (va)>>(SRMMU_PGDIR_SHIFT-PTESIZESHFT) */ ++#define VATOPGDOFF(va) (((va)>>22)&0x3FC) ++#define VATOPMDOFF(va) (((va)>>16)&0xFC) ++ ++#define NOP_INSN 0x01000000 /* Used to patch sparc_save_state */ ++ ++/* Here are some trap goodies */ ++ ++#if 0 ++/* Generic trap entry. */ ++#define TRAP_ENTRY(type, label) \ ++ rd %psr, %l0; b label; rd %wim, %l3; nop; ++#endif ++ ++/* Data/text faults. */ ++#define SRMMU_TFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 1, %l7; ++#define SRMMU_DFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 0, %l7; ++ ++#if 0 ++/* This is for traps we should NEVER get. */ ++#define BAD_TRAP(num) \ ++ rd %psr, %l0; mov num, %l7; b bad_trap_handler; rd %wim, %l3; ++ ++/* This is for traps when we want just skip the instruction which caused it */ ++#define SKIP_TRAP(type, name) \ ++ jmpl %l2, %g0; rett %l2 + 4; nop; nop; ++ ++/* Notice that for the system calls we pull a trick. We load up a ++ * different pointer to the system call vector table in %l7, but call ++ * the same generic system call low-level entry point. The trap table ++ * entry sequences are also HyperSparc pipeline friendly ;-) ++ */ ++ ++/* Software trap for Linux system calls. */ ++#define LINUX_SYSCALL_TRAP \ ++ sethi %hi(C_LABEL(sys_call_table)), %l7; \ ++ or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ ++ b linux_sparc_syscall; \ ++ rd %psr, %l0; ++ ++/* Software trap for SunOS4.1.x system calls. */ ++#define SUNOS_SYSCALL_TRAP \ ++ rd %psr, %l0; \ ++ sethi %hi(C_LABEL(sunos_sys_table)), %l7; \ ++ b linux_sparc_syscall; \ ++ or %l7, %lo(C_LABEL(sunos_sys_table)), %l7; ++ ++/* Software trap for Slowaris system calls. */ ++#define SOLARIS_SYSCALL_TRAP \ ++ b solaris_syscall; \ ++ rd %psr, %l0; \ ++ nop; \ ++ nop; ++ ++#define INDIRECT_SOLARIS_SYSCALL(x) \ ++ mov x, %g1; \ ++ b solaris_syscall; \ ++ rd %psr, %l0; \ ++ nop; ++ ++#define BREAKPOINT_TRAP \ ++ b breakpoint_trap; \ ++ rd %psr,%l0; \ ++ nop; \ ++ nop; ++ ++/* Software trap for Sparc-netbsd system calls. */ ++#define NETBSD_SYSCALL_TRAP \ ++ sethi %hi(C_LABEL(sys_call_table)), %l7; \ ++ or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ ++ b bsd_syscall; \ ++ rd %psr, %l0; ++ ++/* The Get Condition Codes software trap for userland. */ ++#define GETCC_TRAP \ ++ b getcc_trap_handler; mov %psr, %l0; nop; nop; ++ ++/* The Set Condition Codes software trap for userland. */ ++#define SETCC_TRAP \ ++ b setcc_trap_handler; mov %psr, %l0; nop; nop; ++ ++/* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and ++ * gets handled with another macro. ++ */ ++#define TRAP_ENTRY_INTERRUPT(int_level) \ ++ mov int_level, %l7; rd %psr, %l0; b real_irq_entry; rd %wim, %l3; ++ ++/* NMI's (Non Maskable Interrupts) are special, you can't keep them ++ * from coming in, and basically if you get one, the shows over. ;( ++ * On the sun4c they are usually asynchronous memory errors, on the ++ * the sun4m they could be either due to mem errors or a software ++ * initiated interrupt from the prom/kern on an SMP box saying "I ++ * command you to do CPU tricks, read your mailbox for more info." ++ */ ++#define NMI_TRAP \ ++ rd %wim, %l3; b linux_trap_nmi_sun4c; mov %psr, %l0; nop; ++ ++#endif ++ ++/* Window overflows/underflows are special and we need to try to be as ++ * efficient as possible here.... ++ */ ++#define WINDOW_SPILL \ ++ rd %psr, %l0; rd %wim, %l3; b spill_window_entry; nop; ++ ++#define WINDOW_FILL \ ++ rd %psr, %l0; rd %wim, %l3; b fill_window_entry; nop; ++ ++#define STUB_TRAP ba stub_trap; nop; nop; nop; ++ ++#define TRAP_ENTRY(a,b) STUB_TRAP ++#define SKIP_TRAP(a,b) STUB_TRAP ++#define SUNOS_SYSCALL_TRAP STUB_TRAP ++#define SOLARIS_SYSCALL_TRAP STUB_TRAP ++#define NETBSD_SYSCALL_TRAP STUB_TRAP ++#define LINUX_SYSCALL_TRAP STUB_TRAP ++#define BREAKPOINT_TRAP STUB_TRAP ++#define NMI_TRAP STUB_TRAP ++#define GETCC_TRAP STUB_TRAP ++#define SETCC_TRAP STUB_TRAP ++#define BAD_TRAP(n) STUB_TRAP ++#define TRAP_ENTRY_INTERRUPT(i) STUB_TRAP ++#define INDIRECT_SOLARIS_SYSCALL(i) STUB_TRAP ++ ++ .section ".text" ++ .globl start, _start ++_start: ++start: ++ .globl spill_window_entry, fill_window_entry ++C_LABEL(trapbase): ++t_zero: b goprol; nop; nop; nop; ++t_tflt: SRMMU_TFAULT /* Inst. Access Exception */ ++t_bins: TRAP_ENTRY(0x2, bad_instruction) /* Illegal Instruction */ ++t_pins: TRAP_ENTRY(0x3, priv_instruction) /* Privileged Instruction */ ++t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler) /* Floating Point Disabled */ ++t_wovf: WINDOW_SPILL /* Window Overflow */ ++t_wunf: WINDOW_FILL /* Window Underflow */ ++t_mna: TRAP_ENTRY(0x7, mna_handler) /* Memory Address Not Aligned */ ++t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler) /* Floating Point Exception */ ++t_dflt: SRMMU_DFAULT /* Data Miss Exception */ ++t_tio: TRAP_ENTRY(0xa, do_tag_overflow) /* Tagged Instruction Ovrflw */ ++t_wpt: TRAP_ENTRY(0xb, do_watchpoint) /* Watchpoint Detected */ ++t_badc: BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) ++t_irq1: TRAP_ENTRY_INTERRUPT(1) /* IRQ Software/SBUS Level 1 */ ++t_irq2: TRAP_ENTRY_INTERRUPT(2) /* IRQ SBUS Level 2 */ ++t_irq3: TRAP_ENTRY_INTERRUPT(3) /* IRQ SCSI/DMA/SBUS Level 3 */ ++t_irq4: TRAP_ENTRY_INTERRUPT(4) /* IRQ Software Level 4 */ ++t_irq5: TRAP_ENTRY_INTERRUPT(5) /* IRQ SBUS/Ethernet Level 5 */ ++t_irq6: TRAP_ENTRY_INTERRUPT(6) /* IRQ Software Level 6 */ ++t_irq7: TRAP_ENTRY_INTERRUPT(7) /* IRQ Video/SBUS Level 5 */ ++t_irq8: TRAP_ENTRY_INTERRUPT(8) /* IRQ SBUS Level 6 */ ++t_irq9: TRAP_ENTRY_INTERRUPT(9) /* IRQ SBUS Level 7 */ ++t_irq10:TRAP_ENTRY_INTERRUPT(10) /* IRQ Timer #1 (one we use) */ ++t_irq11:TRAP_ENTRY_INTERRUPT(11) /* IRQ Floppy Intr. */ ++t_irq12:TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */ ++t_irq13:TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */ ++t_irq14:TRAP_ENTRY_INTERRUPT(14) /* IRQ Timer #2 */ ++t_nmi: NMI_TRAP /* Level 15 (NMI) */ ++t_racc: TRAP_ENTRY(0x20, do_reg_access) /* General Register Access Error */ ++t_iacce:BAD_TRAP(0x21) /* Instr Access Error */ ++t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23) ++t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled) /* Co-Processor Disabled */ ++t_uflsh:SKIP_TRAP(0x25, unimp_flush) /* Unimplemented FLUSH inst. */ ++t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27) ++t_cpexc:TRAP_ENTRY(0x28, do_cp_exception) /* Co-Processor Exception */ ++t_dacce:SRMMU_DFAULT /* Data Access Error */ ++t_hwdz: TRAP_ENTRY(0x2a, do_hw_divzero) /* Division by zero, you lose... */ ++t_dserr:BAD_TRAP(0x2b) /* Data Store Error */ ++t_daccm:BAD_TRAP(0x2c) /* Data Access MMU-Miss */ ++t_bad2d: BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) ++ BAD_TRAP(0x30) BAD_TRAP(0x31) BAD_TRAP(0x32) BAD_TRAP(0x33) ++ BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) BAD_TRAP(0x37) ++ BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) ++t_iaccm:BAD_TRAP(0x3c) /* Instr Access MMU-Miss */ ++ BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) ++ BAD_TRAP(0x40) BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) ++ BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46) BAD_TRAP(0x47) ++ BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b) ++ BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) ++ BAD_TRAP(0x50) BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) ++ BAD_TRAP(0x54) BAD_TRAP(0x55) BAD_TRAP(0x56) BAD_TRAP(0x57) ++ BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) BAD_TRAP(0x5b) ++ BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) ++ BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) ++ BAD_TRAP(0x64) BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) ++ BAD_TRAP(0x68) BAD_TRAP(0x69) BAD_TRAP(0x6a) BAD_TRAP(0x6b) ++ BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) BAD_TRAP(0x6f) ++ BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) ++ BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) ++ BAD_TRAP(0x78) BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) ++ BAD_TRAP(0x7c) BAD_TRAP(0x7d) BAD_TRAP(0x7e) BAD_TRAP(0x7f) ++t_sunos:SUNOS_SYSCALL_TRAP /* SunOS System Call */ ++t_sbkpt:BREAKPOINT_TRAP /* Software Breakpoint/KGDB */ ++t_divz: BAD_TRAP(0x82) /* Divide by zero trap */ ++t_flwin:TRAP_ENTRY(0x83, do_flush_windows) /* Flush Windows Trap */ ++t_clwin:BAD_TRAP(0x84) /* Clean Windows Trap */ ++t_rchk: BAD_TRAP(0x85) /* Range Check */ ++t_funal:BAD_TRAP(0x86) /* Fix Unaligned Access Trap */ ++t_iovf: BAD_TRAP(0x87) /* Integer Overflow Trap */ ++t_slowl:SOLARIS_SYSCALL_TRAP /* Slowaris System Call */ ++t_netbs:NETBSD_SYSCALL_TRAP /* Net-B.S. System Call */ ++t_bad8a:BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) ++ BAD_TRAP(0x8e) BAD_TRAP(0x8f) ++t_linux:LINUX_SYSCALL_TRAP /* Linux System Call */ ++t_bad91:BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) ++ BAD_TRAP(0x94) BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) ++ BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f) ++t_getcc:GETCC_TRAP /* Get Condition Codes */ ++t_setcc:SETCC_TRAP /* Set Condition Codes */ ++t_bada2:BAD_TRAP(0xa2) BAD_TRAP(0xa3) ++ BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) ++t_slowi:INDIRECT_SOLARIS_SYSCALL(156) ++ BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) ++ BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) ++ BAD_TRAP(0xb0) BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) ++ BAD_TRAP(0xb4) BAD_TRAP(0xb5) BAD_TRAP(0xb6) BAD_TRAP(0xb7) ++ BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) BAD_TRAP(0xbb) ++ BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) ++t_badc0:BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) ++ BAD_TRAP(0xc4) BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) ++ BAD_TRAP(0xc8) BAD_TRAP(0xc9) BAD_TRAP(0xca) BAD_TRAP(0xcb) ++ BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) BAD_TRAP(0xcf) ++ BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) ++t_badd4:BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) ++ BAD_TRAP(0xd8) BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) ++ BAD_TRAP(0xdc) BAD_TRAP(0xdd) BAD_TRAP(0xde) BAD_TRAP(0xdf) ++ BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) BAD_TRAP(0xe3) ++ BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) ++t_bade8:BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) ++ BAD_TRAP(0xec) BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) ++ BAD_TRAP(0xf0) BAD_TRAP(0xf1) BAD_TRAP(0xf2) BAD_TRAP(0xf3) ++ BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) BAD_TRAP(0xf7) ++ BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) ++t_badfc:BAD_TRAP(0xfc) BAD_TRAP(0xfd) ++dbtrap: BAD_TRAP(0xfe) /* Debugger/PROM breakpoint #1 */ ++dbtrap2:BAD_TRAP(0xff) /* Debugger/PROM breakpoint #2 */ ++ ++stub_trap: ++ set (PHYS_JJ_TCX_FB + 0xbf0), %g5 /* 2 cells from side */ ++ set 0x00ffffff, %g4 ++ sta %g4, [%g5] ASI_M_BYPASS ++1: ba 1b; nop ++ ++ .section ".bss" ++ .align 8 ++bss_start: ++ .align 0x1000 ! PAGE_SIZE ++ .globl C_LABEL(bootup_user_stack) ++ .type bootup_user_stack,#object ++ .size bootup_user_stack,0x2000 ++C_LABEL(bootup_user_stack): .skip 0x2000 ++ ++ .section ".text" ++ ++goprol: ++ ! %g1 contains end of memory ++ ! map PROLDATA to PROLBASE+PROLSIZE to end of ram ++ set PROLSIZE+0x1000-PROLDATA+PROLBASE, %g2 ! add 0x1000 for temp tables ++ sub %g1, %g2, %g2 ! start of private memory ++ srl %g2, 0x4, %g7 ! ctx table at s+0x0 ++ add %g2, 0x400, %g3 ! l1 table at s+0x400 ++ srl %g3, 0x4, %g3 ++ or %g3, 0x1, %g3 ++ sta %g3, [%g2] ASI_M_BYPASS ++ add %g2, 0x400, %g2 ! s+0x400 ++ add %g2, 0x800, %g3 ! l2 table for ram (00xxxxxx) at s+0x800 ++ srl %g3, 0x4, %g3 ++ or %g3, 0x1, %g3 ++ sta %g3, [%g2] ASI_M_BYPASS ++ add %g2, 0x500, %g3 ! l2 table for rom (ffxxxxxx) at s+0x900 ++ add %g2, 0x3fc, %g2 ! s+0x7fc ++ srl %g3, 0x4, %g3 ++ or %g3, 0x1, %g3 ++ sta %g3, [%g2] ASI_M_BYPASS ++ add %g2, 0x4, %g2 ! s+0x800 ++ set ((7 << 2) | 2), %g3 ! 7 = U: --- S: RWX (main memory) ++ sta %g3, [%g2] ASI_M_BYPASS ++ add %g2, 0x200, %g3 ! l3 table for rom at s+0xa00 ++ add %g2, 0x1d0, %g2 ! s+0x9d0 ++ srl %g3, 0x4, %g3 ++ or %g3, 0x1, %g3 ++ sta %g3, [%g2] ASI_M_BYPASS ++ add %g2, 0x30, %g2 ! s+0xa00 ++ ++ set PROLBASE, %g3 ++ set 0x1000, %g5 ++ set (PROLDATA-PROLBASE)/0x1000, %g6 ! # of .text pages ++1: srl %g3, 0x4, %g4 ++ or %g4, ((7 << 2) | 2), %g4 ! 4 = U: --X S: --X (rom, execute only) ++ sta %g4, [%g2] ASI_M_BYPASS ++ add %g2, 4, %g2 ++ add %g3, %g5, %g3 ++ deccc %g6 ++ bne 1b ++ nop ++#if 0 ++ set (PROLDATA-PROLRODATA)/0x1000, %g6 ! # of .rodata pages ++1: srl %g3, 0x4, %g4 ++ or %g4, ((0 << 2) | 2), %g4 ! 0 = U: R-- S: R-- (rom, read only) ++ sta %g4, [%g2] ASI_M_BYPASS ++ add %g2, 4, %g2 ++ add %g3, %g5, %g3 ++ deccc %g6 ++ bne 1b ++ nop ++#endif ++ set (PROLBASE+PROLSIZE-PROLDATA)/0x1000, %g6 ! # of .bss pages ++ set 0x1000, %g4 ++ sll %g7, 0x4, %g3 ++ add %g4, %g3, %g3 ++1: srl %g3, 0x4, %g4 ++ or %g4, ((7 << 2) | 2), %g4 ! 5 = U: R-- S: RW- (data area, read/write) ++ sta %g4, [%g2] ASI_M_BYPASS ++ add %g2, 4, %g2 ++ add %g3, %g5, %g3 ++ deccc %g6 ++ bne 1b ++ nop ++ ++ mov %g1, %g3 ++ ++ set AC_M_CTPR, %g2 ++ sta %g7, [%g2] ASI_M_MMUREGS ! set ctx table ptr ++ set 1, %g1 ++ sta %g1, [%g0] ASI_M_MMUREGS ! enable mmu ++ ++ /* ++ * The code which enables traps is a simplified version of ++ * kernel head.S. ++ * ++ * We know number of windows as 8 so we do not calculate them. ++ * The deadwood is here for any case. ++ */ ++ ++ /* Turn on Supervisor, EnableFloating, and all the PIL bits. ++ * Also puts us in register window zero with traps off. ++ */ ++ set (PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2 ++ wr %g2, 0x0, %psr ++ WRITE_PAUSE ++ ++ /* I want a kernel stack NOW! */ ++ set C_LABEL(bootup_user_stack), %g1 ++ set (0x2000 - REGWIN_SZ), %g2 ++ add %g1, %g2, %sp ++ mov 0, %fp /* And for good luck */ ++ ++ /* Zero out our BSS section. */ ++ set C_LABEL(bss_start) , %o0 ! First address of BSS ++ set C_LABEL(end) , %o1 ! Last address of BSS ++ ba 2f ++ nop ++1: ++ st %g0, [%o0] ++2: ++ subcc %o0, %o1, %g0 ++ bl 1b ++ add %o0, 0x4, %o0 ++ ++ sethi %hi( C_LABEL(ram_size) ), %o0 ++ st %g3, [%o0 + %lo( C_LABEL(ram_size) )] ++ ++ mov 2, %g1 ++ wr %g1, 0x0, %wim ! make window 1 invalid ++ WRITE_PAUSE ++ ++#if 0 ++ wr %g0, 0x0, %wim ++ WRITE_PAUSE ++ save ++ rd %psr, %g3 ++ restore ++ and %g3, PSR_CWP, %g3 ++ add %g3, 0x1, %g3 ++#else ++ or %g0, 8, %g3 ++#endif ++ ++#if 0 ++ sethi %hi( C_LABEL(cputyp) ), %o0 ++ st %g7, [%o0 + %lo( C_LABEL(cputyp) )] ++ ++ sethi %hi( C_LABEL(nwindows) ), %g4 ++ st %g3, [%g4 + %lo( C_LABEL(nwindows) )] ++ ++ sub %g3, 0x1, %g3 ++ sethi %hi( C_LABEL(nwindowsm1) ), %g4 ++ st %g3, [%g4 + %lo( C_LABEL(nwindowsm1) )] ++#endif ++ ++ /* Here we go, start using Linux's trap table... */ ++ set C_LABEL(trapbase), %g3 ++ wr %g3, 0x0, %tbr ++ WRITE_PAUSE ++ ++ /* Finally, turn on traps so that we can call c-code. */ ++ rd %psr, %g3 ++ wr %g3, 0x0, %psr ++ WRITE_PAUSE ++ ++ wr %g3, PSR_ET, %psr ++ WRITE_PAUSE ++ ++ .globl prolmain ++ call C_LABEL(prolmain) ++ nop ++ ++3: ++ b 3b ++ nop ++ ++/* ++ * Memory access trap handler ++ * %l0 program %psr from trap table entry ++ * %l1 program %pc from hardware ++ * %l2 program %npc from hardware ++ * %l3 program %wim from trap table entry ++ * %l4 ++ * %l5 ++ * %l6 ++ * %l7 text flag from trap table entry ++ */ ++ ++ .section ".text" ++ .globl srmmu_fault ++C_LABEL(srmmu_fault): ++ ++ set AC_M_SFAR, %l6 ++ set AC_M_SFSR, %l5 ++ lda [%l6] ASI_M_MMUREGS, %l6 ++ lda [%l5] ASI_M_MMUREGS, %l5 ++ ++ set ignore_fault, %l5 ++ ld [%l5], %l5 ++ subcc %l5, %g0, %g0 /* NULL pointer trap faults always */ ++ be 3f ++ nop ++ subcc %l5, %l6, %g0 ++ be 2f ++ nop ++3: ++ ++ set (PHYS_JJ_TCX_FB + 0xbf0), %g5 /* 2 cells from side */ ++ set 0x00ffffff, %g4 ++ sta %g4, [%g5] ASI_M_BYPASS ++ add %g5, 8, %g5 /* On right side */ ++ sta %g4, [%g5] ASI_M_BYPASS ++1: ba 1b; nop ++ ++2: ++ set C_LABEL(fault_ignored), %l5 ++ mov 1, %l6 ++ st %l6, [%l5] ++ ++ /* ++ * Skip the faulting instruction. ++ * I think it works when next instruction is a branch even. ++ */ ++ or %l2, 0, %l1 ++ add %l2, 4, %l2 ++ ++ wr %l0, 0, %psr ++ WRITE_PAUSE ++ jmp %l1 ++ rett %l2 ++ ++/* ++ * Slow external versions of st_bypass and ld_bypass. ++ * rconsole.c uses inlines. We call these in places which are not speed ++ * critical, to avoid compiler bugs. ++ */ ++ .globl C_LABEL(st_bypass) ++C_LABEL(st_bypass): ++ retl ++ sta %o1, [%o0] ASI_M_BYPASS ++ .globl C_LABEL(ld_bypass) ++C_LABEL(ld_bypass): ++ retl ++ lda [%o0] ASI_M_BYPASS, %o0 ++ .globl C_LABEL(sth_bypass) ++C_LABEL(sth_bypass): ++ retl ++ stha %o1, [%o0] ASI_M_BYPASS ++ .globl C_LABEL(ldh_bypass) ++C_LABEL(ldh_bypass): ++ retl ++ lduha [%o0] ASI_M_BYPASS, %o0 ++ .globl C_LABEL(stb_bypass) ++C_LABEL(stb_bypass): ++ retl ++ stba %o1, [%o0] ASI_M_BYPASS ++ .globl C_LABEL(ldb_bypass) ++C_LABEL(ldb_bypass): ++ retl ++ lduba [%o0] ASI_M_BYPASS, %o0 +diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c +--- proll_18.orig/qemu/main.c 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/qemu/main.c 2004-11-23 19:05:34.000000000 +0000 +@@ -0,0 +1,178 @@ ++/** ++ ** Proll (PROM replacement) ++ ** Copyright 1999 Pete Zaitcev ++ ** This code is licensed under GNU General Public License. ++ **/ ++#include ++ ++// #include ++#include ++#include "pgtsrmmu.h" ++#include "iommu.h" /* Typical SBus IOMMU for sun4m */ ++#include "phys_jj.h" ++#include "vconsole.h" ++#include "version.h" ++#include /* __P() */ ++#include /* init_net() */ ++#include /* we are a provider for part of this. */ ++#include /* myipaddr */ ++#include ++#include /* our own prototypes */ ++ ++static void init_idprom(void); ++static void makepages_q(struct phym *t, unsigned int highbase); ++ ++struct vconterm dp0; ++struct mem cmem; /* Current memory, virtual */ ++struct mem cio; /* Current I/O space */ ++struct phym pmem; /* Current phys. mem. */ ++struct iommu ciommu; /* Our IOMMU on sun4m */ ++ ++static char *hw_idprom; ++int ignore_fault, fault_ignored, ram_size; ++ ++/* ++ */ ++void prolmain() ++{ ++ //static const char fname[14] = "00000000.PROL"; ++ static struct banks bb; ++ unsigned int hiphybas; ++ const void *romvec; ++ ++ vcon_init(&dp0, PHYS_JJ_TCX_FB); ++ printk("PROLL %s QEMU\n", PROLL_VERSION_STRING); ++ printk("%d MB total\n", ram_size/(1024*1024)); ++ ++ bb.nbanks = 1; ++ bb.bankv[0].start = 0; ++ bb.bankv[0].length = ram_size; ++ ++ hiphybas = ram_size - PROLSIZE; ++ ++ mem_init(&cmem, (char *) &_end, (char *)(PROLBASE+PROLSIZE)); ++ makepages_q(&pmem, hiphybas); ++ init_mmu_swift((unsigned int)pmem.pctp - PROLBASE + hiphybas); ++ ++ mem_init(&cio, (char *)(PROLBASE+PROLSIZE), ++ (char *)(PROLBASE+PROLSIZE+IOMAPSIZE)); ++ ++ iommu_init(&ciommu, hiphybas); ++ ++ /* ++ */ ++ init_idprom(); ++ sched_init(); ++ le_probe(); ++ init_net(); ++ ++#if 0 ++#if 0 /* RARP */ ++ if (rarp() != 0) fatal(); ++ /* printrarp(); */ ++ xtoa(myipaddr, fname, 8); ++ if (load(servaddr, fname) != 0) fatal(); ++#else ++ if (bootp() != 0) fatal(); ++ /* ++ * boot_rec.bp_file cannot be used because system PROM ++ * uses it to locate ourselves. If we load from boot_rec.bp_file, ++ * we will loop reloading PROLL over and over again. ++ * Thus we use traditional PROLL scheme HEXIPADDR.PROL (single L). ++ */ ++ xtoa(myipaddr, fname, 8); ++ if (load(boot_rec.bp_siaddr, fname) != 0) fatal(); ++#endif ++#endif ++ ++ romvec = init_openprom(bb.nbanks, bb.bankv, hiphybas); ++ ++ printk("Memory used: virt 0x%x:0x%x[%dK] iomap 0x%x:0x%x\n", ++ PROLBASE, (int)cmem.curp, ((unsigned) cmem.curp - PROLBASE)/1024, ++ (int)cio.start, (int)cio.curp); ++ //set_timeout(5); while (!chk_timeout()) { } /* P3: let me read */ ++ ++ { ++ void (*entry)(const void *, int, int, int, int) = (void (*)(const void*, int, int, int, int)) LOADBASE; ++ entry(romvec, 0, 0, 0, 0); ++ } ++ ++ mem_fini(&cmem); ++ vcon_fini(&dp0); ++} ++ ++/* ++ * dvma_alloc over iommu_alloc. ++ */ ++void *dvma_alloc(int size, unsigned int *pphys) ++{ ++ return iommu_alloc(&ciommu, size, pphys); ++} ++ ++/* ++ */ ++void udelay(unsigned long usecs) ++{ ++ int i, n; ++ n = usecs*50; ++ for (i = 0; i < n; i++) { } ++} ++ ++static void init_idprom() ++{ ++ char *va_prom; ++ ++ if ((va_prom = map_io(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE)) == NULL) { ++ printk("init_idprom: cannot map eeprom\n"); ++ fatal(); ++ } ++ bcopy(va_prom + PHYS_JJ_IDPROM_OFF, idprom, IDPROM_SIZE); ++ /* ++ * hw_idprom is not used anywhere. ++ * It's just as we hate to leave hanging pointers (I/O page here). ++ */ ++ hw_idprom = va_prom; ++} ++ ++/* ++ * Make CPU page tables. ++ * Returns pointer to context table. ++ * Here we ignore memory allocation errors which "should not happen" ++ * because we cannot print anything anyways if memory initialization fails. ++ */ ++void makepages_q(struct phym *t, unsigned int highbase) ++{ ++ unsigned int *ctp, *l1, pte; ++ int i; ++ unsigned int pa, va; ++ ++ ctp = mem_zalloc(&cmem, NCTX_SWIFT*sizeof(int), NCTX_SWIFT*sizeof(int)); ++ l1 = mem_zalloc(&cmem, 256*sizeof(int), 256*sizeof(int)); ++ ++ pte = SRMMU_ET_PTD | (((unsigned int)l1 - PROLBASE + highbase) >> 4); ++ for (i = 0; i < NCTX_SWIFT; i++) { ++ ctp[i] = pte; ++ } ++ ++ pa = PROLBASE; ++ for (va = PROLBASE; va < PROLDATA; va += PAGE_SIZE) { ++ map_page(l1, va, pa, 0, highbase); ++ pa += PAGE_SIZE; ++ } ++ pa = highbase + PROLDATA - PROLBASE; ++ for (va = PROLDATA; va < PROLBASE + PROLSIZE; va += PAGE_SIZE) { ++ map_page(l1, va, pa, 0, highbase); ++ pa += PAGE_SIZE; ++ } ++ ++ /* We need to start from LOADBASE, but kernel wants PAGE_SIZE. */ ++ pa = 0; ++ for (va = 0; va < LOWMEMSZ; va += PAGE_SIZE) { ++ map_page(l1, va, pa, 0, highbase); ++ pa += PAGE_SIZE; ++ } ++ ++ t->pctp = ctp; ++ t->pl1 = l1; ++ t->pbas = highbase; ++} +diff -ruN proll_18.orig/qemu/Makefile proll-patch4/qemu/Makefile +--- proll_18.orig/qemu/Makefile 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/qemu/Makefile 2004-11-13 15:50:49.000000000 +0000 +@@ -0,0 +1,119 @@ ++# ++# proll: ++# qemu/Makefile - make PROLL for QEMU ++# $Id: proll.patch,v 1.2 2004-12-19 23:18:01 bellard Exp $ ++# ++# Copyright 1999 Pete Zaitcev ++# This is Free Software is licensed under terms of GNU General Public License. ++# ++ ++CC = gcc ++ ++#CROSS = /usr/local/sparc/bin/sparc-sun-linux- ++CROSS = sparc-unknown-linux-gnu- ++ ++CROSSCC = $(CROSS)gcc ++CROSSLD = $(CROSS)ld ++CROSSNM = $(CROSS)nm ++ ++RM = /bin/rm -f ++ELFTOAOUT = elftoaout ++ ++# ++SRC = ../src ++ ++# Due to remapping algorithm PROLBASE should be algned on PMD. ++# We make PROLBASE a define instead of using _start because we ++# want to shift it to form a PGD entry. A relocatable label will not work. ++# Linux kernel expects us to be at LINUX_OPPROM_BEGVM . ++PROLBASE = 0xffd00000 ++PROLRODATA = 0xffd07000 ++PROLDATA = 0xffd09000 ++PROLSIZE = (240*1024) ++ ++# Linux ++# Fixed %g6 is for arch/sparc/kernel/head.S, it seems ok w/o -ffixed-g6. ++# Kernel uses -fcall-used-g5 -fcall-used-g7, we probably do not need them. ++# __ANSI__ is supposed to be on by default but it is not. ++CFLAGS = -O2 -Wall -DPROLBASE=$(PROLBASE) -DPROLDATA=$(PROLDATA) -DPROLRODATA=$(PROLRODATA) -D__ANSI__=1 -I$(SRC) -mcpu=hypersparc -g ++ASFLAGS = -D__ASSEMBLY__ -I$(SRC) -DPROLRODATA=$(PROLRODATA) -DPROLDATA=$(PROLDATA) -DPROLSIZE=$(PROLSIZE) -g ++# Solaris or Linux/i386 cross compilation ++#CFLAGS = -Iinclude -O ++ ++LDFLAGS = -N -Ttext $(PROLBASE) --section-start .rodata=$(PROLRODATA) -Tdata $(PROLDATA) -Tbss $(PROLDATA) ++ ++ALL = proll.aout ++PROLLEXE = proll.elf ++ ++OBJS = head.o wuf.o wof.o main.o vconsole.o hconsole.o rconsole.o \ ++ printf.o le.o system.o iommu.o \ ++ arp.o netinit.o bootp.o packet.o tftp.o udp.o sched_4m.o openprom.o ++ ++all: $(ALL) ++ ++$(PROLLEXE): $(OBJS) ++ $(CROSSLD) $(LDFLAGS) -o $(PROLLEXE) $(OBJS) ++ ++head.o: head.S $(SRC)/phys_jj.h \ ++ $(SRC)/asi.h $(SRC)/psr.h $(SRC)/crs.h ++ $(CROSSCC) $(ASFLAGS) -DPROLBASE=$(PROLBASE) -o $*.o -c $*.S ++ ++main.o: main.c $(SRC)/asi.h $(SRC)/pgtsrmmu.h $(SRC)/iommu.h \ ++ $(SRC)/phys_jj.h $(SRC)/vconsole.h $(SRC)/version.h $(SRC)/general.h \ ++ $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h ++ $(CROSSCC) $(CFLAGS) -c $*.c ++openprom.o: openprom.c $(SRC)/openprom.h $(SRC)/general.h $(SRC)/romlib.h \ ++ $(SRC)/vconsole.h $(SRC)/system.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $*.c ++ ++system.o: $(SRC)/system.c $(SRC)/vconsole.h $(SRC)/pgtsrmmu.h \ ++ $(SRC)/timer.h $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/asi.h \ ++ $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h $(SRC)/crs.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++iommu.o: $(SRC)/iommu.c $(SRC)/pgtsrmmu.h $(SRC)/phys_jj.h $(SRC)/iommu.h \ ++ $(SRC)/vconsole.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/asi.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++vconsole.o: $(SRC)/vconsole.c $(SRC)/vconsole.h $(SRC)/hconsole.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++hconsole.o: $(SRC)/hconsole.c $(SRC)/hconsole.h $(SRC)/rconsole.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++rconsole.o: $(SRC)/rconsole.c $(SRC)/rconsole.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++printf.o: $(SRC)/printf.c ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++le.o: $(SRC)/le.c $(SRC)/dma.h $(SRC)/system.h $(SRC)/netpriv.h $(SRC)/romlib.h $(SRC)/general.h $(SRC)/net.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++ ++arp.o: $(SRC)/arp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++netinit.o: $(SRC)/netinit.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++tftp.o: $(SRC)/tftp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/tftp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++udp.o: $(SRC)/udp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++packet.o: $(SRC)/packet.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++sched_4m.o: $(SRC)/sched_4m.c $(SRC)/system.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++bootp.o: $(SRC)/bootp.c $(SRC)/general.h $(SRC)/net.h \ ++ $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/bootp.h ++ $(CROSSCC) $(CFLAGS) -DNOBPEXT=1 -c $(SRC)/$*.c ++ ++wuf.o: $(SRC)/wuf.S ++ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S ++wof.o: $(SRC)/wof.S ++ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S ++ ++#genlab.o: genlab.c ++# $(CC) -c $*.c ++# ++#genlab: genlab.o ++# $(CC) -o genlab genlab.o ++ ++clean: ++ $(RM) $(OBJS) ++ $(RM) $(PROLLEXE) proll.aout ++ ++proll.aout: $(PROLLEXE) ++ $(ELFTOAOUT) -o proll.aout $(PROLLEXE) +diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c +--- proll_18.orig/qemu/openprom.c 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/qemu/openprom.c 2004-11-23 19:14:05.000000000 +0000 +@@ -0,0 +1,596 @@ ++/* ++ * PROM interface support ++ * Copyright 1996 The Australian National University. ++ * Copyright 1996 Fujitsu Laboratories Limited ++ * Copyright 1999 Pete A. Zaitcev ++ * This software may be distributed under the terms of the Gnu ++ * Public License version 2 or later ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "phys_jj.h" ++ ++struct property { ++ const char *name; ++ const char *value; ++ const int length; ++}; ++ ++struct node { ++ const struct property *properties; ++ /* short */ const int sibling; ++ /* short */ const int child; ++}; ++ ++static int obp_nextnode(int node); ++static int obp_child(int node); ++static int obp_proplen(int node, char *name); ++static int obp_getprop(int node, char *name, char *val); ++static int obp_setprop(int node, char *name, char *val, int len); ++static const char *obp_nextprop(int node, char *name); ++ ++static char obp_idprom[IDPROM_SIZE]; ++static const struct property null_properties = { NULL, NULL, -1 }; ++static const int prop_true = -1; ++ ++static const struct property propv_root[] = { ++ {"name", "SUNW,JavaStation-1", sizeof("SUNW,JavaStation-1") }, ++ {"idprom", obp_idprom, IDPROM_SIZE}, ++ {"banner-name", "JavaStation", sizeof("JavaStation")}, ++ {"compatible", "sun4m", 6}, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_iommu_reg[] = { ++ 0x0, 0x10000000, 0x00000300, ++}; ++static const struct property propv_iommu[] = { ++ {"name", "iommu", sizeof("iommu")}, ++ {"reg", (char*)&prop_iommu_reg[0], sizeof(prop_iommu_reg) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_sbus_ranges[] = { ++ 0x0, 0x0, 0x0, 0x30000000, 0x10000000, ++ 0x1, 0x0, 0x0, 0x40000000, 0x10000000, ++ 0x2, 0x0, 0x0, 0x50000000, 0x10000000, ++ 0x3, 0x0, 0x0, 0x60000000, 0x10000000, ++ 0x4, 0x0, 0x0, 0x70000000, 0x10000000, ++}; ++static const struct property propv_sbus[] = { ++ {"name", "sbus", 5}, ++ {"ranges", (char*)&prop_sbus_ranges[0], sizeof(prop_sbus_ranges)}, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_tcx_regs[] = { ++ 0x2, 0x00800000, 0x00100000, ++ 0x2, 0x02000000, 0x00000001, ++ 0x2, 0x04000000, 0x00800000, ++ 0x2, 0x06000000, 0x00800000, ++ 0x2, 0x0a000000, 0x00000001, ++ 0x2, 0x0c000000, 0x00000001, ++ 0x2, 0x0e000000, 0x00000001, ++ 0x2, 0x00700000, 0x00001000, ++ 0x2, 0x00200000, 0x00000004, ++ 0x2, 0x00300000, 0x0000081c, ++ 0x2, 0x00000000, 0x00010000, ++ 0x2, 0x00240000, 0x00000004, ++ 0x2, 0x00280000, 0x00000001, ++}; ++ ++#if 1 /* Zaitcev */ ++static const int pixfreq = 0x03dfd240; ++static const int hbporch = 0xa0; ++static const int vfreq = 0x3c; ++#endif ++#if 0 /* Kevin Boone - 70Hz refresh */ ++static const int pixfreq = 0x047868C0; ++static const int hbporch = 0x90; ++static const int vfreq = 0x46; ++#endif ++ ++static const int vbporch = 0x1d; ++static const int vsync = 0x6; ++static const int hsync = 0x88; ++static const int vfporch = 0x3; ++static const int hfporch = 0x18; ++static const int height = 0x300; ++static const int width = 0x400; ++static const int linebytes = 0x400; ++static const int depth = 8; ++static const int tcx_intr[] = { 5, 0 }; ++static const int tcx_interrupts = 5; ++static const struct property propv_sbus_tcx[] = { ++ {"name", "SUNW,tcx", sizeof("SUNW,tcx")}, ++ {"vbporch", (char*)&vbporch, sizeof(int)}, ++ {"hbporch", (char*)&hbporch, sizeof(int)}, ++ {"vsync", (char*)&vsync, sizeof(int)}, ++ {"hsync", (char*)&hsync, sizeof(int)}, ++ {"vfporch", (char*)&vfporch, sizeof(int)}, ++ {"hfporch", (char*)&hfporch, sizeof(int)}, ++ {"pixfreq", (char*)&pixfreq, sizeof(int)}, ++ {"vfreq", (char*)&vfreq, sizeof(int)}, ++ {"height", (char*)&height, sizeof(int)}, ++ {"width", (char*)&width, sizeof(int)}, ++ {"linebytes", (char*)&linebytes, sizeof(int)}, ++ {"depth", (char*)&depth, sizeof(int)}, ++ {"reg", (char*)&prop_tcx_regs[0], sizeof(prop_tcx_regs)}, ++ {"tcx-8-bit", (char*)&prop_true, 0}, ++ {"intr", (char*)&tcx_intr[0], sizeof(tcx_intr)}, ++ {"interrupts", (char*)&tcx_interrupts, sizeof(tcx_interrupts)}, ++ {"device_type", "display", sizeof("display")}, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_cs4231_reg[] = { ++ 0x3, 0x0C000000, 0x00000040 ++}; ++static const int cs4231_interrupts = 5; ++static const int cs4231_intr[] = { 5, 0 }; ++ ++static const struct property propv_sbus_cs4231[] = { ++ {"name", "SUNW,CS4231", sizeof("SUNW,CS4231") }, ++ {"intr", (char*)&cs4231_intr[0], sizeof(cs4231_intr) }, ++ {"interrupts", (char*)&cs4231_interrupts, sizeof(cs4231_interrupts) }, ++ {"reg", (char*)&prop_cs4231_reg[0], sizeof(prop_cs4231_reg) }, ++ {"device_type", "serial", sizeof("serial") }, ++ {"alias", "audio", sizeof("audio") }, ++ {NULL, NULL, -1} ++}; ++ ++static const int cpu_nctx = NCTX_SWIFT; ++static const int cpu_cache_line_size = 0x20; ++static const int cpu_cache_nlines = 0x200; ++static const struct property propv_cpu[] = { ++ {"name", "STP1012PGA", sizeof("STP1012PGA") }, ++ {"device_type", "cpu", 4 }, ++ {"mmu-nctx", (char*)&cpu_nctx, sizeof(int)}, ++ {"cache-line-size", (char*)&cpu_cache_line_size, sizeof(int)}, ++ {"cache-nlines", (char*)&cpu_cache_nlines, sizeof(int)}, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_obio_ranges[] = { ++ 0x0, 0x0, 0x0, 0x71000000, 0x01000000, ++}; ++static const struct property propv_obio[] = { ++ {"name", "obio", 5 }, ++ {"ranges", (char*)&prop_obio_ranges[0], sizeof(prop_obio_ranges) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_auxio_reg[] = { ++ 0x0, 0x00900000, 0x00000001, ++}; ++static const struct property propv_obio_auxio[] = { ++ {"name", "auxio", sizeof("auxio") }, ++ {"reg", (char*)&prop_auxio_reg[0], sizeof(prop_auxio_reg) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_int_reg[] = { ++ 0x0, 0x00e00000, 0x00000010, ++ 0x0, 0x00e10000, 0x00000010, ++}; ++static const struct property propv_obio_int[] = { ++ {"name", "interrupt", sizeof("interrupt")}, ++ {"reg", (char*)&prop_int_reg[0], sizeof(prop_int_reg) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_cnt_reg[] = { ++ 0x0, 0x00d00000, 0x00000010, ++ 0x0, 0x00d10000, 0x00000010, ++}; ++static const struct property propv_obio_cnt[] = { ++ {"name", "counter", sizeof("counter")}, ++ {"reg", (char*)&prop_cnt_reg[0], sizeof(prop_cnt_reg) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_eeprom_reg[] = { ++ 0x0, 0x00200000, 0x00002000, ++}; ++static const struct property propv_obio_eep[] = { ++ {"name", "eeprom", sizeof("eeprom")}, ++ {"reg", (char*)&prop_eeprom_reg[0], sizeof(prop_eeprom_reg) }, ++ {"model", "mk48t08", sizeof("mk48t08")}, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_su_reg[] = { ++ 0x0, 0x003002f8, 0x00000008, ++}; ++static const struct property propv_obio_su[] = { ++ {"name", "su", sizeof("su")}, ++ {"reg", (char*)&prop_su_reg[0], sizeof(prop_su_reg) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_zs_intr[] = { 0x26, 0x0 }; ++static const int prop_zs_reg[] = { ++ 0x4, 0x00000000, 0x0000000f, ++}; ++static const int prop_zs_slave[] = { 0x1 }; ++static const struct property propv_obio_zs[] = { ++ {"name", "zs", sizeof("zs")}, ++ {"reg", (char*)&prop_zs_reg[0], sizeof(prop_zs_reg) }, ++ {"reg", (char*)&prop_zs_slave[0], sizeof(prop_zs_slave) }, ++ {"device_type", "serial", sizeof("serial") }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_zs1_intr[] = { 0x26, 0x0 }; ++static const int prop_zs1_reg[] = { ++ 0x4, 0x00100000, 0x0000000f, ++}; ++static const int prop_zs1_slave[] = { 0x0 }; ++static const struct property propv_obio_zs1[] = { ++ {"name", "zs", sizeof("zs")}, ++ {"reg", (char*)&prop_zs1_reg[0], sizeof(prop_zs1_reg) }, ++ {"reg", (char*)&prop_zs1_slave[0], sizeof(prop_zs1_slave) }, ++ {"device_type", "serial", sizeof("serial") }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_ledma_reg[] = { ++ 0x4, 0x08400010, 0x00000020, ++}; ++static const int prop_ledma_burst = 0x3f; ++static const struct property propv_sbus_ledma[] = { ++ {"name", "ledma", sizeof("ledma")}, ++ {"reg", (char*)&prop_ledma_reg[0], sizeof(prop_ledma_reg) }, ++ {"burst-sizes", (char*)&prop_ledma_burst, sizeof(int) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_le_reg[] = { ++ 0x4, 0x08c00000, 0x00000004, ++}; ++static const int prop_le_busmaster_regval = 0x7; ++static const int prop_le_intr[] = { 0x26, 0x0 }; ++static const struct property propv_sbus_ledma_le[] = { ++ {"name", "le", sizeof("le")}, ++ {"reg", (char*)&prop_le_reg[0], sizeof(prop_le_reg) }, ++ {"busmaster-regval", (char*)&prop_le_busmaster_regval, sizeof(int)}, ++ {"intr", (char*)&prop_le_intr[0], sizeof(prop_le_intr) }, ++ {NULL, NULL, -1} ++}; ++ ++static const struct node nodes[] = { ++ { &null_properties, 1, 0 }, /* 0 = big brother of root */ ++ { propv_root, 0, 2 }, /* 1 "/" */ ++ { propv_iommu, 8, 3 }, /* 2 "/iommu" */ ++ { propv_sbus, 0, 4 }, /* 3 "/iommu/sbus" */ ++ { propv_sbus_tcx, 5, 0 }, /* 4 "/iommu/sbus/SUNW,tcx" */ ++ { propv_sbus_ledma, 7, 6 }, /* 5 "/iommu/sbus/ledma" */ ++ { propv_sbus_ledma_le, 0, 0 }, /* 6 "/iommu/sbus/ledma/le" */ ++ { propv_sbus_cs4231, 0, 0 }, /* 7 "/iommu/sbus/SUNW,CS4231 */ ++ { propv_cpu, 9, 0 }, /* 8 "/STP1012PGA" */ ++ { propv_obio, 0, 10 }, /* 9 "/obio" */ ++ { propv_obio_int, 11, 0 }, /* 10 "/obio/interrupt" */ ++ { propv_obio_cnt, 12, 0 }, /* 11 "/obio/counter" */ ++ { propv_obio_eep, 13, 0 }, /* 12 "/obio/eeprom" */ ++ { propv_obio_su, 14, 0 }, /* 13 "/obio/su" */ ++ { propv_obio_auxio, 0, 0 }, /* 14 "/obio/auxio" */ ++ { propv_obio_zs, 0, 0 }, /* 14 "/obio/zs@0,0" */ ++ { propv_obio_zs1, 0, 0 }, /* 14 "/obio/zs@0,100000" */ ++}; ++ ++static struct linux_mlist_v0 totphys[MAX_BANKS]; ++static struct linux_mlist_v0 totmap[1]; ++static struct linux_mlist_v0 totavail[MAX_BANKS]; ++ ++static struct linux_mlist_v0 *ptphys; ++static struct linux_mlist_v0 *ptmap; ++static struct linux_mlist_v0 *ptavail; ++ ++static const struct linux_nodeops nodeops0 = { ++ obp_nextnode, /* int (*no_nextnode)(int node); */ ++ obp_child, /* int (*no_child)(int node); */ ++ obp_proplen, /* int (*no_proplen)(int node, char *name); */ ++ obp_getprop, /* int (*no_getprop)(int node,char *name,char *val); */ ++ obp_setprop, /* int (*no_setprop)(int node, char *name, ++ char *val, int len); */ ++ obp_nextprop /* char * (*no_nextprop)(int node, char *name); */ ++}; ++ ++static const char arg_nfsroot[] = "console=ttyS0 ip=bootp root=nfs"; ++ ++static const struct linux_arguments_v0 obp_arg = { ++ { "le()", arg_nfsroot, NULL, NULL, NULL, NULL, NULL, NULL }, ++ { "" }, ++ { 'l', 'e' }, 0, 0, 0, NULL, ++ NULL ++}; ++static const struct linux_arguments_v0 * const obp_argp = &obp_arg; ++ ++static const void * const synch_hook = NULL; ++#if 0 ++static const char obp_stdin = PROMDEV_KBD; ++static const char obp_stdout = PROMDEV_SCREEN; ++#else ++static const char obp_stdin = PROMDEV_TTYA; ++static const char obp_stdout = PROMDEV_TTYA; ++#endif ++ ++static int obp_nbgetchar(void); ++static int obp_nbputchar(int ch); ++static void obp_reboot(char *); ++static void obp_abort(void); ++static void obp_halt(void); ++static int obp_devopen(char *str); ++static int obp_devclose(int dev_desc); ++static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf); ++ ++static void doublewalk(unsigned ptab1, unsigned va) ++{ ++unsigned int proc_tablewalk(int ctx, unsigned int va); ++unsigned int mem_tablewalk(unsigned int pa, unsigned int va); ++ ++ proc_tablewalk(0, va); ++ if (ptab1 != 0) mem_tablewalk(ptab1, va); ++} ++ +#ifdef ORIG - #if 0 /* RARP */ - if (rarp() != 0) fatal(); - /* printrarp(); */ -@@ -117,13 +118,20 @@ - xtoa(myipaddr, fname, 8); - if (load(boot_rec.bp_siaddr, fname) != 0) fatal(); ++static const struct linux_romvec romvec0 = { ++ LINUX_OPPROM_MAGIC, /* pv_magic_cookie */ ++ 0, /* pv_romvers - Format selector! */ ++ 77, /* pv_plugin_revision */ ++ 0x10203, /* pv_printrev */ ++ { /* pv_v0mem */ ++ &ptphys, /* v0_totphys */ ++ &ptmap, /* v0_prommap */ ++ &ptavail /* v0_available */ ++ }, ++ &nodeops0, /* struct linux_nodeops *pv_nodeops; */ ++ (void*)doublewalk, /* P3 */ /* char **pv_bootstr; */ ++ { /* struct linux_dev_v0_funcs pv_v0devops; */ ++ &obp_devopen, /* v0_devopen */ ++ &obp_devclose, /* v0_devclose */ ++ &obp_rdblkdev, /* v0_rdblkdev */ ++ NULL, /* v0_wrblkdev */ ++ NULL, /* v0_wrnetdev */ ++ NULL, /* v0_rdnetdev */ ++ NULL, /* v0_rdchardev */ ++ NULL, /* v0_wrchardev */ ++ NULL /* v0_seekdev */ ++ }, ++ &obp_stdin, /* char *pv_stdin */ ++ &obp_stdout, /* char *pv_stdout; */ ++ obp_nbgetchar, /* int (*pv_getchar)(void); */ ++ obp_nbputchar, /* void (*pv_putchar)(int ch); */ ++ obp_nbgetchar, /* int (*pv_nbgetchar)(void); */ ++ obp_nbputchar, /* int (*pv_nbputchar)(int ch); */ ++ NULL, /* void (*pv_putstr)(char *str, int len); */ ++ obp_reboot, /* void (*pv_reboot)(char *bootstr); */ ++ NULL, /* void (*pv_printf)(__const__ char *fmt, ...); */ ++ obp_abort, /* void (*pv_abort)(void); */ ++ NULL, /* __volatile__ int *pv_ticks; */ ++ obp_halt, /* void (*pv_halt)(void); */ ++ (void *)&synch_hook, /* void (**pv_synchook)(void); */ ++ ++#if 0 ++ /* Evaluate a forth string, not different proto for V0 and V2->up. */ ++ union { ++ void (*v0_eval)(int len, char *str); ++ void (*v2_eval)(char *str); ++ } pv_fortheval; ++#endif ++ { 0 }, /* pv_fortheval */ ++ ++ &obp_argp, /* struct linux_arguments_v0 **pv_v0bootargs; */ ++ NULL, /* pv_enaddr */ ++ { /* pv_v2bootargs */ ++ NULL, /* char **bootpath; */ ++ NULL, /* char **bootargs; */ ++ NULL, /* fd_stdin; */ ++ NULL, /* fd_stdout */ ++ }, ++ { /* pv_v2devops */ ++ NULL, /* v2_inst2pkg */ ++ NULL, /* v2_dumb_mem_alloc */ ++ NULL, /* v2_dumb_mem_free */ ++ NULL, /* v2_dumb_mmap */ ++ NULL, /* v2_dumb_munmap */ ++ NULL, /* v2_dev_open */ ++ NULL, /* v2_dev_close */ ++ NULL, /* v2_dev_read */ ++ NULL, /* v2_dev_write */ ++ NULL, /* v2_dev_seek */ ++ NULL, /* v2_wheee2 */ ++ NULL, /* v2_wheee3 */ ++ }, ++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* filler[15] */ ++ NULL, /* pv_setctxt */ ++ NULL, /* v3_cpustart */ ++ NULL, /* v3_cpustop */ ++ NULL, /* v3_cpuidle */ ++ NULL /* v3_cpuresume */ ++}; ++#endif ++ ++static struct linux_romvec romvec0; ++ ++void * ++init_openprom(int bankc, struct bank *bankv, unsigned hiphybas) ++{ ++ int i; ++ ++ /* ++ * Avoid data segment allocations ++ */ ++ ptphys = totphys; ++ ptmap = totmap; ++ ptavail = totavail; ++ /* ++ * Form memory descriptors. ++ */ ++ for (i = 0; i < bankc; i++) { ++ totphys[i].theres_more = &totphys[i+1]; ++ totphys[i].start_adr = (char*) bankv[i].start; ++ totphys[i].num_bytes = bankv[i].length; ++ } ++ totphys[i-1].theres_more = 0; ++ ++ /* ++ * XXX Merged in normal PROM when full banks touch. ++ */ ++ for (i = 0; i < bankc; i++) { ++ unsigned bankbase = bankv[i].start; ++ unsigned banksize = bankv[i].length; ++ if (hiphybas > bankbase && ++ hiphybas < bankbase + banksize) { ++ banksize = hiphybas - bankbase; ++ } ++ totavail[i].theres_more = &totavail[i+1]; ++ totavail[i].start_adr = (char*) bankbase; ++ totavail[i].num_bytes = banksize; ++ } ++ totavail[i-1].theres_more = 0; ++ ++ totmap[0].theres_more = 0; ++ totmap[0].start_adr = (char*) PROLBASE; ++ totmap[0].num_bytes = PROLSIZE; ++ ++ /* ++ * idprom ++ */ ++ bcopy(idprom, obp_idprom, IDPROM_SIZE); ++ ++ // Linux wants a R/W romvec table ++ romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC; ++ romvec0.pv_plugin_revision = 77; ++ romvec0.pv_printrev = 0x10203; ++ romvec0.pv_v0mem.v0_totphys = &ptphys; ++ romvec0.pv_v0mem.v0_prommap = &ptmap; ++ romvec0.pv_v0mem.v0_available = &ptavail; ++ romvec0.pv_nodeops = &nodeops0; ++ romvec0.pv_bootstr = (void *)doublewalk; ++ romvec0.pv_stdin = &obp_stdin; ++ romvec0.pv_stdout = &obp_stdout; ++ romvec0.pv_getchar = obp_nbgetchar; ++ romvec0.pv_putchar = obp_nbputchar; ++ romvec0.pv_nbgetchar = obp_nbgetchar; ++ romvec0.pv_nbputchar = obp_nbputchar; ++ romvec0.pv_reboot = obp_reboot; ++ romvec0.pv_abort = obp_abort; ++ romvec0.pv_halt = obp_halt; ++ romvec0.pv_synchook = &synch_hook; ++ romvec0.pv_v0bootargs = &obp_argp; ++ return &romvec0; ++} ++ ++static const struct property *find_property(int node,char *name) ++{ ++ const struct property *prop = &nodes[node].properties[0]; ++ while (prop && prop->name) { ++ if (bcmp(prop->name, name, 128) == 0) return prop; ++ prop++; ++ } ++ return NULL; ++} ++ ++static int obp_nextnode(int node) ++{ ++ return nodes[node].sibling; ++} ++ ++static int obp_child(int node) ++{ ++ return nodes[node].child; ++} ++ ++static int obp_proplen(int node, char *name) ++{ ++ const struct property *prop = find_property(node,name); ++ if (prop) return prop->length; ++ return -1; ++} ++ ++static int obp_getprop(int node, char *name, char *value) ++{ ++ const struct property *prop; ++ ++ prop = find_property(node,name); ++ if (prop) { ++ memcpy(value,prop->value,prop->length); ++ //printk("obp_getprop '%s'= %s\n", name, value); ++ return prop->length; ++ } ++ //printk("obp_getprop: not found\n"); ++ return -1; ++} ++ ++static int obp_setprop(int node, char *name, char *value, int len) ++{ ++ return -1; ++} ++ ++static const char *obp_nextprop(int node,char *name) ++{ ++ const struct property *prop = find_property(node,name); ++ if (prop) return prop[1].name; ++ return NULL; ++} ++ ++#if 0 ++static unsigned char calc_idprom_cksum(struct idprom *idprom) ++{ ++ unsigned char cksum, i, *ptr = (unsigned char *)idprom; ++ ++ for (i = cksum = 0; i <= 0x0E; i++) ++ cksum ^= *ptr++; ++ ++ return cksum; ++} ++#endif ++ ++static int obp_nbgetchar(void) { ++ return -1; ++} ++ ++static int obp_nbputchar(int ch) { ++ extern struct vconterm dp0; ++ char buf = ch; ++ ++ /* We do not use printk() in order to reduce stack depth. */ ++ vcon_write(&dp0, &buf, 1); ++ return 0; ++} ++ ++static void obp_reboot(char *str) { ++ printk("rebooting (%s): not implemented, freezing\n", str); ++ for (;;) {} ++} ++ ++static void obp_abort() { ++ printk("abort, freezing\n"); ++ for (;;) {} ++} ++ ++static void obp_halt() { ++ printk("halt, freezing\n"); ++ for (;;) {} ++} ++ ++static int obp_devopen(char *str) { ++ //printk("open %s\n", str); ++ return 0; ++} ++ ++static int obp_devclose(int dev_desc) { ++ //printk("close %d\n", dev_desc); ++ return 0; ++} ++ ++static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf) { ++ //printk("rdblkdev: fd %d, num_blks %d, blk_st %d, buf 0x%x\n", dev_desc, num_blks, blk_st, buf); ++ //buf[8] = 'L'; ++ return num_blks; ++} +diff -ruN proll_18.orig/src/arp.c proll-patch4/src/arp.c +--- proll_18.orig/src/arp.c 2001-12-24 05:12:31.000000000 +0000 ++++ proll-patch4/src/arp.c 2004-11-13 15:50:49.000000000 +0000 +@@ -45,7 +45,7 @@ + #endif + static struct arp_cache arp_list[ARPNUM]; /* ARP address cache */ + static int next_arp; /* next table entry */ +-static t_ipaddr def_gw = IP_ANY; /* default routing */ ++static t_ipaddr def_gw; /* default routing */ + + + +@@ -144,7 +144,7 @@ + * + * Resolve IP address and return pointer to hardware address. + */ +-unsigned char *ip_resolve(ip) ++const unsigned char *ip_resolve(ip) + t_ipaddr ip; + { + int i; +@@ -230,14 +230,11 @@ + */ + int init_arp() + { +- /* Set name of module for error messages */ +- net_module_name = "arp"; +- + #ifndef NOARP + /* Register ARP packet type and set send buffer pointer */ + if ((arpbuf = (struct arphdr *)reg_type(htons(ETH_P_ARP), arp_recv)) == NULL) + return(FALSE); #endif +- ++ def_gw = IP_ANY; + return(TRUE); + } +diff -ruN proll_18.orig/src/arp.h proll-patch4/src/arp.h +--- proll_18.orig/src/arp.h 1999-03-18 03:39:43.000000000 +0000 ++++ proll-patch4/src/arp.h 2004-11-13 15:50:49.000000000 +0000 +@@ -104,7 +104,7 @@ + extern int init_arp __P((void)); + + /* Resolve IP address and return pointer to hardware address */ +-extern unsigned char *ip_resolve __P((t_ipaddr ip)); ++extern const unsigned char *ip_resolve __P((t_ipaddr ip)); + + /* Add a new antry to the ARP cache */ + extern void addcache __P((unsigned char *ha, t_ipaddr ip)); +diff -ruN proll_18.orig/src/hconsole.c proll-patch4/src/hconsole.c +--- proll_18.orig/src/hconsole.c 2002-07-23 05:52:48.000000000 +0000 ++++ proll-patch4/src/hconsole.c 2004-11-13 15:50:49.000000000 +0000 +@@ -42,7 +42,11 @@ + * No probing sequence or argument passing, hardcode everything. XXX + */ + raster8_cons_a(q, 768, 1024, (char *)a0); ++#if 1 + raster_cons_2(r, q, 768-(24*11)-1, 1024-(8*80)-1, (24*11), (8*80)); ++#else ++ raster_cons_2(r, q, 0, 0, 768, 1024); +#endif + t->r_ = r; + t->r0_ = q; + t->f_ = &f_master; +diff -ruN proll_18.orig/src/lat7_2.bm proll-patch4/src/lat7_2.bm +--- proll_18.orig/src/lat7_2.bm 1999-02-27 05:48:54.000000000 +0000 ++++ proll-patch4/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 +@@ -1,6 +1,6 @@ + #define lat7_2_width 128 + #define lat7_2_height 88 +-static unsigned char lat7_2_bits[] = { ++static unsigned const char lat7_2_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x12, 0x1e, 0x0c, 0x02, 0x70, 0x18, + 0x22, 0x22, 0x18, 0x00, 0x00, 0x18, 0x18, 0xff, 0x18, 0x00, 0x12, 0x02, +diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch4/src/lat7_2_swapped.bm +--- proll_18.orig/src/lat7_2_swapped.bm 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 +@@ -0,0 +1,121 @@ ++#define lat7_2_width 128 ++#define lat7_2_height 88 ++static unsigned const char lat7_2_bits[] = { ++ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x55, 0x00, 0x2a, 0x00, 0x55, 0x00, 0x2a, 0x00, 0x55, 0x00, 0x00, 0x48, ++ 0x48, 0x78, 0x48, 0x5f, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x78, 0x40, ++ 0x70, 0x40, 0x4f, 0x08, 0x0e, 0x08, 0x08, 0x00, 0x00, 0x30, 0x40, 0x40, ++ 0x40, 0x3e, 0x09, 0x0e, 0x0a, 0x09, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, ++ 0x7f, 0x08, 0x0e, 0x08, 0x08, 0x00, 0x00, 0x0e, 0x0a, 0x0e, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, ++ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x44, 0x64, 0x54, 0x4c, 0x54, 0x10, 0x10, ++ 0x10, 0x1f, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x1f, 0x04, 0x04, 0x04, ++ 0x04, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, ++ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0xff, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, ++ 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, ++ 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x00, ++ 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, ++ 0x06, 0x0c, 0x18, 0x30, 0x18, 0x6c, 0x36, 0x18, 0x0c, 0x00, 0x00, 0x60, ++ 0x30, 0x18, 0x0c, 0x18, 0x36, 0x6c, 0x18, 0x30, 0x00, 0x00, 0x7f, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x7e, ++ 0x18, 0x7e, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x30, 0x78, ++ 0x30, 0x72, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, ++ 0x00, 0x00, 0x00, 0x66, 0x66, 0x22, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x36, 0x7f, 0x36, 0x36, 0x36, 0x7f, 0x36, 0x00, 0x00, 0x00, ++ 0x00, 0x66, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, ++ 0x72, 0x56, 0x6c, 0x18, 0x36, 0x6a, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x24, 0x28, 0x30, 0x4a, 0x44, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, ++ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x18, ++ 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x18, 0x18, ++ 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0x7e, 0x3c, ++ 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, ++ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, ++ 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x00, ++ 0x00, 0x3c, 0x46, 0x4e, 0x5a, 0x72, 0x62, 0x3c, 0x00, 0x00, 0x00, 0x00, ++ 0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, ++ 0x66, 0x06, 0x0c, 0x18, 0x32, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, ++ 0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, ++ 0x66, 0x7e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x60, 0x7c, 0x66, ++ 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x7c, 0x66, 0x66, ++ 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x46, 0x06, 0x0c, 0x18, 0x30, ++ 0x30, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, ++ 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, ++ 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, ++ 0x06, 0x0c, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x5e, ++ 0x56, 0x5e, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x66, ++ 0x7e, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x66, ++ 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, ++ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, ++ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x62, 0x60, 0x78, 0x60, 0x62, 0x7e, 0x00, ++ 0x00, 0x00, 0x00, 0x7e, 0x62, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00, 0x00, ++ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x6e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, ++ 0x00, 0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, ++ 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7e, ++ 0x46, 0x06, 0x06, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6c, ++ 0x78, 0x70, 0x78, 0x6c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, ++ 0x60, 0x60, 0x62, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x41, 0x63, 0x77, 0x7f, ++ 0x6b, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x76, 0x7e, 0x6e, ++ 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, ++ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, ++ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x6e, 0x3c, 0x02, ++ 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x00, 0x00, ++ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x3c, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, ++ 0x00, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, ++ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x66, ++ 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, ++ 0x63, 0x6b, 0x6b, 0x7f, 0x36, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3c, ++ 0x18, 0x3c, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, ++ 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x46, 0x0c, 0x18, 0x30, ++ 0x62, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, ++ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x10, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x60, ++ 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, ++ 0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, ++ 0x7e, 0x60, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x78, ++ 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x66, 0x66, ++ 0x3e, 0x06, 0x3c, 0x00, 0x00, 0x60, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, ++ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x1c, 0x00, ++ 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, ++ 0x00, 0x00, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x7c, 0x66, 0x00, 0x00, 0x00, ++ 0x00, 0x60, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x76, 0x7f, 0x6b, 0x6b, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, ++ 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x66, ++ 0x66, 0x66, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x72, 0x60, ++ 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x3c, 0x06, ++ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x78, 0x30, 0x30, 0x36, 0x1c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3a, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x63, 0x6b, 0x6b, 0x6b, 0x36, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 0x00, 0x00, 0x00, ++ 0x00, 0x7e, 0x0c, 0x18, 0x30, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, ++ 0x18, 0x30, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, ++ 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x30, 0x18, 0x18, 0x0c, ++ 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00}; +diff -ruN proll_18.orig/src/le.c proll-patch4/src/le.c +--- proll_18.orig/src/le.c 2002-07-23 05:52:49.000000000 +0000 ++++ proll-patch4/src/le.c 2004-11-13 15:50:49.000000000 +0000 +@@ -185,8 +185,6 @@ + unsigned short rap; /* register address port */ + }; + +-int sparc_lance_debug = 2; +- + /* The Lance uses 24 bit addresses */ + /* On the Sun4c the DVMA will provide the remaining bytes for us */ + /* On the Sun4m we have to instruct the ledma to provide them */ +diff -ruN proll_18.orig/src/netinit.c proll-patch4/src/netinit.c +--- proll_18.orig/src/netinit.c 2002-09-13 21:53:33.000000000 +0000 ++++ proll-patch4/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 +@@ -49,13 +49,20 @@ + unsigned char myhwaddr[ETH_ALEN]; /* my own hardware addr */ + t_ipaddr myipaddr; /* my own IP address */ + t_ipaddr mynetmask; /* my own netmask */ +- char *net_module_name; /* name of init module */ + t_ipaddr servaddr; /* IP of RARP&TFTP server */ + + /* Broadcast hardware address */ +-unsigned char bcasthw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ++const unsigned char bcasthw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + ++unsigned int seed; ++ ++/* This is taken from x86 to be used in network kernel. Returns 15 bits. */ ++short int random() ++{ ++ seed = (seed + 23968)*0x015A4E35 >> 1; ++ return seed & 0x7FFF; ++} + + /* + ************************************************************************** +@@ -104,10 +111,17 @@ + */ + void init_net() + { ++ /* Avoid data segment allocations */ ++ seed = 151; ++ + /* Initialize the different network layer modules */ + init_packet(); +- if (!init_arp() || !init_udp()) { +- printf("\nERROR: init_%s\n", net_module_name); ++ if (!init_arp()) { ++ printf("\nERROR: init_arp\n"); ++ fatal(); ++ } ++ if (!init_udp()) { ++ printf("\nERROR: init_udp\n"); + fatal(); + } + } +diff -ruN proll_18.orig/src/netpriv.h proll-patch4/src/netpriv.h +--- proll_18.orig/src/netpriv.h 1999-04-27 05:39:37.000000000 +0000 ++++ proll-patch4/src/netpriv.h 2004-11-13 15:50:49.000000000 +0000 +@@ -130,10 +130,9 @@ + * + */ + extern unsigned char myhwaddr[ETH_ALEN]; /* my own hardware address */ +-extern unsigned char bcasthw[ETH_ALEN]; /* broadcast hardware addr */ ++extern const unsigned char bcasthw[ETH_ALEN]; /* broadcast hardware addr */ + extern t_ipaddr myipaddr; /* my own IP address */ + extern t_ipaddr mynetmask; /* netmask for my network */ +-extern char *net_module_name; /* initialized module's name */ + extern t_ipaddr servaddr; /* server IP address */ + + +@@ -150,7 +149,7 @@ + extern unsigned char *reg_type __P((int typeval, int (* receive)())); + + /* Write a packet to the network */ +-extern int write_packet __P((int bufsize, int typeval, unsigned char *addr)); ++extern int write_packet __P((int bufsize, int typeval, const unsigned char *addr)); + + /* Empty read buffer */ + extern void empty_buf __P((void)); +diff -ruN proll_18.orig/src/openprom.h proll-patch4/src/openprom.h +--- proll_18.orig/src/openprom.h 2002-07-14 02:26:30.000000000 +0000 ++++ proll-patch4/src/openprom.h 2004-11-13 15:50:49.000000000 +0000 +@@ -54,20 +54,20 @@ + }; + + struct linux_mem_v0 { +- struct linux_mlist_v0 **v0_totphys; +- struct linux_mlist_v0 **v0_prommap; +- struct linux_mlist_v0 **v0_available; /* What we can use */ ++ struct linux_mlist_v0 * const *v0_totphys; ++ struct linux_mlist_v0 * const *v0_prommap; ++ struct linux_mlist_v0 * const *v0_available; /* What we can use */ + }; + + /* Arguments sent to the kernel from the boot prompt. */ + struct linux_arguments_v0 { +- char *argv[8]; ++ const char *argv[8]; + char args[100]; + char boot_dev[2]; + int boot_dev_ctrl; + int boot_dev_unit; + int dev_partition; +- char *kernel_file_name; ++ const char *kernel_file_name; + void *aieee1; /* XXX */ + }; - romvec = init_openprom(bb.nbanks, bb.bankv, hiphybas); +@@ -91,13 +91,13 @@ + struct linux_mem_v0 pv_v0mem; - printk("Memory used: virt 0x%x:0x%x[%dK] iomap 0x%x:0x%x\n", - PROLBASE, (int)cmem.curp, ((unsigned) cmem.curp - PROLBASE)/1024, - (int)cio.start, (int)cio.curp); + /* Node operations. */ +- struct linux_nodeops *pv_nodeops; ++ const struct linux_nodeops *pv_nodeops; + + char **pv_bootstr; + struct linux_dev_v0_funcs pv_v0devops; + +- char *pv_stdin; +- char *pv_stdout; ++ const char *pv_stdin; ++ const char *pv_stdout; + #define PROMDEV_KBD 0 /* input from keyboard */ + #define PROMDEV_SCREEN 0 /* output to screen */ + #define PROMDEV_TTYA 1 /* in/out to ttya */ +@@ -127,7 +127,7 @@ + void (*v2_eval)(char *str); + } pv_fortheval; + +- struct linux_arguments_v0 **pv_v0bootargs; ++ const struct linux_arguments_v0 * const *pv_v0bootargs; + + /* Get ether address. */ + unsigned int (*pv_enaddr)(int d, char *enaddr); +@@ -175,7 +175,7 @@ + int (*no_proplen)(int node, char *name); + int (*no_getprop)(int node, char *name, char *val); + int (*no_setprop)(int node, char *name, char *val, int len); +- char * (*no_nextprop)(int node, char *name); ++ const char * (*no_nextprop)(int node, char *name); + }; + + /* More fun PROM structures for device probing. */ +diff -ruN proll_18.orig/src/packet.c proll-patch4/src/packet.c +--- proll_18.orig/src/packet.c 2000-02-11 04:56:45.000000000 +0000 ++++ proll-patch4/src/packet.c 2004-11-13 15:50:49.000000000 +0000 +@@ -41,7 +41,7 @@ + int aligner; + } wbuf; + static struct sk_buff *rskb; +-static int nqskb = 0; ++static int nqskb; + + + void init_packet() +@@ -62,6 +62,8 @@ + for (i = 0; i < MAXSKBS; i++) { + skev[i].skb.allocn = i; + } ++ ++ nqskb = 0; + } + + unsigned char *reg_type(int ptype, int (*func)()) +@@ -81,7 +83,7 @@ + return wbuf.s; + } + +-int write_packet(int leng, int type, unsigned char *dst) ++int write_packet(int leng, int type, const unsigned char *dst) + { + struct sk_buff *skb; + unsigned char *s; +diff -ruN proll_18.orig/src/printf.c proll-patch4/src/printf.c +--- proll_18.orig/src/printf.c 1999-03-19 07:03:59.000000000 +0000 ++++ proll-patch4/src/printf.c 2004-11-13 15:50:49.000000000 +0000 +@@ -19,7 +19,7 @@ + static void printn(struct prf_fp *, unsigned long, unsigned int); + static void putchar(char, struct prf_fp *); + +-static char hextab[] = "0123456789ABCDEF"; ++static const char hextab[] = "0123456789ABCDEF"; + + /* + * Scaled down version of C Library printf. +@@ -41,7 +41,7 @@ + void + prf(struct prf_fp *filog, char *fmt, va_list adx) + { +- register c; ++ register int c; + char *s; + + for(;;) { +@@ -60,7 +60,7 @@ + putchar(va_arg(adx,unsigned), filog); + } else if(c == 's') { + s = va_arg(adx,char*); +- while(c = *s++) ++ while((c = *s++)) + putchar(c,filog); + } else if (c == 'l' || c == 'O') { + printn(filog, (long)va_arg(adx,long), c=='l'?10:8); +diff -ruN proll_18.orig/src/rconsole.c proll-patch4/src/rconsole.c +--- proll_18.orig/src/rconsole.c 1999-01-16 07:16:55.000000000 +0000 ++++ proll-patch4/src/rconsole.c 2004-11-13 15:50:49.000000000 +0000 +@@ -28,12 +28,18 @@ + * move to California. Only plain lat7 survived. + * I recreated lat7-1 changes in lat7-2. --zaitcev + */ +#ifdef ORIG - set_timeout(5); while (!chk_timeout()) { } /* P3: let me read */ + #include "lat7_2.bm" /* lat7_1.bm */ +#else -+ printk("loading kernel:"); -+ i = ld_bypass(0x20000000); -+ printk(" done, size %d\n", i); ++#include "lat7_2_swapped.bm" /* lat7_1.bm */ +#endif + #define LAT7_NCHARS 128 + #define LAT7_HEIGHT 11 + #define LAT7_WIDTH 8 - { - void (*entry)(void *, int) = (void (*)(void*, int)) LOADBASE; -diff -ru proll_18.orig/mrcoffee/openprom.c proll_18/mrcoffee/openprom.c ---- proll_18.orig/mrcoffee/openprom.c 2002-09-13 16:17:03.000000000 +0200 -+++ proll_18/mrcoffee/openprom.c 2004-09-21 21:27:16.000000000 +0200 -@@ -144,10 +144,14 @@ - }; ++#ifdef ORIG + static Rf_scan lat7_body[ LAT7_NCHARS*LAT7_HEIGHT ]; ++#endif - static int cpu_nctx = NCTX_SWIFT; -+static int cpu_cache_line_size = 0x20; -+static int cpu_cache_nlines = 0x200; - static struct property propv_cpu[] = { - {"name", "STP1012PGA", sizeof("STP1012PGA") }, - {"device_type", "cpu", 4 }, - {"mmu-nctx", (char*)&cpu_nctx, sizeof(int)}, -+ {"cache-line-size", (char*)&cpu_cache_line_size, sizeof(int)}, -+ {"cache-nlines", (char*)&cpu_cache_nlines, sizeof(int)}, - {NULL, NULL, -1} + #if 1 + /* +@@ -94,6 +100,7 @@ + + #endif + ++#ifdef ORIG + static inline int swapbits(int w0) + { + int w1 = 0; +@@ -105,13 +112,16 @@ + } + return w1; + } ++#endif + + void font_cons_7(struct rfont *p) + { ++#ifdef ORIG + int x; + int col = 0; + int row = 0; + int erow = 0; ++ + for (x = 0; x < LAT7_NCHARS*LAT7_HEIGHT; x++ ) { + lat7_body[ (erow * lat7_2_width/8 + col) * LAT7_HEIGHT + row ] = + swapbits(lat7_2_bits[x]) & 0xFF; +@@ -124,6 +134,9 @@ + } + } + p->body_ = lat7_body; ++#else ++ p->body_ = lat7_2_bits; ++#endif + p->nchars_ = LAT7_NCHARS; + p->width_ = LAT7_WIDTH; + p->height_ = LAT7_HEIGHT; +diff -ruN proll_18.orig/src/rconsole.h proll-patch4/src/rconsole.h +--- proll_18.orig/src/rconsole.h 1999-01-16 05:00:59.000000000 +0000 ++++ proll-patch4/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 +@@ -13,10 +13,10 @@ + */ + + #define RF_MAXWIDTH 16 +-typedef unsigned short Rf_scan; /* __w16 to be used */ ++typedef unsigned char Rf_scan; /* __w16 to be used */ + + struct rfont { +- Rf_scan *body_; ++ const Rf_scan *body_; + int nchars_; /* 128 for ASCII ... 65536 for Unicode */ + int width_; /* [Pixels]. Maximum size is 16. */ + int height_; /* [Pixels == scan lines]. */ +diff -ruN proll_18.orig/src/romlib.h proll-patch4/src/romlib.h +--- proll_18.orig/src/romlib.h 1999-04-20 04:26:45.000000000 +0000 ++++ proll-patch4/src/romlib.h 2004-11-13 15:50:49.000000000 +0000 +@@ -73,12 +73,12 @@ + #define memcpy(dst, src, len) bcopy(src, dst, len) + #define memcmp(x1, x2, len) bcmp(x1, x2, len) + #define memset(p, len, zero) bzero(p, len) +-extern void bcopy(void *b1, void *b2, int length); +-extern int bcmp(void *b1, void *b2, int length); ++extern void bcopy(const void *b1, void *b2, int length); ++extern int bcmp(const void *b1, const void *b2, int length); + extern void bzero(void *b, int c); + /* gcc complains about "conflicting types for builtin function strlen". */ + #define strlen(s) ssize(s) +-extern int ssize(char *s); ++extern int ssize(const char *s); + + + /* +diff -ruN proll_18.orig/src/sched_4m.c proll-patch4/src/sched_4m.c +--- proll_18.orig/src/sched_4m.c 1999-04-27 05:48:51.000000000 +0000 ++++ proll-patch4/src/sched_4m.c 2004-11-13 15:50:49.000000000 +0000 +@@ -108,7 +108,7 @@ + static int set_bolt; /* Tick counter limit */ + static struct handsc hndv[16]; + +-static unsigned int intr_to_mask[16] = { ++static unsigned const int intr_to_mask[16] = { + 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }; +diff -ruN proll_18.orig/src/swap.c proll-patch4/src/swap.c +--- proll_18.orig/src/swap.c 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/src/swap.c 2004-11-13 15:50:49.000000000 +0000 +@@ -0,0 +1,21 @@ ++// Convert the lat7 font so that no conversion is needed at runtime. ++#define ORIG ++#include "rconsole.c" ++ ++#include ++ ++int main() ++{ ++ struct rfont p; ++ int i; ++ ++ font_cons_7(&p); ++ ++ printf(" "); ++ for (i = 0; i < LAT7_NCHARS*LAT7_HEIGHT; i++) { ++ printf("0x%02x, ", p.body_[i]); ++ if ((i % 12) == 11) ++ printf("\n "); ++ } ++ printf("\n"); ++} +diff -ruN proll_18.orig/src/system.c proll-patch4/src/system.c +--- proll_18.orig/src/system.c 2002-07-23 05:52:49.000000000 +0000 ++++ proll-patch4/src/system.c 2004-11-13 15:50:49.000000000 +0000 +@@ -298,8 +298,8 @@ + } + + /* We need to start from LOADBASE, but kernel wants PAGE_SIZE. */ +- pa = PAGE_SIZE; +- for (va = PAGE_SIZE; va < LOWMEMSZ; va += PAGE_SIZE) { ++ pa = 0; ++ for (va = 0; va < LOWMEMSZ; va += PAGE_SIZE) { + map_page(l1, va, pa, 0, highbase); + pa += PAGE_SIZE; + } +@@ -518,12 +518,12 @@ + while (len--) *((char *)s)++ = 0; + } + +-void bcopy(void *f, void *t, int len) { ++void bcopy(const void *f, void *t, int len) { + while (len--) *((char *)t)++ = *((char *)f)++; + } + + /* Comparison is 7-bit */ +-int bcmp(void *s1, void *s2, int len) ++int bcmp(const void *s1, const void *s2, int len) + { + int i; + char ch; +@@ -538,8 +538,8 @@ + return 0; + } + +-int strlen(char *s) { +- char *p; ++int strlen(const char *s) { ++ const char *p; + for (p = s; *p != 0; p++) { } + return p - s; + } +@@ -560,14 +560,6 @@ + va_end(x1); + } + +-/* This is taken from x86 to be used in network kernel. Returns 15 bits. */ +-short int random() +-{ +- static unsigned int seed = 151; +- seed = (seed + 23968)*0x015A4E35 >> 1; +- return seed & 0x7FFF; +-} +- + void fatal() + { + printk("fatal."); +diff -ruN proll_18.orig/src/system.h proll-patch4/src/system.h +--- proll_18.orig/src/system.h 2002-09-13 21:53:32.000000000 +0000 ++++ proll-patch4/src/system.h 2004-11-13 15:50:49.000000000 +0000 +@@ -16,7 +16,7 @@ + #define IOMAPSIZE (1*1024*1024) /* 1 Meg maximum: we do not map framebuffer. */ + #define NCTX_SWIFT 0x100 + +-#define MAX_BANKS 3 /* Allocation for all machines */ ++#define MAX_BANKS 8 /* Allocation for all machines */ + + #ifndef __ASSEMBLY__ + struct bank { +diff -ruN proll_18.orig/src/udp.c proll-patch4/src/udp.c +--- proll_18.orig/src/udp.c 2001-12-24 05:12:53.000000000 +0000 ++++ proll-patch4/src/udp.c 2004-11-13 15:50:49.000000000 +0000 +@@ -81,7 +81,7 @@ + int source; + int dest; + { +- register unsigned char *addr; ++ const register unsigned char *addr; + /* Set global variables */ + usource = source; +@@ -299,9 +299,6 @@ + */ + int init_udp() + { +- /* Set module name for error handling */ +- net_module_name = "udp"; +- + /* Register IP packet type and set write buffer pointer */ + if ((writebuf = reg_type(htons(ETH_P_IP), ip_recv)) == NULL) + return(FALSE); diff --git a/qemu-doc.texi b/qemu-doc.texi index 367beb80a8..ca5cb09b05 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1099,6 +1099,29 @@ Set the initial VGA graphic mode. The default is 800x600x15. More information is available at @url{http://jocelyn.mayer.free.fr/qemu-ppc/}. +@chapter Sparc System emulator invocation + +Use the executable @file{qemu-system-sparc} to simulate a JavaStation +(sun4m architecture). The emulation is far from complete. + +QEMU emulates the following sun4m peripherials: + +@itemize @minus +@item +IOMMU +@item +TCX Frame buffer +@item +Lance (Am7990) Ethernet +@item +Non Volatile RAM M48T08 +@item +Slave I/O: timers, interrupt controllers, Zilog serial ports +@end itemize + +QEMU uses the Proll, a PROM replacement available at +@url{http://people.redhat.com/zaitcev/linux/}. + @chapter QEMU User space emulator invocation @section Quick Start diff --git a/qemu-tech.texi b/qemu-tech.texi index 4e6f507c74..987b3c3eff 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -126,7 +126,7 @@ maximum performances. @itemize -@item Full PowerPC 32 bit emulation, including priviledged instructions, +@item Full PowerPC 32 bit emulation, including privileged instructions, FPU and MMU. @item Can run most PowerPC Linux binaries. @@ -137,7 +137,8 @@ FPU and MMU. @itemize -@item SPARC V8 user support, except FPU instructions. +@item Somewhat complete SPARC V8 emulation, including privileged +instructions, FPU and MMU. @item Can run some SPARC Linux binaries. diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index adf8df2c9d..a66d2e36d7 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -10,23 +10,42 @@ /* trap definitions */ #define TT_ILL_INSN 0x02 #define TT_PRIV_INSN 0x03 +#define TT_NFPU_INSN 0x04 #define TT_WIN_OVF 0x05 #define TT_WIN_UNF 0x06 #define TT_FP_EXCP 0x08 #define TT_DIV_ZERO 0x2a #define TT_TRAP 0x80 +#define TT_EXTINT 0x10 #define PSR_NEG (1<<23) #define PSR_ZERO (1<<22) #define PSR_OVF (1<<21) #define PSR_CARRY (1<<20) #define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY) +#define PSR_EF (1<<12) +#define PSR_PIL 0xf00 #define PSR_S (1<<7) #define PSR_PS (1<<6) #define PSR_ET (1<<5) #define PSR_CWP 0x1f /* Fake impl 0, version 4 */ -#define GET_PSR(env) ((0<<28) | (4<<24) | env->psr | (env->psrs? PSR_S : 0) | (env->psrs? PSR_PS : 0) |(env->psret? PSR_ET : 0) | env->cwp) +#define GET_PSR(env) ((0 << 28) | (4 << 24) | env->psr | \ + (env->psref? PSR_EF : 0) | \ + (env->psrpil << 8) | \ + (env->psrs? PSR_S : 0) | \ + (env->psrs? PSR_PS : 0) | \ + (env->psret? PSR_ET : 0) | env->cwp) + +#define PUT_PSR(env, val) do { int _tmp = val; \ + env->psr = _tmp & ~PSR_ICC; \ + env->psref = (_tmp & PSR_EF)? 1 : 0; \ + env->psrpil = (_tmp & PSR_PIL) >> 8; \ + env->psrs = (_tmp & PSR_S)? 1 : 0; \ + env->psrps = (_tmp & PSR_PS)? 1 : 0; \ + env->psret = (_tmp & PSR_ET)? 1 : 0; \ + set_cwp(_tmp & PSR_CWP & (NWINDOWS - 1)); \ + } while (0) /* Trap base register */ #define TBR_BASE_MASK 0xfffff000 @@ -65,6 +84,9 @@ #define FSR_FTT1 (1<<15) #define FSR_FTT0 (1<<14) #define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0) +#define FSR_FTT_IEEE_EXCP (1 << 14) +#define FSR_FTT_UNIMPFPOP (3 << 14) +#define FSR_FTT_INVAL_FPR (6 << 14) #define FSR_FCC1 (1<<11) #define FSR_FCC0 (1<<10) @@ -106,6 +128,8 @@ typedef struct CPUSPARCState { int psrs; /* supervisor mode (extracted from PSR) */ int psrps; /* previous supervisor mode */ int psret; /* enable traps */ + int psrpil; /* interrupt level */ + int psref; /* enable fpu */ jmp_buf jmp_env; int user_mode_only; int exception_index; @@ -144,6 +168,8 @@ typedef struct CPUSPARCState { CPUSPARCState *cpu_sparc_init(void); int cpu_sparc_exec(CPUSPARCState *s); int cpu_sparc_close(CPUSPARCState *s); +void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f); +double cpu_put_fp64(uint64_t mant, uint16_t exp); struct siginfo; int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 1b3d9a0806..f8edc17153 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -40,6 +40,9 @@ void do_interrupt(int intno, int is_int, int error_code, void raise_exception_err(int exception_index, int error_code); void raise_exception(int tt); void memcpy32(uint32_t *dst, const uint32_t *src); +uint32_t mmu_probe(uint32_t address, int mmulev); +void dump_mmu(void); +void helper_debug(); /* XXX: move that to a generic header */ #if !defined(CONFIG_USER_ONLY) diff --git a/target-sparc/fop_template.h b/target-sparc/fop_template.h index 2987b68d64..eb1e1e3112 100644 --- a/target-sparc/fop_template.h +++ b/target-sparc/fop_template.h @@ -51,18 +51,6 @@ void OPPROTO glue(op_store_FT2_fpr_fpr, REGNAME)(void) } /* double floating point registers moves */ -#if 0 -#define CPU_DOUBLE_U_DEF -typedef union { - double d; - struct { - uint32_t lower; - uint32_t upper; - } l; - uint64_t ll; -} CPU_DoubleU; -#endif /* CPU_DOUBLE_U_DEF */ - void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void) { CPU_DoubleU u; diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 93ef930fbd..76ad643ebb 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -19,7 +19,8 @@ */ #include "exec.h" -#define DEBUG_PCALL +//#define DEBUG_PCALL +//#define DEBUG_MMU /* Sparc MMU emulation */ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, @@ -108,80 +109,71 @@ static const int rw_table[2][8] = { { 0, 1, 0, 1, 0, 0, 0, 0 } }; - -/* Perform address translation */ -int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, - int is_user, int is_softmmu) +int get_physical_address (CPUState *env, uint32_t *physical, int *prot, + int *access_index, uint32_t address, int rw, + int is_user) { - int exception = 0; - int access_perms = 0, access_index = 0; - uint8_t *pde_ptr; + int access_perms = 0; + target_phys_addr_t pde_ptr; uint32_t pde, virt_addr; - int error_code = 0, is_dirty, prot, ret = 0; - unsigned long paddr, vaddr, page_offset; - - if (env->user_mode_only) { - /* user mode only emulation */ - ret = -2; - goto do_fault; - } + int error_code = 0, is_dirty; + unsigned long page_offset; virt_addr = address & TARGET_PAGE_MASK; if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ - paddr = address; - page_offset = address & (TARGET_PAGE_SIZE - 1); - prot = PAGE_READ | PAGE_WRITE; - goto do_mapping; + *physical = address; + *prot = PAGE_READ | PAGE_WRITE; + return 0; } /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ /* Context base + context number */ - pde_ptr = phys_ram_base + (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); - pde = ldl_raw(pde_ptr); + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); /* Ctx pde */ switch (pde & PTE_ENTRYTYPE_MASK) { + default: case 0: /* Invalid */ - error_code = 1; - goto do_fault; - case 2: /* PTE, maybe should not happen? */ + return 1; + case 2: /* L0 PTE, maybe should not happen? */ case 3: /* Reserved */ - error_code = 4; - goto do_fault; - case 1: /* L1 PDE */ - pde_ptr = phys_ram_base + ((address >> 22) & ~3) + ((pde & ~3) << 4); - pde = ldl_raw(pde_ptr); + return 4; + case 1: /* L0 PDE */ + pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); switch (pde & PTE_ENTRYTYPE_MASK) { + default: case 0: /* Invalid */ - error_code = 1; - goto do_fault; + return 1; case 3: /* Reserved */ - error_code = 4; - goto do_fault; - case 1: /* L2 PDE */ - pde_ptr = phys_ram_base + ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); - pde = ldl_raw(pde_ptr); + return 4; + case 1: /* L1 PDE */ + pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); switch (pde & PTE_ENTRYTYPE_MASK) { + default: case 0: /* Invalid */ - error_code = 1; - goto do_fault; + return 1; case 3: /* Reserved */ - error_code = 4; - goto do_fault; - case 1: /* L3 PDE */ - pde_ptr = phys_ram_base + ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); - pde = ldl_raw(pde_ptr); + return 4; + case 1: /* L2 PDE */ + pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); switch (pde & PTE_ENTRYTYPE_MASK) { + default: case 0: /* Invalid */ - error_code = 1; - goto do_fault; + return 1; case 1: /* PDE, should not happen */ case 3: /* Reserved */ - error_code = 4; - goto do_fault; + return 4; case 2: /* L3 PTE */ virt_addr = address & TARGET_PAGE_MASK; page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1); @@ -201,40 +193,58 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, /* update page modified and dirty bits */ is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); if (!(pde & PG_ACCESSED_MASK) || is_dirty) { + uint32_t tmppde; pde |= PG_ACCESSED_MASK; if (is_dirty) pde |= PG_MODIFIED_MASK; - stl_raw(pde_ptr, pde); + tmppde = bswap32(pde); + cpu_physical_memory_write(pde_ptr, (uint8_t *)&tmppde, 4); } - /* check access */ - access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); + *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; - error_code = access_table[access_index][access_perms]; + error_code = access_table[*access_index][access_perms]; if (error_code) - goto do_fault; + return error_code; /* the page can be put in the TLB */ - prot = PAGE_READ; + *prot = PAGE_READ; if (pde & PG_MODIFIED_MASK) { /* only set write access if already dirty... otherwise wait for dirty access */ if (rw_table[is_user][access_perms]) - prot |= PAGE_WRITE; + *prot |= PAGE_WRITE; } /* Even if large ptes, we map only one 4KB page in the cache to avoid filling it too fast */ - virt_addr = address & TARGET_PAGE_MASK; - paddr = ((pde & PTE_ADDR_MASK) << 4) + page_offset; + *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset; + return 0; +} + +/* Perform address translation */ +int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, + int is_user, int is_softmmu) +{ + int exception = 0; + uint32_t virt_addr, paddr; + unsigned long vaddr; + int error_code = 0, prot, ret = 0, access_index; - do_mapping: - vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); + if (env->user_mode_only) { + /* user mode only emulation */ + error_code = -2; + goto do_fault_user; + } - ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); - return ret; + error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); + if (error_code == 0) { + virt_addr = address & TARGET_PAGE_MASK; + vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); + ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); + return ret; + } - do_fault: if (env->mmuregs[3]) /* Fault status register */ env->mmuregs[3] = 1; /* overflow (not read before another fault) */ env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2; @@ -242,7 +252,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, if (env->mmuregs[0] & MMU_NF || env->psret == 0) // No fault return 0; - + do_fault_user: env->exception_index = exception; env->error_code = error_code; return error_code; @@ -289,13 +299,14 @@ void do_interrupt(int intno, int is_int, int error_code, count, intno, error_code, is_int, env->pc, env->npc, env->regwptr[6]); -#if 0 +#if 1 cpu_dump_state(env, logfile, fprintf, 0); { int i; uint8_t *ptr; + fprintf(logfile, " code="); - ptr = env->pc; + ptr = (uint8_t *)env->pc; for(i = 0; i < 16; i++) { fprintf(logfile, " %02x", ldub(ptr + i)); } @@ -304,12 +315,19 @@ void do_interrupt(int intno, int is_int, int error_code, #endif count++; } +#endif +#if !defined(CONFIG_USER_ONLY) + if (env->psret == 0) { + fprintf(logfile, "Trap while interrupts disabled, Error state!\n"); + qemu_system_shutdown_request(); + return; + } #endif env->psret = 0; cwp = (env->cwp - 1) & (NWINDOWS - 1); set_cwp(cwp); - env->regwptr[9] = env->pc; - env->regwptr[10] = env->npc; + env->regwptr[9] = env->pc - 4; // XXX? + env->regwptr[10] = env->pc; env->psrps = env->psrs; env->psrs = 1; env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); @@ -322,3 +340,106 @@ void raise_exception_err(int exception_index, int error_code) { raise_exception(exception_index); } + +uint32_t mmu_probe(uint32_t address, int mmulev) +{ + target_phys_addr_t pde_ptr; + uint32_t pde; + + /* Context base + context number */ + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 2: /* PTE, maybe should not happen? */ + case 3: /* Reserved */ + return 0; + case 1: /* L1 PDE */ + if (mmulev == 3) + return pde; + pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 3: /* Reserved */ + return 0; + case 2: /* L1 PTE */ + return pde; + case 1: /* L2 PDE */ + if (mmulev == 2) + return pde; + pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 3: /* Reserved */ + return 0; + case 2: /* L2 PTE */ + return pde; + case 1: /* L3 PDE */ + if (mmulev == 1) + return pde; + pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 1: /* PDE, should not happen */ + case 3: /* Reserved */ + return 0; + case 2: /* L3 PTE */ + return pde; + } + } + } + } + return 0; +} + +void dump_mmu(void) +{ +#ifdef DEBUG_MMU + uint32_t pa, va, va1, va2; + int n, m, o; + target_phys_addr_t pde_ptr; + uint32_t pde; + + printf("MMU dump:\n"); + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); + printf("Root ptr: 0x%08x, ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]); + for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { + pde_ptr = mmu_probe(va, 2); + if (pde_ptr) { + pa = cpu_get_phys_page_debug(env, va); + printf("VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va, pa, pde_ptr); + for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { + pde_ptr = mmu_probe(va1, 1); + if (pde_ptr) { + pa = cpu_get_phys_page_debug(env, va1); + printf(" VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va1, pa, pde_ptr); + for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { + pde_ptr = mmu_probe(va2, 0); + if (pde_ptr) { + pa = cpu_get_phys_page_debug(env, va2); + printf(" VA: 0x%08x, PA: 0x%08x PTE: 0x%08x\n", va2, pa, pde_ptr); + } + } + } + } + } + } + printf("MMU dump ends\n"); +#endif +} diff --git a/target-sparc/op.c b/target-sparc/op.c index 2cf4ed8411..f8cf2f8934 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -524,13 +524,7 @@ void OPPROTO op_rdpsr(void) void OPPROTO op_wrpsr(void) { - int cwp; - env->psr = T0 & ~PSR_ICC; - env->psrs = (T0 & PSR_S)? 1 : 0; - env->psrps = (T0 & PSR_PS)? 1 : 0; - env->psret = (T0 & PSR_ET)? 1 : 0; - cwp = (T0 & PSR_CWP) & (NWINDOWS - 1); - set_cwp(cwp); + PUT_PSR(env,T0); FORCE_RET(); } @@ -602,10 +596,27 @@ void OPPROTO op_trapcc_T0(void) FORCE_RET(); } -void OPPROTO op_debug(void) +void OPPROTO op_trap_ifnofpu(void) +{ + if (!env->psref) { + env->exception_index = TT_NFPU_INSN; + cpu_loop_exit(); + } + FORCE_RET(); +} + +void OPPROTO op_fpexception_im(void) { - env->exception_index = EXCP_DEBUG; + env->exception_index = TT_FP_EXCP; + env->fsr &= ~FSR_FTT_MASK; + env->fsr |= PARAM1; cpu_loop_exit(); + FORCE_RET(); +} + +void OPPROTO op_debug(void) +{ + helper_debug(); } void OPPROTO op_exit_tb(void) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 3a6de7cfc2..6dead66a8c 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -2,6 +2,8 @@ #include #include "exec.h" +//#define DEBUG_MMU + #ifdef USE_INT_TO_FLOAT_HELPERS void do_fitos(void) { @@ -33,6 +35,13 @@ void do_fcmps (void) { if (isnan(FT0) || isnan(FT1)) { T0 = FSR_FCC1 | FSR_FCC0; + env->fsr &= ~(FSR_FCC1 | FSR_FCC0); + env->fsr |= T0; + if (env->fsr & FSR_NVM) { + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } } else if (FT0 < FT1) { T0 = FSR_FCC0; } else if (FT0 > FT1) { @@ -47,6 +56,13 @@ void do_fcmpd (void) { if (isnan(DT0) || isnan(DT1)) { T0 = FSR_FCC1 | FSR_FCC0; + env->fsr &= ~(FSR_FCC1 | FSR_FCC0); + env->fsr |= T0; + if (env->fsr & FSR_NVM) { + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } } else if (DT0 < DT1) { T0 = FSR_FCC0; } else if (DT0 > DT1) { @@ -59,55 +75,131 @@ void do_fcmpd (void) void helper_ld_asi(int asi, int size, int sign) { - switch(asi) { + uint32_t ret; + + switch (asi) { case 3: /* MMU probe */ - T1 = 0; - return; + { + int mmulev; + + mmulev = (T0 >> 8) & 15; + if (mmulev > 4) + ret = 0; + else { + ret = mmu_probe(T0, mmulev); + //bswap32s(&ret); + } +#ifdef DEBUG_MMU + printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret); +#endif + } + break; case 4: /* read MMU regs */ { - int temp, reg = (T0 >> 8) & 0xf; + int reg = (T0 >> 8) & 0xf; - temp = env->mmuregs[reg]; + ret = env->mmuregs[reg]; if (reg == 3 || reg == 4) /* Fault status, addr cleared on read*/ - env->mmuregs[reg] = 0; - T1 = temp; + env->mmuregs[4] = 0; } - return; + break; case 0x20 ... 0x2f: /* MMU passthrough */ - { - int temp; - - cpu_physical_memory_read(T0, (void *) &temp, size); - bswap32s(&temp); - T1 = temp; - } - return; + cpu_physical_memory_read(T0, (void *) &ret, size); + if (size == 4) + bswap32s(&ret); + else if (size == 2) + bswap16s(&ret); + break; default: - T1 = 0; - return; + ret = 0; + break; } + T1 = ret; } void helper_st_asi(int asi, int size, int sign) { switch(asi) { case 3: /* MMU flush */ - return; + { + int mmulev; + + mmulev = (T0 >> 8) & 15; + switch (mmulev) { + case 0: // flush page + tlb_flush_page(cpu_single_env, T0 & 0xfffff000); + break; + case 1: // flush segment (256k) + case 2: // flush region (16M) + case 3: // flush context (4G) + case 4: // flush entire + tlb_flush(cpu_single_env, 1); + break; + default: + break; + } + dump_mmu(); + return; + } case 4: /* write MMU regs */ { - int reg = (T0 >> 8) & 0xf; + int reg = (T0 >> 8) & 0xf, oldreg; + + oldreg = env->mmuregs[reg]; if (reg == 0) { env->mmuregs[reg] &= ~(MMU_E | MMU_NF); env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); } else env->mmuregs[reg] = T1; + if (oldreg != env->mmuregs[reg]) { +#if 0 + // XXX: Only if MMU mapping change, we may need to flush? + tlb_flush(cpu_single_env, 1); + cpu_loop_exit(); + FORCE_RET(); +#endif + } + dump_mmu(); return; } + case 0x17: /* Block copy, sta access */ + { + // value (T1) = src + // address (T0) = dst + // copy 32 bytes + int src = T1, dst = T0; + uint8_t temp[32]; + + bswap32s(&src); + + cpu_physical_memory_read(src, (void *) &temp, 32); + cpu_physical_memory_write(dst, (void *) &temp, 32); + } + return; + case 0x1f: /* Block fill, stda access */ + { + // value (T1, T2) + // address (T0) = dst + // fill 32 bytes + int i, dst = T0; + uint64_t val; + + val = (((uint64_t)T1) << 32) | T2; + bswap64s(&val); + + for (i = 0; i < 32; i += 8, dst += 8) { + cpu_physical_memory_write(dst, (void *) &val, 8); + } + } + return; case 0x20 ... 0x2f: /* MMU passthrough */ { int temp = T1; - - bswap32s(&temp); + if (size == 4) + bswap32s(&temp); + else if (size == 2) + bswap16s(&temp); + cpu_physical_memory_write(T0, (void *) &temp, size); } return; @@ -116,27 +208,6 @@ void helper_st_asi(int asi, int size, int sign) } } -#if 0 -void do_ldd_raw(uint32_t addr) -{ - T1 = ldl_raw((void *) addr); - T0 = ldl_raw((void *) (addr + 4)); -} - -#if !defined(CONFIG_USER_ONLY) -void do_ldd_user(uint32_t addr) -{ - T1 = ldl_user((void *) addr); - T0 = ldl_user((void *) (addr + 4)); -} -void do_ldd_kernel(uint32_t addr) -{ - T1 = ldl_kernel((void *) addr); - T0 = ldl_kernel((void *) (addr + 4)); -} -#endif -#endif - void helper_rett() { int cwp; @@ -166,3 +237,22 @@ void helper_ldfsr(void) break; } } + +void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f) +{ + int exptemp; + + *pmant = ldexp(frexp(f, &exptemp), 53); + *pexp = exptemp; +} + +double cpu_put_fp64(uint64_t mant, uint16_t exp) +{ + return ldexp((double) mant, exp - 53); +} + +void helper_debug() +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index 2ae74f2cef..9c839a0047 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -43,12 +43,8 @@ void OPPROTO glue(op_swap, MEMSUFFIX)(void) void OPPROTO glue(op_ldd, MEMSUFFIX)(void) { -#if 1 T1 = glue(ldl, MEMSUFFIX)((void *) T0); T0 = glue(ldl, MEMSUFFIX)((void *) (T0 + 4)); -#else - glue(do_ldd, MEMSUFFIX)(T0); -#endif } /*** Floating-point store ***/ diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 2440c0d22e..2f067958d0 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -646,6 +646,7 @@ static void disas_sparc_insn(DisasContext * dc) switch (xop) { case 0x0: case 0x1: /* UNIMPL */ + case 0x5: /*CBN+x */ default: goto illegal_insn; case 0x2: /* BN+x */ @@ -657,16 +658,24 @@ static void disas_sparc_insn(DisasContext * dc) } case 0x6: /* FBN+x */ { +#if !defined(CONFIG_USER_ONLY) + gen_op_trap_ifnofpu(); +#endif target <<= 2; target = sign_extend(target, 22); do_fbranch(dc, target, insn); goto jmp_insn; } case 0x4: /* SETHI */ - gen_movl_imm_T0(target << 10); - gen_movl_T0_reg(rd); - break; - case 0x5: /*CBN+x */ +#define OPTIM +#if defined(OPTIM) + if (rd) { // nop +#endif + gen_movl_imm_T0(target << 10); + gen_movl_T0_reg(rd); +#if defined(OPTIM) + } +#endif break; } break; @@ -691,14 +700,24 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T0(rs1); if (IS_IMM) { rs2 = GET_FIELD(insn, 25, 31); +#if defined(OPTIM) if (rs2 != 0) { - gen_movl_imm_T1(rs2); - gen_op_add_T1_T0(); +#endif + gen_movl_imm_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) } +#endif } else { rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); +#if defined(OPTIM) + if (rs2 != 0) { +#endif + gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) + } +#endif } save_state(dc); cond = GET_FIELD(insn, 3, 6); @@ -707,6 +726,7 @@ static void disas_sparc_insn(DisasContext * dc) dc->is_br = 1; goto jmp_insn; } else { + gen_cond(cond); gen_op_trapcc_T0(); } } else if (xop == 0x28) { @@ -741,7 +761,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); break; #endif - } else if (xop == 0x34 || xop == 0x35) { /* FPU Operations */ + } else if (xop == 0x34) { /* FPU Operations */ +#if !defined(CONFIG_USER_ONLY) + gen_op_trap_ifnofpu(); +#endif rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); @@ -770,6 +793,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fsqrtd(); gen_op_store_DT0_fpr(rd); break; + case 0x2b: /* fsqrtq */ + goto nfpu_insn; case 0x41: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -782,6 +807,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_faddd(); gen_op_store_DT0_fpr(rd); break; + case 0x43: /* faddq */ + goto nfpu_insn; case 0x45: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -794,6 +821,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fsubd(); gen_op_store_DT0_fpr(rd); break; + case 0x47: /* fsubq */ + goto nfpu_insn; case 0x49: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -806,6 +835,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fmuld(); gen_op_store_DT0_fpr(rd); break; + case 0x4b: /* fmulq */ + goto nfpu_insn; case 0x4d: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -818,32 +849,16 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fdivd(); gen_op_store_DT0_fpr(rd); break; - case 0x51: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fcmps(); - break; - case 0x52: - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); - gen_op_fcmpd(); - break; - case 0x55: /* fcmpes */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fcmps(); /* XXX */ - break; - case 0x56: /* fcmped */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); - gen_op_fcmpd(); /* XXX */ - break; + case 0x4f: /* fdivq */ + goto nfpu_insn; case 0x69: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); gen_op_fsmuld(); gen_op_store_DT0_fpr(rd); break; + case 0x6e: /* fdmulq */ + goto nfpu_insn; case 0xc4: gen_op_load_fpr_FT1(rs2); gen_op_fitos(); @@ -854,6 +869,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fdtos(); gen_op_store_FT0_fpr(rd); break; + case 0xc7: /* fqtos */ + goto nfpu_insn; case 0xc8: gen_op_load_fpr_FT1(rs2); gen_op_fitod(); @@ -864,6 +881,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fstod(); gen_op_store_DT0_fpr(rd); break; + case 0xcb: /* fqtod */ + goto nfpu_insn; + case 0xcc: /* fitoq */ + goto nfpu_insn; + case 0xcd: /* fstoq */ + goto nfpu_insn; + case 0xce: /* fdtoq */ + goto nfpu_insn; case 0xd1: gen_op_load_fpr_FT1(rs2); gen_op_fstoi(); @@ -874,13 +899,85 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fdtoi(); gen_op_store_FT0_fpr(rd); break; + case 0xd3: /* fqtoi */ + goto nfpu_insn; default: goto illegal_insn; } - } else { + } else if (xop == 0x35) { /* FPU Operations */ +#if !defined(CONFIG_USER_ONLY) + gen_op_trap_ifnofpu(); +#endif rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ + rs2 = GET_FIELD(insn, 27, 31); + xop = GET_FIELD(insn, 18, 26); + switch (xop) { + case 0x51: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fcmps(); + break; + case 0x52: + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpd(); + break; + case 0x53: /* fcmpq */ + goto nfpu_insn; + case 0x55: /* fcmpes */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */ + break; + case 0x56: /* fcmped */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */ + break; + case 0x57: /* fcmpeq */ + goto nfpu_insn; + default: + goto illegal_insn; + } +#if defined(OPTIM) + } else if (xop == 0x2) { + // clr/mov shortcut + + rs1 = GET_FIELD(insn, 13, 17); + if (rs1 == 0) { + // or %g0, x, y -> mov T1, x; mov y, T1 + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); + gen_movl_imm_T1(rs2); + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); + gen_movl_reg_T1(rs2); + } + gen_movl_T1_reg(rd); + } else { + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + // or x, #0, y -> mov T1, x; mov y, T1 + rs2 = GET_FIELDs(insn, 19, 31); + if (rs2 != 0) { + gen_movl_imm_T1(rs2); + gen_op_or_T1_T0(); + } + } else { /* register */ + // or x, %g0, y -> mov T1, x; mov y, T1 + rs2 = GET_FIELD(insn, 27, 31); + if (rs2 != 0) { + gen_movl_reg_T1(rs2); + gen_op_or_T1_T0(); + } + } + gen_movl_T0_reg(rd); + } +#endif + } else if (xop < 0x38) { + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); gen_movl_imm_T1(rs2); } else { /* register */ @@ -901,10 +998,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_logic_T0_cc(); break; case 0x2: - gen_op_or_T1_T0(); - if (xop & 0x10) - gen_op_logic_T0_cc(); - break; + gen_op_or_T1_T0(); + if (xop & 0x10) + gen_op_logic_T0_cc(); + break; case 0x3: gen_op_xor_T1_T0(); if (xop & 0x10) @@ -964,9 +1061,14 @@ static void disas_sparc_insn(DisasContext * dc) default: goto illegal_insn; } - gen_movl_T0_reg(rd); + gen_movl_T0_reg(rd); } else { switch (xop) { + case 0x20: /* taddcc */ + case 0x21: /* tsubcc */ + case 0x22: /* taddcctv */ + case 0x23: /* tsubcctv */ + goto illegal_insn; case 0x24: /* mulscc */ gen_op_mulscc_T1_T0(); gen_movl_T0_reg(rd); @@ -1021,56 +1123,72 @@ static void disas_sparc_insn(DisasContext * dc) } break; #endif - case 0x38: /* jmpl */ - { - gen_op_add_T1_T0(); - gen_op_movl_npc_T0(); - if (rd != 0) { - gen_op_movl_T0_im((long) (dc->pc)); - gen_movl_T0_reg(rd); - } - dc->pc = dc->npc; - dc->npc = DYNAMIC_PC; - } - goto jmp_insn; -#if !defined(CONFIG_USER_ONLY) - case 0x39: /* rett */ - { - if (!supervisor(dc)) - goto priv_insn; - gen_op_add_T1_T0(); - gen_op_movl_npc_T0(); - gen_op_rett(); -#if 0 - dc->pc = dc->npc; - dc->npc = DYNAMIC_PC; + default: + goto illegal_insn; + } + } + } else { + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); +#if defined(OPTIM) + if (rs2) { #endif - } -#if 0 - goto jmp_insn; + gen_movl_imm_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) + } #endif - break; + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); +#if defined(OPTIM) + if (rs2) { +#endif + gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) + } #endif - case 0x3b: /* flush */ - gen_op_add_T1_T0(); - gen_op_flush_T0(); - break; - case 0x3c: /* save */ - save_state(dc); - gen_op_add_T1_T0(); - gen_op_save(); - gen_movl_T0_reg(rd); - break; - case 0x3d: /* restore */ - save_state(dc); - gen_op_add_T1_T0(); - gen_op_restore(); - gen_movl_T0_reg(rd); - break; - default: - goto illegal_insn; - } } + switch (xop) { + case 0x38: /* jmpl */ + { + gen_op_movl_npc_T0(); + if (rd != 0) { + gen_op_movl_T0_im((long) (dc->pc)); + gen_movl_T0_reg(rd); + } + dc->pc = dc->npc; + dc->npc = DYNAMIC_PC; + } + goto jmp_insn; +#if !defined(CONFIG_USER_ONLY) + case 0x39: /* rett */ + { + if (!supervisor(dc)) + goto priv_insn; + gen_op_movl_npc_T0(); + gen_op_rett(); + } + break; +#endif + case 0x3b: /* flush */ + gen_op_flush_T0(); + break; + case 0x3c: /* save */ + save_state(dc); + gen_op_save(); + gen_movl_T0_reg(rd); + break; + case 0x3d: /* restore */ + save_state(dc); + gen_op_restore(); + gen_movl_T0_reg(rd); + break; + default: + goto illegal_insn; + } } break; } @@ -1081,14 +1199,24 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T0(rs1); if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); +#if defined(OPTIM) if (rs2 != 0) { +#endif gen_movl_imm_T1(rs2); gen_op_add_T1_T0(); +#if defined(OPTIM) } +#endif } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); +#if defined(OPTIM) + if (rs2 != 0) { +#endif + gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) + } +#endif } if (xop < 4 || (xop > 7 && xop < 0x14) || \ (xop > 0x17 && xop < 0x20)) { @@ -1116,8 +1244,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldst(ldstub); break; case 0x0f: /* swap register with memory. Also atomically */ + gen_movl_reg_T1(rd); gen_op_ldst(swap); break; +#if !defined(CONFIG_USER_ONLY) case 0x10: /* load word alternate */ if (!supervisor(dc)) goto priv_insn; @@ -1157,11 +1287,18 @@ static void disas_sparc_insn(DisasContext * dc) case 0x1f: /* swap reg with alt. memory. Also atomically */ if (!supervisor(dc)) goto priv_insn; + gen_movl_reg_T1(rd); gen_op_swapa(insn, 1, 4, 0); break; +#endif + default: + goto illegal_insn; } gen_movl_T1_reg(rd); } else if (xop >= 0x20 && xop < 0x24) { +#if !defined(CONFIG_USER_ONLY) + gen_op_trap_ifnofpu(); +#endif switch (xop) { case 0x20: /* load fpreg */ gen_op_ldst(ldf); @@ -1169,11 +1306,14 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x21: /* load fsr */ gen_op_ldfsr(); + gen_op_store_FT0_fpr(rd); break; case 0x23: /* load double fpreg */ gen_op_ldst(lddf); gen_op_store_DT0_fpr(rd); break; + default: + goto illegal_insn; } } else if (xop < 8 || (xop >= 0x14 && xop < 0x18)) { gen_movl_reg_T1(rd); @@ -1192,6 +1332,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T2(rd + 1); gen_op_ldst(std); break; +#if !defined(CONFIG_USER_ONLY) case 0x14: if (!supervisor(dc)) goto priv_insn; @@ -1214,24 +1355,37 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T2(rd + 1); gen_op_stda(insn, 0, 8, 0); break; +#endif + default: + goto illegal_insn; } } else if (xop > 0x23 && xop < 0x28) { +#if !defined(CONFIG_USER_ONLY) + gen_op_trap_ifnofpu(); +#endif switch (xop) { case 0x24: gen_op_load_fpr_FT0(rd); gen_op_ldst(stf); break; case 0x25: + gen_op_load_fpr_FT0(rd); gen_op_stfsr(); break; case 0x27: gen_op_load_fpr_DT0(rd); gen_op_ldst(stdf); break; + case 0x26: /* stdfq */ + default: + goto illegal_insn; } } else if (xop > 0x33 && xop < 0x38) { /* Co-processor */ + goto illegal_insn; } + else + goto illegal_insn; } } /* default case for non jump instructions */ @@ -1246,17 +1400,24 @@ static void disas_sparc_insn(DisasContext * dc) dc->pc = dc->npc; dc->npc = dc->npc + 4; } - jmp_insn:; + jmp_insn: return; illegal_insn: save_state(dc); gen_op_exception(TT_ILL_INSN); dc->is_br = 1; return; +#if !defined(CONFIG_USER_ONLY) priv_insn: save_state(dc); gen_op_exception(TT_PRIV_INSN); dc->is_br = 1; + return; +#endif + nfpu_insn: + save_state(dc); + gen_op_fpexception_im(FSR_FTT_UNIMPFPOP); + dc->is_br = 1; } static inline int gen_intermediate_code_internal(TranslationBlock * tb, @@ -1271,6 +1432,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, dc->tb = tb; pc_start = tb->pc; dc->pc = pc_start; + last_pc = dc->pc; dc->npc = (target_ulong) tb->cs_base; #if defined(CONFIG_USER_ONLY) dc->mem_idx = 0; @@ -1285,8 +1447,13 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == dc->pc) { - gen_debug(dc, dc->pc); - break; + if (dc->pc != pc_start) + save_state(dc); + gen_op_debug(); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + dc->is_br = 1; + goto exit_gen_loop; } } } @@ -1310,8 +1477,18 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, /* if the next PC is different, we abort now */ if (dc->pc != (last_pc + 4)) break; + /* if single step mode, we generate only one instruction and + generate an exception */ + if (env->singlestep_enabled) { + gen_op_jmp_im(dc->pc); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + break; + } } while ((gen_opc_ptr < gen_opc_end) && (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); + + exit_gen_loop: if (!dc->is_br) { if (dc->pc != DYNAMIC_PC && (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { @@ -1338,7 +1515,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, } #endif } else { - tb->size = dc->npc - pc_start; + tb->size = last_pc + 4 - pc_start; } #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { @@ -1366,14 +1543,10 @@ int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb) return gen_intermediate_code_internal(tb, 1, env); } -CPUSPARCState *cpu_sparc_init(void) -{ - CPUSPARCState *env; - - cpu_exec_init(); +extern int ram_size; - if (!(env = malloc(sizeof(CPUSPARCState)))) - return (NULL); +void cpu_reset(CPUSPARCState *env) +{ memset(env, 0, sizeof(*env)); env->cwp = 0; env->wim = 1; @@ -1381,14 +1554,24 @@ CPUSPARCState *cpu_sparc_init(void) #if defined(CONFIG_USER_ONLY) env->user_mode_only = 1; #else - /* Emulate Prom */ env->psrs = 1; - env->pc = 0x4000; + env->pc = 0xffd00000; + env->gregs[1] = ram_size; + env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */ env->npc = env->pc + 4; - env->mmuregs[0] = (0x10<<24) | MMU_E; /* Impl 1, ver 0, MMU Enabled */ - env->mmuregs[1] = 0x3000 >> 4; /* MMU Context table */ #endif +} + +CPUSPARCState *cpu_sparc_init(void) +{ + CPUSPARCState *env; + + cpu_exec_init(); + + if (!(env = malloc(sizeof(CPUSPARCState)))) + return (NULL); cpu_single_env = env; + cpu_reset(env); return (env); } @@ -1436,11 +1619,24 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "fsr: 0x%08x\n", env->fsr); } +#if defined(CONFIG_USER_ONLY) target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } +#else +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + uint32_t phys_addr; + int prot, access_index; + + if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0) + return -1; + return phys_addr; +} +#endif + void helper_flush(target_ulong addr) { addr &= ~7; diff --git a/vl.c b/vl.c index 78f968eb17..a2e23a7a62 100644 --- a/vl.c +++ b/vl.c @@ -2214,10 +2214,74 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) #elif defined(TARGET_SPARC) void cpu_save(QEMUFile *f, void *opaque) { + CPUState *env = opaque; + int i; + uint32_t tmp; + + for(i = 1; i < 8; i++) + qemu_put_be32s(f, &env->gregs[i]); + tmp = env->regwptr - env->regbase; + qemu_put_be32s(f, &tmp); + for(i = 1; i < NWINDOWS * 16 + 8; i++) + qemu_put_be32s(f, &env->regbase[i]); + + /* FPU */ + for(i = 0; i < 32; i++) { + uint64_t mant; + uint16_t exp; + cpu_get_fp64(&mant, &exp, env->fpr[i]); + qemu_put_be64(f, mant); + qemu_put_be16(f, exp); + } + qemu_put_be32s(f, &env->pc); + qemu_put_be32s(f, &env->npc); + qemu_put_be32s(f, &env->y); + tmp = GET_PSR(env); + qemu_put_be32s(f, &tmp); + qemu_put_be32s(f, &env->fsr); + qemu_put_be32s(f, &env->cwp); + qemu_put_be32s(f, &env->wim); + qemu_put_be32s(f, &env->tbr); + /* MMU */ + for(i = 0; i < 16; i++) + qemu_put_be32s(f, &env->mmuregs[i]); } int cpu_load(QEMUFile *f, void *opaque, int version_id) { + CPUState *env = opaque; + int i; + uint32_t tmp; + + for(i = 1; i < 8; i++) + qemu_get_be32s(f, &env->gregs[i]); + qemu_get_be32s(f, &tmp); + env->regwptr = env->regbase + tmp; + for(i = 1; i < NWINDOWS * 16 + 8; i++) + qemu_get_be32s(f, &env->regbase[i]); + + /* FPU */ + for(i = 0; i < 32; i++) { + uint64_t mant; + uint16_t exp; + + qemu_get_be64s(f, &mant); + qemu_get_be16s(f, &exp); + env->fpr[i] = cpu_put_fp64(mant, exp); + } + qemu_get_be32s(f, &env->pc); + qemu_get_be32s(f, &env->npc); + qemu_get_be32s(f, &env->y); + qemu_get_be32s(f, &tmp); + PUT_PSR(env, tmp); + qemu_get_be32s(f, &env->fsr); + qemu_get_be32s(f, &env->cwp); + qemu_get_be32s(f, &env->wim); + qemu_get_be32s(f, &env->tbr); + /* MMU */ + for(i = 0; i < 16; i++) + qemu_get_be32s(f, &env->mmuregs[i]); + tlb_flush(env, 1); return 0; } #else @@ -2388,7 +2452,7 @@ void qemu_system_shutdown_request(void) static void main_cpu_reset(void *opaque) { -#ifdef TARGET_I386 +#if defined(TARGET_I386) || defined(TARGET_SPARC) CPUState *env = opaque; cpu_reset(env); #endif diff --git a/vl.h b/vl.h index 3f3acf2ae7..9426621276 100644 --- a/vl.h +++ b/vl.h @@ -261,7 +261,7 @@ typedef void QEMUTimerCB(void *opaque); Hz. */ extern QEMUClock *rt_clock; -/* Rge virtual clock is only run during the emulation. It is stopped +/* The virtual clock is only run during the emulation. It is stopped when the virtual machine is stopped. Virtual timers use a high precision clock, usually cpu cycles (use ticks_per_sec). */ extern QEMUClock *vm_clock; @@ -672,25 +672,38 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename); +uint32_t iommu_translate(uint32_t addr); /* iommu.c */ -void iommu_init(uint32_t addr); -uint32_t iommu_translate(uint32_t addr); +void *iommu_init(uint32_t addr); +uint32_t iommu_translate_local(void *opaque, uint32_t addr); /* lance.c */ void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr); /* tcx.c */ -void tcx_init(DisplayState *ds, uint32_t addr); - -/* sched.c */ -void sched_init(); +void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, + unsigned long vram_offset, int vram_size); +void tcx_update_display(void *opaque); +void tcx_invalidate_display(void *opaque); +void tcx_screen_dump(void *opaque, const char *filename); + +/* slavio_intctl.c */ +void *slavio_intctl_init(); +void slavio_pic_info(void *opaque); +void slavio_irq_info(void *opaque); +void slavio_pic_set_irq(void *opaque, int irq, int level); /* magic-load.c */ -void magic_init(const char *kfn, int kloadaddr, uint32_t addr); +int load_elf(const char *filename, uint8_t *addr); +int load_aout(const char *filename, uint8_t *addr); + +/* slavio_timer.c */ +void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2); -/* timer.c */ -void timer_init(uint32_t addr, int irq); +/* slavio_serial.c */ +SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2); +void slavio_serial_ms_kbd_init(int base, int irq); /* NVRAM helpers */ #include "hw/m48t59.h" -- 2.39.2