summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--Makefile.target3
-rw-r--r--cpu-exec.c2
-rw-r--r--disas.c34
-rw-r--r--disas.h10
-rw-r--r--gdbstub.c19
-rw-r--r--hw/fdc.c35
-rw-r--r--hw/iommu.c54
-rw-r--r--hw/lance.c127
-rw-r--r--hw/m48t08.c161
-rw-r--r--hw/m48t08.h8
-rw-r--r--hw/magic-load.c179
-rw-r--r--hw/sched.c268
-rw-r--r--hw/slavio_intctl.c299
-rw-r--r--hw/slavio_serial.c364
-rw-r--r--hw/slavio_timer.c289
-rw-r--r--hw/sun4m.c163
-rw-r--r--hw/tcx.c297
-rw-r--r--hw/timer.c97
-rw-r--r--linux-user/elfload.c16
-rw-r--r--linux-user/main.c2
-rw-r--r--linux-user/signal.c79
-rw-r--r--pc-bios/proll.binbin56856 -> 0 bytes
-rw-r--r--pc-bios/proll.elfbin0 -> 133338 bytes
-rw-r--r--pc-bios/proll.patch2088
-rw-r--r--qemu-doc.texi23
-rw-r--r--qemu-tech.texi5
-rw-r--r--target-sparc/cpu.h28
-rw-r--r--target-sparc/exec.h3
-rw-r--r--target-sparc/fop_template.h12
-rw-r--r--target-sparc/helper.c255
-rw-r--r--target-sparc/op.c29
-rw-r--r--target-sparc/op_helper.c176
-rw-r--r--target-sparc/op_mem.h4
-rw-r--r--target-sparc/translate.c396
-rw-r--r--vl.c66
-rw-r--r--vl.h33
37 files changed, 4490 insertions, 1138 deletions
diff --git a/Makefile b/Makefile
index 3659819fbe..3cf7e504cd 100644
--- a/Makefile
+++ b/Makefile
@@ -50,7 +50,7 @@ install: all
 	install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \
                        pc-bios/vgabios-cirrus.bin \
                        pc-bios/ppc_rom.bin \
-                       pc-bios/proll.bin \
+                       pc-bios/proll.elf \
                        pc-bios/linux_boot.bin "$(datadir)"
 	mkdir -p "$(docdir)"
 	install -m 644 qemu-doc.html  qemu-tech.html "$(docdir)"
@@ -107,7 +107,7 @@ tarbin:
 	$(datadir)/vgabios.bin \
 	$(datadir)/vgabios-cirrus.bin \
 	$(datadir)/ppc_rom.bin \
-	$(datadir)/proll.bin \
+	$(datadir)/proll.elf \
 	$(datadir)/linux_boot.bin \
 	$(docdir)/qemu-doc.html \
 	$(docdir)/qemu-tech.html \
diff --git a/Makefile.target b/Makefile.target
index a5c697ddc9..edf76cffbe 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -175,6 +175,7 @@ endif
 
 ifeq ($(CONFIG_DARWIN),yes)
 OP_CFLAGS+= -mdynamic-no-pic
+LIBS+=-lmx
 endif
 
 #########################################################
@@ -300,7 +301,7 @@ VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
 VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o
 endif
 ifeq ($(TARGET_ARCH), sparc)
-VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o timer.o
+VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o
 endif
 ifdef CONFIG_GDBSTUB
 VL_OBJS+=gdbstub.o 
diff --git a/cpu-exec.c b/cpu-exec.c
index b98c22c58e..cc6324ca10 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -261,7 +261,7 @@ int cpu_exec(CPUState *env1)
                     }
 #elif defined(TARGET_SPARC)
                     if (interrupt_request & CPU_INTERRUPT_HARD) {
-			do_interrupt(0, 0, 0, 0, 0);
+			do_interrupt(env->interrupt_index, 0, 0, 0, 0);
                         env->interrupt_request &= ~CPU_INTERRUPT_HARD;
 		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
 			//do_interrupt(0, 0, 0, 0, 0);
diff --git a/disas.c b/disas.c
index 86f29d2458..bfab8c3bb7 100644
--- a/disas.c
+++ b/disas.c
@@ -9,9 +9,7 @@
 #include "disas.h"
 
 /* Filled in by elfload.c.  Simplistic, but will do for now. */
-unsigned int disas_num_syms;
-void *disas_symtab;
-const char *disas_strtab;
+struct syminfo *syminfos = NULL;
 
 /* Get LENGTH bytes from info's buffer, at target address memaddr.
    Transfer them to myaddr.  */
@@ -203,19 +201,23 @@ const char *lookup_symbol(void *orig_addr)
 {
     unsigned int i;
     /* Hack, because we know this is x86. */
-    Elf32_Sym *sym = disas_symtab;
-
-    for (i = 0; i < disas_num_syms; i++) {
-	if (sym[i].st_shndx == SHN_UNDEF
-	    || sym[i].st_shndx >= SHN_LORESERVE)
-	    continue;
-
-	if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
-	    continue;
-
-	if ((long)orig_addr >= sym[i].st_value
-	    && (long)orig_addr < sym[i].st_value + sym[i].st_size)
-	    return disas_strtab + sym[i].st_name;
+    Elf32_Sym *sym;
+    struct syminfo *s;
+    
+    for (s = syminfos; s; s = s->next) {
+	sym = s->disas_symtab;
+	for (i = 0; i < s->disas_num_syms; i++) {
+	    if (sym[i].st_shndx == SHN_UNDEF
+		|| sym[i].st_shndx >= SHN_LORESERVE)
+		continue;
+
+	    if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
+		continue;
+
+	    if ((long)orig_addr >= sym[i].st_value
+		&& (long)orig_addr < sym[i].st_value + sym[i].st_size)
+		return s->disas_strtab + sym[i].st_name;
+	}
     }
     return "";
 }
diff --git a/disas.h b/disas.h
index c4a251ff8f..5d383faab6 100644
--- a/disas.h
+++ b/disas.h
@@ -9,7 +9,11 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags);
 const char *lookup_symbol(void *orig_addr);
 
 /* Filled in by elfload.c.  Simplistic, but will do for now. */
-extern unsigned int disas_num_syms;
-extern void *disas_symtab;  /* FIXME: includes are a mess --RR */
-extern const char *disas_strtab;
+extern struct syminfo {
+    unsigned int disas_num_syms;
+    void *disas_symtab;
+    const char *disas_strtab;
+    struct syminfo *next;
+} *syminfos;
+
 #endif /* _QEMU_DISAS_H */
diff --git a/gdbstub.c b/gdbstub.c
index 2491c2cd77..e2c8b2dfa8 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -298,11 +298,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
     }
     /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
     registers[64] = tswapl(env->y);
-    tmp = (0<<28) | (4<<24) | env->psr		\
-	| (env->psrs? PSR_S : 0)		\
-	| (env->psrs? PSR_PS : 0)		\
-	| (env->psret? PSR_ET : 0)		\
-	| env->cwp;
+    tmp = GET_PSR(env);
     registers[65] = tswapl(tmp);
     registers[66] = tswapl(env->wim);
     registers[67] = tswapl(env->tbr);
@@ -317,7 +313,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
 
 static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
 {
-    uint32_t *registers = (uint32_t *)mem_buf, tmp;
+    uint32_t *registers = (uint32_t *)mem_buf;
     int i;
 
     /* fill in g0..g7 */
@@ -334,12 +330,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
     }
     /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
     env->y = tswapl(registers[64]);
-    tmp = tswapl(registers[65]);
-    env->psr = tmp & ~PSR_ICC;
-    env->psrs = (tmp & PSR_S)? 1 : 0;
-    env->psrps = (tmp & PSR_PS)? 1 : 0;
-    env->psret = (tmp & PSR_ET)? 1 : 0;
-    env->cwp = (tmp & PSR_CWP);
+    PUT_PSR(env, tswapl(registers[65]));
     env->wim = tswapl(registers[66]);
     env->tbr = tswapl(registers[67]);
     env->pc = tswapl(registers[68]);
@@ -495,8 +486,10 @@ static void gdb_vm_stopped(void *opaque, int reason)
     /* disable single step if it was enable */
     cpu_single_step(cpu_single_env, 0);
 
-    if (reason == EXCP_DEBUG)
+    if (reason == EXCP_DEBUG) {
+	tb_flush(cpu_single_env);
         ret = SIGTRAP;
+    }
     else
         ret = 0;
     snprintf(buf, sizeof(buf), "S%02x", ret);
diff --git a/hw/fdc.c b/hw/fdc.c
index d512b1ca98..ee07328481 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -21,6 +21,10 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+/*
+ * The controller is used in Sun4m systems in a slightly different
+ * way. There are changes in DOR register and DMA is not available.
+ */
 #include "vl.h"
 
 /********************************************************/
@@ -90,6 +94,16 @@ typedef struct fdrive_t {
     uint8_t ro;               /* Is read-only           */
 } fdrive_t;
 
+#ifdef TARGET_SPARC
+#define DMA_read_memory(a,b,c,d)
+#define DMA_write_memory(a,b,c,d)
+#define DMA_register_channel(a,b,c)
+#define DMA_hold_DREQ(a)
+#define DMA_release_DREQ(a)
+#define DMA_get_channel_mode(a) (0)
+#define DMA_schedule(a)
+#endif
+
 static void fd_init (fdrive_t *drv, BlockDriverState *bs)
 {
     /* Drive */
@@ -455,6 +469,18 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
     }
 }
 
+static CPUReadMemoryFunc *fdctrl_mem_read[3] = {
+    fdctrl_read,
+    fdctrl_read,
+    fdctrl_read,
+};
+
+static CPUWriteMemoryFunc *fdctrl_mem_write[3] = {
+    fdctrl_write,
+    fdctrl_write,
+    fdctrl_write,
+};
+
 static void fd_change_cb (void *opaque)
 {
     fdrive_t *drv = opaque;
@@ -473,7 +499,7 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
                        BlockDriverState **fds)
 {
     fdctrl_t *fdctrl;
-//    int io_mem;
+    int io_mem;
     int i;
 
     FLOPPY_DPRINTF("init controller\n");
@@ -504,11 +530,8 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
     fdctrl_reset(fdctrl, 0);
     fdctrl->state = FD_CTRL_ACTIVE;
     if (mem_mapped) {
-        FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
-#if 0
-        io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write);
-        cpu_register_physical_memory(base, 0x08, io_mem);
-#endif
+        io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl);
+        cpu_register_physical_memory(io_base, 0x08, io_mem);
     } else {
         register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl);
         register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl);
diff --git a/hw/iommu.c b/hw/iommu.c
index a9249c4ba7..62927acd54 100644
--- a/hw/iommu.c
+++ b/hw/iommu.c
@@ -117,8 +117,6 @@ typedef struct IOMMUState {
     uint32_t iostart;
 } IOMMUState;
 
-static IOMMUState *ps;
-
 static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
 {
     IOMMUState *s = opaque;
@@ -187,25 +185,61 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = {
     iommu_mem_writew,
 };
 
-uint32_t iommu_translate(uint32_t addr)
+uint32_t iommu_translate_local(void *opaque, uint32_t addr)
 {
-    uint32_t *iopte = (void *)(ps->regs[1] << 4), pa;
+    IOMMUState *s = opaque;
+    uint32_t *iopte = (void *)(s->regs[1] << 4), pa;
 
-    iopte += ((addr - ps->iostart) >> PAGE_SHIFT);
-    cpu_physical_memory_rw((uint32_t)iopte, (void *) &pa, 4, 0);
+    iopte += ((addr - s->iostart) >> PAGE_SHIFT);
+    cpu_physical_memory_read((uint32_t)iopte, (void *) &pa, 4);
     bswap32s(&pa);
     pa = (pa & IOPTE_PAGE) << 4;		/* Loose higher bits of 36 */
     return pa + (addr & PAGE_MASK);
 }
 
-void iommu_init(uint32_t addr)
+static void iommu_save(QEMUFile *f, void *opaque)
+{
+    IOMMUState *s = opaque;
+    int i;
+    
+    qemu_put_be32s(f, &s->addr);
+    for (i = 0; i < sizeof(struct iommu_regs); i += 4)
+	qemu_put_be32s(f, &s->regs[i]);
+    qemu_put_be32s(f, &s->iostart);
+}
+
+static int iommu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    IOMMUState *s = opaque;
+    int i;
+    
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_be32s(f, &s->addr);
+    for (i = 0; i < sizeof(struct iommu_regs); i += 4)
+	qemu_put_be32s(f, &s->regs[i]);
+    qemu_get_be32s(f, &s->iostart);
+
+    return 0;
+}
+
+static void iommu_reset(void *opaque)
+{
+    IOMMUState *s = opaque;
+
+    memset(s->regs, 0, sizeof(struct iommu_regs));
+    s->iostart = 0;
+}
+
+void *iommu_init(uint32_t addr)
 {
     IOMMUState *s;
     int iommu_io_memory;
 
     s = qemu_mallocz(sizeof(IOMMUState));
     if (!s)
-        return;
+        return NULL;
 
     s->addr = addr;
 
@@ -213,6 +247,8 @@ void iommu_init(uint32_t addr)
     cpu_register_physical_memory(addr, sizeof(struct iommu_regs),
                                  iommu_io_memory);
     
-    ps = s;
+    register_savevm("iommu", addr, 1, iommu_save, iommu_load, s);
+    qemu_register_reset(iommu_reset, s);
+    return s;
 }
 
diff --git a/hw/lance.c b/hw/lance.c
index 25ad8c45b2..c594c52e83 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -147,6 +147,7 @@ struct lance_init_block {
 };
 
 #define LEDMA_REGS 4
+#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)
 #if 0
 /* Structure to describe the current status of DMA registers on the Sparc */
 struct sparc_dma_registers {
@@ -157,32 +158,28 @@ struct sparc_dma_registers {
 };
 #endif
 
-typedef struct LEDMAState {
-    uint32_t addr;
-    uint32_t regs[LEDMA_REGS];
-} LEDMAState;
-
 typedef struct LANCEState {
-    uint32_t paddr;
     NetDriverState *nd;
     uint32_t leptr;
     uint16_t addr;
     uint16_t regs[LE_MAXREG];
     uint8_t phys[6]; /* mac address */
     int irq;
-    LEDMAState *ledma;
+    unsigned int rxptr, txptr;
+    uint32_t ledmaregs[LEDMA_REGS];
 } LANCEState;
 
-static unsigned int rxptr, txptr;
-
 static void lance_send(void *opaque);
 
-static void lance_reset(LANCEState *s)
+static void lance_reset(void *opaque)
 {
+    LANCEState *s = opaque;
     memcpy(s->phys, s->nd->macaddr, 6);
-    rxptr = 0;
-    txptr = 0;
+    s->rxptr = 0;
+    s->txptr = 0;
+    memset(s->regs, 0, LE_MAXREG * 2);
     s->regs[LE_CSR0] = LE_C0_STOP;
+    memset(s->ledmaregs, 0, LEDMA_REGS * 4);
 }
 
 static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
@@ -190,7 +187,7 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
     LANCEState *s = opaque;
     uint32_t saddr;
 
-    saddr = addr - s->paddr;
+    saddr = addr & LE_MAXREG;
     switch (saddr >> 1) {
     case LE_RDP:
 	return s->regs[s->addr];
@@ -208,7 +205,7 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val
     uint32_t saddr;
     uint16_t reg;
 
-    saddr = addr - s->paddr;
+    saddr = addr & LE_MAXREG;
     switch (saddr >> 1) {
     case LE_RDP:
 	switch(s->addr) {
@@ -292,7 +289,7 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = {
 static int lance_can_receive(void *opaque)
 {
     LANCEState *s = opaque;
-    void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
+    uint32_t dmaptr = s->leptr + s->ledmaregs[3];
     struct lance_init_block *ib;
     int i;
     uint16_t temp;
@@ -303,7 +300,7 @@ static int lance_can_receive(void *opaque)
     ib = (void *) iommu_translate(dmaptr);
 
     for (i = 0; i < RX_RING_SIZE; i++) {
-	cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
+	cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
 	temp &= 0xff;
 	if (temp == (LE_R1_OWN)) {
 #ifdef DEBUG_LANCE
@@ -323,7 +320,7 @@ static int lance_can_receive(void *opaque)
 static void lance_receive(void *opaque, const uint8_t *buf, int size)
 {
     LANCEState *s = opaque;
-    void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
+    uint32_t dmaptr = s->leptr + s->ledmaregs[3];
     struct lance_init_block *ib;
     unsigned int i, old_rxptr, j;
     uint16_t temp;
@@ -333,23 +330,23 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size)
 
     ib = (void *) iommu_translate(dmaptr);
 
-    old_rxptr = rxptr;
-    for (i = rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
-	cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
+    old_rxptr = s->rxptr;
+    for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
+	cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
 	if (temp == (LE_R1_OWN)) {
-	    rxptr = (rxptr + 1) & RX_RING_MOD_MASK;
+	    s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK;
 	    temp = size;
 	    bswap16s(&temp);
-	    cpu_physical_memory_write(&ib->brx_ring[i].mblength, (void *) &temp, 2);
+	    cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp, 2);
 #if 0
-	    cpu_physical_memory_write(&ib->rx_buf[i], buf, size);
+	    cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size);
 #else
 	    for (j = 0; j < size; j++) {
-		cpu_physical_memory_write(((void *)&ib->rx_buf[i]) + j, &buf[j], 1);
+		cpu_physical_memory_write(((uint32_t)&ib->rx_buf[i]) + j, &buf[j], 1);
 	    }
 #endif
 	    temp = LE_R1_POK;
-	    cpu_physical_memory_write(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
+	    cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
 	    s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR;
 	    if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
 		pic_set_irq(s->irq, 1);
@@ -364,7 +361,7 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size)
 static void lance_send(void *opaque)
 {
     LANCEState *s = opaque;
-    void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
+    uint32_t dmaptr = s->leptr + s->ledmaregs[3];
     struct lance_init_block *ib;
     unsigned int i, old_txptr, j;
     uint16_t temp;
@@ -375,18 +372,18 @@ static void lance_send(void *opaque)
 
     ib = (void *) iommu_translate(dmaptr);
 
-    old_txptr = txptr;
-    for (i = txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
-	cpu_physical_memory_read(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
+    old_txptr = s->txptr;
+    for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
+	cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
 	if (temp == (LE_T1_POK|LE_T1_OWN)) {
-	    cpu_physical_memory_read(&ib->btx_ring[i].length, (void *) &temp, 2);
+	    cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp, 2);
 	    bswap16s(&temp);
 	    temp = (~temp) + 1;
 #if 0
-	    cpu_physical_memory_read(&ib->tx_buf[i], pkt_buf, temp);
+	    cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp);
 #else
 	    for (j = 0; j < temp; j++) {
-		cpu_physical_memory_read(((void *)&ib->tx_buf[i]) + j, &pkt_buf[j], 1);
+		cpu_physical_memory_read((uint32_t)&ib->tx_buf[i] + j, &pkt_buf[j], 1);
 	    }
 #endif
 
@@ -395,8 +392,8 @@ static void lance_send(void *opaque)
 #endif
 	    qemu_send_packet(s->nd, pkt_buf, temp);
 	    temp = LE_T1_POK;
-	    cpu_physical_memory_write(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
-	    txptr = (txptr + 1) & TX_RING_MOD_MASK;
+	    cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
+	    s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
 	    s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
 	}
     }
@@ -404,24 +401,20 @@ static void lance_send(void *opaque)
 
 static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
 {
-    LEDMAState *s = opaque;
+    LANCEState *s = opaque;
     uint32_t saddr;
 
-    saddr = (addr - s->addr) >> 2;
-    if (saddr < LEDMA_REGS)
-	return s->regs[saddr];
-    else
-	return 0;
+    saddr = (addr & LEDMA_MAXADDR) >> 2;
+    return s->ledmaregs[saddr];
 }
 
 static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-    LEDMAState *s = opaque;
+    LANCEState *s = opaque;
     uint32_t saddr;
 
-    saddr = (addr - s->addr) >> 2;
-    if (saddr < LEDMA_REGS)
-	s->regs[saddr] = val;
+    saddr = (addr & LEDMA_MAXADDR) >> 2;
+    s->ledmaregs[saddr] = val;
 }
 
 static CPUReadMemoryFunc *ledma_mem_read[3] = {
@@ -436,33 +429,61 @@ static CPUWriteMemoryFunc *ledma_mem_write[3] = {
     ledma_mem_writel,
 };
 
+static void lance_save(QEMUFile *f, void *opaque)
+{
+    LANCEState *s = opaque;
+    int i;
+    
+    qemu_put_be32s(f, &s->leptr);
+    qemu_put_be16s(f, &s->addr);
+    for (i = 0; i < LE_MAXREG; i ++)
+	qemu_put_be16s(f, &s->regs[i]);
+    qemu_put_buffer(f, s->phys, 6);
+    qemu_put_be32s(f, &s->irq);
+    for (i = 0; i < LEDMA_REGS; i ++)
+	qemu_put_be32s(f, &s->ledmaregs[i]);
+}
+
+static int lance_load(QEMUFile *f, void *opaque, int version_id)
+{
+    LANCEState *s = opaque;
+    int i;
+    
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_be32s(f, &s->leptr);
+    qemu_get_be16s(f, &s->addr);
+    for (i = 0; i < LE_MAXREG; i ++)
+	qemu_get_be16s(f, &s->regs[i]);
+    qemu_get_buffer(f, s->phys, 6);
+    qemu_get_be32s(f, &s->irq);
+    for (i = 0; i < LEDMA_REGS; i ++)
+	qemu_get_be32s(f, &s->ledmaregs[i]);
+    return 0;
+}
+
 void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
 {
     LANCEState *s;
-    LEDMAState *led;
     int lance_io_memory, ledma_io_memory;
 
     s = qemu_mallocz(sizeof(LANCEState));
     if (!s)
         return;
 
-    s->paddr = leaddr;
     s->nd = nd;
     s->irq = irq;
 
     lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
     cpu_register_physical_memory(leaddr, 8, lance_io_memory);
 
-    led = qemu_mallocz(sizeof(LEDMAState));
-    if (!led)
-        return;
-
-    s->ledma = led;
-    led->addr = ledaddr;
-    ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led);
+    ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
     cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
 
     lance_reset(s);
     qemu_add_read_packet(nd, lance_can_receive, lance_receive, s);
+    register_savevm("lance", leaddr, 1, lance_save, lance_load, s);
+    qemu_register_reset(lance_reset, s);
 }
 
diff --git a/hw/m48t08.c b/hw/m48t08.c
index 46ec665570..0945879532 100644
--- a/hw/m48t08.c
+++ b/hw/m48t08.c
@@ -32,19 +32,14 @@
 #define NVRAM_PRINTF(fmt, args...) do { } while (0)
 #endif
 
-#define NVRAM_MAX_MEM 0xfff0
+#define NVRAM_MAX_MEM 0x1ff0
+#define NVRAM_MAXADDR 0x1fff
 
 struct m48t08_t {
-    /* Hardware parameters */
-    int mem_index;
-    uint32_t mem_base;
-    uint16_t size;
     /* RTC management */
     time_t   time_offset;
     time_t   stop_time;
     /* NVRAM storage */
-    uint8_t  lock;
-    uint16_t addr;
     uint8_t *buffer;
 };
 
@@ -83,14 +78,13 @@ static void set_time (m48t08_t *NVRAM, struct tm *tm)
 }
 
 /* Direct access to NVRAM */
-void m48t08_write (m48t08_t *NVRAM, uint32_t val)
+void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val)
 {
     struct tm tm;
     int tmp;
 
-    if (NVRAM->addr > NVRAM_MAX_MEM && NVRAM->addr < 0x2000)
-	NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val);
-    switch (NVRAM->addr) {
+    addr &= NVRAM_MAXADDR;
+    switch (addr) {
     case 0x1FF8:
         /* control */
 	NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
@@ -167,25 +161,18 @@ void m48t08_write (m48t08_t *NVRAM, uint32_t val)
 	}
         break;
     default:
-        /* Check lock registers state */
-        if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
-            break;
-        if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
-            break;
-        if (NVRAM->addr < NVRAM_MAX_MEM ||
-	    (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
-            NVRAM->buffer[NVRAM->addr] = val & 0xFF;
-	}
+	NVRAM->buffer[addr] = val & 0xFF;
         break;
     }
 }
 
-uint32_t m48t08_read (m48t08_t *NVRAM)
+uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr)
 {
     struct tm tm;
-    uint32_t retval = 0xFF;
+    uint8_t retval = 0xFF;
 
-    switch (NVRAM->addr) {
+    addr &= NVRAM_MAXADDR;
+    switch (addr) {
     case 0x1FF8:
         /* control */
 	goto do_read;
@@ -225,65 +212,36 @@ uint32_t m48t08_read (m48t08_t *NVRAM)
         retval = toBCD(tm.tm_year);
         break;
     default:
-        /* Check lock registers state */
-        if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
-            break;
-        if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
-            break;
-        if (NVRAM->addr < NVRAM_MAX_MEM ||
-	    (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
-	do_read:
-            retval = NVRAM->buffer[NVRAM->addr];
-	}
+    do_read:
+	retval = NVRAM->buffer[addr];
         break;
     }
-    if (NVRAM->addr > NVRAM_MAX_MEM + 1 && NVRAM->addr < 0x2000)
-	NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval);
-
     return retval;
 }
 
-void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr)
-{
-    NVRAM->addr = addr;
-}
-
-void m48t08_toggle_lock (m48t08_t *NVRAM, int lock)
-{
-    NVRAM->lock ^= 1 << lock;
-}
-
 static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
     m48t08_t *NVRAM = opaque;
     
-    addr -= NVRAM->mem_base;
-    if (addr < NVRAM_MAX_MEM)
-        NVRAM->buffer[addr] = value;
+    m48t08_write(NVRAM, addr, value);
 }
 
 static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
     m48t08_t *NVRAM = opaque;
     
-    addr -= NVRAM->mem_base;
-    if (addr < NVRAM_MAX_MEM) {
-        NVRAM->buffer[addr] = value >> 8;
-        NVRAM->buffer[addr + 1] = value;
-    }
+    m48t08_write(NVRAM, addr, value);
+    m48t08_write(NVRAM, addr + 1, value >> 8);
 }
 
 static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
     m48t08_t *NVRAM = opaque;
     
-    addr -= NVRAM->mem_base;
-    if (addr < NVRAM_MAX_MEM) {
-        NVRAM->buffer[addr] = value >> 24;
-        NVRAM->buffer[addr + 1] = value >> 16;
-        NVRAM->buffer[addr + 2] = value >> 8;
-        NVRAM->buffer[addr + 3] = value;
-    }
+    m48t08_write(NVRAM, addr, value);
+    m48t08_write(NVRAM, addr + 1, value >> 8);
+    m48t08_write(NVRAM, addr + 2, value >> 16);
+    m48t08_write(NVRAM, addr + 3, value >> 24);
 }
 
 static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
@@ -291,10 +249,7 @@ static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
     m48t08_t *NVRAM = opaque;
     uint32_t retval = 0;
     
-    addr -= NVRAM->mem_base;
-    if (addr < NVRAM_MAX_MEM)
-        retval = NVRAM->buffer[addr];
-
+    retval = m48t08_read(NVRAM, addr);
     return retval;
 }
 
@@ -303,12 +258,8 @@ static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
     m48t08_t *NVRAM = opaque;
     uint32_t retval = 0;
     
-    addr -= NVRAM->mem_base;
-    if (addr < NVRAM_MAX_MEM) {
-        retval = NVRAM->buffer[addr] << 8;
-        retval |= NVRAM->buffer[addr + 1];
-    }
-
+    retval = m48t08_read(NVRAM, addr) << 8;
+    retval |= m48t08_read(NVRAM, addr + 1);
     return retval;
 }
 
@@ -317,14 +268,10 @@ static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
     m48t08_t *NVRAM = opaque;
     uint32_t retval = 0;
     
-    addr -= NVRAM->mem_base;
-    if (addr < NVRAM_MAX_MEM) {
-        retval = NVRAM->buffer[addr] << 24;
-        retval |= NVRAM->buffer[addr + 1] << 16;
-        retval |= NVRAM->buffer[addr + 2] << 8;
-        retval |= NVRAM->buffer[addr + 3];
-    }
-
+    retval = m48t08_read(NVRAM, addr) << 24;
+    retval |= m48t08_read(NVRAM, addr + 1) << 16;
+    retval |= m48t08_read(NVRAM, addr + 2) << 8;
+    retval |= m48t08_read(NVRAM, addr + 3);
     return retval;
 }
 
@@ -340,12 +287,42 @@ static CPUReadMemoryFunc *nvram_read[] = {
     &nvram_readl,
 };
 
+static void nvram_save(QEMUFile *f, void *opaque)
+{
+    m48t08_t *s = opaque;
+    
+    qemu_put_be32s(f, (uint32_t *)&s->time_offset);
+    qemu_put_be32s(f, (uint32_t *)&s->stop_time);
+    qemu_put_buffer(f, s->buffer, 0x2000);
+}
+
+static int nvram_load(QEMUFile *f, void *opaque, int version_id)
+{
+    m48t08_t *s = opaque;
+    
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_be32s(f, (uint32_t *)&s->time_offset);
+    qemu_get_be32s(f, (uint32_t *)&s->stop_time);
+    qemu_get_buffer(f, s->buffer, 0x2000);
+    return 0;
+}
+
+static void m48t08_reset(void *opaque)
+{
+    m48t08_t *s = opaque;
+
+    s->time_offset = 0;
+    s->stop_time = 0;
+}
+
+
 /* Initialisation routine */
