From e80cfcfc8884400e826328b772971913a14d0f44 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 19 Dec 2004 23:18:01 +0000 Subject: [PATCH] SPARC merge git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1179 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 +- Makefile.target | 3 +- cpu-exec.c | 2 +- disas.c | 34 +- disas.h | 10 +- gdbstub.c | 19 +- hw/fdc.c | 35 +- hw/iommu.c | 54 +- hw/lance.c | 127 ++- hw/m48t08.c | 161 ++- hw/m48t08.h | 8 +- hw/magic-load.c | 179 +-- hw/sched.c | 268 ----- hw/slavio_intctl.c | 299 +++++ hw/slavio_serial.c | 364 ++++++ hw/slavio_timer.c | 289 +++++ hw/sun4m.c | 163 ++- hw/tcx.c | 297 +++-- hw/timer.c | 97 -- linux-user/elfload.c | 16 +- linux-user/main.c | 2 + linux-user/signal.c | 79 +- pc-bios/proll.bin | Bin 56856 -> 0 bytes pc-bios/proll.elf | Bin 0 -> 133338 bytes pc-bios/proll.patch | 2088 ++++++++++++++++++++++++++++++++++- qemu-doc.texi | 23 + qemu-tech.texi | 5 +- target-sparc/cpu.h | 28 +- target-sparc/exec.h | 3 + target-sparc/fop_template.h | 12 - target-sparc/helper.c | 255 +++-- target-sparc/op.c | 29 +- target-sparc/op_helper.c | 176 ++- target-sparc/op_mem.h | 4 - target-sparc/translate.c | 396 +++++-- vl.c | 66 +- vl.h | 33 +- 37 files changed, 4490 insertions(+), 1138 deletions(-) delete mode 100644 hw/sched.c create mode 100644 hw/slavio_intctl.c create mode 100644 hw/slavio_serial.c create mode 100644 hw/slavio_timer.c delete mode 100644 hw/timer.c delete mode 100644 pc-bios/proll.bin create mode 100644 pc-bios/proll.elf diff --git a/Makefile b/Makefile index 3659819fbe..3cf7e504cd 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ install: all install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ pc-bios/vgabios-cirrus.bin \ pc-bios/ppc_rom.bin \ - pc-bios/proll.bin \ + pc-bios/proll.elf \ pc-bios/linux_boot.bin "$(datadir)" mkdir -p "$(docdir)" install -m 644 qemu-doc.html qemu-tech.html "$(docdir)" @@ -107,7 +107,7 @@ tarbin: $(datadir)/vgabios.bin \ $(datadir)/vgabios-cirrus.bin \ $(datadir)/ppc_rom.bin \ - $(datadir)/proll.bin \ + $(datadir)/proll.elf \ $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ diff --git a/Makefile.target b/Makefile.target index a5c697ddc9..edf76cffbe 100644 --- a/Makefile.target +++ b/Makefile.target @@ -175,6 +175,7 @@ endif ifeq ($(CONFIG_DARWIN),yes) OP_CFLAGS+= -mdynamic-no-pic +LIBS+=-lmx endif ######################################################### @@ -300,7 +301,7 @@ VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o endif ifeq ($(TARGET_ARCH), sparc) -VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o timer.o +VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o diff --git a/cpu-exec.c b/cpu-exec.c index b98c22c58e..cc6324ca10 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -261,7 +261,7 @@ int cpu_exec(CPUState *env1) } #elif defined(TARGET_SPARC) if (interrupt_request & CPU_INTERRUPT_HARD) { - do_interrupt(0, 0, 0, 0, 0); + do_interrupt(env->interrupt_index, 0, 0, 0, 0); env->interrupt_request &= ~CPU_INTERRUPT_HARD; } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); diff --git a/disas.c b/disas.c index 86f29d2458..bfab8c3bb7 100644 --- a/disas.c +++ b/disas.c @@ -9,9 +9,7 @@ #include "disas.h" /* Filled in by elfload.c. Simplistic, but will do for now. */ -unsigned int disas_num_syms; -void *disas_symtab; -const char *disas_strtab; +struct syminfo *syminfos = NULL; /* Get LENGTH bytes from info's buffer, at target address memaddr. Transfer them to myaddr. */ @@ -203,19 +201,23 @@ const char *lookup_symbol(void *orig_addr) { unsigned int i; /* Hack, because we know this is x86. */ - Elf32_Sym *sym = disas_symtab; - - for (i = 0; i < disas_num_syms; i++) { - if (sym[i].st_shndx == SHN_UNDEF - || sym[i].st_shndx >= SHN_LORESERVE) - continue; - - if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC) - continue; - - if ((long)orig_addr >= sym[i].st_value - && (long)orig_addr < sym[i].st_value + sym[i].st_size) - return disas_strtab + sym[i].st_name; + Elf32_Sym *sym; + struct syminfo *s; + + for (s = syminfos; s; s = s->next) { + sym = s->disas_symtab; + for (i = 0; i < s->disas_num_syms; i++) { + if (sym[i].st_shndx == SHN_UNDEF + || sym[i].st_shndx >= SHN_LORESERVE) + continue; + + if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC) + continue; + + if ((long)orig_addr >= sym[i].st_value + && (long)orig_addr < sym[i].st_value + sym[i].st_size) + return s->disas_strtab + sym[i].st_name; + } } return ""; } diff --git a/disas.h b/disas.h index c4a251ff8f..5d383faab6 100644 --- a/disas.h +++ b/disas.h @@ -9,7 +9,11 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags); const char *lookup_symbol(void *orig_addr); /* Filled in by elfload.c. Simplistic, but will do for now. */ -extern unsigned int disas_num_syms; -extern void *disas_symtab; /* FIXME: includes are a mess --RR */ -extern const char *disas_strtab; +extern struct syminfo { + unsigned int disas_num_syms; + void *disas_symtab; + const char *disas_strtab; + struct syminfo *next; +} *syminfos; + #endif /* _QEMU_DISAS_H */ diff --git a/gdbstub.c b/gdbstub.c index 2491c2cd77..e2c8b2dfa8 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -298,11 +298,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) } /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ registers[64] = tswapl(env->y); - tmp = (0<<28) | (4<<24) | env->psr \ - | (env->psrs? PSR_S : 0) \ - | (env->psrs? PSR_PS : 0) \ - | (env->psret? PSR_ET : 0) \ - | env->cwp; + tmp = GET_PSR(env); registers[65] = tswapl(tmp); registers[66] = tswapl(env->wim); registers[67] = tswapl(env->tbr); @@ -317,7 +313,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) { - uint32_t *registers = (uint32_t *)mem_buf, tmp; + uint32_t *registers = (uint32_t *)mem_buf; int i; /* fill in g0..g7 */ @@ -334,12 +330,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ env->y = tswapl(registers[64]); - tmp = tswapl(registers[65]); - env->psr = tmp & ~PSR_ICC; - env->psrs = (tmp & PSR_S)? 1 : 0; - env->psrps = (tmp & PSR_PS)? 1 : 0; - env->psret = (tmp & PSR_ET)? 1 : 0; - env->cwp = (tmp & PSR_CWP); + PUT_PSR(env, tswapl(registers[65])); env->wim = tswapl(registers[66]); env->tbr = tswapl(registers[67]); env->pc = tswapl(registers[68]); @@ -495,8 +486,10 @@ static void gdb_vm_stopped(void *opaque, int reason) /* disable single step if it was enable */ cpu_single_step(cpu_single_env, 0); - if (reason == EXCP_DEBUG) + if (reason == EXCP_DEBUG) { + tb_flush(cpu_single_env); ret = SIGTRAP; + } else ret = 0; snprintf(buf, sizeof(buf), "S%02x", ret); diff --git a/hw/fdc.c b/hw/fdc.c index d512b1ca98..ee07328481 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -21,6 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +/* + * The controller is used in Sun4m systems in a slightly different + * way. There are changes in DOR register and DMA is not available. + */ #include "vl.h" /********************************************************/ @@ -90,6 +94,16 @@ typedef struct fdrive_t { uint8_t ro; /* Is read-only */ } fdrive_t; +#ifdef TARGET_SPARC +#define DMA_read_memory(a,b,c,d) +#define DMA_write_memory(a,b,c,d) +#define DMA_register_channel(a,b,c) +#define DMA_hold_DREQ(a) +#define DMA_release_DREQ(a) +#define DMA_get_channel_mode(a) (0) +#define DMA_schedule(a) +#endif + static void fd_init (fdrive_t *drv, BlockDriverState *bs) { /* Drive */ @@ -455,6 +469,18 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) } } +static CPUReadMemoryFunc *fdctrl_mem_read[3] = { + fdctrl_read, + fdctrl_read, + fdctrl_read, +}; + +static CPUWriteMemoryFunc *fdctrl_mem_write[3] = { + fdctrl_write, + fdctrl_write, + fdctrl_write, +}; + static void fd_change_cb (void *opaque) { fdrive_t *drv = opaque; @@ -473,7 +499,7 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, BlockDriverState **fds) { fdctrl_t *fdctrl; -// int io_mem; + int io_mem; int i; FLOPPY_DPRINTF("init controller\n"); @@ -504,11 +530,8 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, fdctrl_reset(fdctrl, 0); fdctrl->state = FD_CTRL_ACTIVE; if (mem_mapped) { - FLOPPY_ERROR("memory mapped floppy not supported by now !\n"); -#if 0 - io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write); - cpu_register_physical_memory(base, 0x08, io_mem); -#endif + io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl); + cpu_register_physical_memory(io_base, 0x08, io_mem); } else { register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl); register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl); diff --git a/hw/iommu.c b/hw/iommu.c index a9249c4ba7..62927acd54 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -117,8 +117,6 @@ typedef struct IOMMUState { uint32_t iostart; } IOMMUState; -static IOMMUState *ps; - static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) { IOMMUState *s = opaque; @@ -187,25 +185,61 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = { iommu_mem_writew, }; -uint32_t iommu_translate(uint32_t addr) +uint32_t iommu_translate_local(void *opaque, uint32_t addr) { - uint32_t *iopte = (void *)(ps->regs[1] << 4), pa; + IOMMUState *s = opaque; + uint32_t *iopte = (void *)(s->regs[1] << 4), pa; - iopte += ((addr - ps->iostart) >> PAGE_SHIFT); - cpu_physical_memory_rw((uint32_t)iopte, (void *) &pa, 4, 0); + iopte += ((addr - s->iostart) >> PAGE_SHIFT); + cpu_physical_memory_read((uint32_t)iopte, (void *) &pa, 4); bswap32s(&pa); pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */ return pa + (addr & PAGE_MASK); } -void iommu_init(uint32_t addr) +static void iommu_save(QEMUFile *f, void *opaque) +{ + IOMMUState *s = opaque; + int i; + + qemu_put_be32s(f, &s->addr); + for (i = 0; i < sizeof(struct iommu_regs); i += 4) + qemu_put_be32s(f, &s->regs[i]); + qemu_put_be32s(f, &s->iostart); +} + +static int iommu_load(QEMUFile *f, void *opaque, int version_id) +{ + IOMMUState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->addr); + for (i = 0; i < sizeof(struct iommu_regs); i += 4) + qemu_put_be32s(f, &s->regs[i]); + qemu_get_be32s(f, &s->iostart); + + return 0; +} + +static void iommu_reset(void *opaque) +{ + IOMMUState *s = opaque; + + memset(s->regs, 0, sizeof(struct iommu_regs)); + s->iostart = 0; +} + +void *iommu_init(uint32_t addr) { IOMMUState *s; int iommu_io_memory; s = qemu_mallocz(sizeof(IOMMUState)); if (!s) - return; + return NULL; s->addr = addr; @@ -213,6 +247,8 @@ void iommu_init(uint32_t addr) cpu_register_physical_memory(addr, sizeof(struct iommu_regs), iommu_io_memory); - ps = s; + register_savevm("iommu", addr, 1, iommu_save, iommu_load, s); + qemu_register_reset(iommu_reset, s); + return s; } diff --git a/hw/lance.c b/hw/lance.c index 25ad8c45b2..c594c52e83 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -147,6 +147,7 @@ struct lance_init_block { }; #define LEDMA_REGS 4 +#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1) #if 0 /* Structure to describe the current status of DMA registers on the Sparc */ struct sparc_dma_registers { @@ -157,32 +158,28 @@ struct sparc_dma_registers { }; #endif -typedef struct LEDMAState { - uint32_t addr; - uint32_t regs[LEDMA_REGS]; -} LEDMAState; - typedef struct LANCEState { - uint32_t paddr; NetDriverState *nd; uint32_t leptr; uint16_t addr; uint16_t regs[LE_MAXREG]; uint8_t phys[6]; /* mac address */ int irq; - LEDMAState *ledma; + unsigned int rxptr, txptr; + uint32_t ledmaregs[LEDMA_REGS]; } LANCEState; -static unsigned int rxptr, txptr; - static void lance_send(void *opaque); -static void lance_reset(LANCEState *s) +static void lance_reset(void *opaque) { + LANCEState *s = opaque; memcpy(s->phys, s->nd->macaddr, 6); - rxptr = 0; - txptr = 0; + s->rxptr = 0; + s->txptr = 0; + memset(s->regs, 0, LE_MAXREG * 2); s->regs[LE_CSR0] = LE_C0_STOP; + memset(s->ledmaregs, 0, LEDMA_REGS * 4); } static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) @@ -190,7 +187,7 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) LANCEState *s = opaque; uint32_t saddr; - saddr = addr - s->paddr; + saddr = addr & LE_MAXREG; switch (saddr >> 1) { case LE_RDP: return s->regs[s->addr]; @@ -208,7 +205,7 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val uint32_t saddr; uint16_t reg; - saddr = addr - s->paddr; + saddr = addr & LE_MAXREG; switch (saddr >> 1) { case LE_RDP: switch(s->addr) { @@ -292,7 +289,7 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { static int lance_can_receive(void *opaque) { LANCEState *s = opaque; - void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; int i; uint16_t temp; @@ -303,7 +300,7 @@ static int lance_can_receive(void *opaque) ib = (void *) iommu_translate(dmaptr); for (i = 0; i < RX_RING_SIZE; i++) { - cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); temp &= 0xff; if (temp == (LE_R1_OWN)) { #ifdef DEBUG_LANCE @@ -323,7 +320,7 @@ static int lance_can_receive(void *opaque) static void lance_receive(void *opaque, const uint8_t *buf, int size) { LANCEState *s = opaque; - void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; unsigned int i, old_rxptr, j; uint16_t temp; @@ -333,23 +330,23 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size) ib = (void *) iommu_translate(dmaptr); - old_rxptr = rxptr; - for (i = rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { - cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + old_rxptr = s->rxptr; + for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { + cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); if (temp == (LE_R1_OWN)) { - rxptr = (rxptr + 1) & RX_RING_MOD_MASK; + s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK; temp = size; bswap16s(&temp); - cpu_physical_memory_write(&ib->brx_ring[i].mblength, (void *) &temp, 2); + cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp, 2); #if 0 - cpu_physical_memory_write(&ib->rx_buf[i], buf, size); + cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size); #else for (j = 0; j < size; j++) { - cpu_physical_memory_write(((void *)&ib->rx_buf[i]) + j, &buf[j], 1); + cpu_physical_memory_write(((uint32_t)&ib->rx_buf[i]) + j, &buf[j], 1); } #endif temp = LE_R1_POK; - cpu_physical_memory_write(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) pic_set_irq(s->irq, 1); @@ -364,7 +361,7 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size) static void lance_send(void *opaque) { LANCEState *s = opaque; - void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; unsigned int i, old_txptr, j; uint16_t temp; @@ -375,18 +372,18 @@ static void lance_send(void *opaque) ib = (void *) iommu_translate(dmaptr); - old_txptr = txptr; - for (i = txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { - cpu_physical_memory_read(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); + old_txptr = s->txptr; + for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { + cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); if (temp == (LE_T1_POK|LE_T1_OWN)) { - cpu_physical_memory_read(&ib->btx_ring[i].length, (void *) &temp, 2); + cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp, 2); bswap16s(&temp); temp = (~temp) + 1; #if 0 - cpu_physical_memory_read(&ib->tx_buf[i], pkt_buf, temp); + cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp); #else for (j = 0; j < temp; j++) { - cpu_physical_memory_read(((void *)&ib->tx_buf[i]) + j, &pkt_buf[j], 1); + cpu_physical_memory_read((uint32_t)&ib->tx_buf[i] + j, &pkt_buf[j], 1); } #endif @@ -395,8 +392,8 @@ static void lance_send(void *opaque) #endif qemu_send_packet(s->nd, pkt_buf, temp); temp = LE_T1_POK; - cpu_physical_memory_write(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); - txptr = (txptr + 1) & TX_RING_MOD_MASK; + cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); + s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK; s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; } } @@ -404,24 +401,20 @@ static void lance_send(void *opaque) static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) { - LEDMAState *s = opaque; + LANCEState *s = opaque; uint32_t saddr; - saddr = (addr - s->addr) >> 2; - if (saddr < LEDMA_REGS) - return s->regs[saddr]; - else - return 0; + saddr = (addr & LEDMA_MAXADDR) >> 2; + return s->ledmaregs[saddr]; } static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { - LEDMAState *s = opaque; + LANCEState *s = opaque; uint32_t saddr; - saddr = (addr - s->addr) >> 2; - if (saddr < LEDMA_REGS) - s->regs[saddr] = val; + saddr = (addr & LEDMA_MAXADDR) >> 2; + s->ledmaregs[saddr] = val; } static CPUReadMemoryFunc *ledma_mem_read[3] = { @@ -436,33 +429,61 @@ static CPUWriteMemoryFunc *ledma_mem_write[3] = { ledma_mem_writel, }; +static void lance_save(QEMUFile *f, void *opaque) +{ + LANCEState *s = opaque; + int i; + + qemu_put_be32s(f, &s->leptr); + qemu_put_be16s(f, &s->addr); + for (i = 0; i < LE_MAXREG; i ++) + qemu_put_be16s(f, &s->regs[i]); + qemu_put_buffer(f, s->phys, 6); + qemu_put_be32s(f, &s->irq); + for (i = 0; i < LEDMA_REGS; i ++) + qemu_put_be32s(f, &s->ledmaregs[i]); +} + +static int lance_load(QEMUFile *f, void *opaque, int version_id) +{ + LANCEState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->leptr); + qemu_get_be16s(f, &s->addr); + for (i = 0; i < LE_MAXREG; i ++) + qemu_get_be16s(f, &s->regs[i]); + qemu_get_buffer(f, s->phys, 6); + qemu_get_be32s(f, &s->irq); + for (i = 0; i < LEDMA_REGS; i ++) + qemu_get_be32s(f, &s->ledmaregs[i]); + return 0; +} + void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr) { LANCEState *s; - LEDMAState *led; int lance_io_memory, ledma_io_memory; s = qemu_mallocz(sizeof(LANCEState)); if (!s) return; - s->paddr = leaddr; s->nd = nd; s->irq = irq; lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); cpu_register_physical_memory(leaddr, 8, lance_io_memory); - led = qemu_mallocz(sizeof(LEDMAState)); - if (!led) - return; - - s->ledma = led; - led->addr = ledaddr; - ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led); + ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); cpu_register_physical_memory(ledaddr, 16, ledma_io_memory); lance_reset(s); qemu_add_read_packet(nd, lance_can_receive, lance_receive, s); + register_savevm("lance", leaddr, 1, lance_save, lance_load, s); + qemu_register_reset(lance_reset, s); } diff --git a/hw/m48t08.c b/hw/m48t08.c index 46ec665570..0945879532 100644 --- a/hw/m48t08.c +++ b/hw/m48t08.c @@ -32,19 +32,14 @@ #define NVRAM_PRINTF(fmt, args...) do { } while (0) #endif -#define NVRAM_MAX_MEM 0xfff0 +#define NVRAM_MAX_MEM 0x1ff0 +#define NVRAM_MAXADDR 0x1fff struct m48t08_t { - /* Hardware parameters */ - int mem_index; - uint32_t mem_base; - uint16_t size; /* RTC management */ time_t time_offset; time_t stop_time; /* NVRAM storage */ - uint8_t lock; - uint16_t addr; uint8_t *buffer; }; @@ -83,14 +78,13 @@ static void set_time (m48t08_t *NVRAM, struct tm *tm) } /* Direct access to NVRAM */ -void m48t08_write (m48t08_t *NVRAM, uint32_t val) +void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val) { struct tm tm; int tmp; - if (NVRAM->addr > NVRAM_MAX_MEM && NVRAM->addr < 0x2000) - NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); - switch (NVRAM->addr) { + addr &= NVRAM_MAXADDR; + switch (addr) { case 0x1FF8: /* control */ NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; @@ -167,25 +161,18 @@ void m48t08_write (m48t08_t *NVRAM, uint32_t val) } break; default: - /* Check lock registers state */ - if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) - break; - if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) - break; - if (NVRAM->addr < NVRAM_MAX_MEM || - (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { - NVRAM->buffer[NVRAM->addr] = val & 0xFF; - } + NVRAM->buffer[addr] = val & 0xFF; break; } } -uint32_t m48t08_read (m48t08_t *NVRAM) +uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr) { struct tm tm; - uint32_t retval = 0xFF; + uint8_t retval = 0xFF; - switch (NVRAM->addr) { + addr &= NVRAM_MAXADDR; + switch (addr) { case 0x1FF8: /* control */ goto do_read; @@ -225,65 +212,36 @@ uint32_t m48t08_read (m48t08_t *NVRAM) retval = toBCD(tm.tm_year); break; default: - /* Check lock registers state */ - if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) - break; - if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) - break; - if (NVRAM->addr < NVRAM_MAX_MEM || - (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { - do_read: - retval = NVRAM->buffer[NVRAM->addr]; - } + do_read: + retval = NVRAM->buffer[addr]; break; } - if (NVRAM->addr > NVRAM_MAX_MEM + 1 && NVRAM->addr < 0x2000) - NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); - return retval; } -void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr) -{ - NVRAM->addr = addr; -} - -void m48t08_toggle_lock (m48t08_t *NVRAM, int lock) -{ - NVRAM->lock ^= 1 << lock; -} - static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t08_t *NVRAM = opaque; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) - NVRAM->buffer[addr] = value; + m48t08_write(NVRAM, addr, value); } static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t08_t *NVRAM = opaque; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - NVRAM->buffer[addr] = value >> 8; - NVRAM->buffer[addr + 1] = value; - } + m48t08_write(NVRAM, addr, value); + m48t08_write(NVRAM, addr + 1, value >> 8); } static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t08_t *NVRAM = opaque; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - NVRAM->buffer[addr] = value >> 24; - NVRAM->buffer[addr + 1] = value >> 16; - NVRAM->buffer[addr + 2] = value >> 8; - NVRAM->buffer[addr + 3] = value; - } + m48t08_write(NVRAM, addr, value); + m48t08_write(NVRAM, addr + 1, value >> 8); + m48t08_write(NVRAM, addr + 2, value >> 16); + m48t08_write(NVRAM, addr + 3, value >> 24); } static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) @@ -291,10 +249,7 @@ static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) m48t08_t *NVRAM = opaque; uint32_t retval = 0; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) - retval = NVRAM->buffer[addr]; - + retval = m48t08_read(NVRAM, addr); return retval; } @@ -303,12 +258,8 @@ static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) m48t08_t *NVRAM = opaque; uint32_t retval = 0; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - retval = NVRAM->buffer[addr] << 8; - retval |= NVRAM->buffer[addr + 1]; - } - + retval = m48t08_read(NVRAM, addr) << 8; + retval |= m48t08_read(NVRAM, addr + 1); return retval; } @@ -317,14 +268,10 @@ static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) m48t08_t *NVRAM = opaque; uint32_t retval = 0; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - retval = NVRAM->buffer[addr] << 24; - retval |= NVRAM->buffer[addr + 1] << 16; - retval |= NVRAM->buffer[addr + 2] << 8; - retval |= NVRAM->buffer[addr + 3]; - } - + retval = m48t08_read(NVRAM, addr) << 24; + retval |= m48t08_read(NVRAM, addr + 1) << 16; + retval |= m48t08_read(NVRAM, addr + 2) << 8; + retval |= m48t08_read(NVRAM, addr + 3); return retval; } @@ -340,12 +287,42 @@ static CPUReadMemoryFunc *nvram_read[] = { &nvram_readl, }; +static void nvram_save(QEMUFile *f, void *opaque) +{ + m48t08_t *s = opaque; + + qemu_put_be32s(f, (uint32_t *)&s->time_offset); + qemu_put_be32s(f, (uint32_t *)&s->stop_time); + qemu_put_buffer(f, s->buffer, 0x2000); +} + +static int nvram_load(QEMUFile *f, void *opaque, int version_id) +{ + m48t08_t *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, (uint32_t *)&s->time_offset); + qemu_get_be32s(f, (uint32_t *)&s->stop_time); + qemu_get_buffer(f, s->buffer, 0x2000); + return 0; +} + +static void m48t08_reset(void *opaque) +{ + m48t08_t *s = opaque; + + s->time_offset = 0; + s->stop_time = 0; +} + + /* Initialisation routine */ -m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr) +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size) { m48t08_t *s; - int i; - unsigned char tmp = 0; + int mem_index; s = qemu_mallocz(sizeof(m48t08_t)); if (!s) @@ -355,25 +332,13 @@ m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr) qemu_free(s); return NULL; } - s->size = size; - s->mem_base = mem_base; - s->addr = 0; if (mem_base != 0) { - s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); - cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); + mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); + cpu_register_physical_memory(mem_base, 0x2000, mem_index); } - s->lock = 0; - i = 0x1fd8; - s->buffer[i++] = 0x01; - s->buffer[i++] = 0x80; /* Sun4m OBP */ - memcpy(&s->buffer[i], macaddr, 6); - - /* Calculate checksum */ - for (i = 0x1fd8; i < 0x1fe7; i++) { - tmp ^= s->buffer[i]; - } - s->buffer[0x1fe7] = tmp; + register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s); + qemu_register_reset(m48t08_reset, s); return s; } diff --git a/hw/m48t08.h b/hw/m48t08.h index 9b44bc0d16..985116a099 100644 --- a/hw/m48t08.h +++ b/hw/m48t08.h @@ -3,10 +3,8 @@ typedef struct m48t08_t m48t08_t; -void m48t08_write (m48t08_t *NVRAM, uint32_t val); -uint32_t m48t08_read (m48t08_t *NVRAM); -void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr); -void m48t08_toggle_lock (m48t08_t *NVRAM, int lock); -m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr); +void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val); +uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr); +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size); #endif /* !defined (__M48T08_H__) */ diff --git a/hw/magic-load.c b/hw/magic-load.c index 06a5f743af..713343a758 100644 --- a/hw/magic-load.c +++ b/hw/magic-load.c @@ -1,5 +1,54 @@ #include "vl.h" #include "disas.h" +#include "exec-all.h" + +struct exec +{ + uint32_t a_info; /* Use macros N_MAGIC, etc for access */ + uint32_t a_text; /* length of text, in bytes */ + uint32_t a_data; /* length of data, in bytes */ + uint32_t a_bss; /* length of uninitialized data area, in bytes */ + uint32_t a_syms; /* length of symbol table data in file, in bytes */ + uint32_t a_entry; /* start address */ + uint32_t a_trsize; /* length of relocation info for text, in bytes */ + uint32_t a_drsize; /* length of relocation info for data, in bytes */ +}; + +#ifdef BSWAP_NEEDED +static void bswap_ahdr(struct exec *e) +{ + bswap32s(&e->a_info); + bswap32s(&e->a_text); + bswap32s(&e->a_data); + bswap32s(&e->a_bss); + bswap32s(&e->a_syms); + bswap32s(&e->a_entry); + bswap32s(&e->a_trsize); + bswap32s(&e->a_drsize); +} +#else +#define bswap_ahdr(x) do { } while (0) +#endif + +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define QMAGIC 0314 +#define _N_HDROFF(x) (1024 - sizeof (struct exec)) +#define N_TXTOFF(x) \ + (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ + (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) +#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0) +#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) +#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1)) + +#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) + +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ + : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) + #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB @@ -103,27 +152,27 @@ static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint3 return NULL; } -static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) +static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) { int retval; retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); if (retval < 0) - return -1; + return NULL; retval = read(fd, shdr, sizeof(*shdr)); if (retval < 0) - return -1; + return NULL; bswap_shdr(shdr); if (shdr->sh_type == SHT_STRTAB) return qemu_malloc(shdr->sh_size);; - return 0; + return NULL; } -static int read_program(int fd, struct elf_phdr *phdr, void *dst) +static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry) { int retval; - retval = lseek(fd, 0x4000, SEEK_SET); + retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET); if (retval < 0) return -1; return read(fd, dst, phdr->p_filesz); @@ -178,6 +227,7 @@ static void load_symbols(struct elfhdr *ehdr, int fd) { struct elf_shdr symtab, strtab; struct elf_sym *syms; + struct syminfo *s; int nsyms, i; char *str; @@ -196,20 +246,19 @@ static void load_symbols(struct elfhdr *ehdr, int fd) goto error_freesyms; /* Commit */ - if (disas_symtab) - qemu_free(disas_symtab); /* XXX Merge with old symbols? */ - if (disas_strtab) - qemu_free(disas_strtab); - disas_symtab = syms; - disas_num_syms = nsyms; - disas_strtab = str; + s = qemu_mallocz(sizeof(*s)); + s->disas_symtab = syms; + s->disas_num_syms = nsyms; + s->disas_strtab = str; + s->next = syminfos; + syminfos = s; return; error_freesyms: qemu_free(syms); return; } -int load_elf(const char * filename, uint8_t *addr) +int load_elf(const char *filename, uint8_t *addr) { struct elfhdr ehdr; struct elf_phdr phdr; @@ -227,12 +276,13 @@ int load_elf(const char * filename, uint8_t *addr) if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F' - || ehdr.e_machine != EM_SPARC) + || (ehdr.e_machine != EM_SPARC + && ehdr.e_machine != EM_SPARC32PLUS)) goto error; if (find_phdr(&ehdr, fd, &phdr, PT_LOAD)) goto error; - retval = read_program(fd, &phdr, addr); + retval = read_program(fd, &phdr, addr, ehdr.e_entry); if (retval < 0) goto error; @@ -245,17 +295,45 @@ int load_elf(const char * filename, uint8_t *addr) return -1; } -int load_kernel(const char *filename, uint8_t *addr) +int load_aout(const char *filename, uint8_t *addr) { - int fd, size; + int fd, size, ret; + struct exec e; + uint32_t magic; fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return -1; - /* load 32 bit code */ - size = read(fd, addr, 16 * 1024 * 1024); + + size = read(fd, &e, sizeof(e)); if (size < 0) goto fail; + + bswap_ahdr(&e); + + magic = N_MAGIC(e); + switch (magic) { + case ZMAGIC: + case QMAGIC: + case OMAGIC: + lseek(fd, N_TXTOFF(e), SEEK_SET); + size = read(fd, addr, e.a_text + e.a_data); + if (size < 0) + goto fail; + break; + case NMAGIC: + lseek(fd, N_TXTOFF(e), SEEK_SET); + size = read(fd, addr, e.a_text); + if (size < 0) + goto fail; + ret = read(fd, addr + N_DATADDR(e), e.a_data); + if (ret < 0) + goto fail; + size += ret; + break; + default: + goto fail; + } close(fd); return size; fail: @@ -263,64 +341,3 @@ int load_kernel(const char *filename, uint8_t *addr) return -1; } -typedef struct MAGICState { - uint32_t addr; - uint32_t saved_addr; - int magic_state; - char saved_kfn[1024]; -} MAGICState; - -static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr) -{ - int ret; - MAGICState *s = opaque; - - if (s->magic_state == 0) { - ret = load_elf(s->saved_kfn, (uint8_t *)s->saved_addr); - if (ret < 0) - ret = load_kernel(s->saved_kfn, (uint8_t *)s->saved_addr); - if (ret < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - s->saved_kfn); - } - s->magic_state = 1; /* No more magic */ - tb_flush(); - return bswap32(ret); - } - return 0; -} - -static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -} - - -static CPUReadMemoryFunc *magic_mem_read[3] = { - magic_mem_readl, - magic_mem_readl, - magic_mem_readl, -}; - -static CPUWriteMemoryFunc *magic_mem_write[3] = { - magic_mem_writel, - magic_mem_writel, - magic_mem_writel, -}; - -void magic_init(const char *kfn, int kloadaddr, uint32_t addr) -{ - int magic_io_memory; - MAGICState *s; - - s = qemu_mallocz(sizeof(MAGICState)); - if (!s) - return; - - strcpy(s->saved_kfn, kfn); - s->saved_addr = kloadaddr; - s->magic_state = 0; - s->addr = addr; - magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, s); - cpu_register_physical_memory(addr, 4, magic_io_memory); -} - diff --git a/hw/sched.c b/hw/sched.c deleted file mode 100644 index 2ab966de4c..0000000000 --- a/hw/sched.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * QEMU interrupt controller emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -//#define DEBUG_IRQ_COUNT - -/* These registers are used for sending/receiving irqs from/to - * different cpu's. - */ -struct sun4m_intreg_percpu { - unsigned int tbt; /* Intrs pending for this cpu, by PIL. */ - /* These next two registers are WRITE-ONLY and are only - * "on bit" sensitive, "off bits" written have NO affect. - */ - unsigned int clear; /* Clear this cpus irqs here. */ - unsigned int set; /* Set this cpus irqs here. */ -}; -/* - * djhr - * Actually the clear and set fields in this struct are misleading.. - * according to the SLAVIO manual (and the same applies for the SEC) - * the clear field clears bits in the mask which will ENABLE that IRQ - * the set field sets bits in the mask to DISABLE the IRQ. - * - * Also the undirected_xx address in the SLAVIO is defined as - * RESERVED and write only.. - * - * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor - * sun4m machines, for MP the layout makes more sense. - */ -struct sun4m_intreg_master { - unsigned int tbt; /* IRQ's that are pending, see sun4m masks. */ - unsigned int irqs; /* Master IRQ bits. */ - - /* Again, like the above, two these registers are WRITE-ONLY. */ - unsigned int clear; /* Clear master IRQ's by setting bits here. */ - unsigned int set; /* Set master IRQ's by setting bits here. */ - - /* This register is both READ and WRITE. */ - unsigned int undirected_target; /* Which cpu gets undirected irqs. */ -}; - -#define SUN4M_INT_ENABLE 0x80000000 -#define SUN4M_INT_E14 0x00000080 -#define SUN4M_INT_E10 0x00080000 - -#define SUN4M_HARD_INT(x) (0x000000001 << (x)) -#define SUN4M_SOFT_INT(x) (0x000010000 << (x)) - -#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ -#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ -#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ -#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ -#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ -#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ -#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ -#define SUN4M_INT_REALTIME 0x00080000 /* system timer */ -#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */ -#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */ -#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */ -#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ -#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ - -#define SUN4M_INT_SBUS(x) (1 << (x+7)) -#define SUN4M_INT_VME(x) (1 << (x)) - -typedef struct SCHEDState { - uint32_t addr, addrg; - uint32_t intreg_pending; - uint32_t intreg_enabled; - uint32_t intregm_pending; - uint32_t intregm_enabled; -} SCHEDState; - -static SCHEDState *ps; - -#ifdef DEBUG_IRQ_COUNT -static uint64_t irq_count[32]; -#endif - -static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - case 0: - return s->intreg_pending; - break; - default: - break; - } - return 0; -} - -static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - case 0: - s->intreg_pending = val; - break; - case 1: // clear - s->intreg_enabled &= ~val; - break; - case 2: // set - s->intreg_enabled |= val; - break; - default: - break; - } -} - -static CPUReadMemoryFunc *intreg_mem_read[3] = { - intreg_mem_readl, - intreg_mem_readl, - intreg_mem_readl, -}; - -static CPUWriteMemoryFunc *intreg_mem_write[3] = { - intreg_mem_writel, - intreg_mem_writel, - intreg_mem_writel, -}; - -static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addrg) >> 2; - switch (saddr) { - case 0: - return s->intregm_pending; - break; - case 1: - return s->intregm_enabled; - break; - default: - break; - } - return 0; -} - -static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addrg) >> 2; - switch (saddr) { - case 0: - s->intregm_pending = val; - break; - case 1: - s->intregm_enabled = val; - break; - case 2: // clear - s->intregm_enabled &= ~val; - break; - case 3: // set - s->intregm_enabled |= val; - break; - default: - break; - } -} - -static CPUReadMemoryFunc *intregm_mem_read[3] = { - intregm_mem_readl, - intregm_mem_readl, - intregm_mem_readl, -}; - -static CPUWriteMemoryFunc *intregm_mem_write[3] = { - intregm_mem_writel, - intregm_mem_writel, - intregm_mem_writel, -}; - -void pic_info(void) -{ - term_printf("per-cpu: pending 0x%08x, enabled 0x%08x\n", ps->intreg_pending, ps->intreg_enabled); - term_printf("master: pending 0x%08x, enabled 0x%08x\n", ps->intregm_pending, ps->intregm_enabled); -} - -void irq_info(void) -{ -#ifndef DEBUG_IRQ_COUNT - term_printf("irq statistic code not compiled.\n"); -#else - int i; - int64_t count; - - term_printf("IRQ statistics:\n"); - for (i = 0; i < 32; i++) { - count = irq_count[i]; - if (count > 0) - term_printf("%2d: %lld\n", i, count); - } -#endif -} - -static const unsigned int intr_to_mask[16] = { - 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -void pic_set_irq(int irq, int level) -{ - if (irq < 16) { - unsigned int mask = intr_to_mask[irq]; - ps->intreg_pending |= 1 << irq; - if (ps->intregm_enabled & mask) { - cpu_single_env->interrupt_index = irq; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); - } - } -#ifdef DEBUG_IRQ_COUNT - if (level == 1) - irq_count[irq]++; -#endif -} - -void sched_init(uint32_t addr, uint32_t addrg) -{ - int intreg_io_memory, intregm_io_memory; - SCHEDState *s; - - s = qemu_mallocz(sizeof(SCHEDState)); - if (!s) - return; - s->addr = addr; - s->addrg = addrg; - - intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s); - cpu_register_physical_memory(addr, 3, intreg_io_memory); - - intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s); - cpu_register_physical_memory(addrg, 5, intregm_io_memory); - - ps = s; -} - diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c new file mode 100644 index 0000000000..745467214b --- /dev/null +++ b/hw/slavio_intctl.c @@ -0,0 +1,299 @@ +/* + * QEMU Sparc SLAVIO interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +//#define DEBUG_IRQ_COUNT + +/* + * Registers of interrupt controller in sun4m. + * + * This is the interrupt controller part of chip STP2001 (Slave I/O), also + * produced as NCR89C105. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt + * + * There is a system master controller and one for each cpu. + * + */ + +#define MAX_CPUS 16 + +typedef struct SLAVIO_INTCTLState { + uint32_t intreg_pending[MAX_CPUS]; + uint32_t intregm_pending; + uint32_t intregm_disabled; + uint32_t target_cpu; +#ifdef DEBUG_IRQ_COUNT + uint64_t irq_count[32]; +#endif +} SLAVIO_INTCTLState; + +#define INTCTL_MAXADDR 0xf +#define INTCTLM_MAXADDR 0xf + +// per-cpu interrupt controller +static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + int cpu; + + cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; + saddr = (addr & INTCTL_MAXADDR) >> 2; + switch (saddr) { + case 0: + return s->intreg_pending[cpu]; + default: + break; + } + return 0; +} + +static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + int cpu; + + cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; + saddr = (addr & INTCTL_MAXADDR) >> 2; + switch (saddr) { + case 1: // clear pending softints + if (val & 0x4000) + val |= 80000000; + val &= 0xfffe0000; + s->intreg_pending[cpu] &= ~val; + break; + case 2: // set softint + val &= 0xfffe0000; + s->intreg_pending[cpu] |= val; + break; + default: + break; + } +} + +static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = { + slavio_intctl_mem_readl, + slavio_intctl_mem_readl, + slavio_intctl_mem_readl, +}; + +static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = { + slavio_intctl_mem_writel, + slavio_intctl_mem_writel, + slavio_intctl_mem_writel, +}; + +// master system interrupt controller +static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + + saddr = (addr & INTCTLM_MAXADDR) >> 2; + switch (saddr) { + case 0: + return s->intregm_pending; + case 1: + return s->intregm_disabled; + case 4: + return s->target_cpu; + default: + break; + } + return 0; +} + +static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + + saddr = (addr & INTCTLM_MAXADDR) >> 2; + switch (saddr) { + case 2: // clear (enable) + // Force unused bits + val |= 0x7fb2007f; + s->intregm_disabled &= ~val; + break; + case 3: // set (disable, clear pending) + // Force unused bits + val &= ~0x7fb2007f; + s->intregm_disabled |= val; + s->intregm_pending &= ~val; + break; + case 4: + s->target_cpu = val & (MAX_CPUS - 1); + break; + default: + break; + } +} + +static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = { + slavio_intctlm_mem_readl, + slavio_intctlm_mem_readl, + slavio_intctlm_mem_readl, +}; + +static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = { + slavio_intctlm_mem_writel, + slavio_intctlm_mem_writel, + slavio_intctlm_mem_writel, +}; + +void slavio_pic_info(void *opaque) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + for (i = 0; i < MAX_CPUS; i++) { + term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]); + } + term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled); +} + +void slavio_irq_info(void *opaque) +{ +#ifndef DEBUG_IRQ_COUNT + term_printf("irq statistic code not compiled.\n"); +#else + SLAVIO_INTCTLState *s = opaque; + int i; + int64_t count; + + term_printf("IRQ statistics:\n"); + for (i = 0; i < 32; i++) { + count = s->irq_count[i]; + if (count > 0) + term_printf("%2d: %lld\n", i, count); + } +#endif +} + +static const uint32_t intbit_to_level[32] = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0, +}; + +/* + * "irq" here is the bit number in the system interrupt register to + * separate serial and keyboard interrupts sharing a level. + */ +void slavio_pic_set_irq(void *opaque, int irq, int level) +{ + SLAVIO_INTCTLState *s = opaque; + + if (irq < 32) { + uint32_t mask = 1 << irq; + uint32_t pil = intbit_to_level[irq]; + if (pil > 0) { + if (level) { + s->intregm_pending |= mask; + s->intreg_pending[s->target_cpu] |= 1 << pil; + } + else { + s->intregm_pending &= ~mask; + s->intreg_pending[s->target_cpu] &= ~(1 << pil); + } + if (level && + !(s->intregm_disabled & mask) && + !(s->intregm_disabled & 0x80000000) && + (pil == 15 || (pil > cpu_single_env->psrpil && cpu_single_env->psret == 1))) { +#ifdef DEBUG_IRQ_COUNT + if (level == 1) + s->irq_count[pil]++; +#endif + cpu_single_env->interrupt_index = TT_EXTINT | pil; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } + } + } +} + +static void slavio_intctl_save(QEMUFile *f, void *opaque) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + for (i = 0; i < MAX_CPUS; i++) { + qemu_put_be32s(f, &s->intreg_pending[i]); + } + qemu_put_be32s(f, &s->intregm_pending); + qemu_put_be32s(f, &s->intregm_disabled); + qemu_put_be32s(f, &s->target_cpu); +} + +static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + for (i = 0; i < MAX_CPUS; i++) { + qemu_get_be32s(f, &s->intreg_pending[i]); + } + qemu_get_be32s(f, &s->intregm_pending); + qemu_get_be32s(f, &s->intregm_disabled); + qemu_get_be32s(f, &s->target_cpu); + return 0; +} + +static void slavio_intctl_reset(void *opaque) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + for (i = 0; i < MAX_CPUS; i++) { + s->intreg_pending[i] = 0; + } + s->intregm_disabled = 0xffffffff; + s->intregm_pending = 0; + s->target_cpu = 0; +} + +void *slavio_intctl_init(uint32_t addr, uint32_t addrg) +{ + int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; + SLAVIO_INTCTLState *s; + + s = qemu_mallocz(sizeof(SLAVIO_INTCTLState)); + if (!s) + return NULL; + + for (i = 0; i < MAX_CPUS; i++) { + slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); + cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory); + } + + slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); + cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory); + + register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s); + qemu_register_reset(slavio_intctl_reset, s); + slavio_intctl_reset(s); + return s; +} + diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c new file mode 100644 index 0000000000..348f328f5a --- /dev/null +++ b/hw/slavio_serial.c @@ -0,0 +1,364 @@ +/* + * QEMU Sparc SLAVIO serial port emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG_SERIAL + +/* debug keyboard */ +//#define DEBUG_KBD + +/* debug keyboard : only mouse */ +//#define DEBUG_MOUSE + +/* + * This is the serial port, mouse and keyboard part of chip STP2001 + * (Slave I/O), also produced as NCR89C105. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt + * + * The serial ports implement full AMD AM8530 or Zilog Z8530 chips, + * mouse and keyboard ports don't implement all functions and they are + * only asynchronous. There is no DMA. + * + */ + +typedef struct ChannelState { + int irq; + int reg; + int rxint, txint; + uint8_t rx, tx, wregs[16], rregs[16]; + CharDriverState *chr; +} ChannelState; + +struct SerialState { + struct ChannelState chn[2]; +}; + +#define SERIAL_MAXADDR 7 + +static void slavio_serial_update_irq(ChannelState *s) +{ + if ((s->wregs[1] & 1) && // interrupts enabled + (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending + ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && + s->rxint == 1) || // rx ints enabled, pending + ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p + pic_set_irq(s->irq, 1); + } else { + pic_set_irq(s->irq, 0); + } +} + +static void slavio_serial_reset_chn(ChannelState *s) +{ + int i; + + s->reg = 0; + for (i = 0; i < SERIAL_MAXADDR; i++) { + s->rregs[i] = 0; + s->wregs[i] = 0; + } + s->wregs[4] = 4; + s->wregs[9] = 0xc0; + s->wregs[11] = 8; + s->wregs[14] = 0x30; + s->wregs[15] = 0xf8; + s->rregs[0] = 0x44; + s->rregs[1] = 6; + + s->rx = s->tx = 0; + s->rxint = s->txint = 0; +} + +static void slavio_serial_reset(void *opaque) +{ + SerialState *s = opaque; + slavio_serial_reset_chn(&s->chn[0]); + slavio_serial_reset_chn(&s->chn[1]); +} + +static void slavio_serial_mem_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + SerialState *ser = opaque; + ChannelState *s; + uint32_t saddr; + int newreg, channel; + + val &= 0xff; + saddr = (addr & 3) >> 1; + channel = (addr & SERIAL_MAXADDR) >> 2; + s = &ser->chn[channel]; + switch (saddr) { + case 0: + newreg = 0; + switch (s->reg) { + case 0: + newreg = val & 7; + val &= 0x38; + switch (val) { + case 8: + s->reg |= 0x8; + break; + case 0x20: + s->rxint = 0; + break; + case 0x28: + s->txint = 0; + break; + default: + break; + } + break; + case 1 ... 8: + case 10 ... 15: + s->wregs[s->reg] = val; + break; + case 9: + switch (val & 0xc0) { + case 0: + default: + break; + case 0x40: + slavio_serial_reset_chn(&ser->chn[1]); + return; + case 0x80: + slavio_serial_reset_chn(&ser->chn[0]); + return; + case 0xc0: + slavio_serial_reset(ser); + return; + } + break; + default: + break; + } + if (s->reg == 0) + s->reg = newreg; + else + s->reg = 0; + break; + case 1: + if (s->wregs[5] & 8) { // tx enabled + s->tx = val; + if (s->chr) + qemu_chr_write(s->chr, &s->tx, 1); + s->txint = 1; + } + break; + default: + break; + } +} + +static uint32_t slavio_serial_mem_readb(void *opaque, uint32_t addr) +{ + SerialState *ser = opaque; + ChannelState *s; + uint32_t saddr; + uint32_t ret; + int channel; + + saddr = (addr & 3) >> 1; + channel = (addr & SERIAL_MAXADDR) >> 2; + s = &ser->chn[channel]; + switch (saddr) { + case 0: + ret = s->rregs[s->reg]; + s->reg = 0; + return ret; + case 1: + s->rregs[0] &= ~1; + return s->rx; + default: + break; + } + return 0; +} + +static int serial_can_receive(void *opaque) +{ + ChannelState *s = opaque; + if (((s->wregs[3] & 1) == 0) // Rx not enabled + || ((s->rregs[0] & 1) == 1)) // char already available + return 0; + else + return 1; +} + +static void serial_receive_byte(ChannelState *s, int ch) +{ + s->rregs[0] |= 1; + s->rx = ch; + s->rxint = 1; + slavio_serial_update_irq(s); +} + +static void serial_receive_break(ChannelState *s) +{ + s->rregs[0] |= 0x80; + slavio_serial_update_irq(s); +} + +static void serial_receive1(void *opaque, const uint8_t *buf, int size) +{ + ChannelState *s = opaque; + serial_receive_byte(s, buf[0]); +} + +static void serial_event(void *opaque, int event) +{ + ChannelState *s = opaque; + if (event == CHR_EVENT_BREAK) + serial_receive_break(s); +} + +static CPUReadMemoryFunc *slavio_serial_mem_read[3] = { + slavio_serial_mem_readb, + slavio_serial_mem_readb, + slavio_serial_mem_readb, +}; + +static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = { + slavio_serial_mem_writeb, + slavio_serial_mem_writeb, + slavio_serial_mem_writeb, +}; + +static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) +{ + qemu_put_be32s(f, &s->irq); + qemu_put_be32s(f, &s->reg); + qemu_put_be32s(f, &s->rxint); + qemu_put_be32s(f, &s->txint); + qemu_put_8s(f, &s->rx); + qemu_put_8s(f, &s->tx); + qemu_put_buffer(f, s->wregs, 16); + qemu_put_buffer(f, s->rregs, 16); +} + +static void slavio_serial_save(QEMUFile *f, void *opaque) +{ + SerialState *s = opaque; + + slavio_serial_save_chn(f, &s->chn[0]); + slavio_serial_save_chn(f, &s->chn[1]); +} + +static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) +{ + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->irq); + qemu_get_be32s(f, &s->reg); + qemu_get_be32s(f, &s->rxint); + qemu_get_be32s(f, &s->txint); + qemu_get_8s(f, &s->rx); + qemu_get_8s(f, &s->tx); + qemu_get_buffer(f, s->wregs, 16); + qemu_get_buffer(f, s->rregs, 16); + return 0; +} + +static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) +{ + SerialState *s = opaque; + int ret; + + ret = slavio_serial_load_chn(f, &s->chn[0], version_id); + if (ret != 0) + return ret; + ret = slavio_serial_load_chn(f, &s->chn[1], version_id); + return ret; + +} + +SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2) +{ + int slavio_serial_io_memory; + SerialState *s; + + s = qemu_mallocz(sizeof(SerialState)); + if (!s) + return NULL; + s->chn[0].irq = irq; + s->chn[1].irq = irq; + s->chn[0].chr = chr1; + s->chn[1].chr = chr2; + + slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); + cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); + + if (chr1) { + qemu_chr_add_read_handler(chr1, serial_can_receive, serial_receive1, &s->chn[0]); + qemu_chr_add_event_handler(chr1, serial_event); + } + if (chr2) { + qemu_chr_add_read_handler(chr2, serial_can_receive, serial_receive1, &s->chn[1]); + qemu_chr_add_event_handler(chr2, serial_event); + } + register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s); + qemu_register_reset(slavio_serial_reset, s); + slavio_serial_reset(s); + return s; +} + +static void sunkbd_event(void *opaque, int ch) +{ + ChannelState *s = opaque; + // XXX: PC -> Sun Type 5 translation? + serial_receive_byte(s, ch); +} + +static void sunmouse_event(void *opaque, + int dx, int dy, int dz, int buttons_state) +{ + ChannelState *s = opaque; + int ch; + + // XXX + ch = 0x42; + serial_receive_byte(s, ch); +} + +void slavio_serial_ms_kbd_init(int base, int irq) +{ + int slavio_serial_io_memory; + SerialState *s; + + s = qemu_mallocz(sizeof(SerialState)); + if (!s) + return; + s->chn[0].irq = irq; + s->chn[1].irq = irq; + s->chn[0].chr = NULL; + s->chn[1].chr = NULL; + + slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); + cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); + + qemu_add_kbd_event_handler(sunkbd_event, &s->chn[0]); + qemu_add_mouse_event_handler(sunmouse_event, &s->chn[1]); + qemu_register_reset(slavio_serial_reset, s); + slavio_serial_reset(s); +} diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c new file mode 100644 index 0000000000..43f59d2750 --- /dev/null +++ b/hw/slavio_timer.c @@ -0,0 +1,289 @@ +/* + * QEMU Sparc SLAVIO timer controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG_TIMER + +/* + * Registers of hardware timer in sun4m. + * + * This is the timer/counter part of chip STP2001 (Slave I/O), also + * produced as NCR89C105. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt + * + * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 + * are zero. Bit 31 is 1 when count has been reached. + * + */ + +typedef struct SLAVIO_TIMERState { + uint32_t limit, count, counthigh; + int64_t count_load_time; + int64_t expire_time; + int64_t stop_time, tick_offset; + QEMUTimer *irq_timer; + int irq; + int reached, stopped; + int mode; // 0 = processor, 1 = user, 2 = system +} SLAVIO_TIMERState; + +#define TIMER_MAXADDR 0x1f +#define CNT_FREQ 2000000 +#define MAX_CPUS 16 + +// Update count, set irq, update expire_time +static void slavio_timer_get_out(SLAVIO_TIMERState *s) +{ + int out; + int64_t diff, ticks, count; + uint32_t limit; + + // There are three clock tick units: CPU ticks, register units + // (nanoseconds), and counter ticks (500 ns). + if (s->mode == 1 && s->stopped) + ticks = s->stop_time; + else + ticks = qemu_get_clock(vm_clock) - s->tick_offset; + + out = (ticks >= s->expire_time); + if (out) + s->reached = 0x80000000; + if (!s->limit) + limit = 0x7fffffff; + else + limit = s->limit; + + // Convert register units to counter ticks + limit = limit >> 9; + + // Convert cpu ticks to counter ticks + diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec); + + // Calculate what the counter should be, convert to register + // units + count = diff % limit; + s->count = count << 9; + s->counthigh = count >> 22; + + // Expire time: CPU ticks left to next interrupt + // Convert remaining counter ticks to CPU ticks + s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ); + +#ifdef DEBUG_TIMER + term_printf("timer: irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); +#endif + if (s->mode != 1) + pic_set_irq(s->irq, out); +} + +// timer callback +static void slavio_timer_irq(void *opaque) +{ + SLAVIO_TIMERState *s = opaque; + + if (!s->irq_timer) + return; + slavio_timer_get_out(s); + if (s->mode != 1) + qemu_mod_timer(s->irq_timer, s->expire_time); +} + +static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SLAVIO_TIMERState *s = opaque; + uint32_t saddr; + + saddr = (addr & TIMER_MAXADDR) >> 2; + switch (saddr) { + case 0: + // read limit (system counter mode) or read most signifying + // part of counter (user mode) + if (s->mode != 1) { + // clear irq + pic_set_irq(s->irq, 0); + s->count_load_time = qemu_get_clock(vm_clock); + s->reached = 0; + return s->limit; + } + else { + slavio_timer_get_out(s); + return s->counthigh & 0x7fffffff; + } + case 1: + // read counter and reached bit (system mode) or read lsbits + // of counter (user mode) + slavio_timer_get_out(s); + if (s->mode != 1) + return (s->count & 0x7fffffff) | s->reached; + else + return s->count; + case 3: + // read start/stop status + return s->stopped; + case 4: + // read user/system mode + return s->mode & 1; + default: + return 0; + } +} + +static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SLAVIO_TIMERState *s = opaque; + uint32_t saddr; + + saddr = (addr & TIMER_MAXADDR) >> 2; + switch (saddr) { + case 0: + // set limit, reset counter + s->count_load_time = qemu_get_clock(vm_clock); + // fall through + case 2: + // set limit without resetting counter + if (!val) + s->limit = 0x7fffffff; + else + s->limit = val & 0x7fffffff; + slavio_timer_irq(s); + break; + case 3: + // start/stop user counter + if (s->mode == 1) { + if (val & 1) { + s->stop_time = qemu_get_clock(vm_clock); + s->stopped = 1; + } + else { + if (s->stopped) + s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time; + s->stopped = 0; + } + } + break; + case 4: + // bit 0: user (1) or system (0) counter mode + if (s->mode == 0 || s->mode == 1) + s->mode = val & 1; + break; + default: + break; + } +} + +static CPUReadMemoryFunc *slavio_timer_mem_read[3] = { + slavio_timer_mem_readl, + slavio_timer_mem_readl, + slavio_timer_mem_readl, +}; + +static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = { + slavio_timer_mem_writel, + slavio_timer_mem_writel, + slavio_timer_mem_writel, +}; + +static void slavio_timer_save(QEMUFile *f, void *opaque) +{ + SLAVIO_TIMERState *s = opaque; + + qemu_put_be32s(f, &s->limit); + qemu_put_be32s(f, &s->count); + qemu_put_be32s(f, &s->counthigh); + qemu_put_be64s(f, &s->count_load_time); + qemu_put_be64s(f, &s->expire_time); + qemu_put_be64s(f, &s->stop_time); + qemu_put_be64s(f, &s->tick_offset); + qemu_put_be32s(f, &s->irq); + qemu_put_be32s(f, &s->reached); + qemu_put_be32s(f, &s->stopped); + qemu_put_be32s(f, &s->mode); +} + +static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) +{ + SLAVIO_TIMERState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->limit); + qemu_get_be32s(f, &s->count); + qemu_get_be32s(f, &s->counthigh); + qemu_get_be64s(f, &s->count_load_time); + qemu_get_be64s(f, &s->expire_time); + qemu_get_be64s(f, &s->stop_time); + qemu_get_be64s(f, &s->tick_offset); + qemu_get_be32s(f, &s->irq); + qemu_get_be32s(f, &s->reached); + qemu_get_be32s(f, &s->stopped); + qemu_get_be32s(f, &s->mode); + return 0; +} + +static void slavio_timer_reset(void *opaque) +{ + SLAVIO_TIMERState *s = opaque; + + s->limit = 0; + s->count = 0; + s->count_load_time = qemu_get_clock(vm_clock);; + s->stop_time = s->count_load_time; + s->tick_offset = 0; + s->reached = 0; + s->mode &= 2; + s->stopped = 1; + slavio_timer_get_out(s); +} + +static void slavio_timer_init_internal(uint32_t addr, int irq, int mode) +{ + int slavio_timer_io_memory; + SLAVIO_TIMERState *s; + + s = qemu_mallocz(sizeof(SLAVIO_TIMERState)); + if (!s) + return; + s->irq = irq; + s->mode = mode; + s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s); + + slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, + slavio_timer_mem_write, s); + cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory); + register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s); + qemu_register_reset(slavio_timer_reset, s); + slavio_timer_reset(s); +} + +void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2) +{ + int i; + + for (i = 0; i < MAX_CPUS; i++) { + slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0); + } + + slavio_timer_init_internal(addr2, irq2, 2); +} diff --git a/hw/sun4m.c b/hw/sun4m.c index 80305e09c3..7cc5bd8d9c 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -25,29 +25,32 @@ #include "m48t08.h" #define KERNEL_LOAD_ADDR 0x00004000 -#define MMU_CONTEXT_TBL 0x00003000 -#define MMU_L1PTP (MMU_CONTEXT_TBL + 0x0400) -#define MMU_L2PTP (MMU_CONTEXT_TBL + 0x0800) -#define PROM_ADDR 0xffd04000 +#define PROM_ADDR 0xffd00000 #define PROM_FILENAMEB "proll.bin" #define PROM_FILENAMEE "proll.elf" -#define PROLL_MAGIC_ADDR 0x20000000 -#define PHYS_JJ_EEPROM 0x71200000 /* [2000] MK48T08 */ +#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */ #define PHYS_JJ_IDPROM_OFF 0x1FD8 #define PHYS_JJ_EEPROM_SIZE 0x2000 -#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ +// IRQs are not PIL ones, but master interrupt controller register +// bits +#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */ #define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */ -#define PHYS_JJ_TCX_0E 0x5E000000 /* Top address, one byte used. */ -#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ -#define PHYS_JJ_LEDMA 0x78400010 /* ledma, off by 10 from unused SCSI */ -#define PHYS_JJ_LE 0x78C00000 /* LANCE, typical sun4m */ -#define PHYS_JJ_LE_IRQ 6 -#define PHYS_JJ_CLOCK 0x71D00000 -#define PHYS_JJ_CLOCK_IRQ 10 -#define PHYS_JJ_CLOCK1 0x71D10000 -#define PHYS_JJ_CLOCK1_IRQ 14 -#define PHYS_JJ_INTR0 0x71E00000 /* CPU0 interrupt control registers */ +#define PHYS_JJ_LEDMA 0x78400010 /* Lance DMA controller */ +#define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */ +#define PHYS_JJ_LE_IRQ 16 +#define PHYS_JJ_CLOCK 0x71D00000 /* Per-CPU timer/counter, L14 */ +#define PHYS_JJ_CLOCK_IRQ 7 +#define PHYS_JJ_CLOCK1 0x71D10000 /* System timer/counter, L10 */ +#define PHYS_JJ_CLOCK1_IRQ 19 +#define PHYS_JJ_INTR0 0x71E00000 /* Per-CPU interrupt control registers */ #define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */ +#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */ +#define PHYS_JJ_MS_KBD_IRQ 14 +#define PHYS_JJ_SER 0x71100000 /* Serial */ +#define PHYS_JJ_SER_IRQ 15 +#define PHYS_JJ_SCSI_IRQ 18 +#define PHYS_JJ_FDC 0x71400000 /* Floppy */ +#define PHYS_JJ_FLOPPY_IRQ 22 /* TSC handling */ @@ -57,13 +60,73 @@ uint64_t cpu_get_tsc() } void DMA_run() {} -void SB16_run() {} -int serial_can_receive(SerialState *s) { return 0; } -void serial_receive_byte(SerialState *s, int ch) {} -void serial_receive_break(SerialState *s) {} static m48t08_t *nvram; +static void nvram_init(m48t08_t *nvram, uint8_t *macaddr) +{ + unsigned char tmp = 0; + int i, j; + + i = 0x1fd8; + m48t08_write(nvram, i++, 0x01); + m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */ + j = 0; + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i, macaddr[j]); + + /* Calculate checksum */ + for (i = 0x1fd8; i < 0x1fe7; i++) { + tmp ^= m48t08_read(nvram, i); + } + m48t08_write(nvram, 0x1fe7, tmp); +} + +static void *slavio_intctl; + +void pic_info() +{ + slavio_pic_info(slavio_intctl); +} + +void irq_info() +{ + slavio_irq_info(slavio_intctl); +} + +void pic_set_irq(int irq, int level) +{ + slavio_pic_set_irq(slavio_intctl, irq, level); +} + +static void *tcx; + +void vga_update_display() +{ + tcx_update_display(tcx); +} + +void vga_invalidate_display() +{ + tcx_invalidate_display(tcx); +} + +void vga_screen_dump(const char *filename) +{ + tcx_screen_dump(tcx, filename); +} + +static void *iommu; + +uint32_t iommu_translate(uint32_t addr) +{ + return iommu_translate_local(iommu, addr); +} + /* Sun4m hardware initialisation */ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -72,42 +135,50 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, { char buf[1024]; int ret, linux_boot; - unsigned long bios_offset; + unsigned long vram_size = 0x100000, prom_offset; linux_boot = (kernel_filename != NULL); /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); - bios_offset = ram_size; - iommu_init(PHYS_JJ_IOMMU); - sched_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); - tcx_init(ds, PHYS_JJ_TCX_FB); + iommu = iommu_init(PHYS_JJ_IOMMU); + slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); + tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size); lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); - nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE, &nd_table[0].macaddr); - timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ); - timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); - magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR, PROLL_MAGIC_ADDR); + nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr); + slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); + slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ); + slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[0], serial_hds[1]); + fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); - /* We load Proll as the kernel and start it. It will issue a magic - IO to load the real kernel */ - if (linux_boot) { + prom_offset = ram_size + vram_size; + + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); + ret = load_elf(buf, phys_ram_base + prom_offset); + if (ret < 0) { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); - ret = load_kernel(buf, - phys_ram_base + KERNEL_LOAD_ADDR); + ret = load_image(buf, phys_ram_base + prom_offset); + } + if (ret < 0) { + fprintf(stderr, "qemu: could not load prom '%s'\n", + buf); + exit(1); + } + cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, + prom_offset | IO_MEM_ROM); + + if (linux_boot) { + ret = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (ret < 0) + ret = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (ret < 0) + ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (ret < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", - buf); - exit(1); + kernel_filename); + exit(1); } } - /* Setup a MMU entry for entire address space */ - stl_raw(phys_ram_base + MMU_CONTEXT_TBL, (MMU_L1PTP >> 4) | 1); - stl_raw(phys_ram_base + MMU_L1PTP, (MMU_L2PTP >> 4) | 1); - stl_raw(phys_ram_base + MMU_L1PTP + (0x01 << 2), (MMU_L2PTP >> 4) | 1); // 01.. == 00.. - stl_raw(phys_ram_base + MMU_L1PTP + (0xff << 2), (MMU_L2PTP >> 4) | 1); // ff.. == 00.. - stl_raw(phys_ram_base + MMU_L1PTP + (0xf0 << 2), (MMU_L2PTP >> 4) | 1); // f0.. == 00.. - /* 3 = U:RWX S:RWX */ - stl_raw(phys_ram_base + MMU_L2PTP, (3 << PTE_ACCESS_SHIFT) | 2); - stl_raw(phys_ram_base + MMU_L2PTP, ((0x01 << PTE_PPN_SHIFT) >> 4 ) | (3 << PTE_ACCESS_SHIFT) | 2); } diff --git a/hw/tcx.c b/hw/tcx.c index 7f979946fc..ccac0bffa6 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -25,179 +25,254 @@ #define MAXX 1024 #define MAXY 768 +/* + * Proll uses only small part of display, we need to switch to full + * display when we get linux framebuffer console or X11 running. For + * now it's just slower and awkward. +*/ +#if 1 #define XSZ (8*80) #define YSZ (24*11) #define XOFF (MAXX-XSZ) #define YOFF (MAXY-YSZ) +#else +#define XSZ MAXX +#define YSZ MAXY +#define XOFF 0 +#define YOFF 0 +#endif typedef struct TCXState { uint32_t addr; DisplayState *ds; uint8_t *vram; + unsigned long vram_offset; + uint8_t r[256], g[256], b[256]; } TCXState; -static TCXState *ts; - -void vga_update_display() +static void tcx_draw_line32(TCXState *s1, uint8_t *d, + const uint8_t *s, int width) { - dpy_update(ts->ds, 0, 0, XSZ, YSZ); + int x; + uint8_t val; + + for(x = 0; x < width; x++) { + val = *s++; + *d++ = s1->r[val]; + *d++ = s1->g[val]; + *d++ = s1->b[val]; + d++; + } } -void vga_invalidate_display() {} +static void tcx_draw_line24(TCXState *s1, uint8_t *d, + const uint8_t *s, int width) +{ + int x; + uint8_t val; -static uint32_t tcx_mem_readb(void *opaque, target_phys_addr_t addr) + for(x = 0; x < width; x++) { + val = *s++; + *d++ = s1->r[val]; + *d++ = s1->g[val]; + *d++ = s1->b[val]; + } +} + +static void tcx_draw_line8(TCXState *s1, uint8_t *d, + const uint8_t *s, int width) { - TCXState *s = opaque; - uint32_t saddr; - unsigned int x, y; - - saddr = addr - s->addr - YOFF*MAXX - XOFF; - y = saddr / MAXX; - x = saddr - y * MAXX; - if (x < XSZ && y < YSZ) { - return s->vram[y * XSZ + x]; + int x; + uint8_t val; + + for(x = 0; x < width; x++) { + val = *s++; + /* XXX translate between palettes? */ + *d++ = val; } - return 0; } -static uint32_t tcx_mem_readw(void *opaque, target_phys_addr_t addr) +/* Fixed line length 1024 allows us to do nice tricks not possible on + VGA... */ +void tcx_update_display(void *opaque) { - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = tcx_mem_readb(opaque, addr) << 8; - v |= tcx_mem_readb(opaque, addr + 1); + TCXState *ts = opaque; + uint32_t page; + int y, page_min, page_max, y_start, dd, ds; + uint8_t *d, *s; + void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width); + + if (ts->ds->depth == 0) + return; +#ifdef LD_BYPASS_OK + page = ts->vram_offset + YOFF*MAXX; #else - v = tcx_mem_readb(opaque, addr); - v |= tcx_mem_readb(opaque, addr + 1) << 8; + page = ts->addr + YOFF*MAXX; #endif - return v; + y_start = -1; + page_min = 0x7fffffff; + page_max = -1; + d = ts->ds->data; + s = ts->vram + YOFF*MAXX + XOFF; + dd = ts->ds->linesize; + ds = 1024; + + switch (ts->ds->depth) { + case 32: + f = tcx_draw_line32; + break; + case 24: + f = tcx_draw_line24; + break; + default: + case 8: + f = tcx_draw_line8; + break; + case 0: + return; + } + + for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) { + if (cpu_physical_memory_is_dirty(page)) { + if (y_start < 0) + y_start = y; + if (page < page_min) + page_min = page; + if (page > page_max) + page_max = page; + f(ts, d, s, XSZ); + d += dd; + s += ds; + f(ts, d, s, XSZ); + d += dd; + s += ds; + f(ts, d, s, XSZ); + d += dd; + s += ds; + f(ts, d, s, XSZ); + d += dd; + s += ds; + } else { + if (y_start >= 0) { + /* flush to display */ + dpy_update(ts->ds, 0, y_start, + XSZ, y - y_start); + y_start = -1; + } + d += dd * 4; + s += ds * 4; + } + } + if (y_start >= 0) { + /* flush to display */ + dpy_update(ts->ds, 0, y_start, + XSZ, y - y_start); + } + /* reset modified pages */ + if (page_max != -1) { + cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE); + } } -static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr) +void tcx_invalidate_display(void *opaque) { - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = tcx_mem_readb(opaque, addr) << 24; - v |= tcx_mem_readb(opaque, addr + 1) << 16; - v |= tcx_mem_readb(opaque, addr + 2) << 8; - v |= tcx_mem_readb(opaque, addr + 3); + TCXState *s = opaque; + int i; + + for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) { +#ifdef LD_BYPASS_OK + cpu_physical_memory_set_dirty(s->vram_offset + i); #else - v = tcx_mem_readb(opaque, addr); - v |= tcx_mem_readb(opaque, addr + 1) << 8; - v |= tcx_mem_readb(opaque, addr + 2) << 16; - v |= tcx_mem_readb(opaque, addr + 3) << 24; + cpu_physical_memory_set_dirty(s->addr + i); #endif - return v; + } } -static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void tcx_save(QEMUFile *f, void *opaque) { TCXState *s = opaque; - uint32_t saddr; - unsigned int x, y; - char *sptr; - - saddr = addr - s->addr - YOFF*MAXX - XOFF; - y = saddr / MAXX; - x = saddr - y * MAXX; - if (x < XSZ && y < YSZ) { - sptr = s->ds->data; - if (sptr) { - if (s->ds->depth == 24 || s->ds->depth == 32) { - /* XXX need to do CLUT translation */ - sptr[y * s->ds->linesize + x*4] = val & 0xff; - sptr[y * s->ds->linesize + x*4+1] = val & 0xff; - sptr[y * s->ds->linesize + x*4+2] = val & 0xff; - } - else if (s->ds->depth == 8) { - sptr[y * s->ds->linesize + x] = val & 0xff; - } - } - cpu_physical_memory_set_dirty(addr); - s->vram[y * XSZ + x] = val & 0xff; - } + + qemu_put_be32s(f, (uint32_t *)&s->addr); + qemu_put_be32s(f, (uint32_t *)&s->vram); + qemu_put_buffer(f, s->r, 256); + qemu_put_buffer(f, s->g, 256); + qemu_put_buffer(f, s->b, 256); } -static void tcx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static int tcx_load(QEMUFile *f, void *opaque, int version_id) { -#ifdef TARGET_WORDS_BIGENDIAN - tcx_mem_writeb(opaque, addr, (val >> 8) & 0xff); - tcx_mem_writeb(opaque, addr + 1, val & 0xff); -#else - tcx_mem_writeb(opaque, addr, val & 0xff); - tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif + TCXState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, (uint32_t *)&s->addr); + qemu_get_be32s(f, (uint32_t *)&s->vram); + qemu_get_buffer(f, s->r, 256); + qemu_get_buffer(f, s->g, 256); + qemu_get_buffer(f, s->b, 256); + return 0; } -static void tcx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void tcx_reset(void *opaque) { -#ifdef TARGET_WORDS_BIGENDIAN - tcx_mem_writeb(opaque, addr, (val >> 24) & 0xff); - tcx_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff); - tcx_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff); - tcx_mem_writeb(opaque, addr + 3, val & 0xff); -#else - tcx_mem_writeb(opaque, addr, val & 0xff); - tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); - tcx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); - tcx_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); + TCXState *s = opaque; + + /* Initialize palette */ + memset(s->r, 0, 256); + memset(s->g, 0, 256); + memset(s->b, 0, 256); + s->r[255] = s->g[255] = s->b[255] = 255; + memset(s->vram, 0, MAXX*MAXY); +#ifdef LD_BYPASS_OK + cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY - 1); #endif } -static CPUReadMemoryFunc *tcx_mem_read[3] = { - tcx_mem_readb, - tcx_mem_readw, - tcx_mem_readl, -}; - -static CPUWriteMemoryFunc *tcx_mem_write[3] = { - tcx_mem_writeb, - tcx_mem_writew, - tcx_mem_writel, -}; - -void tcx_init(DisplayState *ds, uint32_t addr) +void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, + unsigned long vram_offset, int vram_size) { TCXState *s; - int tcx_io_memory; s = qemu_mallocz(sizeof(TCXState)); if (!s) - return; + return NULL; s->ds = ds; s->addr = addr; - ts = s; - tcx_io_memory = cpu_register_io_memory(0, tcx_mem_read, tcx_mem_write, s); - cpu_register_physical_memory(addr, 0x100000, - tcx_io_memory); - s->vram = qemu_mallocz(XSZ*YSZ); + s->vram = vram_base; + s->vram_offset = vram_offset; + + cpu_register_physical_memory(addr, vram_size, vram_offset); + + register_savevm("tcx", addr, 1, tcx_save, tcx_load, s); + qemu_register_reset(tcx_reset, s); + tcx_reset(s); dpy_resize(s->ds, XSZ, YSZ); + return s; } -void vga_screen_dump(const char *filename) +void tcx_screen_dump(void *opaque, const char *filename) { - TCXState *s = ts; + TCXState *s = opaque; FILE *f; - uint8_t *d, *d1; - unsigned int v; + uint8_t *d, *d1, v; int y, x; f = fopen(filename, "wb"); if (!f) - return -1; - fprintf(f, "P6\n%d %d\n%d\n", - XSZ, YSZ, 255); - d1 = s->vram; + return; + fprintf(f, "P6\n%d %d\n%d\n", XSZ, YSZ, 255); + d1 = s->vram + YOFF*MAXX + XOFF; for(y = 0; y < YSZ; y++) { d = d1; for(x = 0; x < XSZ; x++) { v = *d; - fputc((v) & 0xff, f); - fputc((v) & 0xff, f); - fputc((v) & 0xff, f); + fputc(s->r[v], f); + fputc(s->g[v], f); + fputc(s->b[v], f); d++; } - d1 += XSZ; + d1 += MAXX; } fclose(f); return; diff --git a/hw/timer.c b/hw/timer.c deleted file mode 100644 index e393fa36fd..0000000000 --- a/hw/timer.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * QEMU Sparc timer controller emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* - * Registers of hardware timer in sun4m. - */ -struct sun4m_timer_percpu { - volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */ - volatile unsigned int l14_cur_count; -}; - -struct sun4m_timer_global { - volatile unsigned int l10_timer_limit; - volatile unsigned int l10_cur_count; -}; - -typedef struct TIMERState { - uint32_t addr; - uint32_t timer_regs[2]; - int irq; -} TIMERState; - -static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr) -{ - TIMERState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - default: - return s->timer_regs[saddr]; - break; - } - return 0; -} - -static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - TIMERState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - default: - s->timer_regs[saddr] = val; - break; - } -} - -static CPUReadMemoryFunc *timer_mem_read[3] = { - timer_mem_readl, - timer_mem_readl, - timer_mem_readl, -}; - -static CPUWriteMemoryFunc *timer_mem_write[3] = { - timer_mem_writel, - timer_mem_writel, - timer_mem_writel, -}; - -void timer_init(uint32_t addr, int irq) -{ - int timer_io_memory; - TIMERState *s; - - s = qemu_mallocz(sizeof(TIMERState)); - if (!s) - return; - s->addr = addr; - s->irq = irq; - - timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s); - cpu_register_physical_memory(addr, 2, timer_io_memory); -} diff --git a/linux-user/elfload.c b/linux-user/elfload.c index cfc4256974..09c33aa90b 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -841,6 +841,7 @@ static void load_symbols(struct elfhdr *hdr, int fd) unsigned int i; struct elf_shdr sechdr, symtab, strtab; char *strings; + struct syminfo *s; lseek(fd, hdr->e_shoff, SEEK_SET); for (i = 0; i < hdr->e_shnum; i++) { @@ -866,24 +867,27 @@ static void load_symbols(struct elfhdr *hdr, int fd) found: /* Now know where the strtab and symtab are. Snarf them. */ - disas_symtab = malloc(symtab.sh_size); - disas_strtab = strings = malloc(strtab.sh_size); - if (!disas_symtab || !disas_strtab) + s = malloc(sizeof(*s)); + s->disas_symtab = malloc(symtab.sh_size); + s->disas_strtab = strings = malloc(strtab.sh_size); + if (!s->disas_symtab || !s->disas_strtab) return; lseek(fd, symtab.sh_offset, SEEK_SET); - if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size) + if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size) return; #ifdef BSWAP_NEEDED for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) - bswap_sym(disas_symtab + sizeof(struct elf_sym)*i); + bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i); #endif lseek(fd, strtab.sh_offset, SEEK_SET); if (read(fd, strings, strtab.sh_size) != strtab.sh_size) return; - disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + s->next = syminfos; + syminfos = s; } static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, diff --git a/linux-user/main.c b/linux-user/main.c index 6ab024e0bf..3d99dda1ad 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -497,6 +497,8 @@ void cpu_loop (CPUSPARCState *env) case TT_WIN_UNF: /* window underflow */ restore_window(env); break; + case 0x100: // XXX, why do we get these? + break; default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); diff --git a/linux-user/signal.c b/linux-user/signal.c index 50f2ba10a0..49278208c5 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1354,13 +1354,14 @@ struct target_rt_signal_frame { __siginfo_fpu_t fpu_state; }; -#define UREG_O0 0 -#define UREG_O6 6 -#define UREG_I0 16 -#define UREG_I1 17 -#define UREG_I2 18 -#define UREG_I6 22 -#define UREG_I7 23 +#define UREG_O0 16 +#define UREG_O6 22 +#define UREG_I0 0 +#define UREG_I1 1 +#define UREG_I2 2 +#define UREG_I6 6 +#define UREG_I7 7 +#define UREG_L0 8 #define UREG_FP UREG_I6 #define UREG_SP UREG_O6 @@ -1385,23 +1386,20 @@ setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask) { int err = 0, i; - fprintf(stderr, "2.a %lx psr: %lx regs: %lx\n", si, env->psr, si->si_regs.psr); err |= __put_user(env->psr, &si->si_regs.psr); - fprintf(stderr, "2.a1 pc:%lx\n", si->si_regs.pc); err |= __put_user(env->pc, &si->si_regs.pc); err |= __put_user(env->npc, &si->si_regs.npc); err |= __put_user(env->y, &si->si_regs.y); - fprintf(stderr, "2.b\n"); for (i=0; i < 7; i++) { err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]); } for (i=0; i < 7; i++) { - err |= __put_user(env->regwptr[i+16], &si->si_regs.u_regs[i+8]); + err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]); } - fprintf(stderr, "2.c\n"); err |= __put_user(mask, &si->si_mask); return err; } + static int setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ CPUState *env, unsigned long mask) @@ -1434,6 +1432,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, sf = (struct target_signal_frame *) get_sigframe(ka, env, sigframe_size); + //fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); #if 0 if (invalid_frame_pointer(sf, sigframe_size)) goto sigill_and_return; @@ -1451,13 +1450,11 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, } for (i = 0; i < 7; i++) { - err |= __put_user(env->regwptr[i + 8], &sf->ss.locals[i]); + err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]); } for (i = 0; i < 7; i++) { - err |= __put_user(env->regwptr[i + 16], &sf->ss.ins[i]); + err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]); } - //err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], - // sizeof(struct reg_window)); if (err) goto sigsegv; @@ -1486,13 +1483,15 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, /* Flush instruction space. */ //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); - //tb_flush(env); + tb_flush(env); } + //cpu_dump_state(env, stderr, fprintf, 0); return; sigill_and_return: force_sig(TARGET_SIGILL); sigsegv: + //fprintf(stderr, "force_sig\n"); force_sig(TARGET_SIGSEGV); } static inline int @@ -1542,13 +1541,16 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, long do_sigreturn(CPUState *env) { struct target_signal_frame *sf; - unsigned long up_psr, pc, npc; + uint32_t up_psr, pc, npc; target_sigset_t set; + sigset_t host_set; __siginfo_fpu_t *fpu_save; - int err; + int err, i; - sf = (struct new_signal_frame *) env->regwptr[UREG_FP]; - fprintf(stderr, "sigreturn sf: %lx\n", &sf); + sf = (struct target_signal_frame *) env->regwptr[UREG_FP]; + fprintf(stderr, "sigreturn\n"); + fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); + //cpu_dump_state(env, stderr, fprintf, 0); /* 1. Make sure we are not getting garbage from the user */ #if 0 @@ -1567,36 +1569,41 @@ long do_sigreturn(CPUState *env) goto segv_and_exit; /* 2. Restore the state */ - up_psr = env->psr; - //err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs) - //); + err |= __get_user(up_psr, &sf->info.si_regs.psr); + /* User can only change condition codes and FPU enabling in %psr. */ env->psr = (up_psr & ~(PSR_ICC /* | PSR_EF */)) | (env->psr & (PSR_ICC /* | PSR_EF */)); - fprintf(stderr, "psr: %lx\n", env->psr); + fprintf(stderr, "psr: %x\n", env->psr); + env->pc = pc-4; + env->npc = pc; + err |= __get_user(env->y, &sf->info.si_regs.y); + for (i=0; i < 7; i++) { + err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]); + } + for (i=0; i < 7; i++) { + err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); + } err |= __get_user(fpu_save, &sf->fpu_save); - if (fpu_save) - err |= restore_fpu_state(env, fpu_save); + //if (fpu_save) + // err |= restore_fpu_state(env, fpu_save); /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. */ err |= __get_user(set.sig[0], &sf->info.si_mask); - //err |= __copy_from_user(&set.sig[1], &sf->extramask, - // (_NSIG_WORDS-1) * sizeof(unsigned int)); + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + err |= (__get_user(set.sig[i], &sf->extramask[i - 1])); + } + + target_to_host_sigset_internal(&host_set, &set); + sigprocmask(SIG_SETMASK, &host_set, NULL); if (err) goto segv_and_exit; -#if 0 - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); - current->blocked = set; - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); -#endif fprintf(stderr, "returning %lx\n", env->regwptr[0]); return env->regwptr[0]; diff --git a/pc-bios/proll.bin b/pc-bios/proll.bin deleted file mode 100644 index 0489cc245fc524bb89eb36582304617ec4ca5b59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56856 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

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