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 | 30 +- 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 | 321 ++++-- 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 | 2098 ++++++++++++++++++++++++++++++++++- 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 | 402 +++++-- vl.c | 66 +- vl.h | 31 +- 37 files changed, 4507 insertions(+), 1155 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; + 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; - 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 (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; + 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) +{ + int x; + uint8_t val; + + for(x = 0; x < width; x++) { + val = *s++; + /* XXX translate between palettes? */ + *d++ = val; + } +} + +/* Fixed line length 1024 allows us to do nice tricks not possible on + VGA... */ +void tcx_update_display(void *opaque) +{ + 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 + page = ts->addr + YOFF*MAXX; +#endif + 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); + } +} + +void tcx_invalidate_display(void *opaque) { TCXState *s = opaque; - uint32_t saddr; - unsigned int x, y; + int i; - 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]; + for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) { +#ifdef LD_BYPASS_OK + cpu_physical_memory_set_dirty(s->vram_offset + i); +#else + cpu_physical_memory_set_dirty(s->addr + i); +#endif } +} + +static void tcx_save(QEMUFile *f, void *opaque) +{ + TCXState *s = opaque; + + 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 int tcx_load(QEMUFile *f, void *opaque, int version_id) +{ + 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 uint32_t tcx_mem_readw(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = tcx_mem_readb(opaque, addr) << 8; - v |= tcx_mem_readb(opaque, addr + 1); -#else - v = tcx_mem_readb(opaque, addr); - v |= tcx_mem_readb(opaque, addr + 1) << 8; -#endif - return v; -} - -static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr) -{ - 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); -#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; -#endif - return v; -} - -static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void tcx_reset(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; - } -} - -static void tcx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -#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); + /* 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 void tcx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -#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); -#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 zcmWe=U}0xuU|@jZg&qtH%L5n~1R7Yf*9j;v3N$ePfXRVqfd=L;AR2}R8kj%8*dQ87 zKUf@ze+eWn(7^lzM8mK^1M>qI8$=_i_g*KUz#!1Td;=s7!vYP=S72-qEzrPx0Yt;F zKm+p`7#l~XDa}SISq6He5J3urH3p6mdz}O&KpnsG%yFi*dSV~XDvj>a~q6He5T|hJp3p6l0z}O&K zpn=&2M8mK^1G5E;4Wb1am`y-53=1?c8^G8gTA+bh2SmfLKm)S|j18g%8kki;Gz<$g zFe|{=AX=b-Sq4PIus{Q|1dI)$1sa$|Kr{>sG%yRm*dSV~XDGY5TRh=yT-1}3!p&xDr$nZWrRN&Oob8$=5!us{P7TK;E3%l}Mh`JV|b|1+WGeE;vqQKN8nEZj0!Tx`Tpz{9{3tbol8X)5V%^nO4{RRmV4GSMQF*Pu-H7tCRG1 z(BRO(%D}+hBCz;CW5)s%H#6IRv1k%VV1UWbVQ^sDBcQ+_X#d51f{>Dgu>F_TNkT~v z1R5BaLG~U{Vqj=k#K6h6|Np-UObRSb0t!rx6CiejmMFo~Ng$ImK zHV3=?7lAf`2Mmof9-z3P-GhOlu>)1CvEud>HV|HWaIXad74RtJWLr49^C4GgRx^$klM#F!cwxIt`e@!rLlzyS(-n7L4MSk?$A zFuqZBU|1xwfME&C0+z-e1r#?o9&uo3Jk!9?c=!Rwr9~`Y`a%P)0|Uzr0S3v2J?z>d63mFHdA0(B$BZ2 z(GnJhEo=v*Hn1I#5ZM3!Hpo4TKxuA?Lju&j0wDJaG%&D%7Rn1?;m~;e0Y~Et28Pup57<`lD%7vkdBC{Z^a6$_(hE3VNG}k0BfUW4gY*K0FVYJ%en>Ac_#?f*qVWL(0~q6o zziyoeY+alQ^&opz2{5p(5ny0jY4U)vTjv3Lm!N}47iYqMu>Oe&3=gaqFg&qd!12O* zfxsK<1ri^u7btwOUZC;AdV#?o>jf4d_jCy`i1r9Dh~Y{vb06=YA!z@ld4iBah64k` zK4B4XUelc*r2IhG{)?^y1OLWJLdicALHSQaNy34FH*k`G0@DQ+C5eVb3Jf9*3~Y-a z`BTqtJFYX|@6+%ifAbN?A zlEOlr1m+2%3nV59FbG~@We{*+;Gc4hr9t2VOM}2fBL$IVEC)Ciu_Q2FU`+y>$F~3f zSCAe-`!9MEgcJ-M82CFT2`~tQ%$_8gBmq*lh{^u{M4bfYHB1RClb8}X9U{4MgJLlsn}h%9>Gz`(C4YX6l%87!Vq1nU3)Hxy=I_~5|6FFrx!K?ev=f|$b(GG~GSgNOqIpTHym z1_4zD?hlh#7=$jcfX$r)G6QPQ24VZJ3=RzZOrrKbLFF7ME~Ypz@P7d5b6{X_S|;+K z!+}9O9+Yk!7q2rvjN5MbcA!t#J)2~&g6ERlo_&@gfk zw*Mk9-DCmR4VHur4h;M@x0n++KynTY{FW1h6e{Zf|NA1y!N9Oc02DspaP4ql;5P!r zi6{eu0LZ`d4>d4M5>Nnz!R-kG48ovv<L(3#k*|rF52j2z(`~MHr z7#I$yDexRnQxG_yroeJQO#z$+K;bb(K!M>Ji-Ldy1H3J^sewUo0gL^Akp>3#hD8dz4T}`mnV@y9 zKm&uw1vUjxz0U{on?M7D0Eq9vz+gK;fI&i_fkCNZ2`F9|EJ1t+1_o6SEzrOq0~I%h z^2I@Z0Oebw1_rhZYziDtK>lE>|1Z$Mz;Z!Nfn@@d0^qdD zN#Ft1v0M!d98mM*LFR$Xa$sQK0X@LOLT+Rth_5UxZDS*-$7br}xFf9<6CZNFRz`!UuLqLHM*_=yk3M>ta5*U;k z82CYPafMBRqhZkk5T6^wzre=8aE%QdA17|GDexfszSzfF7r@e9-s9SzG87}y#ZL|?Fh<5!?z8Ms|1*syE?gIWWF8z`NF z!m43e1E{^n-LUKdNImBSHV5fTYzpAGvS?sn+NR_n392u}8W>n6ur09 z0H+g>njK0GQlRucL4ZNhfq^ai5~~8wG64oqo{@53U`xNms=%=X!k2bnU`qzcgUYT6 z0t_+^3~ccr`56KX97k9ZR3->82!hJ@DFO^a(*zg<<{xNaxW%TRa)C`j29%bS8W_Yk z2q-Wd(BJVfx!qQ4vTNA z1_q`rN)9qmH%dD&u)arfql^Os>uZ=BFM#}x&7A@ak~0Jtq@ZC>AZ}T&gUkn|7f9T) zUPdw>9Ji2gAUBp>rfoX?YgCsg18W)ld46HpM_d)ZTlmi262Z#@9A3^dOYYT`! zO97PEKxGgEsJ$Wts?(+kFbIO;;|7ZY3n*U+G%#pSP-~EBSoVO)sDZ(9g@FBkP?@6E zz~GPOUN)$ESwQaP0Hqr?2T(q61*t=JH!+aJlYj!lR=ov`EgTORw}>?`f!Y!c%M#dG_W%Fg zZt;MzRU?6=g`q*FU1I@b8^Zync8v#2Z3+jN+87QeoTt!H~eXi#>s{VR>r3%Krb4K=y;&(ju_Pl9B?)H6>8}uz*3Vfr0se zl7he#rUmS+RtuPqC@F}r+JBL35m@AML`gw~)&7fAi@<`MBT5Py2b2_aAaV=7fa>QX zN(u&G`_RkBI98kS}fz5&8f*J$EFEs_0AKaxa)~X02h{!n)w37a5(Kuf9pLz;rXX;EEkWdhnu5p$wgi<6YM^>3LF0m&g2n~5 z1cM7|3I;I$gY1FUy)%A5+K((>)D*yGOn}t+Jf9%ufa-FI3w{j@4h+mem)H_m92i*U zLG72h#OA;-QA>gGf{+799k_0X)=4uaupN+eU|^YiiA_NSR33xe3#zL@^fV?0scVon zfy@N12h0<-6qqLoC`e3EasaiLB$yf)IIpNFC`{t||L2mLg2bgJ7lsJ}_6!rX7`P^J zIdEKpwj)4xf$En_ObZkm7A1i6ae@4GfoXxnu_hLV76E&PR*eSE7L5Z;$Cwt#w15_P zEP{+NfYi->yuacF`+}Hf>>vQR80t_xZyXp{d@eC1@LXcwe*+XImspU(QhooI1uP1T57hTRIiL=< z=MJcCdWn7ihe=8f99P))f0=64z(Y8T2(;#$BwSu24VRIf~6Yv7o` zrNBN(2-KHVkl&)jz}c{DfjlTpd;zD4{m5zJ-$X42DLiQcqz^q!{G%{U7-LBjhsaM8 zOrSnIG)*ucr$d@x#E~Zc6Okt5$w?Et^%LY5fZ7mC7^KA-80>c2C&*7=0kyxGyFuv$ zl>cF6!xSb4DNs5FmBkYT7`P@dEs&pRrNBB-OMwYgj!a`>;GD#@Kz@RNg2DtP2F@v6 z3ZOXVn*plx7d6PRG%&DE)@ISC+RzIP7q??ys+p9 z!!)J`EEB-x27`=P0|OU0{R=Q~gT#L=Vqusfz`!{PEbk!0w*UX{2?7k<4T~CN%o-TD zL3tBo{v-kW|C6<#=4&xxgh85Z|NrA4zar<6UHl3E7wRWSOw>;hSRlf{ zF;PE(14J(nVUPvYuMNu`K;dLHf!#sUfq~fx6hbQsXXgr#8-W|%xcgb7Q-B8)KM0oBJa zJ21k92VnR@$HJ872!gRBDsGc(BVAa{e($0jBQ&P{9% zQlPdSG<`@;U`s$rA6u9hI41~z^fG+`=>@fu)F9;!^CT|&KcGHC3zGu}E;B%5KcIFK zRG-!aCIx1J1_sTIRtiiLm>8rdFxmfiU|_lnGMh|yodfBGnhz=u5$*z)b>J{y2898# z-(c?ApuoVH~oLG@yJ2N;9(r7??nD21?(c{4-t40g`{T95|*K9pJds%))S? z*@a;emjm|%Ee38-*?eg+3&RX%1(sRN3CQ_~7u1fOAi%&25}zc%zyneP8t=cb$OV+A zxTk^h)B#YQ`TloMN(Z1Zu8l?tOcPkZ@g5IS`-Dw_XBiWN&?7blfn_WQ1VLskP+^dTstE(BX=7p# zYGXJc2r~y1ZyU`Nm?rQ%0JU{k7AQGzEZ|XKUdHqP&pZJI25@{W2FF)$8^`}Yi%{cB zV1@vLFf_h|X9+McgYr01oUu*UazNy9;^Pf8b^ zVVK68z;mtX2*ZWNEDRHv6<9!XI1`u^IIb)L^Lef<0;dCkDFO^kEue9;1r4CMeK(6a zL0|&Y0$5o>OuArcScH)-c$TpofTRnp1c349P~e&( zpupk4z@Pb5|NkP$OsL!ZjrRXP3*v*!nFMiD4y2u^zyWd($Q=$0 z3~ZN}92f-l|33s$i>=|Npj0fPrHZ`~C-@@newN9T*r4LGEo>!XPODcB}n=m_5+6&Bbc}#kEaf;e;tn z`~SCaDexcRIKXs7%Yh3dFSP&v?}Q`*!vhC zFoNdUXB#Il&SG|86aa}Sg7S$2H`o6E-$DH#rUnKk5Z$-%0V7)jLm7xYP3Zvd6!02< z25|d%s@4LK94p8ikQ``SehSk9#%W9kc&8{WU`uZR>0u2lnQXkgF>`?-l|H!FkEF;uU@6sG-uL2NYhrKT|L{|yosXkZYZ!nFS< zh>ge1d{dbAe+Q`%Xkg%;!nFS@h>d0@>lCK_pF!dR4Gc_EnD&31u~>moZ2$j7pzsH^ zho&(d;Dn|x?gmJj)QB)<(vx&)Oa4HF$eW6exc6d1UmX_RY*5Cdmp z69YrTYJJdHhsKN!28Nl+44eau8Kzn#$WP&7;F{>b0G^+l)Xcy|hMO2>J1{Uz)K=h` zZJZ!7LD+!<2E@89uvifTC#an;njXPz0bK2i(ey~g^oZPMK~9gLbU3Amfpbbw1Guc5 zpv1s+iAjOu2$O;UyZr%%HjM^m@SKlP0#gge|Nlpf96)nKOh=3onA$BK2pog(nL+#` zLJAfj`2$7?;Ib8DHfUV?7@GpeH--m1_ZS`sfXxD}XHa+`b3oyN!~ul|DhCuEC>$_5 zz;J|5LH>x|1EwQ<3UWvE9xxx_Q&2pj_kiUHpMt^>y$7sE_!N|n=sjRN!l$5gMDGDR zXx^-Y`Jn_WgZ=+W0*n7Qu|1fvi|xUj2?7QTJJ=q~YX!}xF*HcEYAj%DfzY5$noOHG z8aUha7BGJ@aA4lRc7VCnERN^#r8mEf`H|Z9c&NeK zazO0?#{snm@VPrsTwGvN&;a!@nHm_BAA!~iF)=V)U}<1z=u%(;_4zWI z+W-F_NbCVi18AL(Nkf-{0;q2+$iT<|>XU=VUUk50wpu0#DJX#W7uXbZpmwkbG6rO0pvWHxw>A!zLmYyKnw2JTDXFi8Nd=LN4j1NG%62q{{CXa@$?G?4#6eP7T# z_XQINh6w@+P9PdtA80)RNc{yS2Zjkk3IZ3D92h`iu)ZrO>_O`gUa&mixxn&30yO?P zfk{DP5i0}7C7uMPhOUGLp#}z*RRRhPf(#52YlIYMP2fskZde3fH*46?mEa)Mz@QIu z%LS1Hwh3JN|Ccb?|8Zd8Trq*k{vUMh9PbAe1r|Yw|2!NRSj{i7F)$o3Nnm@WlfVSB z7c>_(flGlOG%kBV<$(lfO^E{o=XucjPbmAsBmvNx#s?CUwGzzPh_kc}-;~I+s&lMI0l?yDOH9`#>ObrYnk608qK;wB6m=tDAVmiQa zfeRFt3JpdL41QNs6jVTS^GgI2SfJt#Obrai;4llfx+Mci-G|( z-AaMN@DhuH&Lm|9&Pyr^Ix~b63qW%`pf%su*cd=-I`zQ)cp=3JAhlD36lY8jVBm3J zV7UcKQ=l~c#KeK2{{O!NpfRHQ|NmBl!lC~Ef6zKR0fPnxHISXqv?&HMV}g+40tW_` zQ_whLg6iJ@)ju1mpC3dUG%$#P{4{|}0h~raYyUv~YpB?t3t9cs(AAg2n|V28J6<3M}IG2f%STK}hii$UjpA7z7;{STd(+ zGjN0Ehd^$=!~!Za!Q}&ZojFoIR{-Vn`v3pjL2j=9|IY{%H}(Jjf#!QbYf44H_L($* z)|sNLn*^n2P};q~q5v8@Qm?Qi5rGB< zi46kwUqNXL;x-3{3t+c_)w7A(A7B9a>k^BCz$7jQu1iV^JoW$oDL~!E4RRYOEI{jB z!SSXCmahhhZxCSM0L49MT>vP*f%5S+rUZ^FOb<8?XeID~)hi{4957k{Dyvy87=hL` z@CaXEdH^2ZgXYr-57-ho-moZeykY^Z(M%8l#Q{?TgAJ(u6tw@+dVxvl#wE4{@Vpyn z%vS`lhhW(j0sH?~L>r*-q2%Dez`_n%Cjm0^5{m){s9gc}w-JiJ!Fk7lf%(q_Aten^ zcw7S2X^?Wb0TMr7Zh-0;6ge*YdXOAQ>Y?=LMw&JoW$oUILBF*8l&z z7Zg4)w_i|8U^$?cAOH>zy#$^EY6&9s|Nnu;qXh&S7|J#XFi3&Mw?X;Yfr0t@1R$O zqfi3_2S~257j?gjKm&sx$Q>Z{pmD5a0tz;uJhq5Sfq$w_0`nx+ggFxw7=$MX88BQh za^RZ4nlSHx5d+smodm`SObmh(wG`N(H1h-|MTsS>4xn|H9H9Ebfq}UQw05Fl$pI0i z1_n0JI{gVO4I&N<%*m5f4v2vHtPUKL1QePtX(`MC*$bSj3_r2U=slL`bn=0^0(n3p@=R7jzt?CUGhJ zZ&eJVz`*P$%{biHuVE) z3MSySP>}U3AT|#uoP-(}xEdBIFoNu!Af&Xxfq_{8v}St(WX+QSXpZQBnt~2!{QZEM z0*KE6;zQ+ip!#k&Ffa>&^nu!;nECYcJ8(W_Q_z6R!SX3+9deffyHEpz5ZEj>g@Owz z3=AJsz;%)W$iEj<6f^|wzkt|#E~qGg>;$pDTu=e+Ct(i)4O21d0>0-!b0;I*UdpfzP6yB!#q9!?Na)(~i52nXq%AfR9m zT4xWHyEQ>bIRLc&7~}^*8wLi@8XG|c(A)jK|p~` zpn*XZEN=fr&w+ty%LF0i2!RF$b&xwj`vE|-0|V2#2|~&l0u2m`AU=}#iU~r>pt(P3 zH1S0fgp@l38W=>;#OF*9Ql25uz`&0tK5c@K@&-_T1c`&nT45VV`)PuZ@(Bk9roKsB z4V)l32L`5YP?`qC4@!K1=a!Tv98gl4ASh?Ra6u`7Wddlwk`lOHV!NP}0NVfIb%99< zymlPaMuVDH4%+i%(7+%Ln&Ybf|G#sBh|&sZdKLneIg^BvCV<2)C?$x1=EFegsQ&+d zHqiP}kUAu@QYHu~|1fA^U;*g^#nA<&B$Rb~nhc=!j{*Z|UsS^q2T7?01|iV8xK(Tl z9H6~T6Ic{jCa^Jp%1dEU1{MYf1_sdFuE+&e2hjW{XzvTtB9;V3&^ob(B@L2X`~QDl z#&SU9ks1T)-V*@^sfHyCQlPvrfz3exv>pT0C!4@z|3{#Kfprp#{U4Axh!5I#;lRKk z394hD{t*DJt@)$|I*W=y5VW^qv55lXBsK>@ka`CO2EIv5^`N;|P#c65NiEwWH3b%} z{r?{=)KOpr=?Cq1K#nJY3)+9t7ieJcnjoYgQUCwrSx~zK zv^Kc@|Ho6Hx^{&CcrO7+ugN3<(EOqTX#WQ*NDivk8nid8{{P24pgL!P1*lKQ05WR_ zXw7f^|BpLBYC(Gv>i>V-3NjzMrXHkbJxC8ozW)EmHIoDwL>iVj2naPWsDjLHSaLv! zsewTql%GLua|Z@SVI=p1`cxpdOGDj04`epT?I7BLfe}=%F~a-`au>)jI2yXZ`$X9%aMgbR`OSfWanb}K1<;yNHjtktYJv8? zFtCE=dC}XTAoUZ36beA$;K0Dx0@`yn(JTSfcV?>p|Irqdmq2Ixw^X3&8ypxI zD?xfT>M5{n;In6#XqF%_flJ{}{r`^!XnMqY3ocz!(qG z1Le(m=YKp7A5>=+5i9V6_o=V3j`P> zmF>TP%ESLFgp~h7_bds5_7Q^m>7cS;h5&=)B9#J$h9wRn9Q*(O0L8H~0|Uzf0R}-q z26qtA1*xt7{{h?&2C)w)f%oq^d|*;wftlF`+DpK|zz!PsJh0&4 zfmV$N;Qjk;3=aev798N@*#G}`i+~~nXwAok1q}`0z4{9p50?P*_2e8{e zC@HW^5>ndoK?#Ht;O=F&|KfFo;n9|c1r4C_JXTf^pNWCth{B^SAaM?hjw^&ob`f(4**j|~(~Aag)` zQ2YOY5(7hZzYu>b!ACI&9hob3cI2CidF4?t_bn57yRSX-DFI2#r;Fl#h0FdtERzyVr! z1=0_TLs0qwm7Vqf|Gx#TvEKm6N8mn<0|Nu7Ob74N1@-Ge<5iQG>i>iKSRlG#QT>0T z{r~?S(1Ogrg3JW9k3s7$j%YbBK-48Lg7~0y@<#jr|31QnqLv4=pAWQVrd8{KM61OD ziDO<43=0L2ri9t61sWd9K_ z2C$eB;5NP+Q!isG6JA_+{O@%If{;B`y_8|@TO#&tmXsQ&-|n-hc-F2K%v0Qqf# z00U=>fC6KyMgs>lkFmB|EMRQtXkcdA|NjqYZ7j%dAb*40RR8}yIR9@nQjnNxq`)D} zz+ew5AEt0MaBdI-?d4$LoUE0=u|bT16SU`egBa@g&1AC#iK%7@puN=g6NHo*rf@ZI zOcHY7n!xA4F;Pna#OBznmjD|7m8k#!K4X%Q13aC8><6_gKxGtSt#JPT%~lFL(D3a5 zwK3}d{|^AQF;+m*9LEGU1p%nI7f5^+wCw@X16uzBDi<#>DYOWK>N6$=&NZwIp#7pE zi@@vK!R=*Gn*=nT)4UAaCV2o#ze3Qui?ROyzpNXeeefz97(nf0P#YVx4hvL&Ef8Q3 z1MPjDpz6Re(MW*@y5^k)$!y*YObncYjQ{^n5>jTEXrjOZTGu{7NTChXuiL<;z=CAv zPmr0f)EXEz2%zrg5@cau0PR(;|NnRXB%uVB1&}@K?4Z5m(72D9Af#{u7WWre7#Nlt zDae56rA7)8OL!LWgZiA4xauEI5=vkdv~OSl_qiCrG|wd!28IJFpnXURJd2GKctB@p zfWmKr5U8!dAXxwZKWLANAgI0s?Ue_Wy&!uh2q}C3ji-Y4_QUK3*L7?T921zpVZw4j zMS%rmHblK5sC_038pFTFrodAF|Gy4s4;?5DL3_mO|Npx@MZf^w?*NUJgYq!6tUiFW z=bz~a!vUs-1r40Y`4%*9!LtAV50EKaqhhY3s% zK<#K|mIemq3ra~J4k#sk0Le`fN;)u6>j7vSiW?NSpOhRpK>DUIHE>VWTEGNVa|B!- zGBt44|NnPxihu$eaz1ZZmLSd106CZG0v`it{}smrJ_Sb5oRtFuqd%xm2b;TSSi%6R zr%FNj@d6*HzEfZmYG5dY@|i$+=mDPsGgPm`1OW|@dEj{usNOWFTGoa|3M@hm3`tAa zKxF&LX)OTl#TNv* z{R#`Z`~s#+S__yju_WyQjU`;rN??JqSuSWLusSd>g7!}^VbRBSNoxW71D2#c3s^w@ zWcUMe7s#Iu49tf?b>;<@q&=7T6!<1BJ_P|#nFcDSuJ9=c zPGAD<`DWfW2_(movhN2B(iaVGZ7&1Y2 zU0_mN(y)wy1GN59Q2qdDOo$Q6PlU-&kb|5>afvB$1$Yh;G(Kbh#q|P{;s$6r9|l_g z`+-SuL;e5%`k?d)>XVr@Fa%B10fj%qMo=8%k0XW^D|Mw}VkK(|

CKF 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 U|1ZjX0jd3eQ3jNbLCisi0ZKQAMgRZ+ 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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 z ++#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 - - 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); -+#ifdef ORIG - set_timeout(5); while (!chk_timeout()) { } /* P3: let me read */ ++ ++/* 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 -+ printk("loading kernel:"); -+ i = ld_bypass(0x20000000); -+ printk(" done, size %d\n", i); ++ or %g0, 8, %g3 +#endif - - { - 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 @@ - }; - - 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)}, ++ ++#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} ++ {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 ++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 */ + }; + +@@ -91,13 +91,13 @@ + struct linux_mem_v0 pv_v0mem; + + /* 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 + #include "lat7_2.bm" /* lat7_1.bm */ ++#else ++#include "lat7_2_swapped.bm" /* lat7_1.bm */ ++#endif + #define LAT7_NCHARS 128 + #define LAT7_HEIGHT 11 + #define LAT7_WIDTH 8 + ++#ifdef ORIG + static Rf_scan lat7_body[ LAT7_NCHARS*LAT7_HEIGHT ]; ++#endif + + #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; +} - do_mapping: - vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); +/* 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; - ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); - return ret; + if (env->user_mode_only) { + /* user mode only emulation */ + error_code = -2; + goto do_fault_user; + } + + 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_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 = TT_FP_EXCP; + env->fsr &= ~FSR_FTT_MASK; + env->fsr |= PARAM1; + cpu_loop_exit(); + FORCE_RET(); +} + void OPPROTO op_debug(void) { - env->exception_index = EXCP_DEBUG; - cpu_loop_exit(); + 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,6 +1543,25 @@ int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb) return gen_intermediate_code_internal(tb, 1, env); } +extern int ram_size; + +void cpu_reset(CPUSPARCState *env) +{ + memset(env, 0, sizeof(*env)); + env->cwp = 0; + env->wim = 1; + env->regwptr = env->regbase + (env->cwp * 16); +#if defined(CONFIG_USER_ONLY) + env->user_mode_only = 1; +#else + env->psrs = 1; + env->pc = 0xffd00000; + env->gregs[1] = ram_size; + env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */ + env->npc = env->pc + 4; +#endif +} + CPUSPARCState *cpu_sparc_init(void) { CPUSPARCState *env; @@ -1374,21 +1570,8 @@ CPUSPARCState *cpu_sparc_init(void) if (!(env = malloc(sizeof(CPUSPARCState)))) return (NULL); - memset(env, 0, sizeof(*env)); - env->cwp = 0; - env->wim = 1; - env->regwptr = env->regbase + (env->cwp * 16); -#if defined(CONFIG_USER_ONLY) - env->user_mode_only = 1; -#else - /* Emulate Prom */ - env->psrs = 1; - env->pc = 0x4000; - 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 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); +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); -/* sched.c */ -void sched_init(); +/* 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); -/* timer.c */ -void timer_init(uint32_t addr, int irq); +/* slavio_timer.c */ +void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2); + +/* 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"