-m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr)
+m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size)
 {
     m48t08_t *s;
-    int i;
-    unsigned char tmp = 0;
+    int mem_index;
 
     s = qemu_mallocz(sizeof(m48t08_t));
     if (!s)
@@ -355,25 +332,13 @@ m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr)
         qemu_free(s);
         return NULL;
     }
-    s->size = size;
-    s->mem_base = mem_base;
-    s->addr = 0;
     if (mem_base != 0) {
-        s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
-        cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
+        mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
+        cpu_register_physical_memory(mem_base, 0x2000, mem_index);
     }
-    s->lock = 0;
 
-    i = 0x1fd8;
-    s->buffer[i++] = 0x01;
-    s->buffer[i++] = 0x80; /* Sun4m OBP */
-    memcpy(&s->buffer[i], macaddr, 6);
-
-    /* Calculate checksum */
-    for (i = 0x1fd8; i < 0x1fe7; i++) {
-	tmp ^= s->buffer[i];
-    }
-    s->buffer[0x1fe7] = tmp;
+    register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s);
+    qemu_register_reset(m48t08_reset, s);
     return s;
 }
 
diff --git a/hw/m48t08.h b/hw/m48t08.h
index 9b44bc0d16..985116a099 100644
--- a/hw/m48t08.h
+++ b/hw/m48t08.h
@@ -3,10 +3,8 @@
 
 typedef struct m48t08_t m48t08_t;
 
-void m48t08_write (m48t08_t *NVRAM, uint32_t val);
-uint32_t m48t08_read (m48t08_t *NVRAM);
-void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr);
-void m48t08_toggle_lock (m48t08_t *NVRAM, int lock);
-m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr);
+void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val);
+uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr);
+m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size);
 
 #endif /* !defined (__M48T08_H__) */
diff --git a/hw/magic-load.c b/hw/magic-load.c
index 06a5f743af..713343a758 100644
--- a/hw/magic-load.c
+++ b/hw/magic-load.c
@@ -1,5 +1,54 @@
 #include "vl.h"
 #include "disas.h"
+#include "exec-all.h"
+
+struct exec
+{
+  uint32_t a_info;   /* Use macros N_MAGIC, etc for access */
+  uint32_t a_text;   /* length of text, in bytes */
+  uint32_t a_data;   /* length of data, in bytes */
+  uint32_t a_bss;    /* length of uninitialized data area, in bytes */
+  uint32_t a_syms;   /* length of symbol table data in file, in bytes */
+  uint32_t a_entry;  /* start address */
+  uint32_t a_trsize; /* length of relocation info for text, in bytes */
+  uint32_t a_drsize; /* length of relocation info for data, in bytes */
+};
+
+#ifdef BSWAP_NEEDED
+static void bswap_ahdr(struct exec *e)
+{
+    bswap32s(&e->a_info);
+    bswap32s(&e->a_text);
+    bswap32s(&e->a_data);
+    bswap32s(&e->a_bss);
+    bswap32s(&e->a_syms);
+    bswap32s(&e->a_entry);
+    bswap32s(&e->a_trsize);
+    bswap32s(&e->a_drsize);
+}
+#else
+#define bswap_ahdr(x) do { } while (0)
+#endif
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+#define _N_HDROFF(x) (1024 - sizeof (struct exec))
+#define N_TXTOFF(x)							\
+    (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) :	\
+     (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
+#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0)
+#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
+#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1))
+
+#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
+
+#define N_DATADDR(x) \
+    (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
+     : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
+
 
 #define ELF_CLASS   ELFCLASS32
 #define ELF_DATA    ELFDATA2MSB
@@ -103,27 +152,27 @@ static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint3
     return NULL;
 }
 
-static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
+static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
 {
     int retval;
 
     retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
     if (retval < 0)
-	return -1;
+	return NULL;
 
     retval = read(fd, shdr, sizeof(*shdr));
     if (retval < 0)
-	return -1;
+	return NULL;
     bswap_shdr(shdr);
     if (shdr->sh_type == SHT_STRTAB)
 	return qemu_malloc(shdr->sh_size);;
-    return 0;
+    return NULL;
 }
 
-static int read_program(int fd, struct elf_phdr *phdr, void *dst)
+static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry)
 {
     int retval;
-    retval = lseek(fd, 0x4000, SEEK_SET);
+    retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
     if (retval < 0)
 	return -1;
     return read(fd, dst, phdr->p_filesz);
@@ -178,6 +227,7 @@ static void load_symbols(struct elfhdr *ehdr, int fd)
 {
     struct elf_shdr symtab, strtab;
     struct elf_sym *syms;
+    struct syminfo *s;
     int nsyms, i;
     char *str;
 
@@ -196,20 +246,19 @@ static void load_symbols(struct elfhdr *ehdr, int fd)
 	goto error_freesyms;
 
     /* Commit */
-    if (disas_symtab)
-	qemu_free(disas_symtab); /* XXX Merge with old symbols? */
-    if (disas_strtab)
-	qemu_free(disas_strtab);
-    disas_symtab = syms;
-    disas_num_syms = nsyms;
-    disas_strtab = str;
+    s = qemu_mallocz(sizeof(*s));
+    s->disas_symtab = syms;
+    s->disas_num_syms = nsyms;
+    s->disas_strtab = str;
+    s->next = syminfos;
+    syminfos = s;
     return;
  error_freesyms:
     qemu_free(syms);
     return;
 }
 
-int load_elf(const char * filename, uint8_t *addr)
+int load_elf(const char *filename, uint8_t *addr)
 {
     struct elfhdr ehdr;
     struct elf_phdr phdr;
@@ -227,12 +276,13 @@ int load_elf(const char * filename, uint8_t *addr)
 
     if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
 	|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F'
-	|| ehdr.e_machine != EM_SPARC)
+	|| (ehdr.e_machine != EM_SPARC
+	    && ehdr.e_machine != EM_SPARC32PLUS))
 	goto error;
 
     if (find_phdr(&ehdr, fd, &phdr, PT_LOAD))
 	goto error;
-    retval = read_program(fd, &phdr, addr);
+    retval = read_program(fd, &phdr, addr, ehdr.e_entry);
     if (retval < 0)
 	goto error;
 
@@ -245,17 +295,45 @@ int load_elf(const char * filename, uint8_t *addr)
     return -1;
 }
 
-int load_kernel(const char *filename, uint8_t *addr)
+int load_aout(const char *filename, uint8_t *addr)
 {
-    int fd, size;
+    int fd, size, ret;
+    struct exec e;
+    uint32_t magic;
 
     fd = open(filename, O_RDONLY | O_BINARY);
     if (fd < 0)
         return -1;
-    /* load 32 bit code */
-    size = read(fd, addr, 16 * 1024 * 1024);
+
+    size = read(fd, &e, sizeof(e));
     if (size < 0)
         goto fail;
+
+    bswap_ahdr(&e);
+
+    magic = N_MAGIC(e);
+    switch (magic) {
+    case ZMAGIC:
+    case QMAGIC:
+    case OMAGIC:
+	lseek(fd, N_TXTOFF(e), SEEK_SET);
+	size = read(fd, addr, e.a_text + e.a_data);
+	if (size < 0)
+	    goto fail;
+	break;
+    case NMAGIC:
+	lseek(fd, N_TXTOFF(e), SEEK_SET);
+	size = read(fd, addr, e.a_text);
+	if (size < 0)
+	    goto fail;
+	ret = read(fd, addr + N_DATADDR(e), e.a_data);
+	if (ret < 0)
+	    goto fail;
+	size += ret;
+	break;
+    default:
+	goto fail;
+    }
     close(fd);
     return size;
  fail:
@@ -263,64 +341,3 @@ int load_kernel(const char *filename, uint8_t *addr)
     return -1;
 }
 
-typedef struct MAGICState {
-    uint32_t addr;
-    uint32_t saved_addr;
-    int magic_state;
-    char saved_kfn[1024];
-} MAGICState;
-
-static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr)
-{
-    int ret;
-    MAGICState *s = opaque;
-
-    if (s->magic_state == 0) {
-        ret = load_elf(s->saved_kfn, (uint8_t *)s->saved_addr);
-	if (ret < 0)
-	    ret = load_kernel(s->saved_kfn, (uint8_t *)s->saved_addr);
-        if (ret < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
-                    s->saved_kfn);
-        }
-	s->magic_state = 1; /* No more magic */
-	tb_flush();
-	return bswap32(ret);
-    }
-    return 0;
-}
-
-static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-}
-
-
-static CPUReadMemoryFunc *magic_mem_read[3] = {
-    magic_mem_readl,
-    magic_mem_readl,
-    magic_mem_readl,
-};
-
-static CPUWriteMemoryFunc *magic_mem_write[3] = {
-    magic_mem_writel,
-    magic_mem_writel,
-    magic_mem_writel,
-};
-
-void magic_init(const char *kfn, int kloadaddr, uint32_t addr)
-{
-    int magic_io_memory;
-    MAGICState *s;
-
-    s = qemu_mallocz(sizeof(MAGICState));
-    if (!s)
-        return;
-
-    strcpy(s->saved_kfn, kfn);
-    s->saved_addr = kloadaddr;
-    s->magic_state = 0;
-    s->addr = addr;
-    magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, s);
-    cpu_register_physical_memory(addr, 4, magic_io_memory);
-}
-
diff --git a/hw/sched.c b/hw/sched.c
deleted file mode 100644
index 2ab966de4c..0000000000
--- a/hw/sched.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * QEMU interrupt controller emulation
- * 
- * Copyright (c) 2003-2004 Fabrice Bellard
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "vl.h"
-//#define DEBUG_IRQ_COUNT
-
-/* These registers are used for sending/receiving irqs from/to
- * different cpu's.
- */
-struct sun4m_intreg_percpu {
-	unsigned int tbt;        /* Intrs pending for this cpu, by PIL. */
-	/* These next two registers are WRITE-ONLY and are only
-	 * "on bit" sensitive, "off bits" written have NO affect.
-	 */
-	unsigned int clear;  /* Clear this cpus irqs here. */
-	unsigned int set;    /* Set this cpus irqs here. */
-};
-/*
- * djhr
- * Actually the clear and set fields in this struct are misleading..
- * according to the SLAVIO manual (and the same applies for the SEC)
- * the clear field clears bits in the mask which will ENABLE that IRQ
- * the set field sets bits in the mask to DISABLE the IRQ.
- *
- * Also the undirected_xx address in the SLAVIO is defined as
- * RESERVED and write only..
- *
- * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
- *             sun4m machines, for MP the layout makes more sense.
- */
-struct sun4m_intreg_master {
-	unsigned int tbt;        /* IRQ's that are pending, see sun4m masks. */
-	unsigned int irqs;       /* Master IRQ bits. */
-
-	/* Again, like the above, two these registers are WRITE-ONLY. */
-	unsigned int clear;      /* Clear master IRQ's by setting bits here. */
-	unsigned int set;        /* Set master IRQ's by setting bits here. */
-
-	/* This register is both READ and WRITE. */
-	unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
-};
-
-#define SUN4M_INT_ENABLE        0x80000000
-#define SUN4M_INT_E14           0x00000080
-#define SUN4M_INT_E10           0x00080000
-
-#define SUN4M_HARD_INT(x)       (0x000000001 << (x))
-#define SUN4M_SOFT_INT(x)       (0x000010000 << (x))
-
-#define SUN4M_INT_MASKALL       0x80000000        /* mask all interrupts */
-#define SUN4M_INT_MODULE_ERR    0x40000000        /* module error */
-#define SUN4M_INT_M2S_WRITE     0x20000000        /* write buffer error */
-#define SUN4M_INT_ECC           0x10000000        /* ecc memory error */
-#define SUN4M_INT_FLOPPY        0x00400000        /* floppy disk */
-#define SUN4M_INT_MODULE        0x00200000        /* module interrupt */
-#define SUN4M_INT_VIDEO         0x00100000        /* onboard video */
-#define SUN4M_INT_REALTIME      0x00080000        /* system timer */
-#define SUN4M_INT_SCSI          0x00040000        /* onboard scsi */
-#define SUN4M_INT_AUDIO         0x00020000        /* audio/isdn */
-#define SUN4M_INT_ETHERNET      0x00010000        /* onboard ethernet */
-#define SUN4M_INT_SERIAL        0x00008000        /* serial ports */
-#define SUN4M_INT_SBUSBITS      0x00003F80        /* sbus int bits */
-
-#define SUN4M_INT_SBUS(x)       (1 << (x+7))
-#define SUN4M_INT_VME(x)        (1 << (x))
-
-typedef struct SCHEDState {
-    uint32_t addr, addrg;
-    uint32_t intreg_pending;
-    uint32_t intreg_enabled;
-    uint32_t intregm_pending;
-    uint32_t intregm_enabled;
-} SCHEDState;
-
-static SCHEDState *ps;
-
-#ifdef DEBUG_IRQ_COUNT
-static uint64_t irq_count[32];
-#endif
-
-static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr)
-{
-    SCHEDState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr - s->addr) >> 2;
-    switch (saddr) {
-    case 0:
-	return s->intreg_pending;
-	break;
-    default:
-	break;
-    }
-    return 0;
-}
-
-static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    SCHEDState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr - s->addr) >> 2;
-    switch (saddr) {
-    case 0:
-	s->intreg_pending = val;
-	break;
-    case 1: // clear
-	s->intreg_enabled &= ~val;
-	break;
-    case 2: // set
-	s->intreg_enabled |= val;
-	break;
-    default:
-	break;
-    }
-}
-
-static CPUReadMemoryFunc *intreg_mem_read[3] = {
-    intreg_mem_readl,
-    intreg_mem_readl,
-    intreg_mem_readl,
-};
-
-static CPUWriteMemoryFunc *intreg_mem_write[3] = {
-    intreg_mem_writel,
-    intreg_mem_writel,
-    intreg_mem_writel,
-};
-
-static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr)
-{
-    SCHEDState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr - s->addrg) >> 2;
-    switch (saddr) {
-    case 0:
-	return s->intregm_pending;
-	break;
-    case 1:
-	return s->intregm_enabled;
-	break;
-    default:
-	break;
-    }
-    return 0;
-}
-
-static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    SCHEDState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr - s->addrg) >> 2;
-    switch (saddr) {
-    case 0:
-	s->intregm_pending = val;
-	break;
-    case 1:
-	s->intregm_enabled = val;
-	break;
-    case 2: // clear
-	s->intregm_enabled &= ~val;
-	break;
-    case 3: // set
-	s->intregm_enabled |= val;
-	break;
-    default:
-	break;
-    }
-}
-
-static CPUReadMemoryFunc *intregm_mem_read[3] = {
-    intregm_mem_readl,
-    intregm_mem_readl,
-    intregm_mem_readl,
-};
-
-static CPUWriteMemoryFunc *intregm_mem_write[3] = {
-    intregm_mem_writel,
-    intregm_mem_writel,
-    intregm_mem_writel,
-};
-
-void pic_info(void)
-{
-    term_printf("per-cpu: pending 0x%08x, enabled 0x%08x\n", ps->intreg_pending, ps->intreg_enabled);
-    term_printf("master: pending 0x%08x, enabled 0x%08x\n", ps->intregm_pending, ps->intregm_enabled);
-}
-
-void irq_info(void)
-{
-#ifndef DEBUG_IRQ_COUNT
-    term_printf("irq statistic code not compiled.\n");
-#else
-    int i;
-    int64_t count;
-
-    term_printf("IRQ statistics:\n");
-    for (i = 0; i < 32; i++) {
-        count = irq_count[i];
-        if (count > 0)
-            term_printf("%2d: %lld\n", i, count);
-    }
-#endif
-}
-
-static const unsigned int intr_to_mask[16] = {
-	0,	0,	0,	0,	0,	0, SUN4M_INT_ETHERNET,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-};
-
-void pic_set_irq(int irq, int level)
-{
-    if (irq < 16) {
-	unsigned int mask = intr_to_mask[irq];
-	ps->intreg_pending |= 1 << irq;
-	if (ps->intregm_enabled & mask) {
-	    cpu_single_env->interrupt_index = irq;
-	    cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
-	}
-    }
-#ifdef DEBUG_IRQ_COUNT
-    if (level == 1)
-	irq_count[irq]++;
-#endif
-}
-
-void sched_init(uint32_t addr, uint32_t addrg)
-{
-    int intreg_io_memory, intregm_io_memory;
-    SCHEDState *s;
-
-    s = qemu_mallocz(sizeof(SCHEDState));
-    if (!s)
-        return;
-    s->addr = addr;
-    s->addrg = addrg;
-
-    intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s);
-    cpu_register_physical_memory(addr, 3, intreg_io_memory);
-
-    intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s);
-    cpu_register_physical_memory(addrg, 5, intregm_io_memory);
-
-    ps = s;
-}
-
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
new file mode 100644
index 0000000000..745467214b
--- /dev/null
+++ b/hw/slavio_intctl.c
@@ -0,0 +1,299 @@
+/*
+ * QEMU Sparc SLAVIO interrupt controller emulation
+ * 
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+//#define DEBUG_IRQ_COUNT
+
+/*
+ * Registers of interrupt controller in sun4m.
+ *
+ * This is the interrupt controller part of chip STP2001 (Slave I/O), also
+ * produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * There is a system master controller and one for each cpu.
+ * 
+ */
+
+#define MAX_CPUS 16
+
+typedef struct SLAVIO_INTCTLState {
+    uint32_t intreg_pending[MAX_CPUS];
+    uint32_t intregm_pending;
+    uint32_t intregm_disabled;
+    uint32_t target_cpu;
+#ifdef DEBUG_IRQ_COUNT
+    uint64_t irq_count[32];
+#endif
+} SLAVIO_INTCTLState;
+
+#define INTCTL_MAXADDR 0xf
+#define INTCTLM_MAXADDR 0xf
+
+// per-cpu interrupt controller
+static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t saddr;
+    int cpu;
+
+    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
+    saddr = (addr & INTCTL_MAXADDR) >> 2;
+    switch (saddr) {
+    case 0:
+	return s->intreg_pending[cpu];
+    default:
+	break;
+    }
+    return 0;
+}
+
+static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t saddr;
+    int cpu;
+
+    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
+    saddr = (addr & INTCTL_MAXADDR) >> 2;
+    switch (saddr) {
+    case 1: // clear pending softints
+	if (val & 0x4000)
+	    val |= 80000000;
+	val &= 0xfffe0000;
+	s->intreg_pending[cpu] &= ~val;
+	break;
+    case 2: // set softint
+	val &= 0xfffe0000;
+	s->intreg_pending[cpu] |= val;
+	break;
+    default:
+	break;
+    }
+}
+
+static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
+    slavio_intctl_mem_readl,
+    slavio_intctl_mem_readl,
+    slavio_intctl_mem_readl,
+};
+
+static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
+    slavio_intctl_mem_writel,
+    slavio_intctl_mem_writel,
+    slavio_intctl_mem_writel,
+};
+
+// master system interrupt controller
+static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & INTCTLM_MAXADDR) >> 2;
+    switch (saddr) {
+    case 0:
+	return s->intregm_pending;
+    case 1:
+	return s->intregm_disabled;
+    case 4:
+	return s->target_cpu;
+    default:
+	break;
+    }
+    return 0;
+}
+
+static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & INTCTLM_MAXADDR) >> 2;
+    switch (saddr) {
+    case 2: // clear (enable)
+	// Force unused bits
+	val |= 0x7fb2007f;
+	s->intregm_disabled &= ~val;
+	break;
+    case 3: // set (disable, clear pending)
+	// Force unused bits
+	val &= ~0x7fb2007f;
+	s->intregm_disabled |= val;
+	s->intregm_pending &= ~val;
+	break;
+    case 4:
+	s->target_cpu = val & (MAX_CPUS - 1);
+	break;
+    default:
+	break;
+    }
+}
+
+static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
+    slavio_intctlm_mem_readl,
+    slavio_intctlm_mem_readl,
+    slavio_intctlm_mem_readl,
+};
+
+static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
+    slavio_intctlm_mem_writel,
+    slavio_intctlm_mem_writel,
+    slavio_intctlm_mem_writel,
+};
+
+void slavio_pic_info(void *opaque)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+	term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
+    }
+    term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
+}
+
+void slavio_irq_info(void *opaque)
+{
+#ifndef DEBUG_IRQ_COUNT
+    term_printf("irq statistic code not compiled.\n");
+#else
+    SLAVIO_INTCTLState *s = opaque;
+    int i;
+    int64_t count;
+
+    term_printf("IRQ statistics:\n");
+    for (i = 0; i < 32; i++) {
+        count = s->irq_count[i];
+        if (count > 0)
+            term_printf("%2d: %lld\n", i, count);
+    }
+#endif
+}
+
+static const uint32_t intbit_to_level[32] = {
+    2, 3, 5, 7, 9, 11, 0, 14,	3, 5, 7, 9, 11, 13, 12, 12,
+    6, 0, 4, 10, 8, 0, 11, 0,	0, 0, 0, 0, 15, 0, 0, 0,
+};
+
+/*
+ * "irq" here is the bit number in the system interrupt register to
+ * separate serial and keyboard interrupts sharing a level.
+ */
+void slavio_pic_set_irq(void *opaque, int irq, int level)
+{
+    SLAVIO_INTCTLState *s = opaque;
+
+    if (irq < 32) {
+	uint32_t mask = 1 << irq;
+	uint32_t pil = intbit_to_level[irq];
+	if (pil > 0) {
+	    if (level) {
+		s->intregm_pending |= mask;
+		s->intreg_pending[s->target_cpu] |= 1 << pil;
+	    }
+	    else {
+		s->intregm_pending &= ~mask;
+		s->intreg_pending[s->target_cpu] &= ~(1 << pil);
+	    }
+	    if (level &&
+		!(s->intregm_disabled & mask) &&
+		!(s->intregm_disabled & 0x80000000) &&
+		(pil == 15 || (pil > cpu_single_env->psrpil && cpu_single_env->psret == 1))) {
+#ifdef DEBUG_IRQ_COUNT
+		if (level == 1)
+		    s->irq_count[pil]++;
+#endif
+		cpu_single_env->interrupt_index = TT_EXTINT | pil;
+		cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+	    }
+	}
+    }
+}
+
+static void slavio_intctl_save(QEMUFile *f, void *opaque)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    int i;
+    
+    for (i = 0; i < MAX_CPUS; i++) {
+	qemu_put_be32s(f, &s->intreg_pending[i]);
+    }
+    qemu_put_be32s(f, &s->intregm_pending);
+    qemu_put_be32s(f, &s->intregm_disabled);
+    qemu_put_be32s(f, &s->target_cpu);
+}
+
+static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+	qemu_get_be32s(f, &s->intreg_pending[i]);
+    }
+    qemu_get_be32s(f, &s->intregm_pending);
+    qemu_get_be32s(f, &s->intregm_disabled);
+    qemu_get_be32s(f, &s->target_cpu);
+    return 0;
+}
+
+static void slavio_intctl_reset(void *opaque)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+	s->intreg_pending[i] = 0;
+    }
+    s->intregm_disabled = 0xffffffff;
+    s->intregm_pending = 0;
+    s->target_cpu = 0;
+}
+
+void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
+{
+    int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
+    SLAVIO_INTCTLState *s;
+
+    s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
+    if (!s)
+        return NULL;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+	slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
+	cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
+    }
+
+    slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
+    cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
+
+    register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
+    qemu_register_reset(slavio_intctl_reset, s);
+    slavio_intctl_reset(s);
+    return s;
+}
+
diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c
new file mode 100644
index 0000000000..348f328f5a
--- /dev/null
+++ b/hw/slavio_serial.c
@@ -0,0 +1,364 @@
+/*
+ * QEMU Sparc SLAVIO serial port emulation
+ * 
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+//#define DEBUG_SERIAL
+
+/* debug keyboard */
+//#define DEBUG_KBD
+
+/* debug keyboard : only mouse */
+//#define DEBUG_MOUSE
+
+/*
+ * This is the serial port, mouse and keyboard part of chip STP2001
+ * (Slave I/O), also produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ * 
+ * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
+ * mouse and keyboard ports don't implement all functions and they are
+ * only asynchronous. There is no DMA.
+ *
+ */
+
+typedef struct ChannelState {
+    int irq;
+    int reg;
+    int rxint, txint;
+    uint8_t rx, tx, wregs[16], rregs[16];
+    CharDriverState *chr;
+} ChannelState;
+
+struct SerialState {
+    struct ChannelState chn[2];
+};
+
+#define SERIAL_MAXADDR 7
+
+static void slavio_serial_update_irq(ChannelState *s)
+{
+    if ((s->wregs[1] & 1) && // interrupts enabled
+	(((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending
+	 ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) &&
+	  s->rxint == 1) || // rx ints enabled, pending
+	 ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p
+        pic_set_irq(s->irq, 1);
+    } else {
+        pic_set_irq(s->irq, 0);
+    }
+}
+
+static void slavio_serial_reset_chn(ChannelState *s)
+{
+    int i;
+
+    s->reg = 0;
+    for (i = 0; i < SERIAL_MAXADDR; i++) {
+	s->rregs[i] = 0;
+	s->wregs[i] = 0;
+    }
+    s->wregs[4] = 4;
+    s->wregs[9] = 0xc0;
+    s->wregs[11] = 8;
+    s->wregs[14] = 0x30;
+    s->wregs[15] = 0xf8;
+    s->rregs[0] = 0x44;
+    s->rregs[1] = 6;
+
+    s->rx = s->tx = 0;
+    s->rxint = s->txint = 0;
+}
+
+static void slavio_serial_reset(void *opaque)
+{
+    SerialState *s = opaque;
+    slavio_serial_reset_chn(&s->chn[0]);
+    slavio_serial_reset_chn(&s->chn[1]);
+}
+
+static void slavio_serial_mem_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    SerialState *ser = opaque;
+    ChannelState *s;
+    uint32_t saddr;
+    int newreg, channel;
+
+    val &= 0xff;
+    saddr = (addr & 3) >> 1;
+    channel = (addr & SERIAL_MAXADDR) >> 2;
+    s = &ser->chn[channel];
+    switch (saddr) {
+    case 0:
+	newreg = 0;
+	switch (s->reg) {
+	case 0:
+	    newreg = val & 7;
+	    val &= 0x38;
+	    switch (val) {
+	    case 8:
+		s->reg |= 0x8;
+		break;
+	    case 0x20:
+		s->rxint = 0;
+		break;
+	    case 0x28:
+		s->txint = 0;
+		break;
+	    default:
+		break;
+	    }
+	    break;
+	case 1 ... 8:
+	case 10 ... 15:
+	    s->wregs[s->reg] = val;
+	    break;
+	case 9:
+	    switch (val & 0xc0) {
+	    case 0:
+	    default:
+		break;
+	    case 0x40:
+		slavio_serial_reset_chn(&ser->chn[1]);
+		return;
+	    case 0x80:
+		slavio_serial_reset_chn(&ser->chn[0]);
+		return;
+	    case 0xc0:
+		slavio_serial_reset(ser);
+		return;
+	    }
+	    break;
+	default:
+	    break;
+	}
+	if (s->reg == 0)
+	    s->reg = newreg;
+	else
+	    s->reg = 0;
+	break;
+    case 1:
+	if (s->wregs[5] & 8) { // tx enabled
+	    s->tx = val;
+	    if (s->chr)
+		qemu_chr_write(s->chr, &s->tx, 1);
+	    s->txint = 1;
+	}
+	break;
+    default:
+	break;
+    }
+}
+
+static uint32_t slavio_serial_mem_readb(void *opaque, uint32_t addr)
+{
+    SerialState *ser = opaque;
+    ChannelState *s;
+    uint32_t saddr;
+    uint32_t ret;
+    int channel;
+
+    saddr = (addr & 3) >> 1;
+    channel = (addr & SERIAL_MAXADDR) >> 2;
+    s = &ser->chn[channel];
+    switch (saddr) {
+    case 0:
+	ret = s->rregs[s->reg];
+	s->reg = 0;
+	return ret;
+    case 1:
+	s->rregs[0] &= ~1;
+	return s->rx;
+    default:
+	break;
+    }
+    return 0;
+}
+
+static int serial_can_receive(void *opaque)
+{
+    ChannelState *s = opaque;
+    if (((s->wregs[3] & 1) == 0) // Rx not enabled
+	|| ((s->rregs[0] & 1) == 1)) // char already available
+	return 0;
+    else
+	return 1;
+}
+
+static void serial_receive_byte(ChannelState *s, int ch)
+{
+    s->rregs[0] |= 1;
+    s->rx = ch;
+    s->rxint = 1;
+    slavio_serial_update_irq(s);
+}
+
+static void serial_receive_break(ChannelState *s)
+{
+    s->rregs[0] |= 0x80;
+    slavio_serial_update_irq(s);
+}
+
+static void serial_receive1(void *opaque, const uint8_t *buf, int size)
+{
+    ChannelState *s = opaque;
+    serial_receive_byte(s, buf[0]);
+}
+
+static void serial_event(void *opaque, int event)
+{
+    ChannelState *s = opaque;
+    if (event == CHR_EVENT_BREAK)
+        serial_receive_break(s);
+}
+
+static CPUReadMemoryFunc *slavio_serial_mem_read[3] = {
+    slavio_serial_mem_readb,
+    slavio_serial_mem_readb,
+    slavio_serial_mem_readb,
+};
+
+static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = {
+    slavio_serial_mem_writeb,
+    slavio_serial_mem_writeb,
+    slavio_serial_mem_writeb,
+};
+
+static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
+{
+    qemu_put_be32s(f, &s->irq);
+    qemu_put_be32s(f, &s->reg);
+    qemu_put_be32s(f, &s->rxint);
+    qemu_put_be32s(f, &s->txint);
+    qemu_put_8s(f, &s->rx);
+    qemu_put_8s(f, &s->tx);
+    qemu_put_buffer(f, s->wregs, 16);
+    qemu_put_buffer(f, s->rregs, 16);
+}
+
+static void slavio_serial_save(QEMUFile *f, void *opaque)
+{
+    SerialState *s = opaque;
+
+    slavio_serial_save_chn(f, &s->chn[0]);
+    slavio_serial_save_chn(f, &s->chn[1]);
+}
+
+static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
+{
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_be32s(f, &s->irq);
+    qemu_get_be32s(f, &s->reg);
+    qemu_get_be32s(f, &s->rxint);
+    qemu_get_be32s(f, &s->txint);
+    qemu_get_8s(f, &s->rx);
+    qemu_get_8s(f, &s->tx);
+    qemu_get_buffer(f, s->wregs, 16);
+    qemu_get_buffer(f, s->rregs, 16);
+    return 0;
+}
+
+static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id)
+{
+    SerialState *s = opaque;
+    int ret;
+
+    ret = slavio_serial_load_chn(f, &s->chn[0], version_id);
+    if (ret != 0)
+	return ret;
+    ret = slavio_serial_load_chn(f, &s->chn[1], version_id);
+    return ret;
+
+}
+
+SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2)
+{
+    int slavio_serial_io_memory;
+    SerialState *s;
+
+    s = qemu_mallocz(sizeof(SerialState));
+    if (!s)
+        return NULL;
+    s->chn[0].irq = irq;
+    s->chn[1].irq = irq;
+    s->chn[0].chr = chr1;
+    s->chn[1].chr = chr2;
+
+    slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
+    cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
+
+    if (chr1) {
+	qemu_chr_add_read_handler(chr1, serial_can_receive, serial_receive1, &s->chn[0]);
+	qemu_chr_add_event_handler(chr1, serial_event);
+    }
+    if (chr2) {
+	qemu_chr_add_read_handler(chr2, serial_can_receive, serial_receive1, &s->chn[1]);
+	qemu_chr_add_event_handler(chr2, serial_event);
+    }
+    register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s);
+    qemu_register_reset(slavio_serial_reset, s);
+    slavio_serial_reset(s);
+    return s;
+}
+
+static void sunkbd_event(void *opaque, int ch)
+{
+    ChannelState *s = opaque;
+    // XXX: PC -> Sun Type 5 translation?
+    serial_receive_byte(s, ch);
+}
+
+static void sunmouse_event(void *opaque, 
+                               int dx, int dy, int dz, int buttons_state)
+{
+    ChannelState *s = opaque;
+    int ch;
+
+    // XXX
+    ch = 0x42;
+    serial_receive_byte(s, ch);
+}
+
+void slavio_serial_ms_kbd_init(int base, int irq)
+{
+    int slavio_serial_io_memory;
+    SerialState *s;
+
+    s = qemu_mallocz(sizeof(SerialState));
+    if (!s)
+        return;
+    s->chn[0].irq = irq;
+    s->chn[1].irq = irq;
+    s->chn[0].chr = NULL;
+    s->chn[1].chr = NULL;
+
+    slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
+    cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
+
+    qemu_add_kbd_event_handler(sunkbd_event, &s->chn[0]);
+    qemu_add_mouse_event_handler(sunmouse_event, &s->chn[1]);
+    qemu_register_reset(slavio_serial_reset, s);
+    slavio_serial_reset(s);
+}
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
new file mode 100644
index 0000000000..43f59d2750
--- /dev/null
+++ b/hw/slavio_timer.c
@@ -0,0 +1,289 @@
+/*
+ * QEMU Sparc SLAVIO timer controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+//#define DEBUG_TIMER
+
+/*
+ * Registers of hardware timer in sun4m.
+ *
+ * This is the timer/counter part of chip STP2001 (Slave I/O), also
+ * produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ * 
+ * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
+ * are zero. Bit 31 is 1 when count has been reached.
+ *
+ */
+
+typedef struct SLAVIO_TIMERState {
+    uint32_t limit, count, counthigh;
+    int64_t count_load_time;
+    int64_t expire_time;
+    int64_t stop_time, tick_offset;
+    QEMUTimer *irq_timer;
+    int irq;
+    int reached, stopped;
+    int mode; // 0 = processor, 1 = user, 2 = system
+} SLAVIO_TIMERState;
+
+#define TIMER_MAXADDR 0x1f
+#define CNT_FREQ 2000000
+#define MAX_CPUS 16
+
+// Update count, set irq, update expire_time
+static void slavio_timer_get_out(SLAVIO_TIMERState *s)
+{
+    int out;
+    int64_t diff, ticks, count;
+    uint32_t limit;
+
+    // There are three clock tick units: CPU ticks, register units
+    // (nanoseconds), and counter ticks (500 ns).
+    if (s->mode == 1 && s->stopped)
+	ticks = s->stop_time;
+    else
+	ticks = qemu_get_clock(vm_clock) - s->tick_offset;
+
+    out = (ticks >= s->expire_time);
+    if (out)
+	s->reached = 0x80000000;
+    if (!s->limit)
+	limit = 0x7fffffff;
+    else
+	limit = s->limit;
+
+    // Convert register units to counter ticks
+    limit = limit >> 9;
+
+    // Convert cpu ticks to counter ticks
+    diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec);
+
+    // Calculate what the counter should be, convert to register
+    // units
+    count = diff % limit;
+    s->count = count << 9;
+    s->counthigh = count >> 22;
+
+    // Expire time: CPU ticks left to next interrupt
+    // Convert remaining counter ticks to CPU ticks
+    s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ);
+
+#ifdef DEBUG_TIMER
+    term_printf("timer: irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode);
+#endif
+    if (s->mode != 1)
+	pic_set_irq(s->irq, out);
+}
+
+// timer callback
+static void slavio_timer_irq(void *opaque)
+{
+    SLAVIO_TIMERState *s = opaque;
+
+    if (!s->irq_timer)
+        return;
+    slavio_timer_get_out(s);
+    if (s->mode != 1)
+	qemu_mod_timer(s->irq_timer, s->expire_time);
+}
+
+static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    SLAVIO_TIMERState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & TIMER_MAXADDR) >> 2;
+    switch (saddr) {
+    case 0:
+	// read limit (system counter mode) or read most signifying
+	// part of counter (user mode)
+	if (s->mode != 1) {
+	    // clear irq
+	    pic_set_irq(s->irq, 0);
+	    s->count_load_time = qemu_get_clock(vm_clock);
+	    s->reached = 0;
+	    return s->limit;
+	}
+	else {
+	    slavio_timer_get_out(s);
+	    return s->counthigh & 0x7fffffff;
+	}
+    case 1:
+	// read counter and reached bit (system mode) or read lsbits
+	// of counter (user mode)
+	slavio_timer_get_out(s);
+	if (s->mode != 1)
+	    return (s->count & 0x7fffffff) | s->reached;
+	else
+	    return s->count;
+    case 3:
+	// read start/stop status
+	return s->stopped;
+    case 4:
+	// read user/system mode
+	return s->mode & 1;
+    default:
+	return 0;
+    }
+}
+
+static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    SLAVIO_TIMERState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & TIMER_MAXADDR) >> 2;
+    switch (saddr) {
+    case 0:
+	// set limit, reset counter
+	s->count_load_time = qemu_get_clock(vm_clock);
+	// fall through
+    case 2:
+	// set limit without resetting counter
+	if (!val)
+	    s->limit = 0x7fffffff;
+	else
+	    s->limit = val & 0x7fffffff;
+	slavio_timer_irq(s);
+	break;
+    case 3:
+	// start/stop user counter
+	if (s->mode == 1) {
+	    if (val & 1) {
+		s->stop_time = qemu_get_clock(vm_clock);
+		s->stopped = 1;
+	    }
+	    else {
+		if (s->stopped)
+		    s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time;
+		s->stopped = 0;
+	    }
+	}
+	break;
+    case 4:
+	// bit 0: user (1) or system (0) counter mode
+	if (s->mode == 0 || s->mode == 1)
+	    s->mode = val & 1;
+	break;
+    default:
+	break;
+    }
+}
+
+static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
+    slavio_timer_mem_readl,
+    slavio_timer_mem_readl,
+    slavio_timer_mem_readl,
+};
+
+static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
+    slavio_timer_mem_writel,
+    slavio_timer_mem_writel,
+    slavio_timer_mem_writel,
+};
+
+static void slavio_timer_save(QEMUFile *f, void *opaque)
+{
+    SLAVIO_TIMERState *s = opaque;
+
+    qemu_put_be32s(f, &s->limit);
+    qemu_put_be32s(f, &s->count);
+    qemu_put_be32s(f, &s->counthigh);
+    qemu_put_be64s(f, &s->count_load_time);
+    qemu_put_be64s(f, &s->expire_time);
+    qemu_put_be64s(f, &s->stop_time);
+    qemu_put_be64s(f, &s->tick_offset);
+    qemu_put_be32s(f, &s->irq);
+    qemu_put_be32s(f, &s->reached);
+    qemu_put_be32s(f, &s->stopped);
+    qemu_put_be32s(f, &s->mode);
+}
+
+static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
+{
+    SLAVIO_TIMERState *s = opaque;
+    
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_be32s(f, &s->limit);
+    qemu_get_be32s(f, &s->count);
+    qemu_get_be32s(f, &s->counthigh);
+    qemu_get_be64s(f, &s->count_load_time);
+    qemu_get_be64s(f, &s->expire_time);
+    qemu_get_be64s(f, &s->stop_time);
+    qemu_get_be64s(f, &s->tick_offset);
+    qemu_get_be32s(f, &s->irq);
+    qemu_get_be32s(f, &s->reached);
+    qemu_get_be32s(f, &s->stopped);
+    qemu_get_be32s(f, &s->mode);
+    return 0;
+}
+
+static void slavio_timer_reset(void *opaque)
+{
+    SLAVIO_TIMERState *s = opaque;
+
+    s->limit = 0;
+    s->count = 0;
+    s->count_load_time = qemu_get_clock(vm_clock);;
+    s->stop_time = s->count_load_time;
+    s->tick_offset = 0;
+    s->reached = 0;
+    s->mode &= 2;
+    s->stopped = 1;
+    slavio_timer_get_out(s);
+}
+
+static void slavio_timer_init_internal(uint32_t addr, int irq, int mode)
+{
+    int slavio_timer_io_memory;
+    SLAVIO_TIMERState *s;
+
+    s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
+    if (!s)
+        return;
+    s->irq = irq;
+    s->mode = mode;
+    s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s);
+
+    slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
+						    slavio_timer_mem_write, s);
+    cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory);
+    register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s);
+    qemu_register_reset(slavio_timer_reset, s);
+    slavio_timer_reset(s);
+}
+
+void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2)
+{
+    int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+	slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0);
+    }
+
+    slavio_timer_init_internal(addr2, irq2, 2);
+}
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 80305e09c3..7cc5bd8d9c 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -25,29 +25,32 @@
 #include "m48t08.h"
 
 #define KERNEL_LOAD_ADDR     0x00004000
