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 3659819fbe9..3cf7e504cd3 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 a5c697ddc98..edf76cffbe8 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 b98c22c58e8..cc6324ca107 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 86f29d24580..bfab8c3bb76 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 c4a251ff8f0..5d383faab6d 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 2491c2cd772..e2c8b2dfa86 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 d512b1ca98b..ee07328481b 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 a9249c4ba72..62927acd54e 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 25ad8c45b2a..c594c52e832 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 46ec665570d..0945879532d 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 9b44bc0d160..985116a0995 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 06a5f743af6..713343a7589 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 2ab966de4c3..00000000000 --- 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 00000000000..745467214b0 --- /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 00000000000..348f328f5a3 --- /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 00000000000..43f59d2750b --- /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 80305e09c39..7cc5bd8d9c6 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 7f979946fc9..ccac0bffa6d 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 e393fa36fdf..00000000000 --- 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 cfc42569740..09c33aa90b0 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 6ab024e0bf8..3d99dda1ad6 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 50f2ba10a0a..49278208c57 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 Hc-jL100001 literal 56856 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 H=Y{_dN;ii_ diff --git a/pc-bios/proll.elf b/pc-bios/proll.elf new file mode 100644 index 0000000000000000000000000000000000000000..e274b0d19361deb2959c9de7d7eb420ab4b14579 GIT binary patch literal 133338 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%0DCb?M-t9TsN%tGi!}G(yo%ZLHpOL={ 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 literal 0 Hc-jL100001 diff --git a/pc-bios/proll.patch b/pc-bios/proll.patch index b0860e26f47..18a157512a9 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 367beb80a82..ca5cb09b054 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 4e6f507c74c..987b3c3efff 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 adf8df2c9db..a66d2e36d7b 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 1b3d9a08067..f8edc17153d 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 2987b68d64b..eb1e1e31125 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 93ef930fbdf..76ad643ebb7 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 2cf4ed84118..f8cf2f89346 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 3a6de7cfc24..6dead66a8ca 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 2ae74f2cefc..9c839a00473 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 2440c0d22ec..2f067958d02 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 78f968eb17a..a2e23a7a620 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 3f3acf2ae71..94266212766 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.5