-#define MMU_CONTEXT_TBL      0x00003000
-#define MMU_L1PTP            (MMU_CONTEXT_TBL + 0x0400)
-#define MMU_L2PTP            (MMU_CONTEXT_TBL + 0x0800)
-#define PROM_ADDR	     0xffd04000
+#define PROM_ADDR	     0xffd00000
 #define PROM_FILENAMEB	     "proll.bin"
 #define PROM_FILENAMEE	     "proll.elf"
-#define PROLL_MAGIC_ADDR 0x20000000
-#define PHYS_JJ_EEPROM	0x71200000	/* [2000] MK48T08 */
+#define PHYS_JJ_EEPROM	0x71200000	/* m48t08 */
 #define PHYS_JJ_IDPROM_OFF	0x1FD8
 #define PHYS_JJ_EEPROM_SIZE	0x2000
-#define PHYS_JJ_IOMMU	0x10000000	/* First page of sun4m IOMMU */
+// IRQs are not PIL ones, but master interrupt controller register
+// bits
+#define PHYS_JJ_IOMMU	0x10000000	/* I/O MMU */
 #define PHYS_JJ_TCX_FB	0x50800000	/* Start address, frame buffer body */
-#define PHYS_JJ_TCX_0E	0x5E000000	/* Top address, one byte used. */
-#define PHYS_JJ_IOMMU	0x10000000	/* First page of sun4m IOMMU */
-#define PHYS_JJ_LEDMA   0x78400010      /* ledma, off by 10 from unused SCSI */
-#define PHYS_JJ_LE      0x78C00000      /* LANCE, typical sun4m */
-#define PHYS_JJ_LE_IRQ  6
-#define PHYS_JJ_CLOCK	0x71D00000
-#define PHYS_JJ_CLOCK_IRQ  10
-#define PHYS_JJ_CLOCK1	0x71D10000
-#define PHYS_JJ_CLOCK1_IRQ  14
-#define PHYS_JJ_INTR0	0x71E00000	/* CPU0 interrupt control registers */
+#define PHYS_JJ_LEDMA   0x78400010      /* Lance DMA controller */
+#define PHYS_JJ_LE      0x78C00000      /* Lance ethernet */
+#define PHYS_JJ_LE_IRQ     16
+#define PHYS_JJ_CLOCK	0x71D00000      /* Per-CPU timer/counter, L14 */
+#define PHYS_JJ_CLOCK_IRQ  7
+#define PHYS_JJ_CLOCK1	0x71D10000      /* System timer/counter, L10 */
+#define PHYS_JJ_CLOCK1_IRQ 19
+#define PHYS_JJ_INTR0	0x71E00000	/* Per-CPU interrupt control registers */
 #define PHYS_JJ_INTR_G	0x71E10000	/* Master interrupt control registers */
+#define PHYS_JJ_MS_KBD	0x71000000	/* Mouse and keyboard */
+#define PHYS_JJ_MS_KBD_IRQ    14
+#define PHYS_JJ_SER	0x71100000	/* Serial */
+#define PHYS_JJ_SER_IRQ    15
+#define PHYS_JJ_SCSI_IRQ   18
+#define PHYS_JJ_FDC	0x71400000	/* Floppy */
+#define PHYS_JJ_FLOPPY_IRQ 22
 
 /* TSC handling */
 
@@ -57,13 +60,73 @@ uint64_t cpu_get_tsc()
 }
 
 void DMA_run() {}
-void SB16_run() {}
-int serial_can_receive(SerialState *s) { return 0; }
-void serial_receive_byte(SerialState *s, int ch) {}
-void serial_receive_break(SerialState *s) {}
 
 static m48t08_t *nvram;
 
+static void nvram_init(m48t08_t *nvram, uint8_t *macaddr)
+{
+    unsigned char tmp = 0;
+    int i, j;
+
+    i = 0x1fd8;
+    m48t08_write(nvram, i++, 0x01);
+    m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */
+    j = 0;
+    m48t08_write(nvram, i++, macaddr[j++]);
+    m48t08_write(nvram, i++, macaddr[j++]);
+    m48t08_write(nvram, i++, macaddr[j++]);
+    m48t08_write(nvram, i++, macaddr[j++]);
+    m48t08_write(nvram, i++, macaddr[j++]);
+    m48t08_write(nvram, i, macaddr[j]);
+
+    /* Calculate checksum */
+    for (i = 0x1fd8; i < 0x1fe7; i++) {
+	tmp ^= m48t08_read(nvram, i);
+    }
+    m48t08_write(nvram, 0x1fe7, tmp);
+}
+
+static void *slavio_intctl;
+
+void pic_info()
+{
+    slavio_pic_info(slavio_intctl);
+}
+
+void irq_info()
+{
+    slavio_irq_info(slavio_intctl);
+}
+
+void pic_set_irq(int irq, int level)
+{
+    slavio_pic_set_irq(slavio_intctl, irq, level);
+}
+
+static void *tcx;
+
+void vga_update_display()
+{
+    tcx_update_display(tcx);
+}
+
+void vga_invalidate_display()
+{
+    tcx_invalidate_display(tcx);
+}
+
+void vga_screen_dump(const char *filename)
+{
+    tcx_screen_dump(tcx, filename);
+}
+
+static void *iommu;
+
+uint32_t iommu_translate(uint32_t addr)
+{
+    return iommu_translate_local(iommu, addr);
+}
+
 /* Sun4m hardware initialisation */
 void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
              DisplayState *ds, const char **fd_filename, int snapshot,
@@ -72,42 +135,50 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
 {
     char buf[1024];
     int ret, linux_boot;
-    unsigned long bios_offset;
+    unsigned long vram_size = 0x100000, prom_offset;
 
     linux_boot = (kernel_filename != NULL);
 
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, 0);
-    bios_offset = ram_size;
 
-    iommu_init(PHYS_JJ_IOMMU);
-    sched_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
-    tcx_init(ds, PHYS_JJ_TCX_FB);
+    iommu = iommu_init(PHYS_JJ_IOMMU);
+    slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
+    tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size);
     lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA);
-    nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE, &nd_table[0].macaddr);
-    timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ);
-    timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ);
-    magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR, PROLL_MAGIC_ADDR);
+    nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE);
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr);
+    slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ);
+    slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ);
+    slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[0], serial_hds[1]);
+    fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table);
 
-    /* We load Proll as the kernel and start it. It will issue a magic
-       IO to load the real kernel */
-    if (linux_boot) {
+    prom_offset = ram_size + vram_size;
+
+    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
+    ret = load_elf(buf, phys_ram_base + prom_offset);
+    if (ret < 0) {
 	snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
-        ret = load_kernel(buf, 
-		       phys_ram_base + KERNEL_LOAD_ADDR);
+	ret = load_image(buf, phys_ram_base + prom_offset);
+    }
+    if (ret < 0) {
+	fprintf(stderr, "qemu: could not load prom '%s'\n", 
+		buf);
+	exit(1);
+    }
+    cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, 
+                                 prom_offset | IO_MEM_ROM);
+
+    if (linux_boot) {
+        ret = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+        if (ret < 0)
+	    ret = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+	if (ret < 0)
+	    ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
         if (ret < 0) {
             fprintf(stderr, "qemu: could not load kernel '%s'\n", 
-                    buf);
-            exit(1);
+                    kernel_filename);
+	    exit(1);
         }
     }
-    /* Setup a MMU entry for entire address space */
-    stl_raw(phys_ram_base + MMU_CONTEXT_TBL, (MMU_L1PTP >> 4) | 1);
-    stl_raw(phys_ram_base + MMU_L1PTP, (MMU_L2PTP >> 4) | 1);
-    stl_raw(phys_ram_base + MMU_L1PTP + (0x01 << 2), (MMU_L2PTP >> 4) | 1); // 01.. == 00..
-    stl_raw(phys_ram_base + MMU_L1PTP + (0xff << 2), (MMU_L2PTP >> 4) | 1); // ff.. == 00..
-    stl_raw(phys_ram_base + MMU_L1PTP + (0xf0 << 2), (MMU_L2PTP >> 4) | 1); // f0.. == 00..
-    /* 3 = U:RWX S:RWX */
-    stl_raw(phys_ram_base + MMU_L2PTP, (3 << PTE_ACCESS_SHIFT) | 2);
-    stl_raw(phys_ram_base + MMU_L2PTP, ((0x01 << PTE_PPN_SHIFT) >> 4 ) | (3 << PTE_ACCESS_SHIFT) | 2);
 }
diff --git a/hw/tcx.c b/hw/tcx.c
index 7f979946fc..ccac0bffa6 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -25,179 +25,254 @@
 
 #define MAXX 1024
 #define MAXY 768
+/*
+ * Proll uses only small part of display, we need to switch to full
+ * display when we get linux framebuffer console or X11 running. For
+ * now it's just slower and awkward.
+*/
+#if 1
 #define XSZ (8*80)
 #define YSZ (24*11)
 #define XOFF (MAXX-XSZ)
 #define YOFF (MAXY-YSZ)
+#else
+#define XSZ MAXX
+#define YSZ MAXY
+#define XOFF 0
+#define YOFF 0
+#endif
 
 typedef struct TCXState {
     uint32_t addr;
     DisplayState *ds;
     uint8_t *vram;
+    unsigned long vram_offset;
+    uint8_t r[256], g[256], b[256];
 } TCXState;
 
-static TCXState *ts;
-
-void vga_update_display()
+static void tcx_draw_line32(TCXState *s1, uint8_t *d, 
+			    const uint8_t *s, int width)
 {
-    dpy_update(ts->ds, 0, 0, XSZ, YSZ);
+    int x;
+    uint8_t val;
+
+    for(x = 0; x < width; x++) {
+	val = *s++;
+	*d++ = s1->r[val];
+	*d++ = s1->g[val];
+	*d++ = s1->b[val];
+	d++;
+    }
 }
 
-void vga_invalidate_display() {}
+static void tcx_draw_line24(TCXState *s1, uint8_t *d, 
+			    const uint8_t *s, int width)
+{
+    int x;
+    uint8_t val;
 
-static uint32_t tcx_mem_readb(void *opaque, target_phys_addr_t addr)
+    for(x = 0; x < width; x++) {
+	val = *s++;
+	*d++ = s1->r[val];
+	*d++ = s1->g[val];
+	*d++ = s1->b[val];
+    }
+}
+
+static void tcx_draw_line8(TCXState *s1, uint8_t *d, 
+			   const uint8_t *s, int width)
 {
-    TCXState *s = opaque;
-    uint32_t saddr;
-    unsigned int x, y;
-
-    saddr = addr - s->addr - YOFF*MAXX - XOFF;
-    y = saddr / MAXX;
-    x = saddr - y * MAXX;
-    if (x < XSZ && y < YSZ) {
-	return s->vram[y * XSZ + x];
+    int x;
+    uint8_t val;
+
+    for(x = 0; x < width; x++) {
+	val = *s++;
+	/* XXX translate between palettes? */
+	*d++ = val;
     }
-    return 0;
 }
 
-static uint32_t tcx_mem_readw(void *opaque, target_phys_addr_t addr)
+/* Fixed line length 1024 allows us to do nice tricks not possible on
+   VGA... */
+void tcx_update_display(void *opaque)
 {
-    uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = tcx_mem_readb(opaque, addr) << 8;
-    v |= tcx_mem_readb(opaque, addr + 1);
+    TCXState *ts = opaque;
+    uint32_t page;
+    int y, page_min, page_max, y_start, dd, ds;
+    uint8_t *d, *s;
+    void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);
+
+    if (ts->ds->depth == 0)
+	return;
+#ifdef LD_BYPASS_OK
+    page = ts->vram_offset + YOFF*MAXX;
 #else
-    v = tcx_mem_readb(opaque, addr);
-    v |= tcx_mem_readb(opaque, addr + 1) << 8;
+    page = ts->addr + YOFF*MAXX;
 #endif
-    return v;
+    y_start = -1;
+    page_min = 0x7fffffff;
+    page_max = -1;
+    d = ts->ds->data;
+    s = ts->vram + YOFF*MAXX + XOFF;
+    dd = ts->ds->linesize;
+    ds = 1024;
+
+    switch (ts->ds->depth) {
+    case 32:
+	f = tcx_draw_line32;
+	break;
+    case 24:
+	f = tcx_draw_line24;
+	break;
+    default:
+    case 8:
+	f = tcx_draw_line8;
+	break;
+    case 0:
+	return;
+    }
+
+    for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) {
+	if (cpu_physical_memory_is_dirty(page)) {
+	    if (y_start < 0)
+                y_start = y;
+            if (page < page_min)
+                page_min = page;
+            if (page > page_max)
+                page_max = page;
+	    f(ts, d, s, XSZ);
+	    d += dd;
+	    s += ds;
+	    f(ts, d, s, XSZ);
+	    d += dd;
+	    s += ds;
+	    f(ts, d, s, XSZ);
+	    d += dd;
+	    s += ds;
+	    f(ts, d, s, XSZ);
+	    d += dd;
+	    s += ds;
+	} else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_update(ts->ds, 0, y_start, 
+                           XSZ, y - y_start);
+                y_start = -1;
+            }
+	    d += dd * 4;
+	    s += ds * 4;
+	}
+    }
+    if (y_start >= 0) {
+	/* flush to display */
+	dpy_update(ts->ds, 0, y_start, 
+		   XSZ, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_max != -1) {
+        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
+    }
 }
 
-static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr)
+void tcx_invalidate_display(void *opaque)
 {
-    uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = tcx_mem_readb(opaque, addr) << 24;
-    v |= tcx_mem_readb(opaque, addr + 1) << 16;
-    v |= tcx_mem_readb(opaque, addr + 2) << 8;
-    v |= tcx_mem_readb(opaque, addr + 3);
+    TCXState *s = opaque;
+    int i;
+
+    for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
+#ifdef LD_BYPASS_OK
+	cpu_physical_memory_set_dirty(s->vram_offset + i);
 #else
-    v = tcx_mem_readb(opaque, addr);
-    v |= tcx_mem_readb(opaque, addr + 1) << 8;
-    v |= tcx_mem_readb(opaque, addr + 2) << 16;
-    v |= tcx_mem_readb(opaque, addr + 3) << 24;
+	cpu_physical_memory_set_dirty(s->addr + i);
 #endif
-    return v;
+    }
 }
 
-static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void tcx_save(QEMUFile *f, void *opaque)
 {
     TCXState *s = opaque;
-    uint32_t saddr;
-    unsigned int x, y;
-    char *sptr;
-
-    saddr = addr - s->addr - YOFF*MAXX - XOFF;
-    y = saddr / MAXX;
-    x = saddr - y * MAXX;
-    if (x < XSZ && y < YSZ) {
-	sptr = 	s->ds->data;
-	if (sptr) {
-	    if (s->ds->depth == 24 || s->ds->depth == 32) {
-		/* XXX need to do CLUT translation */
-		sptr[y * s->ds->linesize + x*4] = val & 0xff;
-		sptr[y * s->ds->linesize + x*4+1] = val & 0xff;
-		sptr[y * s->ds->linesize + x*4+2] = val & 0xff;
-	    }
-	    else if (s->ds->depth == 8) {
-		sptr[y * s->ds->linesize + x] = val & 0xff;
-	    }
-	}
-	cpu_physical_memory_set_dirty(addr);
-	s->vram[y * XSZ + x] = val & 0xff;
-    }
+    
+    qemu_put_be32s(f, (uint32_t *)&s->addr);
+    qemu_put_be32s(f, (uint32_t *)&s->vram);
+    qemu_put_buffer(f, s->r, 256);
+    qemu_put_buffer(f, s->g, 256);
+    qemu_put_buffer(f, s->b, 256);
 }
 
-static void tcx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+static int tcx_load(QEMUFile *f, void *opaque, int version_id)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    tcx_mem_writeb(opaque, addr, (val >> 8) & 0xff);
-    tcx_mem_writeb(opaque, addr + 1, val & 0xff);
-#else
-    tcx_mem_writeb(opaque, addr, val & 0xff);
-    tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
+    TCXState *s = opaque;
+    
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_be32s(f, (uint32_t *)&s->addr);
+    qemu_get_be32s(f, (uint32_t *)&s->vram);
+    qemu_get_buffer(f, s->r, 256);
+    qemu_get_buffer(f, s->g, 256);
+    qemu_get_buffer(f, s->b, 256);
+    return 0;
 }
 
-static void tcx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void tcx_reset(void *opaque)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    tcx_mem_writeb(opaque, addr, (val >> 24) & 0xff);
-    tcx_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
-    tcx_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
-    tcx_mem_writeb(opaque, addr + 3, val & 0xff);
-#else
-    tcx_mem_writeb(opaque, addr, val & 0xff);
-    tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    tcx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    tcx_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+    TCXState *s = opaque;
+
+    /* Initialize palette */
+    memset(s->r, 0, 256);
+    memset(s->g, 0, 256);
+    memset(s->b, 0, 256);
+    s->r[255] = s->g[255] = s->b[255] = 255;
+    memset(s->vram, 0, MAXX*MAXY);
+#ifdef LD_BYPASS_OK
+    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY - 1);
 #endif
 }
 
-static CPUReadMemoryFunc *tcx_mem_read[3] = {
-    tcx_mem_readb,
-    tcx_mem_readw,
-    tcx_mem_readl,
-};
-
-static CPUWriteMemoryFunc *tcx_mem_write[3] = {
-    tcx_mem_writeb,
-    tcx_mem_writew,
-    tcx_mem_writel,
-};
-
-void tcx_init(DisplayState *ds, uint32_t addr)
+void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
+	      unsigned long vram_offset, int vram_size)
 {
     TCXState *s;
-    int tcx_io_memory;
 
     s = qemu_mallocz(sizeof(TCXState));
     if (!s)
-        return;
+        return NULL;
     s->ds = ds;
     s->addr = addr;
-    ts = s;
-    tcx_io_memory = cpu_register_io_memory(0, tcx_mem_read, tcx_mem_write, s);
-    cpu_register_physical_memory(addr, 0x100000, 
-                                 tcx_io_memory);
-    s->vram = qemu_mallocz(XSZ*YSZ);
+    s->vram = vram_base;
+    s->vram_offset = vram_offset;
+
+    cpu_register_physical_memory(addr, vram_size, vram_offset);
+
+    register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
+    qemu_register_reset(tcx_reset, s);
+    tcx_reset(s);
     dpy_resize(s->ds, XSZ, YSZ);
+    return s;
 }
 
-void vga_screen_dump(const char *filename)
+void tcx_screen_dump(void *opaque, const char *filename)
 {
-    TCXState *s = ts;
+    TCXState *s = opaque;
     FILE *f;
-    uint8_t *d, *d1;
-    unsigned int v;
+    uint8_t *d, *d1, v;
     int y, x;
 
     f = fopen(filename, "wb");
     if (!f)
-        return -1;
-    fprintf(f, "P6\n%d %d\n%d\n",
-            XSZ, YSZ, 255);
-    d1 = s->vram;
+        return;
+    fprintf(f, "P6\n%d %d\n%d\n", XSZ, YSZ, 255);
+    d1 = s->vram + YOFF*MAXX + XOFF;
     for(y = 0; y < YSZ; y++) {
         d = d1;
         for(x = 0; x < XSZ; x++) {
             v = *d;
-            fputc((v) & 0xff, f);
-            fputc((v) & 0xff, f);
-            fputc((v) & 0xff, f);
+            fputc(s->r[v], f);
+            fputc(s->g[v], f);
+            fputc(s->b[v], f);
             d++;
         }
-        d1 += XSZ;
+        d1 += MAXX;
     }
     fclose(f);
     return;
diff --git a/hw/timer.c b/hw/timer.c
deleted file mode 100644
index e393fa36fd..0000000000
--- a/hw/timer.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * QEMU Sparc timer controller emulation
- * 
- * Copyright (c) 2003-2004 Fabrice Bellard
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "vl.h"
-
-/*
- * Registers of hardware timer in sun4m.
- */
-struct sun4m_timer_percpu {
-	volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */
-	volatile unsigned int l14_cur_count;
-};
-
-struct sun4m_timer_global {
-        volatile unsigned int l10_timer_limit;
-        volatile unsigned int l10_cur_count;
-};
-
-typedef struct TIMERState {
-    uint32_t addr;
-    uint32_t timer_regs[2];
-    int irq;
-} TIMERState;
-
-static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr)
-{
-    TIMERState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr - s->addr) >> 2;
-    switch (saddr) {
-    default:
-	return s->timer_regs[saddr];
-	break;
-    }
-    return 0;
-}
-
-static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    TIMERState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr - s->addr) >> 2;
-    switch (saddr) {
-    default:
-	s->timer_regs[saddr] = val;
-	break;
-    }
-}
-
-static CPUReadMemoryFunc *timer_mem_read[3] = {
-    timer_mem_readl,
-    timer_mem_readl,
-    timer_mem_readl,
-};
-
-static CPUWriteMemoryFunc *timer_mem_write[3] = {
-    timer_mem_writel,
-    timer_mem_writel,
-    timer_mem_writel,
-};
-
-void timer_init(uint32_t addr, int irq)
-{
-    int timer_io_memory;
-    TIMERState *s;
-
-    s = qemu_mallocz(sizeof(TIMERState));
-    if (!s)
-        return;
-    s->addr = addr;
-    s->irq = irq;
-
-    timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s);
-    cpu_register_physical_memory(addr, 2, timer_io_memory);
-}
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index cfc4256974..09c33aa90b 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -841,6 +841,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     unsigned int i;
     struct elf_shdr sechdr, symtab, strtab;
     char *strings;
+    struct syminfo *s;
 
     lseek(fd, hdr->e_shoff, SEEK_SET);
     for (i = 0; i < hdr->e_shnum; i++) {
@@ -866,24 +867,27 @@ static void load_symbols(struct elfhdr *hdr, int fd)
 
  found:
     /* Now know where the strtab and symtab are.  Snarf them. */
-    disas_symtab = malloc(symtab.sh_size);
-    disas_strtab = strings = malloc(strtab.sh_size);
-    if (!disas_symtab || !disas_strtab)
+    s = malloc(sizeof(*s));
+    s->disas_symtab = malloc(symtab.sh_size);
+    s->disas_strtab = strings = malloc(strtab.sh_size);
+    if (!s->disas_symtab || !s->disas_strtab)
 	return;
 	
     lseek(fd, symtab.sh_offset, SEEK_SET);
-    if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size)
+    if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)
 	return;
 
 #ifdef BSWAP_NEEDED
     for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
-	bswap_sym(disas_symtab + sizeof(struct elf_sym)*i);
+	bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i);
 #endif
 
     lseek(fd, strtab.sh_offset, SEEK_SET);
     if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
 	return;
-    disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
+    s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
+    s->next = syminfos;
+    syminfos = s;
 }
 
 static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
diff --git a/linux-user/main.c b/linux-user/main.c
index 6ab024e0bf..3d99dda1ad 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -497,6 +497,8 @@ void cpu_loop (CPUSPARCState *env)
         case TT_WIN_UNF: /* window underflow */
             restore_window(env);
             break;
+	case 0x100: // XXX, why do we get these?
+	    break;
         default:
             printf ("Unhandled trap: 0x%x\n", trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 50f2ba10a0..49278208c5 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1354,13 +1354,14 @@ struct target_rt_signal_frame {
 	__siginfo_fpu_t		fpu_state;
 };
 
-#define UREG_O0        0
-#define UREG_O6        6
-#define UREG_I0        16
-#define UREG_I1        17
-#define UREG_I2        18
-#define UREG_I6        22
-#define UREG_I7        23
+#define UREG_O0        16
+#define UREG_O6        22
+#define UREG_I0        0
+#define UREG_I1        1
+#define UREG_I2        2
+#define UREG_I6        6
+#define UREG_I7        7
+#define UREG_L0	       8
 #define UREG_FP        UREG_I6
 #define UREG_SP        UREG_O6
 
@@ -1385,23 +1386,20 @@ setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask)
 {
 	int err = 0, i;
 
-	fprintf(stderr, "2.a %lx psr: %lx regs: %lx\n", si, env->psr, si->si_regs.psr);
 	err |= __put_user(env->psr, &si->si_regs.psr);
-	fprintf(stderr, "2.a1 pc:%lx\n", si->si_regs.pc);
 	err |= __put_user(env->pc, &si->si_regs.pc);
 	err |= __put_user(env->npc, &si->si_regs.npc);
 	err |= __put_user(env->y, &si->si_regs.y);
-	fprintf(stderr, "2.b\n");
 	for (i=0; i < 7; i++) {
 		err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
 	}
 	for (i=0; i < 7; i++) {
-		err |= __put_user(env->regwptr[i+16], &si->si_regs.u_regs[i+8]);
+		err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
 	}
-	fprintf(stderr, "2.c\n");
 	err |= __put_user(mask, &si->si_mask);
 	return err;
 }
+
 static int
 setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
 		 CPUState *env, unsigned long mask)
@@ -1434,6 +1432,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
 	sf = (struct target_signal_frame *)
 		get_sigframe(ka, env, sigframe_size);
 
+	//fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
 #if 0
 	if (invalid_frame_pointer(sf, sigframe_size))
 		goto sigill_and_return;
@@ -1451,13 +1450,11 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
 	}
 
 	for (i = 0; i < 7; i++) {
-	  	err |= __put_user(env->regwptr[i + 8], &sf->ss.locals[i]);
+	  	err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
 	}
 	for (i = 0; i < 7; i++) {
-	  	err |= __put_user(env->regwptr[i + 16], &sf->ss.ins[i]);
+	  	err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
 	}
-	//err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
-	//		      sizeof(struct reg_window));
 	if (err)
 		goto sigsegv;
 
@@ -1486,13 +1483,15 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
 
 		/* Flush instruction space. */
 		//flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
-		//tb_flush(env);
+		tb_flush(env);
 	}
+	//cpu_dump_state(env, stderr, fprintf, 0);
 	return;
 
 sigill_and_return:
 	force_sig(TARGET_SIGILL);
 sigsegv:
+	//fprintf(stderr, "force_sig\n");
 	force_sig(TARGET_SIGSEGV);
 }
 static inline int
@@ -1542,13 +1541,16 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
 long do_sigreturn(CPUState *env)
 {
         struct target_signal_frame *sf;
-        unsigned long up_psr, pc, npc;
+        uint32_t up_psr, pc, npc;
         target_sigset_t set;
+        sigset_t host_set;
         __siginfo_fpu_t *fpu_save;
-        int err;
+        int err, i;
 
-        sf = (struct new_signal_frame *) env->regwptr[UREG_FP];
-	fprintf(stderr, "sigreturn sf: %lx\n", &sf);
+        sf = (struct target_signal_frame *) env->regwptr[UREG_FP];
+	fprintf(stderr, "sigreturn\n");
+	fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
+	//cpu_dump_state(env, stderr, fprintf, 0);
 
         /* 1. Make sure we are not getting garbage from the user */
 #if 0
@@ -1567,36 +1569,41 @@ long do_sigreturn(CPUState *env)
                 goto segv_and_exit;
 
         /* 2. Restore the state */
-        up_psr = env->psr;
-        //err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs)
-	//);
+        err |= __get_user(up_psr, &sf->info.si_regs.psr);
+
         /* User can only change condition codes and FPU enabling in %psr. */
         env->psr = (up_psr & ~(PSR_ICC /* | PSR_EF */))
                   | (env->psr & (PSR_ICC /* | PSR_EF */));
-	fprintf(stderr, "psr: %lx\n", env->psr);
+	fprintf(stderr, "psr: %x\n", env->psr);
+	env->pc = pc-4;
+	env->npc = pc;
+        err |= __get_user(env->y, &sf->info.si_regs.y);
+	for (i=0; i < 7; i++) {
+		err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
+	}
+	for (i=0; i < 7; i++) {
+		err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
+	}
 
         err |= __get_user(fpu_save, &sf->fpu_save);
 
-        if (fpu_save)
-                err |= restore_fpu_state(env, fpu_save);
+        //if (fpu_save)
+        //        err |= restore_fpu_state(env, fpu_save);
 
         /* This is pretty much atomic, no amount locking would prevent
          * the races which exist anyways.
          */
         err |= __get_user(set.sig[0], &sf->info.si_mask);
-        //err |= __copy_from_user(&set.sig[1], &sf->extramask,
-        //                        (_NSIG_WORDS-1) * sizeof(unsigned int));
+        for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+            err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
+        }
+
+        target_to_host_sigset_internal(&host_set, &set);
+        sigprocmask(SIG_SETMASK, &host_set, NULL);
 
         if (err)
                 goto segv_and_exit;
 
-#if 0
-        sigdelsetmask(&set, ~_BLOCKABLE);
-        spin_lock_irq(&current->sigmask_lock);
-        current->blocked = set;
-        recalc_sigpending(current);
-        spin_unlock_irq(&current->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 0489cc245f..0000000000
--- a/pc-bios/proll.bin
+++ /dev/null
Binary files differdiff --git a/pc-bios/proll.elf b/pc-bios/proll.elf
new file mode 100644
index 0000000000..e274b0d193
--- /dev/null
+++ b/pc-bios/proll.elf
Binary files differdiff --git a/pc-bios/proll.patch b/pc-bios/proll.patch
index b0860e26f4..18a157512a 100644
--- a/pc-bios/proll.patch
+++ b/pc-bios/proll.patch
@@ -1,50 +1,2064 @@
-diff -ru proll_18.orig/mrcoffee/main.c proll_18/mrcoffee/main.c
---- proll_18.orig/mrcoffee/main.c	2002-09-13 16:16:59.000000000 +0200
-+++ proll_18/mrcoffee/main.c	2004-09-26 11:52:23.000000000 +0200
-@@ -101,6 +101,7 @@
- 	le_probe();
- 	init_net();
+diff -ruN proll_18.orig/Makefile proll-patch4/Makefile
+--- proll_18.orig/Makefile	2002-09-13 14:16:59.000000000 +0000
++++ proll-patch4/Makefile	2004-11-13 15:50:49.000000000 +0000
+@@ -4,6 +4,7 @@
+ 	make -C krups-ser    all
+ 	make -C espresso     all
+ 	make -C espresso-ser all
++	make -C qemu all
  
+ clean:
+ 	make -C mrcoffee clean
+@@ -11,3 +12,4 @@
+ 	make -C krups-ser    clean
+ 	make -C espresso     clean
+ 	make -C espresso-ser clean
++	make -C qemu clean
+diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S
+--- proll_18.orig/qemu/head.S	1970-01-01 00:00:00.000000000 +0000
++++ proll-patch4/qemu/head.S	2004-11-13 15:50:49.000000000 +0000
+@@ -0,0 +1,515 @@
++/**
++ ** Standalone startup code for Linux PROM emulator.
++ ** Copyright 1999 Pete A. Zaitcev
++ ** This code is licensed under GNU General Public License.
++ **/
++/*
++ * $Id: proll.patch,v 1.2 2004-12-19 23:18:01 bellard Exp $
++ */
++
++#include <psr.h>
++#include <asi.h>
++#include <crs.h>
++/* #include <asm/head.h> */	/* Trap entries. Do not use. */
++#include "phys_jj.h"
++
++#define C_LABEL(name)	name
++#define REGWIN_SZ   0x40
++
++#define WRITE_PAUSE    nop; nop; nop; /* Have to do this after %wim/%psr chg */
++
++  /* 22 is 24-2, (va)>>(SRMMU_PGDIR_SHIFT-PTESIZESHFT) */
++#define VATOPGDOFF(va) (((va)>>22)&0x3FC)
++#define VATOPMDOFF(va) (((va)>>16)&0xFC)
++
++#define NOP_INSN       0x01000000     /* Used to patch sparc_save_state */
++
++/* Here are some trap goodies */
++
++#if 0
++/* Generic trap entry. */
++#define TRAP_ENTRY(type, label) \
++	rd %psr, %l0; b label; rd %wim, %l3; nop;
++#endif
++
++/* Data/text faults. */
++#define SRMMU_TFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 1, %l7;
++#define SRMMU_DFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 0, %l7;
++
++#if 0
++/* This is for traps we should NEVER get. */
++#define BAD_TRAP(num) \
++        rd %psr, %l0; mov num, %l7; b bad_trap_handler; rd %wim, %l3;
++
++/* This is for traps when we want just skip the instruction which caused it */
++#define SKIP_TRAP(type, name) \
++	jmpl %l2, %g0; rett %l2 + 4; nop; nop;
++
++/* Notice that for the system calls we pull a trick.  We load up a
++ * different pointer to the system call vector table in %l7, but call
++ * the same generic system call low-level entry point.  The trap table
++ * entry sequences are also HyperSparc pipeline friendly ;-)
++ */
++
++/* Software trap for Linux system calls. */
++#define LINUX_SYSCALL_TRAP \
++        sethi %hi(C_LABEL(sys_call_table)), %l7; \
++        or %l7, %lo(C_LABEL(sys_call_table)), %l7; \
++        b linux_sparc_syscall; \
++        rd %psr, %l0;
++
++/* Software trap for SunOS4.1.x system calls. */
++#define SUNOS_SYSCALL_TRAP \
++        rd %psr, %l0; \
++        sethi %hi(C_LABEL(sunos_sys_table)), %l7; \
++        b linux_sparc_syscall; \
++        or %l7, %lo(C_LABEL(sunos_sys_table)), %l7;
++
++/* Software trap for Slowaris system calls. */
++#define SOLARIS_SYSCALL_TRAP \
++        b solaris_syscall; \
++        rd %psr, %l0; \
++        nop; \
++        nop;
++
++#define INDIRECT_SOLARIS_SYSCALL(x) \
++	mov x, %g1; \
++	b solaris_syscall; \
++	rd %psr, %l0; \
++	nop;
++
++#define BREAKPOINT_TRAP \
++	b breakpoint_trap; \
++	rd %psr,%l0; \
++	nop; \
++	nop;
++
++/* Software trap for Sparc-netbsd system calls. */
++#define NETBSD_SYSCALL_TRAP \
++        sethi %hi(C_LABEL(sys_call_table)), %l7; \
++        or %l7, %lo(C_LABEL(sys_call_table)), %l7; \
++        b bsd_syscall; \
++        rd %psr, %l0;
++
++/* The Get Condition Codes software trap for userland. */
++#define GETCC_TRAP \
++        b getcc_trap_handler; mov %psr, %l0; nop; nop;
++
++/* The Set Condition Codes software trap for userland. */
++#define SETCC_TRAP \
++        b setcc_trap_handler; mov %psr, %l0; nop; nop;
++
++/* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and
++ * gets handled with another macro.
++ */
++#define TRAP_ENTRY_INTERRUPT(int_level) \
++        mov int_level, %l7; rd %psr, %l0; b real_irq_entry; rd %wim, %l3;
++
++/* NMI's (Non Maskable Interrupts) are special, you can't keep them
++ * from coming in, and basically if you get one, the shows over. ;(
++ * On the sun4c they are usually asynchronous memory errors, on the
++ * the sun4m they could be either due to mem errors or a software
++ * initiated interrupt from the prom/kern on an SMP box saying "I
++ * command you to do CPU tricks, read your mailbox for more info."
++ */
++#define NMI_TRAP \
++        rd %wim, %l3; b linux_trap_nmi_sun4c; mov %psr, %l0; nop;
++
++#endif
++
++/* Window overflows/underflows are special and we need to try to be as
++ * efficient as possible here....
++ */
++#define WINDOW_SPILL \
++        rd %psr, %l0; rd %wim, %l3; b spill_window_entry; nop;
++
++#define WINDOW_FILL \
++        rd %psr, %l0; rd %wim, %l3; b fill_window_entry; nop;
++
++#define STUB_TRAP	ba stub_trap; nop; nop; nop;
++
++#define TRAP_ENTRY(a,b)		STUB_TRAP
++#define SKIP_TRAP(a,b)		STUB_TRAP
++#define SUNOS_SYSCALL_TRAP	STUB_TRAP
++#define SOLARIS_SYSCALL_TRAP	STUB_TRAP
++#define NETBSD_SYSCALL_TRAP	STUB_TRAP
++#define LINUX_SYSCALL_TRAP	STUB_TRAP
++#define BREAKPOINT_TRAP		STUB_TRAP
++#define NMI_TRAP		STUB_TRAP
++#define GETCC_TRAP		STUB_TRAP
++#define SETCC_TRAP		STUB_TRAP
++#define BAD_TRAP(n)		STUB_TRAP
++#define	TRAP_ENTRY_INTERRUPT(i)		STUB_TRAP
++#define	INDIRECT_SOLARIS_SYSCALL(i)	STUB_TRAP
++
++	.section ".text"
++	.globl start, _start
++_start:
++start:
++	.globl spill_window_entry, fill_window_entry
++C_LABEL(trapbase):
++t_zero:	b goprol; nop; nop; nop;
++t_tflt:	SRMMU_TFAULT                        /* Inst. Access Exception        */
++t_bins:	TRAP_ENTRY(0x2, bad_instruction)    /* Illegal Instruction           */
++t_pins:	TRAP_ENTRY(0x3, priv_instruction)   /* Privileged Instruction        */
++t_fpd:	TRAP_ENTRY(0x4, fpd_trap_handler)   /* Floating Point Disabled       */
++t_wovf:	WINDOW_SPILL                        /* Window Overflow               */
++t_wunf:	WINDOW_FILL                         /* Window Underflow              */
++t_mna:	TRAP_ENTRY(0x7, mna_handler)        /* Memory Address Not Aligned    */
++t_fpe:	TRAP_ENTRY(0x8, fpe_trap_handler)   /* Floating Point Exception      */
++t_dflt:	SRMMU_DFAULT                        /* Data Miss Exception           */
++t_tio:	TRAP_ENTRY(0xa, do_tag_overflow)    /* Tagged Instruction Ovrflw     */
++t_wpt:	TRAP_ENTRY(0xb, do_watchpoint)      /* Watchpoint Detected           */
++t_badc:	BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10)
++t_irq1:	TRAP_ENTRY_INTERRUPT(1)             /* IRQ Software/SBUS Level 1     */
++t_irq2:	TRAP_ENTRY_INTERRUPT(2)             /* IRQ SBUS Level 2              */
++t_irq3:	TRAP_ENTRY_INTERRUPT(3)             /* IRQ SCSI/DMA/SBUS Level 3     */
++t_irq4:	TRAP_ENTRY_INTERRUPT(4)             /* IRQ Software Level 4          */
++t_irq5:	TRAP_ENTRY_INTERRUPT(5)             /* IRQ SBUS/Ethernet Level 5     */
++t_irq6:	TRAP_ENTRY_INTERRUPT(6)             /* IRQ Software Level 6          */
++t_irq7:	TRAP_ENTRY_INTERRUPT(7)             /* IRQ Video/SBUS Level 5        */
++t_irq8:	TRAP_ENTRY_INTERRUPT(8)             /* IRQ SBUS Level 6              */
++t_irq9:	TRAP_ENTRY_INTERRUPT(9)             /* IRQ SBUS Level 7              */
++t_irq10:TRAP_ENTRY_INTERRUPT(10)            /* IRQ Timer #1 (one we use)     */
++t_irq11:TRAP_ENTRY_INTERRUPT(11)            /* IRQ Floppy Intr.              */
++t_irq12:TRAP_ENTRY_INTERRUPT(12)            /* IRQ Zilog serial chip         */
++t_irq13:TRAP_ENTRY_INTERRUPT(13)            /* IRQ Audio Intr.               */
++t_irq14:TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */
++t_nmi:	NMI_TRAP                            /* Level 15 (NMI)                */
++t_racc:	TRAP_ENTRY(0x20, do_reg_access)     /* General Register Access Error */
++t_iacce:BAD_TRAP(0x21)                      /* Instr Access Error            */
++t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23)
++t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled)    /* Co-Processor Disabled         */
++t_uflsh:SKIP_TRAP(0x25, unimp_flush)        /* Unimplemented FLUSH inst.     */
++t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27)
++t_cpexc:TRAP_ENTRY(0x28, do_cp_exception)   /* Co-Processor Exception        */
++t_dacce:SRMMU_DFAULT                        /* Data Access Error             */
++t_hwdz:	TRAP_ENTRY(0x2a, do_hw_divzero)     /* Division by zero, you lose... */
++t_dserr:BAD_TRAP(0x2b)                      /* Data Store Error              */
++t_daccm:BAD_TRAP(0x2c)                      /* Data Access MMU-Miss          */
++t_bad2d:               BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f)
++        BAD_TRAP(0x30) BAD_TRAP(0x31) BAD_TRAP(0x32) BAD_TRAP(0x33)
++        BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) BAD_TRAP(0x37)
++        BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b)
++t_iaccm:BAD_TRAP(0x3c)                      /* Instr Access MMU-Miss         */
++ BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f)
++ BAD_TRAP(0x40) BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43)
++ BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46) BAD_TRAP(0x47)
++ BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b)
++ BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f)
++ BAD_TRAP(0x50) BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53)
++ BAD_TRAP(0x54) BAD_TRAP(0x55) BAD_TRAP(0x56) BAD_TRAP(0x57)
++ BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) BAD_TRAP(0x5b)
++ BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f)
++ BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63)
++ BAD_TRAP(0x64) BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67)
++ BAD_TRAP(0x68) BAD_TRAP(0x69) BAD_TRAP(0x6a) BAD_TRAP(0x6b)
++ BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) BAD_TRAP(0x6f)
++ BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73)
++ BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77)
++ BAD_TRAP(0x78) BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b)
++ BAD_TRAP(0x7c) BAD_TRAP(0x7d) BAD_TRAP(0x7e) BAD_TRAP(0x7f)
++t_sunos:SUNOS_SYSCALL_TRAP                  /* SunOS System Call             */
++t_sbkpt:BREAKPOINT_TRAP                     /* Software Breakpoint/KGDB      */
++t_divz:	BAD_TRAP(0x82)                      /* Divide by zero trap           */
++t_flwin:TRAP_ENTRY(0x83, do_flush_windows)  /* Flush Windows Trap            */
++t_clwin:BAD_TRAP(0x84)                      /* Clean Windows Trap            */
++t_rchk:	BAD_TRAP(0x85)                      /* Range Check                   */
++t_funal:BAD_TRAP(0x86)                      /* Fix Unaligned Access Trap     */
++t_iovf:	BAD_TRAP(0x87)                      /* Integer Overflow Trap         */
++t_slowl:SOLARIS_SYSCALL_TRAP                /* Slowaris System Call          */
++t_netbs:NETBSD_SYSCALL_TRAP                 /* Net-B.S. System Call          */
++t_bad8a:BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d)
++ BAD_TRAP(0x8e) BAD_TRAP(0x8f)
++t_linux:LINUX_SYSCALL_TRAP                  /* Linux System Call             */
++t_bad91:BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93)
++ BAD_TRAP(0x94) BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97)
++ BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f)
++t_getcc:GETCC_TRAP                          /* Get Condition Codes           */
++t_setcc:SETCC_TRAP                          /* Set Condition Codes           */
++t_bada2:BAD_TRAP(0xa2) BAD_TRAP(0xa3)
++ BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
++t_slowi:INDIRECT_SOLARIS_SYSCALL(156)
++ BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
++ BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf)
++ BAD_TRAP(0xb0) BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3)
++ BAD_TRAP(0xb4) BAD_TRAP(0xb5) BAD_TRAP(0xb6) BAD_TRAP(0xb7)
++ BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) BAD_TRAP(0xbb)
++ BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf)
++t_badc0:BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3)
++ BAD_TRAP(0xc4) BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7)
++ BAD_TRAP(0xc8) BAD_TRAP(0xc9) BAD_TRAP(0xca) BAD_TRAP(0xcb)
++ BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) BAD_TRAP(0xcf)
++ BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3)
++t_badd4:BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7)
++ BAD_TRAP(0xd8) BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb)
++ BAD_TRAP(0xdc) BAD_TRAP(0xdd) BAD_TRAP(0xde) BAD_TRAP(0xdf)
++ BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) BAD_TRAP(0xe3)
++ BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7)
++t_bade8:BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb)
++ BAD_TRAP(0xec) BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef)
++ BAD_TRAP(0xf0) BAD_TRAP(0xf1) BAD_TRAP(0xf2) BAD_TRAP(0xf3)
++ BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) BAD_TRAP(0xf7)
++ BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
++t_badfc:BAD_TRAP(0xfc) BAD_TRAP(0xfd)
++dbtrap:	BAD_TRAP(0xfe)                      /* Debugger/PROM breakpoint #1   */
++dbtrap2:BAD_TRAP(0xff)                      /* Debugger/PROM breakpoint #2   */	
++
++stub_trap:
++   set (PHYS_JJ_TCX_FB + 0xbf0), %g5	/* 2 cells from side */
++   set 0x00ffffff, %g4
++   sta %g4, [%g5] ASI_M_BYPASS
++1:	ba 1b; nop
++
++	.section ".bss"
++	.align 8
++bss_start:
++	.align	0x1000		! PAGE_SIZE
++	.globl C_LABEL(bootup_user_stack)
++        .type   bootup_user_stack,#object
++        .size   bootup_user_stack,0x2000
++C_LABEL(bootup_user_stack):		.skip 0x2000
++
++	.section ".text"
++
++goprol:
++	! %g1 contains end of memory
++	! map PROLDATA to PROLBASE+PROLSIZE to end of ram
++	set	PROLSIZE+0x1000-PROLDATA+PROLBASE, %g2	! add 0x1000 for temp tables
++	sub	%g1, %g2, %g2			! start of private memory
++	srl	%g2, 0x4, %g7			! ctx table at s+0x0
++	add	%g2, 0x400, %g3			! l1 table at s+0x400
++	srl	%g3, 0x4, %g3
++	or	%g3, 0x1, %g3
++	sta	%g3, [%g2] ASI_M_BYPASS
++	add	%g2, 0x400, %g2			! s+0x400
++	add	%g2, 0x800, %g3			! l2 table for ram (00xxxxxx) at s+0x800
++	srl	%g3, 0x4, %g3
++	or	%g3, 0x1, %g3
++	sta	%g3, [%g2] ASI_M_BYPASS
++	add	%g2, 0x500, %g3			! l2 table for rom (ffxxxxxx) at s+0x900
++	add	%g2, 0x3fc, %g2			! s+0x7fc
++	srl	%g3, 0x4, %g3
++	or	%g3, 0x1, %g3
++	sta	%g3, [%g2] ASI_M_BYPASS
++	add	%g2, 0x4, %g2			! s+0x800
++	set	((7 << 2) | 2), %g3		! 7 = U: --- S: RWX (main memory)
++	sta	%g3, [%g2] ASI_M_BYPASS
++	add	%g2, 0x200, %g3			! l3 table for rom at s+0xa00
++	add	%g2, 0x1d0, %g2			! s+0x9d0
++	srl	%g3, 0x4, %g3
++	or	%g3, 0x1, %g3
++	sta	%g3, [%g2] ASI_M_BYPASS
++	add	%g2, 0x30, %g2			! s+0xa00
++
++	set	PROLBASE, %g3
++	set	0x1000, %g5
++	set	(PROLDATA-PROLBASE)/0x1000, %g6 ! # of .text pages
++1:	srl	%g3, 0x4, %g4
++	or	%g4, ((7 << 2) | 2), %g4	! 4 = U: --X S: --X (rom, execute only)
++	sta	%g4, [%g2] ASI_M_BYPASS
++	add	%g2, 4, %g2
++	add	%g3, %g5, %g3
++	deccc	%g6
++	bne	1b
++	 nop
++#if 0	
++	set	(PROLDATA-PROLRODATA)/0x1000, %g6 ! # of .rodata pages
++1:	srl	%g3, 0x4, %g4
++	or	%g4, ((0 << 2) | 2), %g4	! 0 = U: R-- S: R-- (rom, read only)
++	sta	%g4, [%g2] ASI_M_BYPASS
++	add	%g2, 4, %g2
++	add	%g3, %g5, %g3
++	deccc	%g6
++	bne	1b
++	 nop
++#endif
++	set	(PROLBASE+PROLSIZE-PROLDATA)/0x1000, %g6 ! # of .bss pages
++	set	0x1000, %g4
++	sll	%g7, 0x4, %g3
++	add	%g4, %g3, %g3
++1:	srl	%g3, 0x4, %g4
++	or	%g4, ((7 << 2) | 2), %g4        ! 5 = U: R-- S: RW- (data area, read/write)
++	sta	%g4, [%g2] ASI_M_BYPASS
++	add	%g2, 4, %g2
++	add	%g3, %g5, %g3
++	deccc	%g6
++	bne	1b
++	 nop
++
++	mov	%g1, %g3
++
++	set     AC_M_CTPR, %g2
++	sta     %g7, [%g2] ASI_M_MMUREGS	! set ctx table ptr
++	set	1, %g1
++	sta     %g1, [%g0] ASI_M_MMUREGS	! enable mmu
++
++	/*
++	 * The code which enables traps is a simplified version of
++	 * kernel head.S.
++	 *
++	 * We know number of windows as 8 so we do not calculate them.
++	 * The deadwood is here for any case.
++	 */
++
++	/* Turn on Supervisor, EnableFloating, and all the PIL bits.
++	 * Also puts us in register window zero with traps off.
++	 */
++	set	(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
++	wr	%g2, 0x0, %psr
++	WRITE_PAUSE
++
++	/* I want a kernel stack NOW! */
++	set	C_LABEL(bootup_user_stack), %g1
++	set	(0x2000 - REGWIN_SZ), %g2
++	add	%g1, %g2, %sp
++	mov	0, %fp			/* And for good luck */
++
++	/* Zero out our BSS section. */
++	set	C_LABEL(bss_start) , %o0	! First address of BSS
++	set	C_LABEL(end) , %o1		! Last address of BSS
++	ba	2f
++	 nop
++1:
++	st	%g0, [%o0]
++2:
++	subcc	%o0, %o1, %g0
++	bl	1b
++	 add	%o0, 0x4, %o0
++
++	sethi	%hi( C_LABEL(ram_size) ), %o0
++	st	%g3, [%o0 + %lo( C_LABEL(ram_size) )]
++
++	mov	2, %g1
++	wr	%g1, 0x0, %wim			! make window 1 invalid
++	WRITE_PAUSE
++
++#if 0
++	wr  %g0, 0x0, %wim
++	WRITE_PAUSE
++	save
++	rd  %psr, %g3
++	restore
++	and  %g3, PSR_CWP, %g3
++	add  %g3, 0x1, %g3
++#else
++	or	%g0, 8, %g3
++#endif
++
++#if 0
++	sethi	%hi( C_LABEL(cputyp) ), %o0
++	st	%g7, [%o0 + %lo( C_LABEL(cputyp) )]
++
++	sethi	%hi( C_LABEL(nwindows) ), %g4
++	st	%g3, [%g4 + %lo( C_LABEL(nwindows) )]
++
++	sub	%g3, 0x1, %g3
++	sethi	%hi( C_LABEL(nwindowsm1) ), %g4
++	st	%g3, [%g4 + %lo( C_LABEL(nwindowsm1) )]
++#endif
++
++	/* Here we go, start using Linux's trap table... */
++	set	C_LABEL(trapbase), %g3
++	wr	%g3, 0x0, %tbr
++	WRITE_PAUSE
++
++	/* Finally, turn on traps so that we can call c-code. */
++	rd	%psr, %g3
++	wr	%g3, 0x0, %psr
++	WRITE_PAUSE
++
++	wr	%g3, PSR_ET, %psr
++	WRITE_PAUSE
++
++	.globl prolmain
++	call C_LABEL(prolmain)
++	 nop
++
++3:
++	b       3b
++	 nop
++
++/*
++ * Memory access trap handler
++ *   %l0  program %psr from trap table entry
++ *   %l1  program %pc from hardware
++ *   %l2  program %npc from hardware
++ *   %l3  program %wim from trap table entry
++ *   %l4
++ *   %l5
++ *   %l6
++ *   %l7  text flag from trap table entry
++ */
++
++	.section ".text"
++	.globl srmmu_fault
++C_LABEL(srmmu_fault):
++
++	set AC_M_SFAR, %l6
++	set AC_M_SFSR, %l5
++	lda [%l6] ASI_M_MMUREGS, %l6
++	lda [%l5] ASI_M_MMUREGS, %l5
++
++	set ignore_fault, %l5
++	ld [%l5], %l5
++	subcc %l5, %g0, %g0		/* NULL pointer trap faults always */
++	be 3f
++	 nop
++	subcc %l5, %l6, %g0
++	be 2f
++	 nop
++3:
++
++   set (PHYS_JJ_TCX_FB + 0xbf0), %g5	/* 2 cells from side */
++   set 0x00ffffff, %g4
++   sta %g4, [%g5] ASI_M_BYPASS
++   add %g5, 8, %g5			/* On right side */
++   sta %g4, [%g5] ASI_M_BYPASS
++1:	ba 1b; nop
++
++2:
++	set C_LABEL(fault_ignored), %l5
++	mov 1, %l6
++	st %l6, [%l5]
++
++	/*
++	 * Skip the faulting instruction.
++	 * I think it works when next instruction is a branch even.
++	 */
++	or %l2, 0, %l1
++	add %l2, 4, %l2
++
++	wr %l0, 0, %psr
++	WRITE_PAUSE
++	jmp %l1
++	rett %l2
++
++/*
++ * Slow external versions of st_bypass and ld_bypass.
++ * rconsole.c uses inlines. We call these in places which are not speed
++ * critical, to avoid compiler bugs.
++ */
++	.globl C_LABEL(st_bypass)
++C_LABEL(st_bypass):
++	retl
++	 sta %o1, [%o0] ASI_M_BYPASS
++	.globl C_LABEL(ld_bypass)
++C_LABEL(ld_bypass):
++	retl
++	 lda [%o0] ASI_M_BYPASS, %o0
++	.globl C_LABEL(sth_bypass)
++C_LABEL(sth_bypass):
++	retl
++	 stha %o1, [%o0] ASI_M_BYPASS
++	.globl C_LABEL(ldh_bypass)
++C_LABEL(ldh_bypass):
++	retl
++	 lduha [%o0] ASI_M_BYPASS, %o0
++	.globl C_LABEL(stb_bypass)
++C_LABEL(stb_bypass):
++	retl
++	 stba %o1, [%o0] ASI_M_BYPASS
++	.globl C_LABEL(ldb_bypass)
++C_LABEL(ldb_bypass):
++	retl
++	 lduba [%o0] ASI_M_BYPASS, %o0
+diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c
+--- proll_18.orig/qemu/main.c	1970-01-01 00:00:00.000000000 +0000
++++ proll-patch4/qemu/main.c	2004-11-23 19:05:34.000000000 +0000
+@@ -0,0 +1,178 @@
++/**
++ ** Proll (PROM replacement)
++ ** Copyright 1999 Pete Zaitcev
++ ** This code is licensed under GNU General Public License.
++ **/
++#include <stdarg.h>
++
++// #include <asm/contregs.h>
++#include <asi.h>
++#include "pgtsrmmu.h"
++#include "iommu.h"		/* Typical SBus IOMMU for sun4m */
++#include "phys_jj.h"
++#include "vconsole.h"
++#include "version.h"
++#include <general.h>		/* __P() */
++#include <net.h>		/* init_net() */
++#include <romlib.h>		/* we are a provider for part of this. */
++#include <netpriv.h>		/* myipaddr */
++#include <arpa.h>
++#include <system.h>		/* 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 <asm-sparc/openprom.h>.
++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 <openprom.h>
++#include <general.h>
++#include <romlib.h>
++#include <system.h>
++#include <vconsole.h>
++#include "phys_jj.h"
++
++struct property {
++	const char *name;
++	const char *value;
++	const int length;
++};
++
++struct node {
++	const struct property *properties;
++	/* short */ const int sibling;
++	/* short */ const int child;
++};
++
++static int obp_nextnode(int node);
++static int obp_child(int node);
++static int obp_proplen(int node, char *name);
++static int obp_getprop(int node, char *name, char *val);
++static int obp_setprop(int node, char *name, char *val, int len);
++static const char *obp_nextprop(int node, char *name);
++
++static char obp_idprom[IDPROM_SIZE];
++static const struct property null_properties = { NULL, NULL, -1 };
++static const int prop_true = -1;
++
++static const struct property propv_root[] = {
++	{"name",	"SUNW,JavaStation-1", sizeof("SUNW,JavaStation-1") },
++	{"idprom",	obp_idprom, IDPROM_SIZE},
++	{"banner-name", "JavaStation", sizeof("JavaStation")},
++	{"compatible",	"sun4m", 6},
++	{NULL, NULL, -1}
++};
++
++static const int prop_iommu_reg[] = {
++	0x0, 0x10000000, 0x00000300,
++};
++static const struct property propv_iommu[] = {
++	{"name",	"iommu", sizeof("iommu")},
++	{"reg",		(char*)&prop_iommu_reg[0], sizeof(prop_iommu_reg) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_sbus_ranges[] = {
++	0x0, 0x0, 0x0, 0x30000000, 0x10000000,
++	0x1, 0x0, 0x0, 0x40000000, 0x10000000,
++	0x2, 0x0, 0x0, 0x50000000, 0x10000000,
++	0x3, 0x0, 0x0, 0x60000000, 0x10000000,
++	0x4, 0x0, 0x0, 0x70000000, 0x10000000,
++};
++static const struct property propv_sbus[] = {
++	{"name",	"sbus", 5},
++	{"ranges",	(char*)&prop_sbus_ranges[0], sizeof(prop_sbus_ranges)},
++	{NULL, NULL, -1}
++};
++
++static const int prop_tcx_regs[] = {
++	0x2, 0x00800000, 0x00100000,
++	0x2, 0x02000000, 0x00000001,
++	0x2, 0x04000000, 0x00800000,
++	0x2, 0x06000000, 0x00800000,
++	0x2, 0x0a000000, 0x00000001,
++	0x2, 0x0c000000, 0x00000001,
++	0x2, 0x0e000000, 0x00000001,
++	0x2, 0x00700000, 0x00001000,
++	0x2, 0x00200000, 0x00000004,
++	0x2, 0x00300000, 0x0000081c,
++	0x2, 0x00000000, 0x00010000,
++	0x2, 0x00240000, 0x00000004,
++	0x2, 0x00280000, 0x00000001,
++};
++
++#if 1	/* Zaitcev */
++static const int pixfreq = 0x03dfd240;
++static const int hbporch = 0xa0;
++static const int vfreq = 0x3c;
++#endif
++#if 0	/* Kevin Boone - 70Hz refresh */
++static const int pixfreq = 0x047868C0;
++static const int hbporch = 0x90;
++static const int vfreq = 0x46;
++#endif
++
++static const int vbporch = 0x1d;
++static const int vsync = 0x6;
++static const int hsync = 0x88;
++static const int vfporch = 0x3;
++static const int hfporch = 0x18;
++static const int height = 0x300;
++static const int width = 0x400;
++static const int linebytes = 0x400;
++static const int depth = 8;
++static const int tcx_intr[] = { 5, 0 };
++static const int tcx_interrupts = 5;
++static const struct property propv_sbus_tcx[] = {
++	{"name",	"SUNW,tcx", sizeof("SUNW,tcx")},
++	{"vbporch",	(char*)&vbporch, sizeof(int)},
++	{"hbporch",	(char*)&hbporch, sizeof(int)},
++	{"vsync",	(char*)&vsync, sizeof(int)},
++	{"hsync",	(char*)&hsync, sizeof(int)},
++	{"vfporch",	(char*)&vfporch, sizeof(int)},
++	{"hfporch",	(char*)&hfporch, sizeof(int)},
++	{"pixfreq",	(char*)&pixfreq, sizeof(int)},
++	{"vfreq",	(char*)&vfreq, sizeof(int)},
++	{"height",	(char*)&height, sizeof(int)},
++	{"width",	(char*)&width, sizeof(int)},
++	{"linebytes",	(char*)&linebytes, sizeof(int)},
++	{"depth",	(char*)&depth, sizeof(int)},
++	{"reg",		(char*)&prop_tcx_regs[0], sizeof(prop_tcx_regs)},
++	{"tcx-8-bit",	(char*)&prop_true, 0},
++	{"intr",	(char*)&tcx_intr[0], sizeof(tcx_intr)},
++	{"interrupts",	(char*)&tcx_interrupts, sizeof(tcx_interrupts)},
++	{"device_type",	"display", sizeof("display")},
++	{NULL, NULL, -1}
++};
++
++static const int prop_cs4231_reg[] = {
++	0x3, 0x0C000000, 0x00000040
++};
++static const int cs4231_interrupts = 5;
++static const int cs4231_intr[] = { 5, 0 };
++
++static const struct property propv_sbus_cs4231[] = {
++	{"name",	"SUNW,CS4231", sizeof("SUNW,CS4231") },
++	{"intr",	(char*)&cs4231_intr[0], sizeof(cs4231_intr) },
++	{"interrupts",  (char*)&cs4231_interrupts, sizeof(cs4231_interrupts) },	
++	{"reg",		(char*)&prop_cs4231_reg[0], sizeof(prop_cs4231_reg) },
++	{"device_type", "serial", sizeof("serial") },
++	{"alias",	"audio", sizeof("audio") },
++	{NULL, NULL, -1}
++};
++
++static const int cpu_nctx = NCTX_SWIFT;
++static const int cpu_cache_line_size = 0x20;
++static const int cpu_cache_nlines = 0x200;
++static const struct property propv_cpu[] = {
++	{"name",	"STP1012PGA", sizeof("STP1012PGA") },
++	{"device_type",	"cpu", 4 },
++	{"mmu-nctx",	(char*)&cpu_nctx, sizeof(int)},
++	{"cache-line-size",	(char*)&cpu_cache_line_size, sizeof(int)},
++	{"cache-nlines",	(char*)&cpu_cache_nlines, sizeof(int)},
++	{NULL, NULL, -1}
++};
++
++static const int prop_obio_ranges[] = {
++	0x0, 0x0, 0x0, 0x71000000, 0x01000000,
++};
++static const struct property propv_obio[] = {
++	{"name",	"obio", 5 },
++	{"ranges",	(char*)&prop_obio_ranges[0], sizeof(prop_obio_ranges) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_auxio_reg[] = {
++	0x0, 0x00900000, 0x00000001,
++};
++static const struct property propv_obio_auxio[] = {
++	{"name",	"auxio", sizeof("auxio") },
++	{"reg",		(char*)&prop_auxio_reg[0], sizeof(prop_auxio_reg) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_int_reg[] = {
++	0x0, 0x00e00000, 0x00000010,
++	0x0, 0x00e10000, 0x00000010,
++};
++static const struct property propv_obio_int[] = {
++	{"name",	"interrupt", sizeof("interrupt")},
++	{"reg",		(char*)&prop_int_reg[0], sizeof(prop_int_reg) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_cnt_reg[] = {
++	0x0, 0x00d00000, 0x00000010,
++	0x0, 0x00d10000, 0x00000010,
++};
++static const struct property propv_obio_cnt[] = {
++	{"name",	"counter", sizeof("counter")},
++	{"reg",		(char*)&prop_cnt_reg[0], sizeof(prop_cnt_reg) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_eeprom_reg[] = {
++	0x0, 0x00200000, 0x00002000,
++};
++static const struct property propv_obio_eep[] = {
++	{"name",	"eeprom", sizeof("eeprom")},
++	{"reg",		(char*)&prop_eeprom_reg[0], sizeof(prop_eeprom_reg) },
++	{"model",	"mk48t08", sizeof("mk48t08")},
++	{NULL, NULL, -1}
++};
++
++static const int prop_su_reg[] = {
++	0x0, 0x003002f8, 0x00000008,
++};
++static const struct property propv_obio_su[] = {
++	{"name",	"su", sizeof("su")},
++	{"reg",		(char*)&prop_su_reg[0], sizeof(prop_su_reg) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_zs_intr[] = { 0x26, 0x0 };
++static const int prop_zs_reg[] = {
++	0x4, 0x00000000, 0x0000000f,
++};
++static const int prop_zs_slave[] = { 0x1 };
++static const struct property propv_obio_zs[] = {
++	{"name",	"zs", sizeof("zs")},
++	{"reg",		(char*)&prop_zs_reg[0], sizeof(prop_zs_reg) },
++	{"reg",		(char*)&prop_zs_slave[0], sizeof(prop_zs_slave) },
++	{"device_type", "serial", sizeof("serial") },
++	{NULL, NULL, -1}
++};
++
++static const int prop_zs1_intr[] = { 0x26, 0x0 };
++static const int prop_zs1_reg[] = {
++	0x4, 0x00100000, 0x0000000f,
++};
++static const int prop_zs1_slave[] = { 0x0 };
++static const struct property propv_obio_zs1[] = {
++	{"name",	"zs", sizeof("zs")},
++	{"reg",		(char*)&prop_zs1_reg[0], sizeof(prop_zs1_reg) },
++	{"reg",		(char*)&prop_zs1_slave[0], sizeof(prop_zs1_slave) },
++	{"device_type", "serial", sizeof("serial") },
++	{NULL, NULL, -1}
++};
++
++static const int prop_ledma_reg[] = {
++	0x4, 0x08400010, 0x00000020,
++};
++static const int prop_ledma_burst = 0x3f;
++static const struct property propv_sbus_ledma[] = {
++	{"name",	"ledma", sizeof("ledma")},
++	{"reg",		(char*)&prop_ledma_reg[0], sizeof(prop_ledma_reg) },
++	{"burst-sizes",	(char*)&prop_ledma_burst, sizeof(int) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_le_reg[] = {
++	0x4, 0x08c00000, 0x00000004,
++};
++static const int prop_le_busmaster_regval = 0x7;
++static const int prop_le_intr[] = { 0x26, 0x0 };
++static const struct property propv_sbus_ledma_le[] = {
++	{"name",	"le", sizeof("le")},
++	{"reg",		(char*)&prop_le_reg[0], sizeof(prop_le_reg) },
++	{"busmaster-regval",	(char*)&prop_le_busmaster_regval, sizeof(int)},
++	{"intr",	(char*)&prop_le_intr[0], sizeof(prop_le_intr) },
++	{NULL, NULL, -1}
++};
++
++static const struct node nodes[] = {
++	{ &null_properties,	 1,  0 }, /* 0 = big brother of root */
++	{ propv_root,		 0,  2 }, /*  1 "/" */
++	{ propv_iommu,		 8,  3 }, /*  2 "/iommu" */
++	{ propv_sbus,		 0,  4 }, /*  3 "/iommu/sbus" */
++	{ propv_sbus_tcx,	 5,  0 }, /*  4 "/iommu/sbus/SUNW,tcx" */
++	{ propv_sbus_ledma,	 7,  6 }, /*  5 "/iommu/sbus/ledma" */
++	{ propv_sbus_ledma_le,	 0,  0 }, /*  6 "/iommu/sbus/ledma/le" */
++	{ propv_sbus_cs4231,	 0,  0 }, /*  7 "/iommu/sbus/SUNW,CS4231 */
++	{ propv_cpu,		 9,  0 }, /*  8 "/STP1012PGA" */
++	{ propv_obio,		 0, 10 }, /*  9 "/obio" */
++	{ propv_obio_int,	11,  0 }, /* 10 "/obio/interrupt" */
++	{ propv_obio_cnt,	12,  0 }, /* 11 "/obio/counter" */
++	{ propv_obio_eep,	13,  0 }, /* 12 "/obio/eeprom" */
++	{ propv_obio_su,	14,  0 }, /* 13 "/obio/su" */
++	{ propv_obio_auxio,	 0,  0 }, /* 14 "/obio/auxio" */
++	{ propv_obio_zs,	 0,  0 }, /* 14 "/obio/zs@0,0" */
++	{ propv_obio_zs1,	 0,  0 }, /* 14 "/obio/zs@0,100000" */
++};
++
++static struct linux_mlist_v0 totphys[MAX_BANKS];
++static struct linux_mlist_v0 totmap[1];
++static struct linux_mlist_v0 totavail[MAX_BANKS];
++
++static struct linux_mlist_v0 *ptphys;
++static struct linux_mlist_v0 *ptmap;
++static struct linux_mlist_v0 *ptavail;
++
++static const struct linux_nodeops nodeops0 = {
++        obp_nextnode,	/* int (*no_nextnode)(int node); */
++        obp_child,	/* int (*no_child)(int node); */
++        obp_proplen,	/* int (*no_proplen)(int node, char *name); */
++        obp_getprop,	/* int (*no_getprop)(int node,char *name,char *val); */
++        obp_setprop,	/* int (*no_setprop)(int node, char *name,
++				 char *val, int len); */
++        obp_nextprop	/* char * (*no_nextprop)(int node, char *name); */
++};
++
++static const char arg_nfsroot[] = "console=ttyS0 ip=bootp root=nfs";
++
++static const struct linux_arguments_v0 obp_arg = {
++	{ "le()", arg_nfsroot, NULL, NULL, NULL, NULL, NULL, NULL },
++	{ "" },
++	{ 'l', 'e' },  0, 0, 0, NULL,
++	NULL
++};
++static const struct linux_arguments_v0 * const obp_argp = &obp_arg;
++
++static const void * const synch_hook = NULL;
++#if 0
++static const char obp_stdin = PROMDEV_KBD;
++static const char obp_stdout = PROMDEV_SCREEN;
++#else
++static const char obp_stdin = PROMDEV_TTYA;
++static const char obp_stdout = PROMDEV_TTYA;
++#endif
++
++static int obp_nbgetchar(void);
++static int obp_nbputchar(int ch);
++static void obp_reboot(char *);
++static void obp_abort(void);
++static void obp_halt(void);
++static int obp_devopen(char *str);
++static int obp_devclose(int dev_desc);
++static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf);
++
++static void doublewalk(unsigned ptab1, unsigned va)
++{
++unsigned int proc_tablewalk(int ctx, unsigned int va);
++unsigned int mem_tablewalk(unsigned int pa, unsigned int va);
++
++	proc_tablewalk(0, va);
++	if (ptab1 != 0) mem_tablewalk(ptab1, va);
++}
++
 +#ifdef ORIG
- #if 0 /* RARP */
- 	if (rarp() != 0) fatal();
- 	/* printrarp(); */
-@@ -117,13 +118,20 @@
- 	xtoa(myipaddr, fname, 8);
- 	if (load(boot_rec.bp_siaddr, fname) != 0) fatal();
++static const struct linux_romvec romvec0 = {
++	LINUX_OPPROM_MAGIC,		/* pv_magic_cookie */
++	0,				/* pv_romvers - Format selector! */
++	77,				/* pv_plugin_revision */
++	0x10203,			/* pv_printrev */
++	{				/* pv_v0mem */
++		&ptphys,		/* v0_totphys */
++		&ptmap,			/* v0_prommap */
++		&ptavail		/* v0_available */
++	},
++        &nodeops0,			/* struct linux_nodeops *pv_nodeops; */
++        (void*)doublewalk, /* P3 */	/* char **pv_bootstr; */
++	{				/* struct linux_dev_v0_funcs pv_v0devops; */
++		&obp_devopen,		/* v0_devopen */
++		&obp_devclose,		/* v0_devclose */
++		&obp_rdblkdev,		/* v0_rdblkdev */
++		NULL,			/* v0_wrblkdev */
++		NULL,			/* v0_wrnetdev */
++		NULL,			/* v0_rdnetdev */
++		NULL,			/* v0_rdchardev */
++		NULL,			/* v0_wrchardev */
++		NULL			/* v0_seekdev */
++	},
++        &obp_stdin,			/* char *pv_stdin */
++        &obp_stdout,			/* char *pv_stdout; */
++        obp_nbgetchar,			/* int (*pv_getchar)(void); */
++        obp_nbputchar,			/* void (*pv_putchar)(int ch); */
++        obp_nbgetchar,			/* int (*pv_nbgetchar)(void); */
++        obp_nbputchar,			/* int (*pv_nbputchar)(int ch); */
++        NULL,			/* void (*pv_putstr)(char *str, int len); */
++        obp_reboot,			/* void (*pv_reboot)(char *bootstr); */
++        NULL,		/* void (*pv_printf)(__const__ char *fmt, ...); */
++        obp_abort,			/* void (*pv_abort)(void); */
++        NULL,				/* __volatile__ int *pv_ticks; */
++        obp_halt,			/* void (*pv_halt)(void); */
++        (void *)&synch_hook,		/* void (**pv_synchook)(void); */
++
++#if 0
++        /* Evaluate a forth string, not different proto for V0 and V2->up. */
++        union {
++                void (*v0_eval)(int len, char *str);
++                void (*v2_eval)(char *str);
++        } pv_fortheval;
++#endif
++	{ 0 },			/* pv_fortheval */
++
++        &obp_argp,		/* struct linux_arguments_v0 **pv_v0bootargs; */
++	NULL,			/* pv_enaddr */
++	{			/* pv_v2bootargs */
++        	NULL,		/* char **bootpath; */
++		NULL,		/* char **bootargs; */
++		NULL,		/* fd_stdin; */
++		NULL,		/* fd_stdout */
++	},
++	{			/* pv_v2devops */
++        	NULL,		/* v2_inst2pkg */
++        	NULL,		/* v2_dumb_mem_alloc */
++        	NULL,		/* v2_dumb_mem_free */
++        	NULL,		/* v2_dumb_mmap */
++        	NULL,		/* v2_dumb_munmap */
++        	NULL,		/* v2_dev_open */
++        	NULL,		/* v2_dev_close */
++        	NULL,		/* v2_dev_read */
++        	NULL,		/* v2_dev_write */
++        	NULL,		/* v2_dev_seek */
++        	NULL,		/* v2_wheee2 */
++        	NULL,		/* v2_wheee3 */
++	},
++	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* filler[15] */
++        NULL,			/* pv_setctxt */
++        NULL,			/* v3_cpustart */
++        NULL,			/* v3_cpustop */
++        NULL,			/* v3_cpuidle */
++        NULL			/* v3_cpuresume */
++};
++#endif
++
++static struct linux_romvec romvec0;
++
++void *
++init_openprom(int bankc, struct bank *bankv, unsigned hiphybas)
++{
++	int i;
++
++	/*
++	 * Avoid data segment allocations
++	 */
++	ptphys = totphys;
++	ptmap = totmap;
++	ptavail = totavail;
++	/*
++	 * Form memory descriptors.
++	 */
++	for (i = 0; i < bankc; i++) {
++		totphys[i].theres_more = &totphys[i+1];
++		totphys[i].start_adr = (char*) bankv[i].start;
++		totphys[i].num_bytes = bankv[i].length;
++	}
++	totphys[i-1].theres_more = 0;
++
++	/*
++	 * XXX Merged in normal PROM when full banks touch.
++	 */
++	for (i = 0; i < bankc; i++) {
++		unsigned bankbase = bankv[i].start;
++		unsigned banksize = bankv[i].length;
++		if (hiphybas > bankbase &&
++		    hiphybas < bankbase + banksize) {
++			banksize = hiphybas - bankbase;
++		}
++		totavail[i].theres_more = &totavail[i+1];
++		totavail[i].start_adr = (char*) bankbase;
++		totavail[i].num_bytes = banksize;
++	}
++	totavail[i-1].theres_more = 0;
++
++	totmap[0].theres_more = 0;
++	totmap[0].start_adr = (char*) PROLBASE;
++	totmap[0].num_bytes = PROLSIZE;
++
++	/*
++	 * idprom
++	 */
++	bcopy(idprom, obp_idprom, IDPROM_SIZE);
++
++	// Linux wants a R/W romvec table
++	romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC;
++	romvec0.pv_plugin_revision = 77;
++	romvec0.pv_printrev = 0x10203;
++	romvec0.pv_v0mem.v0_totphys = &ptphys;
++	romvec0.pv_v0mem.v0_prommap = &ptmap;
++	romvec0.pv_v0mem.v0_available = &ptavail;
++	romvec0.pv_nodeops = &nodeops0;
++	romvec0.pv_bootstr = (void *)doublewalk;
++	romvec0.pv_stdin = &obp_stdin;
++	romvec0.pv_stdout = &obp_stdout;
++	romvec0.pv_getchar = obp_nbgetchar;
++	romvec0.pv_putchar = obp_nbputchar;
++	romvec0.pv_nbgetchar = obp_nbgetchar;
++	romvec0.pv_nbputchar = obp_nbputchar;
++	romvec0.pv_reboot = obp_reboot;
++	romvec0.pv_abort = obp_abort;
++	romvec0.pv_halt = obp_halt;
++	romvec0.pv_synchook = &synch_hook;
++	romvec0.pv_v0bootargs = &obp_argp;
++	return &romvec0;
++}
++
++static const struct property *find_property(int node,char *name)
++{
++	const struct property *prop = &nodes[node].properties[0];
++	while (prop && prop->name) {
++		if (bcmp(prop->name, name, 128) == 0) return prop;
++		prop++;
++	}
++	return NULL;
++}
++
++static int obp_nextnode(int node)
++{
++	return nodes[node].sibling;
++}
++
++static int obp_child(int node)
++{
++	return nodes[node].child;
++}
++
++static int obp_proplen(int node, char *name)
++{
++	const struct property *prop = find_property(node,name);
++	if (prop) return prop->length;
++	return -1;
++}
++
++static int obp_getprop(int node, char *name, char *value)
++{
++	const struct property *prop;
++
++	prop = find_property(node,name);
++	if (prop) {
++		memcpy(value,prop->value,prop->length);
++		//printk("obp_getprop '%s'= %s\n", name, value);
++		return prop->length;
++	}
++        //printk("obp_getprop: not found\n");
++	return -1;
++}
++
++static int obp_setprop(int node, char *name, char *value, int len)
++{
++	return -1;
++}
++
++static const char *obp_nextprop(int node,char *name)
++{
++	const struct property *prop = find_property(node,name);
++	if (prop) return prop[1].name;
++	return NULL;
++}
++
++#if 0
++static unsigned char calc_idprom_cksum(struct idprom *idprom)
++{
++        unsigned char cksum, i, *ptr = (unsigned char *)idprom;
++
++        for (i = cksum = 0; i <= 0x0E; i++)
++                cksum ^= *ptr++;
++
++        return cksum;
++}
++#endif
++
++static int obp_nbgetchar(void) {
++	return -1;
++}
++
++static int obp_nbputchar(int ch) {
++	extern struct vconterm dp0;
++	char buf = ch;
++
++	/* We do not use printk() in order to reduce stack depth. */
++	vcon_write(&dp0, &buf, 1);
++	return 0;
++}
++
++static void obp_reboot(char *str) {
++	printk("rebooting (%s): not implemented, freezing\n", str);
++	for (;;) {}
++}
++
++static void obp_abort() {
++	printk("abort, freezing\n");
++	for (;;) {}
++}
++
++static void obp_halt() {
++	printk("halt, freezing\n");
++	for (;;) {}
++}
++
++static int obp_devopen(char *str) {
++        //printk("open %s\n", str);
++	return 0;
++}
++
++static int obp_devclose(int dev_desc) {
++        //printk("close %d\n", dev_desc);
++	return 0;
++}
++
++static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf) {
++    //printk("rdblkdev: fd %d, num_blks %d, blk_st %d, buf 0x%x\n", dev_desc, num_blks, blk_st, buf);
++    //buf[8] = 'L';
++    return num_blks;
++}
+diff -ruN proll_18.orig/src/arp.c proll-patch4/src/arp.c
+--- proll_18.orig/src/arp.c	2001-12-24 05:12:31.000000000 +0000
++++ proll-patch4/src/arp.c	2004-11-13 15:50:49.000000000 +0000
+@@ -45,7 +45,7 @@
+ #endif
+ static struct arp_cache arp_list[ARPNUM];	/* ARP address cache	*/
+ static int next_arp;				/* next table entry	*/
+-static t_ipaddr def_gw = IP_ANY;		/* default routing	*/
++static t_ipaddr def_gw;				/* default routing	*/
+ 
+ 
+ 
+@@ -144,7 +144,7 @@
+  * 
+  * Resolve IP address and return pointer to hardware address.
+  */
+-unsigned char *ip_resolve(ip)
++const unsigned char *ip_resolve(ip)
+ t_ipaddr ip;
+ {
+   int i;
+@@ -230,14 +230,11 @@
+  */
+ int init_arp()
+ {
+-  /* Set name of module for error messages */
+-  net_module_name = "arp";
+-
+ #ifndef NOARP
+   /* Register ARP packet type and set send buffer pointer */
+   if ((arpbuf = (struct arphdr *)reg_type(htons(ETH_P_ARP), arp_recv)) == NULL)
+ 	return(FALSE);
  #endif
+-
++  def_gw = IP_ANY;
+   return(TRUE);
+ }
+diff -ruN proll_18.orig/src/arp.h proll-patch4/src/arp.h
+--- proll_18.orig/src/arp.h	1999-03-18 03:39:43.000000000 +0000
++++ proll-patch4/src/arp.h	2004-11-13 15:50:49.000000000 +0000
+@@ -104,7 +104,7 @@
+ extern int init_arp __P((void));
+ 
+ /* Resolve IP address and return pointer to hardware address */
+-extern unsigned char *ip_resolve __P((t_ipaddr ip));
++extern const unsigned char *ip_resolve __P((t_ipaddr ip));
+ 
+ /* Add a new antry to the ARP cache */
+ extern void addcache __P((unsigned char *ha, t_ipaddr ip));
+diff -ruN proll_18.orig/src/hconsole.c proll-patch4/src/hconsole.c
+--- proll_18.orig/src/hconsole.c	2002-07-23 05:52:48.000000000 +0000
++++ proll-patch4/src/hconsole.c	2004-11-13 15:50:49.000000000 +0000
+@@ -42,7 +42,11 @@
+  	 * No probing sequence or argument passing, hardcode everything. XXX
+ 	 */
+ 	raster8_cons_a(q, 768, 1024, (char *)a0);
++#if 1
+ 	raster_cons_2(r, q, 768-(24*11)-1, 1024-(8*80)-1, (24*11), (8*80));
++#else
++	raster_cons_2(r, q, 0, 0, 768, 1024);
 +#endif
+ 	t->r_ = r;
+ 	t->r0_ = q;
+ 	t->f_ = &f_master;
+diff -ruN proll_18.orig/src/lat7_2.bm proll-patch4/src/lat7_2.bm
+--- proll_18.orig/src/lat7_2.bm	1999-02-27 05:48:54.000000000 +0000
++++ proll-patch4/src/lat7_2.bm	2004-11-13 15:50:49.000000000 +0000
+@@ -1,6 +1,6 @@
+ #define lat7_2_width 128
+ #define lat7_2_height 88
+-static unsigned char lat7_2_bits[] = {
++static unsigned const char lat7_2_bits[] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x12, 0x1e, 0x0c, 0x02, 0x70, 0x18,
+    0x22, 0x22, 0x18, 0x00, 0x00, 0x18, 0x18, 0xff, 0x18, 0x00, 0x12, 0x02,
+diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch4/src/lat7_2_swapped.bm
+--- proll_18.orig/src/lat7_2_swapped.bm	1970-01-01 00:00:00.000000000 +0000
++++ proll-patch4/src/lat7_2_swapped.bm	2004-11-13 15:50:49.000000000 +0000
+@@ -0,0 +1,121 @@
++#define lat7_2_width 128
++#define lat7_2_height 88
++static unsigned const char lat7_2_bits[] = {
++   0x00, 0x00, 0x18, 0x3c, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 
++   0x55, 0x00, 0x2a, 0x00, 0x55, 0x00, 0x2a, 0x00, 0x55, 0x00, 0x00, 0x48, 
++   0x48, 0x78, 0x48, 0x5f, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x78, 0x40, 
++   0x70, 0x40, 0x4f, 0x08, 0x0e, 0x08, 0x08, 0x00, 0x00, 0x30, 0x40, 0x40, 
++   0x40, 0x3e, 0x09, 0x0e, 0x0a, 0x09, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 
++   0x7f, 0x08, 0x0e, 0x08, 0x08, 0x00, 0x00, 0x0e, 0x0a, 0x0e, 0x00, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 
++   0x7e, 0x00, 0x00, 0x00, 0x00, 0x44, 0x64, 0x54, 0x4c, 0x54, 0x10, 0x10, 
++   0x10, 0x1f, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x1f, 0x04, 0x04, 0x04, 
++   0x04, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 
++   0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
++   0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
++   0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0xff, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 
++   0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 
++   0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x00, 
++   0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 
++   0x06, 0x0c, 0x18, 0x30, 0x18, 0x6c, 0x36, 0x18, 0x0c, 0x00, 0x00, 0x60, 
++   0x30, 0x18, 0x0c, 0x18, 0x36, 0x6c, 0x18, 0x30, 0x00, 0x00, 0x7f, 0x36, 
++   0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x7e, 
++   0x18, 0x7e, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x30, 0x78, 
++   0x30, 0x72, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 
++   0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, 
++   0x00, 0x00, 0x00, 0x66, 0x66, 0x22, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x36, 0x7f, 0x36, 0x36, 0x36, 0x7f, 0x36, 0x00, 0x00, 0x00, 
++   0x00, 0x66, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 
++   0x72, 0x56, 0x6c, 0x18, 0x36, 0x6a, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x18, 
++   0x24, 0x28, 0x30, 0x4a, 0x44, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
++   0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x18, 
++   0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x18, 0x18, 
++   0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0x7e, 0x3c, 
++   0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
++   0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
++   0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x00, 
++   0x00, 0x3c, 0x46, 0x4e, 0x5a, 0x72, 0x62, 0x3c, 0x00, 0x00, 0x00, 0x00, 
++   0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, 
++   0x66, 0x06, 0x0c, 0x18, 0x32, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
++   0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
++   0x66, 0x7e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x60, 0x7c, 0x66, 
++   0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x7c, 0x66, 0x66, 
++   0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x46, 0x06, 0x0c, 0x18, 0x30, 
++   0x30, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, 
++   0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 
++   0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
++   0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
++   0x06, 0x0c, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x5e, 
++   0x56, 0x5e, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x66, 
++   0x7e, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x66, 
++   0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, 
++   0x3c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 
++   0x00, 0x00, 0x00, 0x00, 0x7e, 0x62, 0x60, 0x78, 0x60, 0x62, 0x7e, 0x00, 
++   0x00, 0x00, 0x00, 0x7e, 0x62, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00, 0x00, 
++   0x00, 0x00, 0x3c, 0x66, 0x60, 0x6e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 
++   0x00, 0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
++   0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7e, 
++   0x46, 0x06, 0x06, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6c, 
++   0x78, 0x70, 0x78, 0x6c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, 
++   0x60, 0x60, 0x62, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x41, 0x63, 0x77, 0x7f, 
++   0x6b, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x76, 0x7e, 0x6e, 
++   0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 
++   0x3c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 
++   0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x6e, 0x3c, 0x02, 
++   0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x00, 0x00, 
++   0x00, 0x00, 0x3c, 0x66, 0x60, 0x3c, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 
++   0x00, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
++   0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x66, 
++   0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 
++   0x63, 0x6b, 0x6b, 0x7f, 0x36, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3c, 
++   0x18, 0x3c, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 
++   0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x46, 0x0c, 0x18, 0x30, 
++   0x62, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
++   0x3c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 
++   0x00, 0x00, 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 
++   0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 
++   0x00, 0x08, 0x10, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x3c, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x60, 
++   0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
++   0x3c, 0x66, 0x60, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 
++   0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
++   0x7e, 0x60, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x78, 
++   0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x66, 0x66, 
++   0x3e, 0x06, 0x3c, 0x00, 0x00, 0x60, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, 
++   0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x1c, 0x00, 
++   0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 
++   0x00, 0x00, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x7c, 0x66, 0x00, 0x00, 0x00, 
++   0x00, 0x60, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x76, 0x7f, 0x6b, 0x6b, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
++   0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
++   0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x66, 
++   0x66, 0x66, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x72, 0x60, 
++   0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x3c, 0x06, 
++   0x3c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x78, 0x30, 0x30, 0x36, 0x1c, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3a, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x63, 0x6b, 0x6b, 0x6b, 0x36, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 0x00, 0x00, 0x00, 
++   0x00, 0x7e, 0x0c, 0x18, 0x30, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 
++   0x18, 0x30, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 
++   0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x30, 0x18, 0x18, 0x0c, 
++   0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x00, 0x00, 0x00, 0x00, 
++   0x00, 0x00, 0x00, 0x00};
+diff -ruN proll_18.orig/src/le.c proll-patch4/src/le.c
+--- proll_18.orig/src/le.c	2002-07-23 05:52:49.000000000 +0000
++++ proll-patch4/src/le.c	2004-11-13 15:50:49.000000000 +0000
+@@ -185,8 +185,6 @@
+ 	unsigned short rap;			/* register address port */
+ };
+ 
+-int sparc_lance_debug = 2;
+-
+ /* The Lance uses 24 bit addresses */
+ /* On the Sun4c the DVMA will provide the remaining bytes for us */
+ /* On the Sun4m we have to instruct the ledma to provide them    */
+diff -ruN proll_18.orig/src/netinit.c proll-patch4/src/netinit.c
+--- proll_18.orig/src/netinit.c	2002-09-13 21:53:33.000000000 +0000
++++ proll-patch4/src/netinit.c	2004-11-13 15:50:49.000000000 +0000
+@@ -49,13 +49,20 @@
+ unsigned char     myhwaddr[ETH_ALEN];		/* my own hardware addr	*/
+          t_ipaddr myipaddr;			/* my own IP address	*/
+          t_ipaddr mynetmask;			/* my own netmask	*/
+-         char    *net_module_name;		/* name of init module	*/
+          t_ipaddr servaddr;			/* IP of RARP&TFTP server */
+ 
+ /* Broadcast hardware address */
+-unsigned char bcasthw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
++const unsigned char bcasthw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ 
+ 
++unsigned int seed;
++
++/* This is taken from x86 to be used in network kernel. Returns 15 bits. */
++short int random()
++{
++	seed = (seed + 23968)*0x015A4E35 >> 1;
++	return seed & 0x7FFF;
++}
+ 
+ /*
+  **************************************************************************
+@@ -104,10 +111,17 @@
+  */
+ void init_net()
+ {
++  /* Avoid data segment allocations */
++  seed = 151;
++
+   /* Initialize the different network layer modules */
+   init_packet();
+-  if (!init_arp() || !init_udp()) {
+-	printf("\nERROR: init_%s\n", net_module_name);
++  if (!init_arp()) {
++	printf("\nERROR: init_arp\n");
++	fatal();
++  }
++  if (!init_udp()) {
++	printf("\nERROR: init_udp\n");
+ 	fatal();
+   }
+ }
+diff -ruN proll_18.orig/src/netpriv.h proll-patch4/src/netpriv.h
+--- proll_18.orig/src/netpriv.h	1999-04-27 05:39:37.000000000 +0000
++++ proll-patch4/src/netpriv.h	2004-11-13 15:50:49.000000000 +0000
+@@ -130,10 +130,9 @@
+  *
+  */
+ extern unsigned char myhwaddr[ETH_ALEN]; /* my own hardware address	*/
+-extern unsigned char bcasthw[ETH_ALEN];  /* broadcast hardware addr	*/
++extern const unsigned char bcasthw[ETH_ALEN];  /* broadcast hardware addr	*/
+ extern t_ipaddr      myipaddr;           /* my own IP address		*/
+ extern t_ipaddr      mynetmask;		 /* netmask for my network	*/
+-extern char         *net_module_name;	 /* initialized module's name	*/
+ extern t_ipaddr      servaddr;           /* server IP address		*/
+ 
+ 
+@@ -150,7 +149,7 @@
+ extern unsigned char *reg_type __P((int typeval, int (* receive)()));
+ 
+ /* Write a packet to the network */
+-extern int write_packet __P((int bufsize, int typeval, unsigned char *addr));
++extern int write_packet __P((int bufsize, int typeval, const unsigned char *addr));
+ 
+ /* Empty read buffer */
+ extern void empty_buf __P((void));
+diff -ruN proll_18.orig/src/openprom.h proll-patch4/src/openprom.h
+--- proll_18.orig/src/openprom.h	2002-07-14 02:26:30.000000000 +0000
++++ proll-patch4/src/openprom.h	2004-11-13 15:50:49.000000000 +0000
+@@ -54,20 +54,20 @@
+ };
+ 
+ struct linux_mem_v0 {
+-	struct linux_mlist_v0 **v0_totphys;
+-	struct linux_mlist_v0 **v0_prommap;
+-	struct linux_mlist_v0 **v0_available; /* What we can use */
++	struct linux_mlist_v0 * const *v0_totphys;
++	struct linux_mlist_v0 * const *v0_prommap;
++	struct linux_mlist_v0 * const *v0_available; /* What we can use */
+ };
+ 
+ /* Arguments sent to the kernel from the boot prompt. */
+ struct linux_arguments_v0 {
+-	char *argv[8];
++	const char *argv[8];
+ 	char args[100];
+ 	char boot_dev[2];
+ 	int boot_dev_ctrl;
+ 	int boot_dev_unit;
+ 	int dev_partition;
+-	char *kernel_file_name;
++	const char *kernel_file_name;
+ 	void *aieee1;           /* XXX */
+ };
  
- 	romvec = init_openprom(bb.nbanks, bb.bankv, hiphybas);
+@@ -91,13 +91,13 @@
+ 	struct linux_mem_v0 pv_v0mem;
  
- 	printk("Memory used: virt 0x%x:0x%x[%dK] iomap 0x%x:0x%x\n",
- 	    PROLBASE, (int)cmem.curp, ((unsigned) cmem.curp - PROLBASE)/1024,
- 	    (int)cio.start, (int)cio.curp);
+ 	/* Node operations. */
+-	struct linux_nodeops *pv_nodeops;
++	const struct linux_nodeops *pv_nodeops;
+ 
+ 	char **pv_bootstr;
+ 	struct linux_dev_v0_funcs pv_v0devops;
+ 
+-	char *pv_stdin;
+-	char *pv_stdout;
++	const char *pv_stdin;
++	const char *pv_stdout;
+ #define	PROMDEV_KBD	0		/* input from keyboard */
+ #define	PROMDEV_SCREEN	0		/* output to screen */
+ #define	PROMDEV_TTYA	1		/* in/out to ttya */
+@@ -127,7 +127,7 @@
+ 		void (*v2_eval)(char *str);
+ 	} pv_fortheval;
+ 
+-	struct linux_arguments_v0 **pv_v0bootargs;
++	const struct linux_arguments_v0 * const *pv_v0bootargs;
+ 
+ 	/* Get ether address. */
+ 	unsigned int (*pv_enaddr)(int d, char *enaddr);
+@@ -175,7 +175,7 @@
+ 	int (*no_proplen)(int node, char *name);
+ 	int (*no_getprop)(int node, char *name, char *val);
+ 	int (*no_setprop)(int node, char *name, char *val, int len);
+-	char * (*no_nextprop)(int node, char *name);
++	const char * (*no_nextprop)(int node, char *name);
+ };
+ 
+ /* More fun PROM structures for device probing. */
+diff -ruN proll_18.orig/src/packet.c proll-patch4/src/packet.c
+--- proll_18.orig/src/packet.c	2000-02-11 04:56:45.000000000 +0000
++++ proll-patch4/src/packet.c	2004-11-13 15:50:49.000000000 +0000
+@@ -41,7 +41,7 @@
+ 	int aligner;
+ } wbuf;
+ static struct sk_buff *rskb;
+-static int nqskb = 0;
++static int nqskb;
+ 
+ 
+ void init_packet()
+@@ -62,6 +62,8 @@
+ 	for (i = 0; i < MAXSKBS; i++) {
+ 		skev[i].skb.allocn = i;
+ 	}
++
++	nqskb = 0;
+ }
+ 
+ unsigned char *reg_type(int ptype, int (*func)())
+@@ -81,7 +83,7 @@
+ 	return wbuf.s;
+ }
+ 
+-int write_packet(int leng, int type, unsigned char *dst)
++int write_packet(int leng, int type, const unsigned char *dst)
+ {
+ 	struct sk_buff *skb;
+ 	unsigned char *s;
+diff -ruN proll_18.orig/src/printf.c proll-patch4/src/printf.c
+--- proll_18.orig/src/printf.c	1999-03-19 07:03:59.000000000 +0000
++++ proll-patch4/src/printf.c	2004-11-13 15:50:49.000000000 +0000
+@@ -19,7 +19,7 @@
+ static void printn(struct prf_fp *, unsigned long, unsigned int);
+ static void putchar(char, struct prf_fp *);
+ 
+-static char hextab[] = "0123456789ABCDEF";
++static const char hextab[] = "0123456789ABCDEF";
+ 
+ /*
+  * Scaled down version of C Library printf.
+@@ -41,7 +41,7 @@
+ void
+ prf(struct prf_fp *filog, char *fmt, va_list adx)
+ {
+-        register c;
++        register int c;
+         char *s;
+ 
+ 	for(;;) {
+@@ -60,7 +60,7 @@
+                 	putchar(va_arg(adx,unsigned), filog);
+         	} else if(c == 's') {
+                 	s = va_arg(adx,char*);
+-               		while(c = *s++)
++               		while((c = *s++))
+                         	putchar(c,filog);
+        		} else if (c == 'l' || c == 'O') {
+         	        printn(filog, (long)va_arg(adx,long), c=='l'?10:8);
+diff -ruN proll_18.orig/src/rconsole.c proll-patch4/src/rconsole.c
+--- proll_18.orig/src/rconsole.c	1999-01-16 07:16:55.000000000 +0000
++++ proll-patch4/src/rconsole.c	2004-11-13 15:50:49.000000000 +0000
+@@ -28,12 +28,18 @@
+  * move to California. Only plain lat7 survived. 
+  * I recreated lat7-1 changes in lat7-2.  --zaitcev
+  */
 +#ifdef ORIG
- 	set_timeout(5);  while (!chk_timeout()) { }  /* P3: let me read */
+ #include "lat7_2.bm"	/* lat7_1.bm */
 +#else
-+	printk("loading kernel:");
-+	i = ld_bypass(0x20000000);
-+	printk(" done, size %d\n", i);
++#include "lat7_2_swapped.bm"	/* lat7_1.bm */
 +#endif
+ #define LAT7_NCHARS  128
+ #define LAT7_HEIGHT   11
+ #define LAT7_WIDTH     8
  
- 	{
- 		void (*entry)(void *, int) = (void (*)(void*, int)) LOADBASE;
-diff -ru proll_18.orig/mrcoffee/openprom.c proll_18/mrcoffee/openprom.c
---- proll_18.orig/mrcoffee/openprom.c	2002-09-13 16:17:03.000000000 +0200
-+++ proll_18/mrcoffee/openprom.c	2004-09-21 21:27:16.000000000 +0200
-@@ -144,10 +144,14 @@
- };
++#ifdef ORIG
+ static Rf_scan lat7_body[ LAT7_NCHARS*LAT7_HEIGHT ];
++#endif
  
- static int cpu_nctx = NCTX_SWIFT;
-+static int cpu_cache_line_size = 0x20;
-+static int cpu_cache_nlines = 0x200;
- static struct property propv_cpu[] = {
- 	{"name",	"STP1012PGA", sizeof("STP1012PGA") },
- 	{"device_type",	"cpu", 4 },
- 	{"mmu-nctx",	(char*)&cpu_nctx, sizeof(int)},
-+	{"cache-line-size",	(char*)&cpu_cache_line_size, sizeof(int)},
-+	{"cache-nlines",	(char*)&cpu_cache_nlines, sizeof(int)},
- 	{NULL, NULL, -1}
+ #if 1
+ /*
+@@ -94,6 +100,7 @@
+ 
+ #endif
+ 
++#ifdef ORIG
+ static inline int swapbits(int w0)
+ {
+   int w1 = 0;
+@@ -105,13 +112,16 @@
+   }
+   return w1;
+ }
++#endif
+ 
+ void font_cons_7(struct rfont *p)
+ {
++#ifdef ORIG
+   int x;
+   int col = 0;
+   int row = 0;
+   int erow = 0;
++
+   for (x = 0; x < LAT7_NCHARS*LAT7_HEIGHT; x++ ) {
+     lat7_body[ (erow * lat7_2_width/8 + col) * LAT7_HEIGHT + row ] =
+                                             swapbits(lat7_2_bits[x]) & 0xFF;
+@@ -124,6 +134,9 @@
+     }
+   }
+   p->body_ = lat7_body;
++#else
++  p->body_ = lat7_2_bits;
++#endif
+   p->nchars_ = LAT7_NCHARS;
+   p->width_ = LAT7_WIDTH;
+   p->height_ = LAT7_HEIGHT;
+diff -ruN proll_18.orig/src/rconsole.h proll-patch4/src/rconsole.h
+--- proll_18.orig/src/rconsole.h	1999-01-16 05:00:59.000000000 +0000
++++ proll-patch4/src/rconsole.h	2004-11-13 15:50:49.000000000 +0000
+@@ -13,10 +13,10 @@
+  */
+ 
+ #define RF_MAXWIDTH  16
+-typedef unsigned short Rf_scan;        /*  __w16 to be used */
++typedef unsigned char Rf_scan;        /*  __w16 to be used */
+ 
+ struct rfont {
+-  Rf_scan *body_;
++  const Rf_scan *body_;
+   int nchars_;                 /* 128 for ASCII ...  65536 for Unicode   */
+   int width_;                  /* [Pixels]. Maximum size is 16.          */
+   int height_;                 /* [Pixels == scan lines].                */
+diff -ruN proll_18.orig/src/romlib.h proll-patch4/src/romlib.h
+--- proll_18.orig/src/romlib.h	1999-04-20 04:26:45.000000000 +0000
++++ proll-patch4/src/romlib.h	2004-11-13 15:50:49.000000000 +0000
+@@ -73,12 +73,12 @@
+ #define memcpy(dst, src, len)	bcopy(src, dst, len)
+ #define memcmp(x1, x2, len)	bcmp(x1, x2, len)
+ #define memset(p, len, zero)	bzero(p, len)
+-extern void bcopy(void *b1, void *b2, int length);
+-extern int  bcmp(void *b1, void *b2, int length);
++extern void bcopy(const void *b1, void *b2, int length);
++extern int  bcmp(const void *b1, const void *b2, int length);
+ extern void bzero(void *b, int c);
+ /* gcc complains about "conflicting types for builtin function strlen". */
+ #define strlen(s)		ssize(s)
+-extern int ssize(char *s);
++extern int ssize(const char *s);
+ 
+ 
+ /*
+diff -ruN proll_18.orig/src/sched_4m.c proll-patch4/src/sched_4m.c
+--- proll_18.orig/src/sched_4m.c	1999-04-27 05:48:51.000000000 +0000
++++ proll-patch4/src/sched_4m.c	2004-11-13 15:50:49.000000000 +0000
+@@ -108,7 +108,7 @@
+ static int set_bolt;			/* Tick counter limit */
+ static struct handsc hndv[16];
+ 
+-static unsigned int intr_to_mask[16] = {
++static unsigned const int intr_to_mask[16] = {
+ 	0,	0,	0,	0,	0,	0, SUN4M_INT_ETHERNET,	0,
+ 	0,	0,	0,	0,	0,	0,	0,	0,
  };
+diff -ruN proll_18.orig/src/swap.c proll-patch4/src/swap.c
+--- proll_18.orig/src/swap.c	1970-01-01 00:00:00.000000000 +0000
++++ proll-patch4/src/swap.c	2004-11-13 15:50:49.000000000 +0000
+@@ -0,0 +1,21 @@
++// Convert the lat7 font so that no conversion is needed at runtime.
++#define ORIG
++#include "rconsole.c"
++
++#include <stdio.h>
++
++int main()
++{
++    struct rfont p;
++    int i;
++
++    font_cons_7(&p);
++
++    printf("   ");
++    for (i = 0; i < LAT7_NCHARS*LAT7_HEIGHT; i++) {
++	printf("0x%02x, ", p.body_[i]);
++	if ((i % 12) == 11)
++	    printf("\n   ");
++    }
++    printf("\n");
++}
+diff -ruN proll_18.orig/src/system.c proll-patch4/src/system.c
+--- proll_18.orig/src/system.c	2002-07-23 05:52:49.000000000 +0000
++++ proll-patch4/src/system.c	2004-11-13 15:50:49.000000000 +0000
+@@ -298,8 +298,8 @@
+ 	}
+ 
+ 	/* We need to start from LOADBASE, but kernel wants PAGE_SIZE. */
+-	pa = PAGE_SIZE;
+-	for (va = PAGE_SIZE; va < LOWMEMSZ; va += PAGE_SIZE) {
++	pa = 0;
++	for (va = 0; va < LOWMEMSZ; va += PAGE_SIZE) {
+ 		map_page(l1, va, pa, 0, highbase);
+ 		pa += PAGE_SIZE;
+ 	}
+@@ -518,12 +518,12 @@
+ 	while (len--) *((char *)s)++ = 0;
+ }
+ 
+-void bcopy(void *f, void *t, int len) {
++void bcopy(const void *f, void *t, int len) {
+ 	while (len--) *((char *)t)++ = *((char *)f)++;
+ }
+ 
+ /* Comparison is 7-bit */
+-int bcmp(void *s1, void *s2, int len)
++int bcmp(const void *s1, const void *s2, int len)
+ {
+ 	int i;
+ 	char ch;
+@@ -538,8 +538,8 @@
+ 	return 0;
+ }
+ 
+-int strlen(char *s) {
+-	char *p;
++int strlen(const char *s) {
++	const char *p;
+ 	for (p = s; *p != 0; p++) { }
+ 	return p - s;
+ }
+@@ -560,14 +560,6 @@
+ 	va_end(x1);
+ }
+ 
+-/* This is taken from x86 to be used in network kernel. Returns 15 bits. */
+-short int random()
+-{
+-	static unsigned int seed = 151;
+-	seed = (seed + 23968)*0x015A4E35 >> 1;
+-	return seed & 0x7FFF;
+-}
+-
+ void fatal()
+ {
+ 	printk("fatal.");
+diff -ruN proll_18.orig/src/system.h proll-patch4/src/system.h
+--- proll_18.orig/src/system.h	2002-09-13 21:53:32.000000000 +0000
++++ proll-patch4/src/system.h	2004-11-13 15:50:49.000000000 +0000
+@@ -16,7 +16,7 @@
+ #define IOMAPSIZE (1*1024*1024) /* 1 Meg maximum: we do not map framebuffer. */
+ #define NCTX_SWIFT  0x100
+ 
+-#define MAX_BANKS      3		/* Allocation for all machines */
++#define MAX_BANKS      8		/* Allocation for all machines */
+ 
+ #ifndef __ASSEMBLY__
+ struct bank {
+diff -ruN proll_18.orig/src/udp.c proll-patch4/src/udp.c
+--- proll_18.orig/src/udp.c	2001-12-24 05:12:53.000000000 +0000
++++ proll-patch4/src/udp.c	2004-11-13 15:50:49.000000000 +0000
+@@ -81,7 +81,7 @@
+ int      source;
+ int      dest;
+ {
+-  register unsigned char *addr;
++  const register unsigned char *addr;
  
+   /* Set global variables */
+   usource = source;
+@@ -299,9 +299,6 @@
+  */
+ int init_udp()
+ {
+-  /* Set module name for error handling */
+-  net_module_name = "udp";
+-
+   /* Register IP packet type and set write buffer pointer */
+   if ((writebuf = reg_type(htons(ETH_P_IP), ip_recv)) == NULL)
+ 	return(FALSE);
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 367beb80a8..ca5cb09b05 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -1099,6 +1099,29 @@ Set the initial VGA graphic mode. The default is 800x600x15.
 More information is available at
 @url{http://jocelyn.mayer.free.fr/qemu-ppc/}.
 
+@chapter Sparc System emulator invocation
+
+Use the executable @file{qemu-system-sparc} to simulate a JavaStation
+(sun4m architecture). The emulation is far from complete.
+
+QEMU emulates the following sun4m peripherials:
+
+@itemize @minus
+@item 
+IOMMU
+@item
+TCX Frame buffer
+@item 
+Lance (Am7990) Ethernet
+@item
+Non Volatile RAM M48T08
+@item
+Slave I/O: timers, interrupt controllers, Zilog serial ports
+@end itemize
+
+QEMU uses the Proll, a PROM replacement available at
+@url{http://people.redhat.com/zaitcev/linux/}.
+
 @chapter QEMU User space emulator invocation
 
 @section Quick Start
diff --git a/qemu-tech.texi b/qemu-tech.texi
index 4e6f507c74..987b3c3eff 100644
--- a/qemu-tech.texi
+++ b/qemu-tech.texi
@@ -126,7 +126,7 @@ maximum performances.
 
 @itemize
 
-@item Full PowerPC 32 bit emulation, including priviledged instructions, 
+@item Full PowerPC 32 bit emulation, including privileged instructions, 
 FPU and MMU.
 
 @item Can run most PowerPC Linux binaries.
@@ -137,7 +137,8 @@ FPU and MMU.
 
 @itemize
 
-@item SPARC V8 user support, except FPU instructions.
+@item Somewhat complete SPARC V8 emulation, including privileged
+instructions, FPU and MMU.
 
 @item Can run some SPARC Linux binaries.
 
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index adf8df2c9d..a66d2e36d7 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -10,23 +10,42 @@
 /* trap definitions */
 #define TT_ILL_INSN 0x02
 #define TT_PRIV_INSN 0x03
+#define TT_NFPU_INSN 0x04
 #define TT_WIN_OVF  0x05
 #define TT_WIN_UNF  0x06 
 #define TT_FP_EXCP  0x08
 #define TT_DIV_ZERO 0x2a
 #define TT_TRAP     0x80
+#define TT_EXTINT   0x10
 
 #define PSR_NEG   (1<<23)
 #define PSR_ZERO  (1<<22)
 #define PSR_OVF   (1<<21)
 #define PSR_CARRY (1<<20)
 #define PSR_ICC   (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY)
+#define PSR_EF    (1<<12)
+#define PSR_PIL   0xf00
 #define PSR_S     (1<<7)
 #define PSR_PS    (1<<6)
 #define PSR_ET    (1<<5)
 #define PSR_CWP   0x1f
 /* Fake impl 0, version 4 */
-#define GET_PSR(env) ((0<<28) | (4<<24) | env->psr | (env->psrs? PSR_S : 0) | (env->psrs? PSR_PS : 0) |(env->psret? PSR_ET : 0) | env->cwp)
+#define GET_PSR(env) ((0 << 28) | (4 << 24) | env->psr |		\
+		      (env->psref? PSR_EF : 0) |			\
+		      (env->psrpil << 8) |				\
+		      (env->psrs? PSR_S : 0) |				\
+		      (env->psrs? PSR_PS : 0) |				\
+		      (env->psret? PSR_ET : 0) | env->cwp)
+
+#define PUT_PSR(env, val) do { int _tmp = val;				\
+	env->psr = _tmp & ~PSR_ICC;					\
+	env->psref = (_tmp & PSR_EF)? 1 : 0;				\
+	env->psrpil = (_tmp & PSR_PIL) >> 8;				\
+	env->psrs = (_tmp & PSR_S)? 1 : 0;				\
+	env->psrps = (_tmp & PSR_PS)? 1 : 0;				\
+	env->psret = (_tmp & PSR_ET)? 1 : 0;				\
+	set_cwp(_tmp & PSR_CWP & (NWINDOWS - 1));			\
+    } while (0)
 
 /* Trap base register */
 #define TBR_BASE_MASK 0xfffff000
@@ -65,6 +84,9 @@
 #define FSR_FTT1   (1<<15)
 #define FSR_FTT0   (1<<14)
 #define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
+#define FSR_FTT_IEEE_EXCP (1 << 14)
+#define FSR_FTT_UNIMPFPOP (3 << 14)
+#define FSR_FTT_INVAL_FPR (6 << 14)
 
 #define FSR_FCC1  (1<<11)
 #define FSR_FCC0  (1<<10)
@@ -106,6 +128,8 @@ typedef struct CPUSPARCState {
     int      psrs;     /* supervisor mode (extracted from PSR) */
     int      psrps;    /* previous supervisor mode */
     int      psret;    /* enable traps */
+    int      psrpil;   /* interrupt level */
+    int      psref;    /* enable fpu */
     jmp_buf  jmp_env;
     int user_mode_only;
     int exception_index;
@@ -144,6 +168,8 @@ typedef struct CPUSPARCState {
 CPUSPARCState *cpu_sparc_init(void);
 int cpu_sparc_exec(CPUSPARCState *s);
 int cpu_sparc_close(CPUSPARCState *s);
+void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f);
+double cpu_put_fp64(uint64_t mant, uint16_t exp);
 
 struct siginfo;
 int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
diff --git a/target-sparc/exec.h b/target-sparc/exec.h
index 1b3d9a0806..f8edc17153 100644
--- a/target-sparc/exec.h
+++ b/target-sparc/exec.h
@@ -40,6 +40,9 @@ void do_interrupt(int intno, int is_int, int error_code,
 void raise_exception_err(int exception_index, int error_code);
 void raise_exception(int tt);
 void memcpy32(uint32_t *dst, const uint32_t *src);
+uint32_t mmu_probe(uint32_t address, int mmulev);
+void dump_mmu(void);
+void helper_debug();
 
 /* XXX: move that to a generic header */
 #if !defined(CONFIG_USER_ONLY)
diff --git a/target-sparc/fop_template.h b/target-sparc/fop_template.h
index 2987b68d64..eb1e1e3112 100644
--- a/target-sparc/fop_template.h
+++ b/target-sparc/fop_template.h
@@ -51,18 +51,6 @@ void OPPROTO glue(op_store_FT2_fpr_fpr, REGNAME)(void)
 }
 
 /* double floating point registers moves */
-#if 0
-#define CPU_DOUBLE_U_DEF
-typedef union {
-    double d;
-    struct {
-        uint32_t lower;
-        uint32_t upper;
-    } l;
-    uint64_t ll;
-} CPU_DoubleU;
-#endif /* CPU_DOUBLE_U_DEF */
-
 void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void)
 {
     CPU_DoubleU u;
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 93ef930fbd..76ad643ebb 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -19,7 +19,8 @@
  */
 #include "exec.h"
 
-#define DEBUG_PCALL
+//#define DEBUG_PCALL
+//#define DEBUG_MMU
 
 /* Sparc MMU emulation */
 int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
@@ -108,80 +109,71 @@ static const int rw_table[2][8] = {
     { 0, 1, 0, 1, 0, 0, 0, 0 }
 };
 
-
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
-                              int is_user, int is_softmmu)
+int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
+			  int *access_index, uint32_t address, int rw,
+			  int is_user)
 {
-    int exception = 0;
-    int access_perms = 0, access_index = 0;
-    uint8_t *pde_ptr;
+    int access_perms = 0;
+    target_phys_addr_t pde_ptr;
     uint32_t pde, virt_addr;
-    int error_code = 0, is_dirty, prot, ret = 0;
-    unsigned long paddr, vaddr, page_offset;
-
-    if (env->user_mode_only) {
-        /* user mode only emulation */
-        ret = -2;
-        goto do_fault;
-    }
+    int error_code = 0, is_dirty;
+    unsigned long page_offset;
 
     virt_addr = address & TARGET_PAGE_MASK;
     if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
-	paddr = address;
-	page_offset = address & (TARGET_PAGE_SIZE - 1);
-        prot = PAGE_READ | PAGE_WRITE;
-        goto do_mapping;
+	*physical = address;
+        *prot = PAGE_READ | PAGE_WRITE;
+        return 0;
     }
 
     /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
     /* Context base + context number */
-    pde_ptr = phys_ram_base + (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
-    pde = ldl_raw(pde_ptr);
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
+    cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+    bswap32s(&pde);
 
     /* Ctx pde */
     switch (pde & PTE_ENTRYTYPE_MASK) {
+    default:
     case 0: /* Invalid */
-        error_code = 1;
-        goto do_fault;
-    case 2: /* PTE, maybe should not happen? */
+	return 1;
+    case 2: /* L0 PTE, maybe should not happen? */
     case 3: /* Reserved */
-        error_code = 4;
-        goto do_fault;
-    case 1: /* L1 PDE */
-	pde_ptr = phys_ram_base + ((address >> 22) & ~3) + ((pde & ~3) << 4);
-	pde = ldl_raw(pde_ptr);
+        return 4;
+    case 1: /* L0 PDE */
+	pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+	cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+	bswap32s(&pde);
 
 	switch (pde & PTE_ENTRYTYPE_MASK) {
+	default:
 	case 0: /* Invalid */
-	    error_code = 1;
-	    goto do_fault;
+	    return 1;
 	case 3: /* Reserved */
-	    error_code = 4;
-	    goto do_fault;
-	case 1: /* L2 PDE */
-	    pde_ptr = phys_ram_base + ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
-	    pde = ldl_raw(pde_ptr);
+	    return 4;
+	case 1: /* L1 PDE */
+	    pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+	    cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+	    bswap32s(&pde);
 
 	    switch (pde & PTE_ENTRYTYPE_MASK) {
+	    default:
 	    case 0: /* Invalid */
-		error_code = 1;
-		goto do_fault;
+		return 1;
 	    case 3: /* Reserved */
-		error_code = 4;
-		goto do_fault;
-	    case 1: /* L3 PDE */
-		pde_ptr = phys_ram_base + ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
-		pde = ldl_raw(pde_ptr);
+		return 4;
+	    case 1: /* L2 PDE */
+		pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+		cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+		bswap32s(&pde);
 
 		switch (pde & PTE_ENTRYTYPE_MASK) {
+		default:
 		case 0: /* Invalid */
-		    error_code = 1;
-		    goto do_fault;
+		    return 1;
 		case 1: /* PDE, should not happen */
 		case 3: /* Reserved */
-		    error_code = 4;
-		    goto do_fault;
+		    return 4;
 		case 2: /* L3 PTE */
 		    virt_addr = address & TARGET_PAGE_MASK;
 		    page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
@@ -201,40 +193,58 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
     /* update page modified and dirty bits */
     is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
     if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
+	uint32_t tmppde;
 	pde |= PG_ACCESSED_MASK;
 	if (is_dirty)
 	    pde |= PG_MODIFIED_MASK;
-	stl_raw(pde_ptr, pde);
+	tmppde = bswap32(pde);
+	cpu_physical_memory_write(pde_ptr, (uint8_t *)&tmppde, 4);
     }
-
     /* check access */
-    access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
+    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
     access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
-    error_code = access_table[access_index][access_perms];
+    error_code = access_table[*access_index][access_perms];
     if (error_code)
-	goto do_fault;
+	return error_code;
 
     /* the page can be put in the TLB */
-    prot = PAGE_READ;
+    *prot = PAGE_READ;
     if (pde & PG_MODIFIED_MASK) {
         /* only set write access if already dirty... otherwise wait
            for dirty access */
 	if (rw_table[is_user][access_perms])
-	        prot |= PAGE_WRITE;
+	        *prot |= PAGE_WRITE;
     }
 
     /* Even if large ptes, we map only one 4KB page in the cache to
        avoid filling it too fast */
-    virt_addr = address & TARGET_PAGE_MASK;
-    paddr = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
+    *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
+    return 0;
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+                              int is_user, int is_softmmu)
+{
+    int exception = 0;
+    uint32_t virt_addr, paddr;
+    unsigned long vaddr;
+    int error_code = 0, prot, ret = 0, access_index;
 
- do_mapping:
-    vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
+    if (env->user_mode_only) {
+        /* user mode only emulation */
+        error_code = -2;
+	goto do_fault_user;
+    }
 
-    ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
-    return ret;
+    error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
+    if (error_code == 0) {
+	virt_addr = address & TARGET_PAGE_MASK;
+	vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
+	ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
+	return ret;
+    }
 
- do_fault:
     if (env->mmuregs[3]) /* Fault status register */
 	env->mmuregs[3] = 1; /* overflow (not read before another fault) */
     env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2;
@@ -242,7 +252,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
 
     if (env->mmuregs[0] & MMU_NF || env->psret == 0) // No fault
 	return 0;
-
+ do_fault_user:
     env->exception_index = exception;
     env->error_code = error_code;
     return error_code;
@@ -289,13 +299,14 @@ void do_interrupt(int intno, int is_int, int error_code,
                     count, intno, error_code, is_int,
                     env->pc,
                     env->npc, env->regwptr[6]);
-#if 0
+#if 1
 	cpu_dump_state(env, logfile, fprintf, 0);
 	{
 	    int i;
 	    uint8_t *ptr;
+
 	    fprintf(logfile, "       code=");
-	    ptr = env->pc;
+	    ptr = (uint8_t *)env->pc;
 	    for(i = 0; i < 16; i++) {
 		fprintf(logfile, " %02x", ldub(ptr + i));
 	    }
@@ -305,11 +316,18 @@ void do_interrupt(int intno, int is_int, int error_code,
 	count++;
     }
 #endif
+#if !defined(CONFIG_USER_ONLY) 
+    if (env->psret == 0) {
+	fprintf(logfile, "Trap while interrupts disabled, Error state!\n");
+	qemu_system_shutdown_request();
+	return;
+    }
+#endif
     env->psret = 0;
     cwp = (env->cwp - 1) & (NWINDOWS - 1); 
     set_cwp(cwp);
-    env->regwptr[9] = env->pc;
-    env->regwptr[10] = env->npc;
+    env->regwptr[9] = env->pc - 4; // XXX?
+    env->regwptr[10] = env->pc;
     env->psrps = env->psrs;
     env->psrs = 1;
     env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
@@ -322,3 +340,106 @@ void raise_exception_err(int exception_index, int error_code)
 {
     raise_exception(exception_index);
 }
+
+uint32_t mmu_probe(uint32_t address, int mmulev)
+{
+    target_phys_addr_t pde_ptr;
+    uint32_t pde;
+
+    /* Context base + context number */
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
+    cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+    bswap32s(&pde);
+    switch (pde & PTE_ENTRYTYPE_MASK) {
+    default:
+    case 0: /* Invalid */
+    case 2: /* PTE, maybe should not happen? */
+    case 3: /* Reserved */
+	return 0;
+    case 1: /* L1 PDE */
+	if (mmulev == 3)
+	    return pde;
+	pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+	cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+	bswap32s(&pde);
+
+	switch (pde & PTE_ENTRYTYPE_MASK) {
+	default:
+	case 0: /* Invalid */
+	case 3: /* Reserved */
+	    return 0;
+	case 2: /* L1 PTE */
+	    return pde;
+	case 1: /* L2 PDE */
+	    if (mmulev == 2)
+		return pde;
+	    pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+	    cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+	    bswap32s(&pde);
+
+	    switch (pde & PTE_ENTRYTYPE_MASK) {
+	    default:
+	    case 0: /* Invalid */
+	    case 3: /* Reserved */
+		return 0;
+	    case 2: /* L2 PTE */
+		return pde;
+	    case 1: /* L3 PDE */
+		if (mmulev == 1)
+		    return pde;
+		pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+		cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+		bswap32s(&pde);
+
+		switch (pde & PTE_ENTRYTYPE_MASK) {
+		default:
+		case 0: /* Invalid */
+		case 1: /* PDE, should not happen */
+		case 3: /* Reserved */
+		    return 0;
+		case 2: /* L3 PTE */
+		    return pde;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+void dump_mmu(void)
+{
+#ifdef DEBUG_MMU
+    uint32_t pa, va, va1, va2;
+    int n, m, o;
+    target_phys_addr_t pde_ptr;
+    uint32_t pde;
+
+    printf("MMU dump:\n");
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
+    cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+    bswap32s(&pde);
+    printf("Root ptr: 0x%08x, ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]);
+    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
+	pde_ptr = mmu_probe(va, 2);
+	if (pde_ptr) {
+	    pa = cpu_get_phys_page_debug(env, va);
+	    printf("VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va, pa, pde_ptr);
+	    for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
+		pde_ptr = mmu_probe(va1, 1);
+		if (pde_ptr) {
+		    pa = cpu_get_phys_page_debug(env, va1);
+		    printf(" VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va1, pa, pde_ptr);
+		    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
+			pde_ptr = mmu_probe(va2, 0);
+			if (pde_ptr) {
+			    pa = cpu_get_phys_page_debug(env, va2);
+			    printf("  VA: 0x%08x, PA: 0x%08x PTE: 0x%08x\n", va2, pa, pde_ptr);
+			}
+		    }
+		}
+	    }
+	}
+    }
+    printf("MMU dump ends\n");
+#endif
+}
diff --git a/target-sparc/op.c b/target-sparc/op.c
index 2cf4ed8411..f8cf2f8934 100644
--- a/target-sparc/op.c
+++ b/target-sparc/op.c
@@ -524,13 +524,7 @@ void OPPROTO op_rdpsr(void)
 
 void OPPROTO op_wrpsr(void)
 {
-    int cwp;
-    env->psr = T0 & ~PSR_ICC;
-    env->psrs = (T0 & PSR_S)? 1 : 0;
-    env->psrps = (T0 & PSR_PS)? 1 : 0;
-    env->psret = (T0 & PSR_ET)? 1 : 0;
-    cwp = (T0 & PSR_CWP) & (NWINDOWS - 1);
-    set_cwp(cwp);
+    PUT_PSR(env,T0);
     FORCE_RET();
 }
 
@@ -602,10 +596,27 @@ void OPPROTO op_trapcc_T0(void)
     FORCE_RET();
 }
 
-void OPPROTO op_debug(void)
+void OPPROTO op_trap_ifnofpu(void)
+{
+    if (!env->psref) {
+        env->exception_index = TT_NFPU_INSN;
+        cpu_loop_exit();
+    }
+    FORCE_RET();
+}
+
+void OPPROTO op_fpexception_im(void)
 {
-    env->exception_index = EXCP_DEBUG;
+    env->exception_index = TT_FP_EXCP;
+    env->fsr &= ~FSR_FTT_MASK;
+    env->fsr |= PARAM1;
     cpu_loop_exit();
+    FORCE_RET();
+}
+
+void OPPROTO op_debug(void)
+{
+    helper_debug();
 }
 
 void OPPROTO op_exit_tb(void)
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 3a6de7cfc2..6dead66a8c 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -2,6 +2,8 @@
 #include <fenv.h>
 #include "exec.h"
 
+//#define DEBUG_MMU
+
 #ifdef USE_INT_TO_FLOAT_HELPERS
 void do_fitos(void)
 {
@@ -33,6 +35,13 @@ void do_fcmps (void)
 {
     if (isnan(FT0) || isnan(FT1)) {
         T0 = FSR_FCC1 | FSR_FCC0;
+	env->fsr &= ~(FSR_FCC1 | FSR_FCC0);
+	env->fsr |= T0;
+	if (env->fsr & FSR_NVM) {
+	    raise_exception(TT_FP_EXCP);
+	} else {
+	    env->fsr |= FSR_NVA;
+	}
     } else if (FT0 < FT1) {
         T0 = FSR_FCC0;
     } else if (FT0 > FT1) {
@@ -47,6 +56,13 @@ void do_fcmpd (void)
 {
     if (isnan(DT0) || isnan(DT1)) {
         T0 = FSR_FCC1 | FSR_FCC0;
+	env->fsr &= ~(FSR_FCC1 | FSR_FCC0);
+	env->fsr |= T0;
+	if (env->fsr & FSR_NVM) {
+	    raise_exception(TT_FP_EXCP);
+	} else {
+	    env->fsr |= FSR_NVA;
+	}
     } else if (DT0 < DT1) {
         T0 = FSR_FCC0;
     } else if (DT0 > DT1) {
@@ -59,55 +75,131 @@ void do_fcmpd (void)
 
 void helper_ld_asi(int asi, int size, int sign)
 {
-    switch(asi) {
+    uint32_t ret;
+
+    switch (asi) {
     case 3: /* MMU probe */
-	T1 = 0;
-	return;
+	{
+	    int mmulev;
+
+	    mmulev = (T0 >> 8) & 15;
+	    if (mmulev > 4)
+		ret = 0;
+	    else {
+		ret = mmu_probe(T0, mmulev);
+		//bswap32s(&ret);
+	    }
+#ifdef DEBUG_MMU
+	    printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
+#endif
+	}
+	break;
     case 4: /* read MMU regs */
 	{
-	    int temp, reg = (T0 >> 8) & 0xf;
+	    int reg = (T0 >> 8) & 0xf;
 	    
-	    temp = env->mmuregs[reg];
+	    ret = env->mmuregs[reg];
 	    if (reg == 3 || reg == 4) /* Fault status, addr cleared on read*/
-		env->mmuregs[reg] = 0;
-	    T1 = temp;
+		env->mmuregs[4] = 0;
 	}
-	return;
+	break;
     case 0x20 ... 0x2f: /* MMU passthrough */
-	{
-	    int temp;
-	    
-	    cpu_physical_memory_read(T0, (void *) &temp, size);
-	    bswap32s(&temp);
-	    T1 = temp;
-	}
-	return;
+	cpu_physical_memory_read(T0, (void *) &ret, size);
+	if (size == 4)
+	    bswap32s(&ret);
+	else if (size == 2)
+	    bswap16s(&ret);
+	break;
     default:
-	T1 = 0;
-	return;
+	ret = 0;
+	break;
     }
+    T1 = ret;
 }
 
 void helper_st_asi(int asi, int size, int sign)
 {
     switch(asi) {
     case 3: /* MMU flush */
-	return;
+	{
+	    int mmulev;
+
+	    mmulev = (T0 >> 8) & 15;
+	    switch (mmulev) {
+	    case 0: // flush page
+		tlb_flush_page(cpu_single_env, T0 & 0xfffff000);
+		break;
+	    case 1: // flush segment (256k)
+	    case 2: // flush region (16M)
+	    case 3: // flush context (4G)
+	    case 4: // flush entire
+		tlb_flush(cpu_single_env, 1);
+		break;
+	    default:
+		break;
+	    }
+	    dump_mmu();
+	    return;
+	}
     case 4: /* write MMU regs */
 	{
-	    int reg = (T0 >> 8) & 0xf;
+	    int reg = (T0 >> 8) & 0xf, oldreg;
+	    
+	    oldreg = env->mmuregs[reg];
 	    if (reg == 0) {
 		env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
 		env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
 	    } else
 		env->mmuregs[reg] = T1;
+	    if (oldreg != env->mmuregs[reg]) {
+#if 0
+		// XXX: Only if MMU mapping change, we may need to flush?
+		tlb_flush(cpu_single_env, 1);
+		cpu_loop_exit();
+		FORCE_RET();
+#endif
+	    }
+	    dump_mmu();
 	    return;
 	}
+    case 0x17: /* Block copy, sta access */
+	{
+	    // value (T1) = src
+	    // address (T0) = dst
+	    // copy 32 bytes
+	    int src = T1, dst = T0;
+	    uint8_t temp[32];
+	    
+	    bswap32s(&src);
+
+	    cpu_physical_memory_read(src, (void *) &temp, 32);
+	    cpu_physical_memory_write(dst, (void *) &temp, 32);
+	}
+	return;
+    case 0x1f: /* Block fill, stda access */
+	{
+	    // value (T1, T2)
+	    // address (T0) = dst
+	    // fill 32 bytes
+	    int i, dst = T0;
+	    uint64_t val;
+	    
+	    val = (((uint64_t)T1) << 32) | T2;
+	    bswap64s(&val);
+
+	    for (i = 0; i < 32; i += 8, dst += 8) {
+		cpu_physical_memory_write(dst, (void *) &val, 8);
+	    }
+	}
+	return;
     case 0x20 ... 0x2f: /* MMU passthrough */
 	{
 	    int temp = T1;
-	    
-	    bswap32s(&temp);
+	    if (size == 4)
+		bswap32s(&temp);
+	    else if (size == 2)
+		bswap16s(&temp);
+
 	    cpu_physical_memory_write(T0, (void *) &temp, size);
 	}
 	return;
@@ -116,27 +208,6 @@ void helper_st_asi(int asi, int size, int sign)
     }
 }
 
-#if 0
-void do_ldd_raw(uint32_t addr)
-{
-    T1 = ldl_raw((void *) addr);
-    T0 = ldl_raw((void *) (addr + 4));
-}
-
-#if !defined(CONFIG_USER_ONLY)
-void do_ldd_user(uint32_t addr)
-{
-    T1 = ldl_user((void *) addr);
-    T0 = ldl_user((void *) (addr + 4));
-}
-void do_ldd_kernel(uint32_t addr)
-{
-    T1 = ldl_kernel((void *) addr);
-    T0 = ldl_kernel((void *) (addr + 4));
-}
-#endif
-#endif
-
 void helper_rett()
 {
     int cwp;
@@ -166,3 +237,22 @@ void helper_ldfsr(void)
 	break;
     }
 }
+
+void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f)
+{
+    int exptemp;
+
+    *pmant = ldexp(frexp(f, &exptemp), 53);
+    *pexp = exptemp;
+}
+
+double cpu_put_fp64(uint64_t mant, uint16_t exp)
+{
+    return ldexp((double) mant, exp - 53);
+}
+
+void helper_debug()
+{
+    env->exception_index = EXCP_DEBUG;
+    cpu_loop_exit();
+}
diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h
index 2ae74f2cef..9c839a0047 100644
--- a/target-sparc/op_mem.h
+++ b/target-sparc/op_mem.h
@@ -43,12 +43,8 @@ void OPPROTO glue(op_swap, MEMSUFFIX)(void)
 
 void OPPROTO glue(op_ldd, MEMSUFFIX)(void)
 {
-#if 1
     T1 = glue(ldl, MEMSUFFIX)((void *) T0);
     T0 = glue(ldl, MEMSUFFIX)((void *) (T0 + 4));
-#else
-    glue(do_ldd, MEMSUFFIX)(T0);
-#endif
 }
 
 /***                         Floating-point store                          ***/
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 2440c0d22e..2f067958d0 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -646,6 +646,7 @@ static void disas_sparc_insn(DisasContext * dc)
 	    switch (xop) {
 	    case 0x0:
 	    case 0x1:		/* UNIMPL */
+	    case 0x5:		/*CBN+x */
 	    default:
                 goto illegal_insn;
 	    case 0x2:		/* BN+x */
@@ -657,16 +658,24 @@ static void disas_sparc_insn(DisasContext * dc)
 		}
 	    case 0x6:		/* FBN+x */
 		{
+#if !defined(CONFIG_USER_ONLY)
+		    gen_op_trap_ifnofpu();
+#endif
 		    target <<= 2;
 		    target = sign_extend(target, 22);
 		    do_fbranch(dc, target, insn);
 		    goto jmp_insn;
 		}
 	    case 0x4:		/* SETHI */
-		gen_movl_imm_T0(target << 10);
-		gen_movl_T0_reg(rd);
-		break;
-	    case 0x5:		/*CBN+x */
+#define OPTIM
+#if defined(OPTIM)
+		if (rd) { // nop
+#endif
+		    gen_movl_imm_T0(target << 10);
+		    gen_movl_T0_reg(rd);
+#if defined(OPTIM)
+		}
+#endif
 		break;
 	    }
 	    break;
@@ -691,14 +700,24 @@ static void disas_sparc_insn(DisasContext * dc)
                 gen_movl_reg_T0(rs1);
 		if (IS_IMM) {
 		    rs2 = GET_FIELD(insn, 25, 31);
+#if defined(OPTIM)
 		    if (rs2 != 0) {
-			 gen_movl_imm_T1(rs2);
-			 gen_op_add_T1_T0();
+#endif
+			gen_movl_imm_T1(rs2);
+			gen_op_add_T1_T0();
+#if defined(OPTIM)
 		    }
+#endif
                 } else {
                     rs2 = GET_FIELD(insn, 27, 31);
-                    gen_movl_reg_T1(rs2);
-                    gen_op_add_T1_T0();
+#if defined(OPTIM)
+		    if (rs2 != 0) {
+#endif
+			gen_movl_reg_T1(rs2);
+			gen_op_add_T1_T0();
+#if defined(OPTIM)
+		    }
+#endif
                 }
                 save_state(dc);
                 cond = GET_FIELD(insn, 3, 6);
@@ -707,6 +726,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     dc->is_br = 1;
                     goto jmp_insn;
                 } else {
+		    gen_cond(cond);
                     gen_op_trapcc_T0();
                 }
             } else if (xop == 0x28) {
@@ -741,7 +761,10 @@ static void disas_sparc_insn(DisasContext * dc)
                 gen_movl_T0_reg(rd);
                 break;
 #endif
-	    } else if (xop == 0x34 || xop == 0x35) {	/* FPU Operations */
+	    } else if (xop == 0x34) {	/* FPU Operations */
+#if !defined(CONFIG_USER_ONLY)
+		gen_op_trap_ifnofpu();
+#endif
                 rs1 = GET_FIELD(insn, 13, 17);
 	        rs2 = GET_FIELD(insn, 27, 31);
 	        xop = GET_FIELD(insn, 18, 26);
@@ -770,6 +793,8 @@ static void disas_sparc_insn(DisasContext * dc)
 			gen_op_fsqrtd();
 			gen_op_store_DT0_fpr(rd);
 			break;
+		    case 0x2b: /* fsqrtq */
+		        goto nfpu_insn;
 		    case 0x41:
                 	gen_op_load_fpr_FT0(rs1);
                 	gen_op_load_fpr_FT1(rs2);
@@ -782,6 +807,8 @@ static void disas_sparc_insn(DisasContext * dc)
 			gen_op_faddd();
 			gen_op_store_DT0_fpr(rd);
 			break;
+		    case 0x43: /* faddq */
+		        goto nfpu_insn;
 		    case 0x45:
                 	gen_op_load_fpr_FT0(rs1);
                 	gen_op_load_fpr_FT1(rs2);
@@ -794,6 +821,8 @@ static void disas_sparc_insn(DisasContext * dc)
 			gen_op_fsubd();
 			gen_op_store_DT0_fpr(rd);
 			break;
+		    case 0x47: /* fsubq */
+		        goto nfpu_insn;
 		    case 0x49:
                 	gen_op_load_fpr_FT0(rs1);
                 	gen_op_load_fpr_FT1(rs2);
@@ -806,6 +835,8 @@ static void disas_sparc_insn(DisasContext * dc)
 			gen_op_fmuld();
 			gen_op_store_DT0_fpr(rd);
 			break;
+		    case 0x4b: /* fmulq */
+		        goto nfpu_insn;
 		    case 0x4d:
                 	gen_op_load_fpr_FT0(rs1);
                 	gen_op_load_fpr_FT1(rs2);
@@ -818,32 +849,16 @@ static void disas_sparc_insn(DisasContext * dc)
 			gen_op_fdivd();
 			gen_op_store_DT0_fpr(rd);
 			break;
-		    case 0x51:
-                	gen_op_load_fpr_FT0(rs1);
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fcmps();
-			break;
-		    case 0x52:
-                	gen_op_load_fpr_DT0(rs1);
-                	gen_op_load_fpr_DT1(rs2);
-			gen_op_fcmpd();
-			break;
-		    case 0x55: /* fcmpes */
-                	gen_op_load_fpr_FT0(rs1);
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fcmps(); /* XXX */
-			break;
-		    case 0x56: /* fcmped */
-                	gen_op_load_fpr_DT0(rs1);
-                	gen_op_load_fpr_DT1(rs2);
-			gen_op_fcmpd(); /* XXX */
-			break;
+		    case 0x4f: /* fdivq */
+		        goto nfpu_insn;
 		    case 0x69:
                 	gen_op_load_fpr_FT0(rs1);
                 	gen_op_load_fpr_FT1(rs2);
 			gen_op_fsmuld();
 			gen_op_store_DT0_fpr(rd);
 			break;
+		    case 0x6e: /* fdmulq */
+		        goto nfpu_insn;
 		    case 0xc4:
                 	gen_op_load_fpr_FT1(rs2);
 			gen_op_fitos();
@@ -854,6 +869,8 @@ static void disas_sparc_insn(DisasContext * dc)
 			gen_op_fdtos();
 			gen_op_store_FT0_fpr(rd);
 			break;
+		    case 0xc7: /* fqtos */
+		        goto nfpu_insn;
 		    case 0xc8:
                 	gen_op_load_fpr_FT1(rs2);
 			gen_op_fitod();
@@ -864,6 +881,14 @@ static void disas_sparc_insn(DisasContext * dc)
 			gen_op_fstod();
 			gen_op_store_DT0_fpr(rd);
 			break;
+		    case 0xcb: /* fqtod */
+		        goto nfpu_insn;
+		    case 0xcc: /* fitoq */
+		        goto nfpu_insn;
+		    case 0xcd: /* fstoq */
+		        goto nfpu_insn;
+		    case 0xce: /* fdtoq */
+		        goto nfpu_insn;
 		    case 0xd1:
                 	gen_op_load_fpr_FT1(rs2);
 			gen_op_fstoi();
@@ -874,13 +899,85 @@ static void disas_sparc_insn(DisasContext * dc)
 			gen_op_fdtoi();
 			gen_op_store_FT0_fpr(rd);
 			break;
+		    case 0xd3: /* fqtoi */
+		        goto nfpu_insn;
 		    default:
                 	goto illegal_insn;
 		}
-	    } else {
+	    } else if (xop == 0x35) {	/* FPU Operations */
+#if !defined(CONFIG_USER_ONLY)
+		gen_op_trap_ifnofpu();
+#endif
                 rs1 = GET_FIELD(insn, 13, 17);
-                gen_movl_reg_T0(rs1);
-                if (IS_IMM) {	/* immediate */
+	        rs2 = GET_FIELD(insn, 27, 31);
+	        xop = GET_FIELD(insn, 18, 26);
+		switch (xop) {
+		    case 0x51:
+                	gen_op_load_fpr_FT0(rs1);
+                	gen_op_load_fpr_FT1(rs2);
+			gen_op_fcmps();
+			break;
+		    case 0x52:
+                	gen_op_load_fpr_DT0(rs1);
+                	gen_op_load_fpr_DT1(rs2);
+			gen_op_fcmpd();
+			break;
+		    case 0x53: /* fcmpq */
+		        goto nfpu_insn;
+		    case 0x55: /* fcmpes */
+                	gen_op_load_fpr_FT0(rs1);
+                	gen_op_load_fpr_FT1(rs2);
+			gen_op_fcmps(); /* XXX should trap if qNaN or sNaN  */
+			break;
+		    case 0x56: /* fcmped */
+                	gen_op_load_fpr_DT0(rs1);
+                	gen_op_load_fpr_DT1(rs2);
+			gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN  */
+			break;
+		    case 0x57: /* fcmpeq */
+		        goto nfpu_insn;
+		    default:
+                	goto illegal_insn;
+		}
+#if defined(OPTIM)
+	    } else if (xop == 0x2) {
+		// clr/mov shortcut
+
+                rs1 = GET_FIELD(insn, 13, 17);
+		if (rs1 == 0) {
+		    // or %g0, x, y -> mov T1, x; mov y, T1
+		    if (IS_IMM) {	/* immediate */
+			rs2 = GET_FIELDs(insn, 19, 31);
+			gen_movl_imm_T1(rs2);
+		    } else {		/* register */
+			rs2 = GET_FIELD(insn, 27, 31);
+			gen_movl_reg_T1(rs2);
+		    }
+		    gen_movl_T1_reg(rd);
+		} else {
+		    gen_movl_reg_T0(rs1);
+		    if (IS_IMM) {	/* immediate */
+			// or x, #0, y -> mov T1, x; mov y, T1
+			rs2 = GET_FIELDs(insn, 19, 31);
+			if (rs2 != 0) {
+			    gen_movl_imm_T1(rs2);
+			    gen_op_or_T1_T0();
+			}
+		    } else {		/* register */
+			// or x, %g0, y -> mov T1, x; mov y, T1
+			rs2 = GET_FIELD(insn, 27, 31);
+			if (rs2 != 0) {
+			    gen_movl_reg_T1(rs2);
+			    gen_op_or_T1_T0();
+			}
+		    }
+		    gen_movl_T0_reg(rd);
+		}
+#endif
+	    } else if (xop < 0x38) {
+                rs1 = GET_FIELD(insn, 13, 17);
+		gen_movl_reg_T0(rs1);
+		if (IS_IMM) {	/* immediate */
                     rs2 = GET_FIELDs(insn, 19, 31);
                     gen_movl_imm_T1(rs2);
                 } else {		/* register */
@@ -901,10 +998,10 @@ static void disas_sparc_insn(DisasContext * dc)
                             gen_op_logic_T0_cc();
                         break;
                     case 0x2:
-                        gen_op_or_T1_T0();
-                        if (xop & 0x10)
-                            gen_op_logic_T0_cc();
-                        break;
+			gen_op_or_T1_T0();
+			if (xop & 0x10)
+			    gen_op_logic_T0_cc();
+			break;
                     case 0x3:
                         gen_op_xor_T1_T0();
                         if (xop & 0x10)
@@ -964,9 +1061,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     default:
                         goto illegal_insn;
                     }
-                    gen_movl_T0_reg(rd);
+		    gen_movl_T0_reg(rd);
                 } else {
                     switch (xop) {
+		    case 0x20: /* taddcc */
+		    case 0x21: /* tsubcc */
+		    case 0x22: /* taddcctv */
+		    case 0x23: /* tsubcctv */
+			goto illegal_insn;
                     case 0x24: /* mulscc */
                         gen_op_mulscc_T1_T0();
                         gen_movl_T0_reg(rd);
@@ -1021,56 +1123,72 @@ static void disas_sparc_insn(DisasContext * dc)
                         }
                         break;
 #endif
-                    case 0x38:	/* jmpl */
-                        {
-                            gen_op_add_T1_T0();
-                            gen_op_movl_npc_T0();
-                            if (rd != 0) {
-                                gen_op_movl_T0_im((long) (dc->pc));
-                                gen_movl_T0_reg(rd);
-                            }
-                            dc->pc = dc->npc;
-                            dc->npc = DYNAMIC_PC;
-                        }
-                        goto jmp_insn;
-#if !defined(CONFIG_USER_ONLY)
-                    case 0x39:	/* rett */
-                        {
-			    if (!supervisor(dc))
-				goto priv_insn;
-                            gen_op_add_T1_T0();
-                            gen_op_movl_npc_T0();
-                            gen_op_rett();
-#if 0
-			    dc->pc = dc->npc;
-			    dc->npc = DYNAMIC_PC;
+		    default:
+			goto illegal_insn;
+		    }
+		}
+	    } else {
+                rs1 = GET_FIELD(insn, 13, 17);
+		gen_movl_reg_T0(rs1);
+                if (IS_IMM) {	/* immediate */
+		    rs2 = GET_FIELDs(insn, 19, 31);
+#if defined(OPTIM)
+		    if (rs2) {
 #endif
-                        }
-#if 0
-                        goto jmp_insn;
+			gen_movl_imm_T1(rs2);
+			gen_op_add_T1_T0();
+#if defined(OPTIM)
+		    }
 #endif
-			break;
+                } else {		/* register */
+                    rs2 = GET_FIELD(insn, 27, 31);
+#if defined(OPTIM)
+		    if (rs2) {
+#endif
+			gen_movl_reg_T1(rs2);
+			gen_op_add_T1_T0();
+#if defined(OPTIM)
+		    }
 #endif
-                    case 0x3b: /* flush */
-                        gen_op_add_T1_T0();
-                        gen_op_flush_T0();
-                        break;
-                    case 0x3c:	/* save */
-                        save_state(dc);
-                        gen_op_add_T1_T0();
-                        gen_op_save();
-                        gen_movl_T0_reg(rd);
-                        break;
-                    case 0x3d:	/* restore */
-                        save_state(dc);
-                        gen_op_add_T1_T0();
-                        gen_op_restore();
-                        gen_movl_T0_reg(rd);
-                        break;
-                    default:
-                        goto illegal_insn;
-                    }
                 }
+		switch (xop) {
+		case 0x38:	/* jmpl */
+		    {
+			gen_op_movl_npc_T0();
+			if (rd != 0) {
+			    gen_op_movl_T0_im((long) (dc->pc));
+			    gen_movl_T0_reg(rd);
+			}
+			dc->pc = dc->npc;
+			dc->npc = DYNAMIC_PC;
+		    }
+		    goto jmp_insn;
+#if !defined(CONFIG_USER_ONLY)
+		case 0x39:	/* rett */
+		    {
+			if (!supervisor(dc))
+			    goto priv_insn;
+			gen_op_movl_npc_T0();
+			gen_op_rett();
+		    }
+		    break;
+#endif
+		case 0x3b: /* flush */
+		    gen_op_flush_T0();
+		    break;
+		case 0x3c:	/* save */
+		    save_state(dc);
+		    gen_op_save();
+		    gen_movl_T0_reg(rd);
+		    break;
+		case 0x3d:	/* restore */
+		    save_state(dc);
+		    gen_op_restore();
+		    gen_movl_T0_reg(rd);
+		    break;
+		default:
+		    goto illegal_insn;
+		}
             }
 	    break;
 	}
@@ -1081,14 +1199,24 @@ static void disas_sparc_insn(DisasContext * dc)
 	    gen_movl_reg_T0(rs1);
 	    if (IS_IMM) {	/* immediate */
 		rs2 = GET_FIELDs(insn, 19, 31);
+#if defined(OPTIM)
 		if (rs2 != 0) {
+#endif
 		    gen_movl_imm_T1(rs2);
 		    gen_op_add_T1_T0();
+#if defined(OPTIM)
 		}
+#endif
 	    } else {		/* register */
 		rs2 = GET_FIELD(insn, 27, 31);
-		gen_movl_reg_T1(rs2);
-	        gen_op_add_T1_T0();
+#if defined(OPTIM)
+		if (rs2 != 0) {
+#endif
+		    gen_movl_reg_T1(rs2);
+		    gen_op_add_T1_T0();
+#if defined(OPTIM)
+		}
+#endif
 	    }
 	    if (xop < 4 || (xop > 7 && xop < 0x14) || \
 		    (xop > 0x17 && xop < 0x20)) {
@@ -1116,8 +1244,10 @@ static void disas_sparc_insn(DisasContext * dc)
 		    gen_op_ldst(ldstub);
 		    break;
 		case 0x0f:	/* swap register with memory. Also atomically */
+		    gen_movl_reg_T1(rd);
 		    gen_op_ldst(swap);
 		    break;
+#if !defined(CONFIG_USER_ONLY)
 		case 0x10:	/* load word alternate */
 		    if (!supervisor(dc))
 			goto priv_insn;
@@ -1157,11 +1287,18 @@ static void disas_sparc_insn(DisasContext * dc)
 		case 0x1f:	/* swap reg with alt. memory. Also atomically */
 		    if (!supervisor(dc))
 			goto priv_insn;
+		    gen_movl_reg_T1(rd);
 		    gen_op_swapa(insn, 1, 4, 0);
 		    break;
+#endif
+		default:
+		    goto illegal_insn;
 		}
 		gen_movl_T1_reg(rd);
 	    } else if (xop >= 0x20 && xop < 0x24) {
+#if !defined(CONFIG_USER_ONLY)
+		gen_op_trap_ifnofpu();
+#endif
 		switch (xop) {
 		case 0x20:	/* load fpreg */
 		    gen_op_ldst(ldf);
@@ -1169,11 +1306,14 @@ static void disas_sparc_insn(DisasContext * dc)
 		    break;
 		case 0x21:	/* load fsr */
 		    gen_op_ldfsr();
+		    gen_op_store_FT0_fpr(rd);
 		    break;
 		case 0x23:	/* load double fpreg */
 		    gen_op_ldst(lddf);
 		    gen_op_store_DT0_fpr(rd);
 		    break;
+		default:
+		    goto illegal_insn;
 		}
 	    } else if (xop < 8 || (xop >= 0x14 && xop < 0x18)) {
 		gen_movl_reg_T1(rd);
@@ -1192,6 +1332,7 @@ static void disas_sparc_insn(DisasContext * dc)
 		    gen_movl_reg_T2(rd + 1);
 		    gen_op_ldst(std);
 		    break;
+#if !defined(CONFIG_USER_ONLY)
 		case 0x14:
 		    if (!supervisor(dc))
 			goto priv_insn;
@@ -1214,24 +1355,37 @@ static void disas_sparc_insn(DisasContext * dc)
 		    gen_movl_reg_T2(rd + 1);
 		    gen_op_stda(insn, 0, 8, 0);
 		    break;
+#endif
+		default:
+		    goto illegal_insn;
 		}
 	    } else if (xop > 0x23 && xop < 0x28) {
+#if !defined(CONFIG_USER_ONLY)
+		gen_op_trap_ifnofpu();
+#endif
 		switch (xop) {
 		case 0x24:
                     gen_op_load_fpr_FT0(rd);
 		    gen_op_ldst(stf);
 		    break;
 		case 0x25:
+                    gen_op_load_fpr_FT0(rd);
 		    gen_op_stfsr();
 		    break;
 		case 0x27:
                     gen_op_load_fpr_DT0(rd);
 		    gen_op_ldst(stdf);
 		    break;
+		case 0x26: /* stdfq */
+		default:
+		    goto illegal_insn;
 		}
 	    } else if (xop > 0x33 && xop < 0x38) {
 		/* Co-processor */
+		goto illegal_insn;
             }
+	    else
+		goto illegal_insn;
 	}
     }
     /* default case for non jump instructions */
@@ -1246,17 +1400,24 @@ static void disas_sparc_insn(DisasContext * dc)
 	dc->pc = dc->npc;
 	dc->npc = dc->npc + 4;
     }
-  jmp_insn:;
+ jmp_insn:
     return;
  illegal_insn:
     save_state(dc);
     gen_op_exception(TT_ILL_INSN);
     dc->is_br = 1;
     return;
+#if !defined(CONFIG_USER_ONLY)
  priv_insn:
     save_state(dc);
     gen_op_exception(TT_PRIV_INSN);
     dc->is_br = 1;
+    return;
+#endif
+ nfpu_insn:
+    save_state(dc);
+    gen_op_fpexception_im(FSR_FTT_UNIMPFPOP);
+    dc->is_br = 1;
 }
 
 static inline int gen_intermediate_code_internal(TranslationBlock * tb,
@@ -1271,6 +1432,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
     dc->tb = tb;
     pc_start = tb->pc;
     dc->pc = pc_start;
+    last_pc = dc->pc;
     dc->npc = (target_ulong) tb->cs_base;
 #if defined(CONFIG_USER_ONLY)
     dc->mem_idx = 0;
@@ -1285,8 +1447,13 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
         if (env->nb_breakpoints > 0) {
             for(j = 0; j < env->nb_breakpoints; j++) {
                 if (env->breakpoints[j] == dc->pc) {
-                    gen_debug(dc, dc->pc);
-                    break;
+		    if (dc->pc != pc_start)
+			save_state(dc);
+                    gen_op_debug();
+		    gen_op_movl_T0_0();
+		    gen_op_exit_tb();
+		    dc->is_br = 1;
+                    goto exit_gen_loop;
                 }
             }
         }
@@ -1310,8 +1477,18 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
 	/* if the next PC is different, we abort now */
 	if (dc->pc != (last_pc + 4))
 	    break;
+        /* if single step mode, we generate only one instruction and
+           generate an exception */
+        if (env->singlestep_enabled) {
+            gen_op_jmp_im(dc->pc);
+            gen_op_movl_T0_0();
+            gen_op_exit_tb();
+            break;
+        }
     } while ((gen_opc_ptr < gen_opc_end) &&
 	     (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
+
+ exit_gen_loop:
     if (!dc->is_br) {
         if (dc->pc != DYNAMIC_PC && 
             (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
@@ -1338,7 +1515,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
         }
 #endif
     } else {
-        tb->size = dc->npc - pc_start;
+        tb->size = last_pc + 4 - pc_start;
     }
 #ifdef DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM) {
@@ -1366,14 +1543,10 @@ int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
     return gen_intermediate_code_internal(tb, 1, env);
 }
 
-CPUSPARCState *cpu_sparc_init(void)
-{
-    CPUSPARCState *env;
-
-    cpu_exec_init();
+extern int ram_size;
 
-    if (!(env = malloc(sizeof(CPUSPARCState))))
-	return (NULL);
+void cpu_reset(CPUSPARCState *env)
+{
     memset(env, 0, sizeof(*env));
     env->cwp = 0;
     env->wim = 1;
@@ -1381,14 +1554,24 @@ CPUSPARCState *cpu_sparc_init(void)
 #if defined(CONFIG_USER_ONLY)
     env->user_mode_only = 1;
 #else
-    /* Emulate Prom */
     env->psrs = 1;
-    env->pc = 0x4000;
+    env->pc = 0xffd00000;
+    env->gregs[1] = ram_size;
+    env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */
     env->npc = env->pc + 4;
-    env->mmuregs[0] = (0x10<<24) | MMU_E; /* Impl 1, ver 0, MMU Enabled */
-    env->mmuregs[1] = 0x3000 >> 4; /* MMU Context table */
 #endif
+}
+
+CPUSPARCState *cpu_sparc_init(void)
+{
+    CPUSPARCState *env;
+
+    cpu_exec_init();
+
+    if (!(env = malloc(sizeof(CPUSPARCState))))
+	return (NULL);
     cpu_single_env = env;
+    cpu_reset(env);
     return (env);
 }
 
@@ -1436,11 +1619,24 @@ void cpu_dump_state(CPUState *env, FILE *f,
     cpu_fprintf(f, "fsr: 0x%08x\n", env->fsr);
 }
 
+#if defined(CONFIG_USER_ONLY)
 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     return addr;
 }
 
+#else
+target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    uint32_t phys_addr;
+    int prot, access_index;
+
+    if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0)
+        return -1;
+    return phys_addr;
+}
+#endif
+
 void helper_flush(target_ulong addr)
 {
     addr &= ~7;
diff --git a/vl.c b/vl.c
index 78f968eb17..a2e23a7a62 100644
--- a/vl.c
+++ b/vl.c
@@ -2214,10 +2214,74 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
 #elif defined(TARGET_SPARC)
 void cpu_save(QEMUFile *f, void *opaque)
 {
+    CPUState *env = opaque;
+    int i;
+    uint32_t tmp;
+
+    for(i = 1; i < 8; i++)
+        qemu_put_be32s(f, &env->gregs[i]);
+    tmp = env->regwptr - env->regbase;
+    qemu_put_be32s(f, &tmp);
+    for(i = 1; i < NWINDOWS * 16 + 8; i++)
+        qemu_put_be32s(f, &env->regbase[i]);
+
+    /* FPU */
+    for(i = 0; i < 32; i++) {
+        uint64_t mant;
+        uint16_t exp;
+	cpu_get_fp64(&mant, &exp, env->fpr[i]);
+        qemu_put_be64(f, mant);
+        qemu_put_be16(f, exp);
+    }
+    qemu_put_be32s(f, &env->pc);
+    qemu_put_be32s(f, &env->npc);
+    qemu_put_be32s(f, &env->y);
+    tmp = GET_PSR(env);
+    qemu_put_be32s(f, &tmp);
+    qemu_put_be32s(f, &env->fsr);
+    qemu_put_be32s(f, &env->cwp);
+    qemu_put_be32s(f, &env->wim);
+    qemu_put_be32s(f, &env->tbr);
+    /* MMU */
+    for(i = 0; i < 16; i++)
+        qemu_put_be32s(f, &env->mmuregs[i]);
 }
 
 int cpu_load(QEMUFile *f, void *opaque, int version_id)
 {
+    CPUState *env = opaque;
+    int i;
+    uint32_t tmp;
+
+    for(i = 1; i < 8; i++)
+        qemu_get_be32s(f, &env->gregs[i]);
+    qemu_get_be32s(f, &tmp);
+    env->regwptr = env->regbase + tmp;
+    for(i = 1; i < NWINDOWS * 16 + 8; i++)
+        qemu_get_be32s(f, &env->regbase[i]);
+
+    /* FPU */
+    for(i = 0; i < 32; i++) {
+        uint64_t mant;
+        uint16_t exp;
+
+        qemu_get_be64s(f, &mant);
+        qemu_get_be16s(f, &exp);
+	env->fpr[i] = cpu_put_fp64(mant, exp);
+    }
+    qemu_get_be32s(f, &env->pc);
+    qemu_get_be32s(f, &env->npc);
+    qemu_get_be32s(f, &env->y);
+    qemu_get_be32s(f, &tmp);
+    PUT_PSR(env, tmp);
+    qemu_get_be32s(f, &env->fsr);
+    qemu_get_be32s(f, &env->cwp);
+    qemu_get_be32s(f, &env->wim);
+    qemu_get_be32s(f, &env->tbr);
+    /* MMU */
+    for(i = 0; i < 16; i++)
+        qemu_get_be32s(f, &env->mmuregs[i]);
+    tlb_flush(env, 1);
     return 0;
 }
 #else
@@ -2388,7 +2452,7 @@ void qemu_system_shutdown_request(void)
 
 static void main_cpu_reset(void *opaque)
 {
-#ifdef TARGET_I386
+#if defined(TARGET_I386) || defined(TARGET_SPARC)
     CPUState *env = opaque;
     cpu_reset(env);
 #endif
diff --git a/vl.h b/vl.h
index 3f3acf2ae7..9426621276 100644
--- a/vl.h
+++ b/vl.h
@@ -261,7 +261,7 @@ typedef void QEMUTimerCB(void *opaque);
    Hz. */
 extern QEMUClock *rt_clock;
 
-/* Rge virtual clock is only run during the emulation. It is stopped
+/* The virtual clock is only run during the emulation. It is stopped
    when the virtual machine is stopped. Virtual timers use a high
    precision clock, usually cpu cycles (use ticks_per_sec). */
 extern QEMUClock *vm_clock;
@@ -672,25 +672,38 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
              DisplayState *ds, const char **fd_filename, int snapshot,
              const char *kernel_filename, const char *kernel_cmdline,
              const char *initrd_filename);
+uint32_t iommu_translate(uint32_t addr);
 
 /* iommu.c */
-void iommu_init(uint32_t addr);
-uint32_t iommu_translate(uint32_t addr);
+void *iommu_init(uint32_t addr);
+uint32_t iommu_translate_local(void *opaque, uint32_t addr);
 
 /* lance.c */
 void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr);
 
 /* tcx.c */
-void tcx_init(DisplayState *ds, uint32_t addr);
-
-/* sched.c */
-void sched_init();
+void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
+	      unsigned long vram_offset, int vram_size);
+void tcx_update_display(void *opaque);
+void tcx_invalidate_display(void *opaque);
+void tcx_screen_dump(void *opaque, const char *filename);
+
+/* slavio_intctl.c */
+void *slavio_intctl_init();
+void slavio_pic_info(void *opaque);
+void slavio_irq_info(void *opaque);
+void slavio_pic_set_irq(void *opaque, int irq, int level);
 
 /* magic-load.c */
-void magic_init(const char *kfn, int kloadaddr, uint32_t addr);
+int load_elf(const char *filename, uint8_t *addr);
+int load_aout(const char *filename, uint8_t *addr);
+
+/* slavio_timer.c */
+void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2);
 
-/* timer.c */
-void timer_init(uint32_t addr, int irq);
+/* slavio_serial.c */
+SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2);
+void slavio_serial_ms_kbd_init(int base, int irq);
 
 /* NVRAM helpers */
 #include "hw/m48t59.h"