summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2005-03-13 09:43:36 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2005-03-13 09:43:36 +0000
commit6f7e9aec5eb5bdfa57a9e458e391b785c283a007 (patch)
tree8679501a365f5fa7ee5b4e6fdd8d6a4f6e92f679
parentb756921ad18c8d293da634ff3b4e950ec8ae3f80 (diff)
downloadfocaccia-qemu-6f7e9aec5eb5bdfa57a9e458e391b785c283a007.tar.gz
focaccia-qemu-6f7e9aec5eb5bdfa57a9e458e391b785c283a007.zip
sparc fixes (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1326 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--Makefile.target2
-rw-r--r--TODO1
-rw-r--r--hw/esp.c192
-rw-r--r--hw/fdc.c37
-rw-r--r--hw/sun4m.c110
-rw-r--r--hw/tcx.c129
-rw-r--r--pc-bios/proll.elfbin133338 -> 41236 bytes
-rw-r--r--pc-bios/proll.patch1545
-rw-r--r--target-sparc/helper.c18
-rw-r--r--target-sparc/op_helper.c4
-rw-r--r--vl.c10
-rw-r--r--vl.h5
12 files changed, 1564 insertions, 489 deletions
diff --git a/Makefile.target b/Makefile.target
index 5c82e38a60..68563299e7 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -338,7 +338,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_BASE_ARCH), sparc)
-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
+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 esp.o
 endif
 ifdef CONFIG_GDBSTUB
 VL_OBJS+=gdbstub.o 
diff --git a/TODO b/TODO
index cd38950544..088c26c69b 100644
--- a/TODO
+++ b/TODO
@@ -3,7 +3,6 @@ short term:
 - debug option in 'configure' script + disable -fomit-frame-pointer
 - Precise VGA timings for old games/demos (malc patch)
 - merge PIC spurious interrupt patch
-- merge VNC keyboard patch
 - merge Solaris patch
 - warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
 - config file (at least for windows/Mac OS X)
diff --git a/hw/esp.c b/hw/esp.c
new file mode 100644
index 0000000000..2456c345fd
--- /dev/null
+++ b/hw/esp.c
@@ -0,0 +1,192 @@
+/*
+ * QEMU ESP emulation
+ * 
+ * Copyright (c) 2005 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"
+
+/* debug ESP card */
+#define DEBUG_ESP
+
+#ifdef DEBUG_ESP
+#define DPRINTF(fmt, args...) \
+do { printf("ESP: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+#define ESPDMA_REGS 4
+#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
+#define ESP_MAXREG 0x3f
+
+typedef struct ESPState {
+    BlockDriverState **bd;
+    uint8_t regs[ESP_MAXREG];
+    int irq;
+    uint32_t espdmaregs[ESPDMA_REGS];
+} ESPState;
+
+static void esp_reset(void *opaque)
+{
+    ESPState *s = opaque;
+    memset(s->regs, 0, ESP_MAXREG);
+    s->regs[0x0e] = 0x4; // Indicate fas100a
+    memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
+}
+
+static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    ESPState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & ESP_MAXREG) >> 2;
+    switch (saddr) {
+    default:
+	break;
+    }
+    DPRINTF("esp: read reg[%d]: 0x%2.2x\n", saddr, s->regs[saddr]);
+    return s->regs[saddr];
+}
+
+static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    ESPState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & ESP_MAXREG) >> 2;
+    DPRINTF("esp: write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->regs[saddr], val);
+    switch (saddr) {
+    case 3:
+	// Command
+	switch(val & 0x7f) {
+	case 0:
+	    DPRINTF("esp: NOP (%2.2x)\n", val);
+	    break;
+	case 2:
+	    DPRINTF("esp: Chip reset (%2.2x)\n", val);
+	    esp_reset(s);
+	    break;
+	case 3:
+	    DPRINTF("esp: Bus reset (%2.2x)\n", val);
+	    break;
+	case 0x1a:
+	    DPRINTF("esp: Set ATN (%2.2x)\n", val);
+	    break;
+	case 0x42:
+	    DPRINTF("esp: Select with ATN (%2.2x)\n", val);
+	    s->regs[4] = 0x1a; // Status: TCNT | TDONE | CMD
+	    s->regs[5] = 0x20; // Intr: Disconnect, nobody there
+	    s->regs[6] = 0x4;  // Seq: Cmd done
+	    pic_set_irq(s->irq, 1);
+	    break;
+	}
+	break;
+    case 4 ... 7:
+    case 9 ... 0xf:
+	break;
+    default:
+	s->regs[saddr] = val;
+	break;
+    }
+}
+
+static CPUReadMemoryFunc *esp_mem_read[3] = {
+    esp_mem_readb,
+    esp_mem_readb,
+    esp_mem_readb,
+};
+
+static CPUWriteMemoryFunc *esp_mem_write[3] = {
+    esp_mem_writeb,
+    esp_mem_writeb,
+    esp_mem_writeb,
+};
+
+static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    ESPState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & ESPDMA_MAXADDR) >> 2;
+    return s->espdmaregs[saddr];
+}
+
+static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    ESPState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & ESPDMA_MAXADDR) >> 2;
+    s->espdmaregs[saddr] = val;
+}
+
+static CPUReadMemoryFunc *espdma_mem_read[3] = {
+    espdma_mem_readl,
+    espdma_mem_readl,
+    espdma_mem_readl,
+};
+
+static CPUWriteMemoryFunc *espdma_mem_write[3] = {
+    espdma_mem_writel,
+    espdma_mem_writel,
+    espdma_mem_writel,
+};
+
+static void esp_save(QEMUFile *f, void *opaque)
+{
+    ESPState *s = opaque;
+    
+}
+
+static int esp_load(QEMUFile *f, void *opaque, int version_id)
+{
+    ESPState *s = opaque;
+    
+    if (version_id != 1)
+        return -EINVAL;
+
+    return 0;
+}
+
+void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
+{
+    ESPState *s;
+    int esp_io_memory, espdma_io_memory;
+
+    s = qemu_mallocz(sizeof(ESPState));
+    if (!s)
+        return;
+
+    s->bd = bd;
+    s->irq = irq;
+
+    esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
+    cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
+
+    espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
+    cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
+
+    esp_reset(s);
+
+    register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
+    qemu_register_reset(esp_reset, s);
+}
+
diff --git a/hw/fdc.c b/hw/fdc.c
index fc6b50257f..3890ace120 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -94,21 +94,6 @@ typedef struct fdrive_t {
     uint8_t ro;               /* Is read-only           */
 } fdrive_t;
 
-#ifdef TARGET_SPARC
-/* XXX: suppress those hacks */
-#define DMA_read_memory(a,b,c,d)
-#define DMA_write_memory(a,b,c,d)
-void DMA_register_channel (int nchan,
-                           DMA_transfer_handler transfer_handler,
-                           void *opaque)
-{
-}
-#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 */
@@ -423,6 +408,12 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg)
     uint32_t retval;
 
     switch (reg & 0x07) {
+#ifdef TARGET_SPARC
+    case 0x00:
+	// Identify to Linux as S82078B
+	retval = fdctrl_read_statusB(fdctrl);
+	break;
+#endif
     case 0x01:
 	retval = fdctrl_read_statusB(fdctrl);
 	break;
@@ -577,6 +568,14 @@ static void fdctrl_reset_irq (fdctrl_t *fdctrl)
 
 static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status)
 {
+#ifdef TARGET_SPARC
+    // Sparc mutation
+    if (!fdctrl->dma_en) {
+	fdctrl->state &= ~FD_CTRL_BUSY;
+	fdctrl->int_status = status;
+	return;
+    }
+#endif
     if (~(fdctrl->state & FD_CTRL_INTR)) {
         pic_set_irq(fdctrl->irq_lvl, 1);
         fdctrl->state |= FD_CTRL_INTR;
@@ -980,11 +979,11 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
         len = dma_len - fdctrl->data_pos;
         if (len + rel_pos > FD_SECTOR_LEN)
             len = FD_SECTOR_LEN - rel_pos;
-        FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x "
-                       "(%d-0x%08x 0x%08x)\n", len, size, fdctrl->data_pos,
+        FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
+                       "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
                        fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,
                        cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
-                       fd_sector(cur_drv) * 512, addr);
+                       fd_sector(cur_drv) * 512);
         if (fdctrl->data_dir != FD_DIR_WRITE ||
 	    len < FD_SECTOR_LEN || rel_pos != 0) {
             /* READ & SCAN commands and realign to a sector for WRITE */
@@ -1045,7 +1044,7 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
 	    FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
 			   cur_drv->head, cur_drv->track, cur_drv->sect,
 			   fd_sector(cur_drv),
-			   fdctrl->data_pos - size);
+			   fdctrl->data_pos - len);
             /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
                error in fact */
             if (cur_drv->sect >= cur_drv->last_sect ||
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 0af062d967..b186b23f13 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -36,7 +36,10 @@
 // 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_FB	0x50000000	/* TCX frame buffer */
+#define PHYS_JJ_ESPDMA  0x78400000      /* ESP DMA controller */
+#define PHYS_JJ_ESP     0x78800000      /* ESP SCSI */
+#define PHYS_JJ_ESP_IRQ    18
 #define PHYS_JJ_LEDMA   0x78400010      /* Lance DMA controller */
 #define PHYS_JJ_LE      0x78C00000      /* Lance ethernet */
 #define PHYS_JJ_LE_IRQ     16
@@ -50,7 +53,6 @@
 #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
 
@@ -61,32 +63,86 @@ uint64_t cpu_get_tsc()
     return qemu_get_clock(vm_clock);
 }
 
-void DMA_run() {}
+int DMA_get_channel_mode (int nchan)
+{
+    return 0;
+}
+int DMA_read_memory (int nchan, void *buf, int pos, int size)
+{
+    return 0;
+}
+int DMA_write_memory (int nchan, void *buf, int pos, int size)
+{
+    return 0;
+}
+void DMA_hold_DREQ (int nchan) {}
+void DMA_release_DREQ (int nchan) {}
+void DMA_schedule(int nchan) {}
+void DMA_run (void) {}
+void DMA_init (int high_page_enable) {}
+void DMA_register_channel (int nchan,
+                           DMA_transfer_handler transfer_handler,
+                           void *opaque)
+{
+}
+
+static void nvram_set_word (m48t08_t *nvram, uint32_t addr, uint16_t value)
+{
+    m48t08_write(nvram, addr++, (value >> 8) & 0xff);
+    m48t08_write(nvram, addr++, value & 0xff);
+}
+
+static void nvram_set_lword (m48t08_t *nvram, uint32_t addr, uint32_t value)
+{
+    m48t08_write(nvram, addr++, value >> 24);
+    m48t08_write(nvram, addr++, (value >> 16) & 0xff);
+    m48t08_write(nvram, addr++, (value >> 8) & 0xff);
+    m48t08_write(nvram, addr++, value & 0xff);
+}
+
+static void nvram_set_string (m48t08_t *nvram, uint32_t addr,
+                       const unsigned char *str, uint32_t max)
+{
+    unsigned int i;
+
+    for (i = 0; i < max && str[i] != '\0'; i++) {
+        m48t08_write(nvram, addr + i, str[i]);
+    }
+    m48t08_write(nvram, addr + max - 1, '\0');
+}
 
 static m48t08_t *nvram;
 
-static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline)
+extern int nographic;
+
+static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline,
+		       int boot_device, uint32_t RAM_size,
+		       uint32_t kernel_size,
+		       int width, int height, int depth)
 {
     unsigned char tmp = 0;
     int i, j;
 
-    i = 0x40;
+    // Try to match PPC NVRAM
+    nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
+    nvram_set_lword(nvram,  0x10, 0x00000001); /* structure v1 */
+    // NVRAM_size, arch not applicable
+    m48t08_write(nvram, 0x2F, nographic & 0xff);
+    nvram_set_lword(nvram,  0x30, RAM_size);
+    m48t08_write(nvram, 0x34, boot_device & 0xff);
+    nvram_set_lword(nvram,  0x38, KERNEL_LOAD_ADDR);
+    nvram_set_lword(nvram,  0x3C, kernel_size);
     if (cmdline) {
-	uint32_t cmdline_len;
-
 	strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
-	m48t08_write(nvram, i++, CMDLINE_ADDR >> 24);
-	m48t08_write(nvram, i++, (CMDLINE_ADDR >> 16) & 0xff);
-	m48t08_write(nvram, i++, (CMDLINE_ADDR >> 8) & 0xff);
-	m48t08_write(nvram, i++, CMDLINE_ADDR & 0xff);
-
-	cmdline_len = strlen(cmdline);
-	m48t08_write(nvram, i++, cmdline_len >> 24);
-	m48t08_write(nvram, i++, (cmdline_len >> 16) & 0xff);
-	m48t08_write(nvram, i++, (cmdline_len >> 8) & 0xff);
-	m48t08_write(nvram, i++, cmdline_len & 0xff);
+	nvram_set_lword(nvram,  0x40, CMDLINE_ADDR);
+        nvram_set_lword(nvram,  0x44, strlen(cmdline));
     }
+    // initrd_image, initrd_size passed differently
+    nvram_set_word(nvram,   0x54, width);
+    nvram_set_word(nvram,   0x56, height);
+    nvram_set_word(nvram,   0x58, depth);
 
+    // Sun4m specific use
     i = 0x1fd8;
     m48t08_write(nvram, i++, 0x01);
     m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */
@@ -155,7 +211,7 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
     char buf[1024];
     int ret, linux_boot;
     unsigned int i;
-    unsigned long vram_size = 0x100000, prom_offset, initrd_size;
+    long vram_size = 0x100000, prom_offset, initrd_size, kernel_size;
 
     linux_boot = (kernel_filename != NULL);
 
@@ -164,14 +220,14 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
 
     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);
+    tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height);
     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);
-    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline);
     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);
+    esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA);
 
     prom_offset = ram_size + vram_size;
 
@@ -189,13 +245,14 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
     cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, 
                                  prom_offset | IO_MEM_ROM);
 
+    kernel_size = 0;
     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) {
+        kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+        if (kernel_size < 0)
+	    kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+	if (kernel_size < 0)
+	    kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+        if (kernel_size < 0) {
             fprintf(stderr, "qemu: could not load kernel '%s'\n", 
                     kernel_filename);
 	    exit(1);
@@ -222,4 +279,5 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
 	    }
         }
     }
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth);
 }
diff --git a/hw/tcx.c b/hw/tcx.c
index 6c4df7c89a..c0fddf31d7 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -1,7 +1,7 @@
 /*
- * QEMU Sun4m System Emulator
+ * QEMU TCX Frame buffer
  * 
- * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2003-2005 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
@@ -25,29 +25,16 @@
 
 #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
+#define TCX_DAC_NREGS 16
 
 typedef struct TCXState {
     uint32_t addr;
     DisplayState *ds;
     uint8_t *vram;
     unsigned long vram_offset;
+    uint16_t width, height;
     uint8_t r[256], g[256], b[256];
+    uint8_t dac_index, dac_state;
 } TCXState;
 
 static void tcx_draw_line32(TCXState *s1, uint8_t *d, 
@@ -58,9 +45,9 @@ static void tcx_draw_line32(TCXState *s1, uint8_t *d,
 
     for(x = 0; x < width; x++) {
 	val = *s++;
-	*d++ = s1->r[val];
-	*d++ = s1->g[val];
 	*d++ = s1->b[val];
+	*d++ = s1->g[val];
+	*d++ = s1->r[val];
 	d++;
     }
 }
@@ -73,9 +60,9 @@ static void tcx_draw_line24(TCXState *s1, uint8_t *d,
 
     for(x = 0; x < width; x++) {
 	val = *s++;
-	*d++ = s1->r[val];
-	*d++ = s1->g[val];
 	*d++ = s1->b[val];
+	*d++ = s1->g[val];
+	*d++ = s1->r[val];
     }
 }
 
@@ -104,12 +91,12 @@ void tcx_update_display(void *opaque)
 
     if (ts->ds->depth == 0)
 	return;
-    page = ts->vram_offset + YOFF*MAXX;
+    page = ts->vram_offset;
     y_start = -1;
     page_min = 0x7fffffff;
     page_max = -1;
     d = ts->ds->data;
-    s = ts->vram + YOFF*MAXX + XOFF;
+    s = ts->vram;
     dd = ts->ds->linesize;
     ds = 1024;
 
@@ -128,7 +115,7 @@ void tcx_update_display(void *opaque)
 	return;
     }
     
-    for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) {
+    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
 	if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
 	    if (y_start < 0)
                 y_start = y;
@@ -136,23 +123,23 @@ void tcx_update_display(void *opaque)
                 page_min = page;
             if (page > page_max)
                 page_max = page;
-	    f(ts, d, s, XSZ);
+	    f(ts, d, s, ts->width);
 	    d += dd;
 	    s += ds;
-	    f(ts, d, s, XSZ);
+	    f(ts, d, s, ts->width);
 	    d += dd;
 	    s += ds;
-	    f(ts, d, s, XSZ);
+	    f(ts, d, s, ts->width);
 	    d += dd;
 	    s += ds;
-	    f(ts, d, s, XSZ);
+	    f(ts, d, s, ts->width);
 	    d += dd;
 	    s += ds;
 	} else {
             if (y_start >= 0) {
                 /* flush to display */
                 dpy_update(ts->ds, 0, y_start, 
-                           XSZ, y - y_start);
+                           ts->width, y - y_start);
                 y_start = -1;
             }
 	    d += dd * 4;
@@ -162,7 +149,7 @@ void tcx_update_display(void *opaque)
     if (y_start >= 0) {
 	/* flush to display */
 	dpy_update(ts->ds, 0, y_start, 
-		   XSZ, y - y_start);
+		   ts->width, y - y_start);
     }
     /* reset modified pages */
     if (page_max != -1) {
@@ -187,9 +174,13 @@ static void tcx_save(QEMUFile *f, void *opaque)
     
     qemu_put_be32s(f, (uint32_t *)&s->addr);
     qemu_put_be32s(f, (uint32_t *)&s->vram);
+    qemu_put_be16s(f, (uint16_t *)&s->height);
+    qemu_put_be16s(f, (uint16_t *)&s->width);
     qemu_put_buffer(f, s->r, 256);
     qemu_put_buffer(f, s->g, 256);
     qemu_put_buffer(f, s->b, 256);
+    qemu_put_8s(f, &s->dac_index);
+    qemu_put_8s(f, &s->dac_state);
 }
 
 static int tcx_load(QEMUFile *f, void *opaque, int version_id)
@@ -201,9 +192,13 @@ static int tcx_load(QEMUFile *f, void *opaque, int version_id)
 
     qemu_get_be32s(f, (uint32_t *)&s->addr);
     qemu_get_be32s(f, (uint32_t *)&s->vram);
+    qemu_get_be16s(f, (uint16_t *)&s->height);
+    qemu_get_be16s(f, (uint16_t *)&s->width);
     qemu_get_buffer(f, s->r, 256);
     qemu_get_buffer(f, s->g, 256);
     qemu_get_buffer(f, s->b, 256);
+    qemu_get_8s(f, &s->dac_index);
+    qemu_get_8s(f, &s->dac_state);
     return 0;
 }
 
@@ -219,12 +214,66 @@ static void tcx_reset(void *opaque)
     memset(s->vram, 0, MAXX*MAXY);
     cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY,
                                     VGA_DIRTY_FLAG);
+    s->dac_index = 0;
+    s->dac_state = 0;
+}
+
+static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    TCXState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2;
+    switch (saddr) {
+    case 0:
+	s->dac_index = val >> 24;
+	s->dac_state = 0;
+	break;
+    case 1:
+	switch (s->dac_state) {
+	case 0:
+	    s->r[s->dac_index] = val >> 24;
+	    s->dac_state++;
+	    break;
+	case 1:
+	    s->g[s->dac_index] = val >> 24;
+	    s->dac_state++;
+	    break;
+	case 2:
+	    s->b[s->dac_index] = val >> 24;
+	default:
+	    s->dac_state = 0;
+	    break;
+	}
+	break;
+    default:
+	break;
+    }
+    return;
 }
 
+static CPUReadMemoryFunc *tcx_dac_read[3] = {
+    tcx_dac_readl,
+    tcx_dac_readl,
+    tcx_dac_readl,
+};
+
+static CPUWriteMemoryFunc *tcx_dac_write[3] = {
+    tcx_dac_writel,
+    tcx_dac_writel,
+    tcx_dac_writel,
+};
+
 void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
-	      unsigned long vram_offset, int vram_size)
+	       unsigned long vram_offset, int vram_size, int width, int height)
 {
     TCXState *s;
+    int io_memory;
 
     s = qemu_mallocz(sizeof(TCXState));
     if (!s)
@@ -233,13 +282,17 @@ void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
     s->addr = addr;
     s->vram = vram_base;
     s->vram_offset = vram_offset;
+    s->width = width;
+    s->height = height;
 
-    cpu_register_physical_memory(addr, vram_size, vram_offset);
+    cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset);
+    io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s);
+    cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory);
 
     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);
+    dpy_resize(s->ds, width, height);
     return s;
 }
 
@@ -253,11 +306,11 @@ void tcx_screen_dump(void *opaque, const char *filename)
     f = fopen(filename, "wb");
     if (!f)
         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++) {
+    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+    d1 = s->vram;
+    for(y = 0; y < s->height; y++) {
         d = d1;
-        for(x = 0; x < XSZ; x++) {
+        for(x = 0; x < s->width; x++) {
             v = *d;
             fputc(s->r[v], f);
             fputc(s->g[v], f);
diff --git a/pc-bios/proll.elf b/pc-bios/proll.elf
index e274b0d193..f960c83e61 100644
--- a/pc-bios/proll.elf
+++ b/pc-bios/proll.elf
Binary files differdiff --git a/pc-bios/proll.patch b/pc-bios/proll.patch
index 18a157512a..5f2e027d49 100644
--- a/pc-bios/proll.patch
+++ b/pc-bios/proll.patch
@@ -1,6 +1,6 @@
-diff -ruN proll_18.orig/Makefile proll-patch4/Makefile
+diff -ruN proll_18.orig/Makefile proll-patch7/Makefile
 --- proll_18.orig/Makefile	2002-09-13 14:16:59.000000000 +0000
-+++ proll-patch4/Makefile	2004-11-13 15:50:49.000000000 +0000
++++ proll-patch7/Makefile	2004-11-13 15:50:49.000000000 +0000
 @@ -4,6 +4,7 @@
  	make -C krups-ser    all
  	make -C espresso     all
@@ -14,17 +14,143 @@ diff -ruN proll_18.orig/Makefile proll-patch4/Makefile
  	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
+diff -ruN proll_18.orig/qemu/Makefile proll-patch7/qemu/Makefile
+--- proll_18.orig/qemu/Makefile	1970-01-01 00:00:00.000000000 +0000
++++ proll-patch7/qemu/Makefile	2005-03-02 16:41:50.000000000 +0000
+@@ -0,0 +1,122 @@
++#
++# proll:
++# qemu/Makefile - make PROLL for QEMU
++# $Id: proll.patch,v 1.3 2005-03-13 09:43:36 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 -DQEMU
++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 $(CONSOLE) \
++ printf.o le.o system_qemu.o iommu.o \
++ arp.o netinit.o bootp.o packet.o tftp.o udp.o sched_4m.o openprom.o \
++ vconsole.o hconsole.o rconsole.o vcons_zs.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_qemu.o:       system_qemu.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 $*.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
++vcons_zs.o:	$(SRC)/vcons_zs.c $(SRC)/vconsole.h $(SRC)/system.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/head.S proll-patch7/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 @@
++++ proll-patch7/qemu/head.S	2005-03-02 15:30:47.000000000 +0000
+@@ -0,0 +1,539 @@
 +/**
 + ** 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 $
++ * $Id: proll.patch,v 1.3 2005-03-13 09:43:36 bellard Exp $
 + */
 +
 +#include <psr.h>
@@ -167,6 +293,31 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S
 +_start:
 +start:
 +	.globl spill_window_entry, fill_window_entry
++
++#define	EXPORT_TRAP(trap) \
++	.globl trap; \
++	.type trap,function; \
++	.size trap, 16
++
++EXPORT_TRAP(t_zero)
++EXPORT_TRAP(t_wovf)
++EXPORT_TRAP(t_wunf)
++EXPORT_TRAP(t_irq1)
++EXPORT_TRAP(t_irq2)
++EXPORT_TRAP(t_irq3)
++EXPORT_TRAP(t_irq4)
++EXPORT_TRAP(t_irq5)
++EXPORT_TRAP(t_irq6)
++EXPORT_TRAP(t_irq7)
++EXPORT_TRAP(t_irq8)
++EXPORT_TRAP(t_irq9)
++EXPORT_TRAP(t_irq10)
++EXPORT_TRAP(t_irq11)
++EXPORT_TRAP(t_irq12)
++EXPORT_TRAP(t_irq13)
++EXPORT_TRAP(t_irq14)
++EXPORT_TRAP(t_irq15)
++
 +C_LABEL(trapbase):
 +t_zero:	b goprol; nop; nop; nop;
 +t_tflt:	SRMMU_TFAULT                        /* Inst. Access Exception        */
@@ -294,6 +445,8 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S
 +
 +goprol:
 +	! %g1 contains end of memory
++	set	PHYS_JJ_EEPROM + 0x30, %g1
++	lda	[%g1] ASI_M_BYPASS, %g1
 +	! 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
@@ -397,9 +550,6 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S
 +	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
@@ -533,10 +683,10 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S
 +C_LABEL(ldb_bypass):
 +	retl
 +	 lduba [%o0] ASI_M_BYPASS, %o0
-diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c
+diff -ruN proll_18.orig/qemu/main.c proll-patch7/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-patch7/qemu/main.c	2005-03-02 20:08:23.000000000 +0000
+@@ -0,0 +1,173 @@
 +/**
 + ** Proll (PROM replacement)
 + ** Copyright 1999 Pete Zaitcev
@@ -558,8 +708,11 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c
 +#include <arpa.h>
 +#include <system.h>		/* our own prototypes */
 +
++void *init_openprom_qemu(int bankc, struct bank *bankv, unsigned hiphybas, const char *cmdline, char boot_device, int nographic);
++int vcon_zs_init(struct vconterm *t, unsigned int a0);
++int vcon_zs_write(struct vconterm *t, char *data, int leng);
++
 +static void init_idprom(void);
-+static void makepages_q(struct phym *t, unsigned int highbase);
 +
 +struct vconterm dp0;
 +struct mem cmem;		/* Current memory, virtual */
@@ -567,20 +720,48 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c
 +struct phym pmem;		/* Current phys. mem. */
 +struct iommu ciommu;		/* Our IOMMU on sun4m */
 +
-+static char *hw_idprom;
-+int ignore_fault, fault_ignored, ram_size;
++static struct {
++    const char id[16];
++    unsigned int version;
++    char pad1[0x1c]; // Pad to 0x30
++    unsigned int ram_size;
++    char boot_device;
++    unsigned int load_addr, kernel_size;
++    unsigned int cmdline, cmdline_len;
++    char pad2[0x0c]; // Pad to 0x54
++    unsigned short width, height, depth;
++} *hw_idprom;
++
++int ignore_fault, fault_ignored;
++void *printk_fn;
++unsigned int q_height, q_width;
 +
 +/*
 + */
 +void prolmain()
 +{
-+	//static const char fname[14] = "00000000.PROL";
++	static char fname[14];
 +	static struct banks bb;
 +	unsigned int hiphybas;
 +	const void *romvec;
++	unsigned int ram_size;
++	char nographic;
++
++	nographic = ldb_bypass(PHYS_JJ_EEPROM + 0x2F);
++	if (!nographic) {
++	    q_width = ldh_bypass(PHYS_JJ_EEPROM + 0x54);
++	    q_height = ldh_bypass(PHYS_JJ_EEPROM + 0x56);
++	    vcon_init(&dp0, PHYS_JJ_TCX_FB);
++	    printk_fn = vcon_write;
++	}
++	else {
++	    vcon_zs_init(&dp0, 0x71100000);
++	    printk_fn = vcon_zs_write;
++	}
++
 +
-+	vcon_init(&dp0, PHYS_JJ_TCX_FB);
 +	printk("PROLL %s QEMU\n", PROLL_VERSION_STRING);
++	ram_size = ld_bypass(PHYS_JJ_EEPROM + 0x30);
 +	printk("%d MB total\n", ram_size/(1024*1024));
 +
 +	bb.nbanks = 1;
@@ -590,7 +771,7 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c
 +	hiphybas = ram_size - PROLSIZE;
 +
 +	mem_init(&cmem, (char *) &_end, (char *)(PROLBASE+PROLSIZE));
-+	makepages_q(&pmem, hiphybas);
++	makepages(&pmem, hiphybas);
 +	init_mmu_swift((unsigned int)pmem.pctp - PROLBASE + hiphybas);
 +
 +	mem_init(&cio, (char *)(PROLBASE+PROLSIZE),
@@ -601,38 +782,46 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c
 +	/*
 +	 */
 +	init_idprom();
++	printk("NVRAM: id %s version %d\n", hw_idprom->id, hw_idprom->version);
++	if (!nographic)
++	    printk("Prom console: TCX %dx%d\n", q_width, q_height);
++	else
++	    printk("Prom console: serial\n");
 +	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
++	printk("Boot device: %c\n", hw_idprom->boot_device);
++	if (hw_idprom->boot_device == 'n') {
++	    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);
++	    fname[9] = '.';
++	    fname[10] = 'P';
++	    fname[11] = 'R';
++	    fname[12] = 'O';
++	    fname[13] = 'L';
++	    fname[14] = 0;
++	    
++	    if (load(boot_rec.bp_siaddr, fname) != 0) fatal();
++	}
 +
-+	romvec = init_openprom(bb.nbanks, bb.bankv, hiphybas);
++	romvec = init_openprom_qemu(bb.nbanks, bb.bankv, hiphybas,
++				    (void *)hw_idprom->cmdline, hw_idprom->boot_device, nographic);
 +
 +	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;
++	    void (*entry)(const void *, int, int, int, int) = (void *) hw_idprom->load_addr;
++		printk("Kernel loaded at 0x%x, size %dK, command line = '%s'\n",
++		       *entry, hw_idprom->kernel_size/1024, hw_idprom->cmdline);
 +		entry(romvec, 0, 0, 0, 0);
 +	}
 +
@@ -652,14 +841,12 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c
 + */
 +void udelay(unsigned long usecs)
 +{
-+	int i, n;
-+	n = usecs*50;
-+	for (i = 0; i < n; i++) { }
++    // Qemu hardware is perfect and does not need any delays!
 +}
 +
 +static void init_idprom()
 +{
-+	char *va_prom;
++	void *va_prom;
 +
 +	if ((va_prom = map_io(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE)) == NULL) {
 +		printk("init_idprom: cannot map eeprom\n");
@@ -673,175 +860,10 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c
 +	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
+diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/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 @@
++++ proll-patch7/qemu/openprom.c	2005-03-02 20:09:57.000000000 +0000
+@@ -0,0 +1,646 @@
 +/*
 + * PROM interface support
 + * Copyright 1996 The Australian National University.
@@ -858,6 +880,8 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +#include <vconsole.h>
 +#include "phys_jj.h"
 +
++//#define DEBUG_OBP
++
 +struct property {
 +	const char *name;
 +	const char *value;
@@ -908,6 +932,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +static const struct property propv_sbus[] = {
 +	{"name",	"sbus", 5},
 +	{"ranges",	(char*)&prop_sbus_ranges[0], sizeof(prop_sbus_ranges)},
++	{"device_type",	"hierarchical", sizeof("hierarchical") },
 +	{NULL, NULL, -1}
 +};
 +
@@ -1005,6 +1030,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +static const struct property propv_obio[] = {
 +	{"name",	"obio", 5 },
 +	{"ranges",	(char*)&prop_obio_ranges[0], sizeof(prop_obio_ranges) },
++	{"device_type",	"hierarchical", sizeof("hierarchical") },
 +	{NULL, NULL, -1}
 +};
 +
@@ -1056,29 +1082,35 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +	{NULL, NULL, -1}
 +};
 +
-+static const int prop_zs_intr[] = { 0x26, 0x0 };
++static const int prop_zs_intr[] = { 12, 0x0 };
 +static const int prop_zs_reg[] = {
-+	0x4, 0x00000000, 0x0000000f,
++	0x0, 0x00000000, 0x00000008,
 +};
-+static const int prop_zs_slave[] = { 0x1 };
++static const int prop_zs_addr = { 0x70000000 };
++static const int prop_zs_slave[] = { 1 };
 +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) },
++	{"slave",	(char*)&prop_zs_slave[0], sizeof(prop_zs_slave) },
 +	{"device_type", "serial", sizeof("serial") },
++	{"intr",	(char*)&prop_zs_intr[0], sizeof(prop_zs_intr) },
++	//	{"address",	(char*)&prop_zs_addr, sizeof(prop_zs_addr) },
 +	{NULL, NULL, -1}
 +};
 +
-+static const int prop_zs1_intr[] = { 0x26, 0x0 };
++static const int prop_zs1_intr[] = { 12, 0x0 };
 +static const int prop_zs1_reg[] = {
-+	0x4, 0x00100000, 0x0000000f,
++	0x0, 0x00100000, 0x00000008,
 +};
-+static const int prop_zs1_slave[] = { 0x0 };
++static const int prop_zs1_addr = { 0x70100000 };
++static const int prop_zs1_slave[] = { 0 };
 +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) },
++	{"slave",	(char*)&prop_zs1_slave[0], sizeof(prop_zs1_slave) },
 +	{"device_type", "serial", sizeof("serial") },
++	{"intr",	(char*)&prop_zs1_intr[0], sizeof(prop_zs1_intr) },
++	//	{"address",	(char*)&prop_zs1_addr, sizeof(prop_zs1_addr) },
 +	{NULL, NULL, -1}
 +};
 +
@@ -1106,24 +1138,110 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +	{NULL, NULL, -1}
 +};
 +
++static const int prop_espdma_reg[] = {
++	0x4, 0x08400000, 0x00000010,
++};
++// Disabled, not implemented yet
++static const struct property propv_sbus_espdma[] = {
++	{"name",	"xxxespdma", sizeof("xxxespdma")}, 
++	{"reg",		(char*)&prop_espdma_reg[0], sizeof(prop_espdma_reg) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_esp_reg[] = {
++	0x4, 0x08800000, 0x00000040,
++};
++static const int prop_esp_intr[] = { 0x24, 0x0 };
++static const struct property propv_sbus_espdma_esp[] = {
++	{"name",	"esp", sizeof("esp")},
++	{"reg",		(char*)&prop_esp_reg[0], sizeof(prop_esp_reg) },
++	{"intr",	(char*)&prop_esp_intr[0], sizeof(prop_esp_intr) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_bpp_reg[] = {
++	0x4, 0x0c800000, 0x0000001c,
++};
++static const int prop_bpp_intr[] = { 0x33, 0x0 };
++static const struct property propv_sbus_bpp[] = {
++	{"name",	"SUNW,bpp", sizeof("SUNW,bpp")},
++	{"reg",		(char*)&prop_bpp_reg[0], sizeof(prop_bpp_reg) },
++	{"intr",	(char*)&prop_bpp_intr[0], sizeof(prop_bpp_intr) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_fd_intr[] = { 0x2b, 0x0 };
++static const int prop_fd_reg[] = {
++	0x0, 0x00400000, 0x0000000f,
++};
++static const struct property propv_obio_fd[] = {
++	{"name",	"SUNW,fdtwo", sizeof("SUNW,fdtwo")},
++	{"reg",		(char*)&prop_fd_reg[0], sizeof(prop_fd_reg) },
++	{"device_type", "block", sizeof("block") },
++	{"intr",	(char*)&prop_fd_intr[0], sizeof(prop_fd_intr) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_pw_intr[] = { 0x22, 0x0 };
++static const int prop_pw_reg[] = {
++	0x0, 0x00910000, 0x00000001,
++};
++static const struct property propv_obio_pw[] = {
++	{"name",	"power", sizeof("power")},
++	{"reg",		(char*)&prop_pw_reg[0], sizeof(prop_pw_reg) },
++	{"intr",	(char*)&prop_pw_intr[0], sizeof(prop_pw_intr) },
++	{NULL, NULL, -1}
++};
++
++static const int prop_cf_reg[] = {
++	0x0, 0x00800000, 0x00000001,
++};
++static const struct property propv_obio_cf[] = {
++	{"name",	"slavioconfig", sizeof("slavioconfig")},
++	{"reg",		(char*)&prop_cf_reg[0], sizeof(prop_cf_reg) },
++	{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_iommu,		11,  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_sbus_cs4231,	 8,  0 }, /*  7 "/iommu/sbus/SUNW,CS4231 */
++	{ propv_sbus_bpp,	 9,  0 }, /*  8 "/iommu/sbus/SUNW,bpp */
++	{ propv_sbus_espdma,	 0, 10 }, /*  9 "/iommu/sbus/espdma" */
++	{ propv_sbus_espdma_esp, 0,  0 }, /* 10 "/iommu/sbus/espdma/esp" */
++	{ propv_cpu,		12,  0 }, /* 11 "/STP1012PGA" */
++	{ propv_obio,		 0, 13 }, /* 12 "/obio" */
++	{ propv_obio_int,	14,  0 }, /* 13 "/obio/interrupt" */
++	{ propv_obio_cnt,	15,  0 }, /* 14 "/obio/counter" */
++	{ propv_obio_eep,	16,  0 }, /* 15 "/obio/eeprom" */
++	{ propv_obio_auxio,	17,  0 }, /* 16 "/obio/auxio" */
++	{ propv_obio_zs,	18,  0 }, /* 17 "/obio/zs@0,0" */
++	{ propv_obio_zs1,	19,  0 }, /* 18 "/obio/zs@0,100000" */
++	{ propv_obio_fd,	20,  0 }, /* 19 "/obio/SUNW,fdtwo" */
++	{ propv_obio_pw,	21,  0 }, /* 20 "/obio/power" */
++	{ propv_obio_cf,	 0,  0 }, /* 21 "/obio/slavioconfig@0,800000" */
++#if 0
 +	{ 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" */
++	{ propv_cpu,		18,  0 }, /* 17 "/STP1012PGA" */
++	{ propv_cpu,		19,  0 }, /* 18 "/STP1012PGA" */
++
++	{ propv_cpu,		20,  0 }, /* 19 "/STP1012PGA" */
++	{ propv_cpu,		21,  0 }, /* 20 "/STP1012PGA" */
++	{ propv_cpu,		22,  0 }, /* 21 "/STP1012PGA" */
++	{ propv_cpu,		23,  0 }, /* 22 "/STP1012PGA" */
++	{ propv_cpu,		24,  0 }, /* 23 "/STP1012PGA" */
++	{ propv_cpu,		25,  0 }, /* 24 "/STP1012PGA" */
++	{ propv_cpu,		26,  0 }, /* 25 "/STP1012PGA" */
++	{ propv_cpu,		27,  0 }, /* 26 "/STP1012PGA" */
++	{ propv_cpu,		28,  0 }, /* 27 "/STP1012PGA" */
++	{ propv_cpu,		29,  0 }, /* 28 "/STP1012PGA" */
++	{ propv_cpu,		30,  0 }, /* 29 "/STP1012PGA" */
++#endif
 +};
 +
 +static struct linux_mlist_v0 totphys[MAX_BANKS];
@@ -1144,24 +1262,11 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +        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 struct linux_arguments_v0 obp_arg;
 +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 void (*synch_hook)(void);
++static char obp_stdin, obp_stdout;
 +
 +static int obp_nbgetchar(void);
 +static int obp_nbputchar(int ch);
@@ -1181,88 +1286,11 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +	if (ptab1 != 0) mem_tablewalk(ptab1, va);
 +}
 +
-+#ifdef ORIG
-+static const struct linux_romvec romvec0 = {
-+	LINUX_OPPROM_MAGIC,		/* pv_magic_cookie */
-+	0,				/* pv_romvers - Format selector! */
-+	77,				/* pv_plugin_revision */
-+	0x10203,			/* pv_printrev */
-+	{				/* pv_v0mem */
-+		&ptphys,		/* v0_totphys */
-+		&ptmap,			/* v0_prommap */
-+		&ptavail		/* v0_available */
-+	},
-+        &nodeops0,			/* struct linux_nodeops *pv_nodeops; */
-+        (void*)doublewalk, /* P3 */	/* char **pv_bootstr; */
-+	{				/* struct linux_dev_v0_funcs pv_v0devops; */
-+		&obp_devopen,		/* v0_devopen */
-+		&obp_devclose,		/* v0_devclose */
-+		&obp_rdblkdev,		/* v0_rdblkdev */
-+		NULL,			/* v0_wrblkdev */
-+		NULL,			/* v0_wrnetdev */
-+		NULL,			/* v0_rdnetdev */
-+		NULL,			/* v0_rdchardev */
-+		NULL,			/* v0_wrchardev */
-+		NULL			/* v0_seekdev */
-+	},
-+        &obp_stdin,			/* char *pv_stdin */
-+        &obp_stdout,			/* char *pv_stdout; */
-+        obp_nbgetchar,			/* int (*pv_getchar)(void); */
-+        obp_nbputchar,			/* void (*pv_putchar)(int ch); */
-+        obp_nbgetchar,			/* int (*pv_nbgetchar)(void); */
-+        obp_nbputchar,			/* int (*pv_nbputchar)(int ch); */
-+        NULL,			/* void (*pv_putstr)(char *str, int len); */
-+        obp_reboot,			/* void (*pv_reboot)(char *bootstr); */
-+        NULL,		/* void (*pv_printf)(__const__ char *fmt, ...); */
-+        obp_abort,			/* void (*pv_abort)(void); */
-+        NULL,				/* __volatile__ int *pv_ticks; */
-+        obp_halt,			/* void (*pv_halt)(void); */
-+        (void *)&synch_hook,		/* void (**pv_synchook)(void); */
-+
-+#if 0
-+        /* Evaluate a forth string, not different proto for V0 and V2->up. */
-+        union {
-+                void (*v0_eval)(int len, char *str);
-+                void (*v2_eval)(char *str);
-+        } pv_fortheval;
-+#endif
-+	{ 0 },			/* pv_fortheval */
-+
-+        &obp_argp,		/* struct linux_arguments_v0 **pv_v0bootargs; */
-+	NULL,			/* pv_enaddr */
-+	{			/* pv_v2bootargs */
-+        	NULL,		/* char **bootpath; */
-+		NULL,		/* char **bootargs; */
-+		NULL,		/* fd_stdin; */
-+		NULL,		/* fd_stdout */
-+	},
-+	{			/* pv_v2devops */
-+        	NULL,		/* v2_inst2pkg */
-+        	NULL,		/* v2_dumb_mem_alloc */
-+        	NULL,		/* v2_dumb_mem_free */
-+        	NULL,		/* v2_dumb_mmap */
-+        	NULL,		/* v2_dumb_munmap */
-+        	NULL,		/* v2_dev_open */
-+        	NULL,		/* v2_dev_close */
-+        	NULL,		/* v2_dev_read */
-+        	NULL,		/* v2_dev_write */
-+        	NULL,		/* v2_dev_seek */
-+        	NULL,		/* v2_wheee2 */
-+        	NULL,		/* v2_wheee3 */
-+	},
-+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* filler[15] */
-+        NULL,			/* pv_setctxt */
-+        NULL,			/* v3_cpustart */
-+        NULL,			/* v3_cpustop */
-+        NULL,			/* v3_cpuidle */
-+        NULL			/* v3_cpuresume */
-+};
-+#endif
-+
 +static struct linux_romvec romvec0;
 +
 +void *
-+init_openprom(int bankc, struct bank *bankv, unsigned hiphybas)
++init_openprom_qemu(int bankc, struct bank *bankv, unsigned hiphybas,
++		   const char *cmdline, char boot_device, int nographic)
 +{
 +	int i;
 +
@@ -1316,10 +1344,13 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +	romvec0.pv_v0mem.v0_available = &ptavail;
 +	romvec0.pv_nodeops = &nodeops0;
 +	romvec0.pv_bootstr = (void *)doublewalk;
++	romvec0.pv_v0devops.v0_devopen = &obp_devopen;
++	romvec0.pv_v0devops.v0_devclose = &obp_devclose;
++	romvec0.pv_v0devops.v0_rdblkdev = &obp_rdblkdev;
 +	romvec0.pv_stdin = &obp_stdin;
 +	romvec0.pv_stdout = &obp_stdout;
 +	romvec0.pv_getchar = obp_nbgetchar;
-+	romvec0.pv_putchar = obp_nbputchar;
++	romvec0.pv_putchar = (void (*)(int))obp_nbputchar;
 +	romvec0.pv_nbgetchar = obp_nbgetchar;
 +	romvec0.pv_nbputchar = obp_nbputchar;
 +	romvec0.pv_reboot = obp_reboot;
@@ -1327,6 +1358,27 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +	romvec0.pv_halt = obp_halt;
 +	romvec0.pv_synchook = &synch_hook;
 +	romvec0.pv_v0bootargs = &obp_argp;
++	switch(boot_device) {
++	default:
++	case 'a':
++	    obp_arg.argv[0] = "fd()";
++	    break;
++	case 'c':
++	    obp_arg.argv[0] = "sd()";
++	    break;
++	case 'n':
++	    obp_arg.argv[0] = "le()";
++	    break;
++	}
++	obp_arg.argv[1] = cmdline;
++
++	if (nographic) {
++	    obp_stdin = PROMDEV_TTYA;
++	    obp_stdout = PROMDEV_TTYA;
++	} else {
++	    obp_stdin = PROMDEV_KBD;
++	    obp_stdout = PROMDEV_SCREEN;
++	}
 +	return &romvec0;
 +}
 +
@@ -1342,18 +1394,32 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +
 +static int obp_nextnode(int node)
 +{
++#ifdef DEBUG_OBP
++        printk("obp_nextnode(%d) = %d\n", node, nodes[node].sibling);
++#endif
 +	return nodes[node].sibling;
 +}
 +
 +static int obp_child(int node)
 +{
++#ifdef DEBUG_OBP
++        printk("obp_child(%d) = %d\n", node, nodes[node].child);
++#endif
 +	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;
++	if (prop) {
++#ifdef DEBUG_OBP
++	    printk("obp_proplen(%d, %s) = %d\n", node, name, prop->length);
++#endif
++	    return prop->length;
++	}
++#ifdef DEBUG_OBP
++	printk("obp_proplen(%d, %s) (no prop)\n", node, name);
++#endif
 +	return -1;
 +}
 +
@@ -1364,47 +1430,47 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +	prop = find_property(node,name);
 +	if (prop) {
 +		memcpy(value,prop->value,prop->length);
-+		//printk("obp_getprop '%s'= %s\n", name, value);
++#ifdef DEBUG_OBP
++		printk("obp_getprop(%d, %s) = %s\n", node, name, value);
++#endif
 +		return prop->length;
 +	}
-+        //printk("obp_getprop: not found\n");
++#ifdef DEBUG_OBP
++        printk("obp_getprop(%d, %s): not found\n", node, name);
++#endif
 +	return -1;
 +}
 +
 +static int obp_setprop(int node, char *name, char *value, int len)
 +{
++#ifdef DEBUG_OBP
++        printk("obp_setprop(%d, %s) = %s (%d)\n", node, name, value, len);
++#endif
 +	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;
++	if (prop) {
++#ifdef DEBUG_OBP
++	    printk("obp_nextprop(%d, %s) = %s\n", node, name, prop[1].name);
++#endif
++	    return prop[1].name;
++	}
++#ifdef DEBUG_OBP
++        printk("obp_nextprop(%d, %s): not found\n", node, name);
++#endif
 +	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;
++	extern struct vconterm dp0;
++	return vcon_getch(&dp0);
 +}
 +
 +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);
++	printk("%c", ch);
 +	return 0;
 +}
 +
@@ -1424,23 +1490,449 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c
 +}
 +
 +static int obp_devopen(char *str) {
-+        //printk("open %s\n", str);
++#ifdef DEBUG_OBP
++        printk("open %s\n", str);
++#endif
 +	return 0;
 +}
 +
 +static int obp_devclose(int dev_desc) {
-+        //printk("close %d\n", dev_desc);
++#ifdef DEBUG_OBP
++        printk("close %d\n", dev_desc);
++#endif
 +	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);
++#ifdef DEBUG_OBP
++    printk("rdblkdev: fd %d, num_blks %d, blk_st %d, buf 0x%x\n", dev_desc, num_blks, blk_st, buf);
++#endif
 +    //buf[8] = 'L';
 +    return num_blks;
 +}
-diff -ruN proll_18.orig/src/arp.c proll-patch4/src/arp.c
+diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch7/qemu/system_qemu.c
+--- proll_18.orig/qemu/system_qemu.c	1970-01-01 00:00:00.000000000 +0000
++++ proll-patch7/qemu/system_qemu.c	2005-03-02 16:10:20.000000000 +0000
+@@ -0,0 +1,416 @@
++/**
++ ** Proll (PROM replacement)
++ ** system.c: shared miscallenea.
++ ** Copyright 1999 Pete Zaitcev
++ ** This code is licensed under GNU General Public License.
++ **/
++#include <stdarg.h>
++#include <asi.h>
++#include <crs.h>
++#ifndef NULL
++#define	NULL ((void*)0)
++#endif
++
++#include "pgtsrmmu.h"
++
++#include "vconsole.h"
++#include <timer.h>		/* Local copy of 2.2 style include */
++#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 */
++
++/*
++ * We export this.
++ */
++char idprom[IDPROM_SIZE];
++
++
++/*
++ * Create an I/O mapping to pa[size].
++ * Returns va of the mapping or 0 if unsuccessful.
++ */
++void *
++map_io(unsigned pa, int size)
++{
++	void *va;
++	unsigned int npages;
++	unsigned int off;
++	unsigned int mva;
++
++	off = pa & (PAGE_SIZE-1);
++	npages = (off + size + (PAGE_SIZE-1)) / PAGE_SIZE;
++	pa &= ~(PAGE_SIZE-1);
++
++	va = mem_alloc(&cio, npages*PAGE_SIZE, PAGE_SIZE);
++	if (va == 0) return va;
++
++	mva = (unsigned int) va;
++    /* printk("map_io: va 0x%x pa 0x%x off 0x%x npages %d\n", va, pa, off, npages); */ /* P3 */
++	while (npages-- != 0) {
++		map_page(pmem.pl1, mva, pa, 1, pmem.pbas);
++		mva += PAGE_SIZE;
++		pa += PAGE_SIZE;
++	}
++
++	return (void *)((unsigned int)va + off);
++}
++
++/*
++ * Tablewalk routine used for testing.
++ * Returns PTP/PTE.
++ */
++unsigned int
++proc_tablewalk(int ctx, unsigned int va)
++{
++	unsigned int pa1;
++
++	__asm__ __volatile__ ("lda [%1] %2, %0" :
++				"=r" (pa1) :
++				"r" (AC_M_CTPR), "i" (ASI_M_MMUREGS));
++	/* printk(" ctpr %x ctx %x\n", pa1, ctx); */ /* P3 */
++	pa1 <<= 4;
++	pa1 = ld_bypass(pa1 + (ctx << 2));
++	if ((pa1 & 0x03) == 0) goto invalid;
++	return mem_tablewalk((pa1 & 0xFFFFFFF0) << 4, va);
++
++invalid:
++	printk(" invalid %x\n", pa1);
++	return 0;
++}
++
++/*
++ * Walk the tables in memory, starting at physical address pa.
++ */
++unsigned int
++mem_tablewalk(unsigned int pa, unsigned int va)
++{
++	unsigned int pa1;
++
++	printk("pa %x va %x", pa, va);
++	pa1 = ld_bypass(pa + (((va&0xFF000000)>>24) << 2));
++	if ((pa1 & 0x03) == 0) goto invalid;
++	printk(" l1 %x", pa1);
++	pa1 <<= 4;    pa1 &= 0xFFFFFF00;
++	pa1 = ld_bypass(pa1 + (((va&0x00FC0000)>>18) << 2));
++	if ((pa1 & 0x03) == 0) goto invalid;
++	printk(" l2 %x", pa1);
++	pa1 <<= 4;    pa1 &= 0xFFFFFF00;
++	pa1 = ld_bypass(pa1 + (((va&0x0003F000)>>12) << 2));
++	if ((pa1 & 0x03) == 0) goto invalid;
++	printk(" l3 %x", pa1);
++	printk(" off %x\n", va&0x00000FFF);
++	return pa1;
++invalid:
++	printk(" invalid %x\n", pa1);
++	return 0;
++}
++
++/*
++ * 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(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;
++}
++
++/*
++ * Create a memory mapping from va to epa in page table pgd.
++ * highbase is used for v2p translation.
++ */
++int
++map_page(unsigned int *pgd, unsigned int va,
++    unsigned int epa, int type, unsigned int highbase)
++{
++	unsigned int pte;
++	unsigned int *p;
++	unsigned int pa;
++
++	pte = pgd[((va)>>SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD-1)];
++	if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) {
++		p = mem_zalloc(&cmem, SRMMU_PTRS_PER_PMD*sizeof(int),
++		    SRMMU_PTRS_PER_PMD*sizeof(int));
++		if (p == 0) goto drop;
++		pte = SRMMU_ET_PTD |
++		    (((unsigned int)p - PROLBASE + highbase) >> 4);
++		pgd[((va)>>SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD-1)] = pte;
++		/* barrier() */
++	}
++
++	pa = ((pte & 0xFFFFFFF0) << 4);
++	pa += (((va)>>SRMMU_PMD_SHIFT & (SRMMU_PTRS_PER_PMD-1)) << 2);
++	pte = ld_bypass(pa);
++	if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) {
++		p = mem_zalloc(&cmem, SRMMU_PTRS_PER_PTE*sizeof(int),
++		    SRMMU_PTRS_PER_PTE*sizeof(int));
++		if (p == 0) goto drop;
++		pte = SRMMU_ET_PTD |
++		    (((unsigned int)p - PROLBASE + highbase) >> 4);
++		st_bypass(pa, pte);
++	}
++
++	pa = ((pte & 0xFFFFFFF0) << 4);
++	pa += (((va)>>PAGE_SHIFT & (SRMMU_PTRS_PER_PTE-1)) << 2);
++
++	pte = SRMMU_ET_PTE | ((epa & PAGE_MASK) >> 4);
++	if (type) {		/* I/O */
++		pte |= SRMMU_REF;
++		/* SRMMU cannot make Supervisor-only, but not exectutable */
++		pte |= SRMMU_PRIV;
++	} else {		/* memory */
++		pte |= SRMMU_REF|SRMMU_CACHE;
++		pte |= SRMMU_PRIV;		/* Supervisor only access */
++	}
++	st_bypass(pa, pte);
++	return 0;
++
++drop:
++	return -1;
++}
++
++/*
++ * Switch page tables.
++ */
++void
++init_mmu_swift(unsigned int ctp_phy)
++{
++	unsigned int addr;
++
++	/*
++	 * Flush cache
++	 */
++	for (addr = 0; addr < 0x2000; addr += 0x10) {
++		__asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : :
++		    "r" (addr), "i" (ASI_M_DATAC_TAG));
++		__asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : :
++		    "r" (addr<<1), "i" (ASI_M_TXTC_TAG));
++	}
++
++	/*
++	 * Switch ctx table
++	 */
++	ctp_phy >>= 4;
++	/* printk("done flushing, switching to %x\n", ctp_phy); */
++	__asm__ __volatile__ ("sta %0, [%1] %2\n\t" : :
++	    "r" (ctp_phy), "r" (AC_M_CTPR), "i" (ASI_M_MMUREGS));
++
++	/*
++	 * Flush old page table references
++	 */
++	__asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : :
++	    "r" (0x400), "i" (ASI_M_FLUSH_PROBE) : "memory");
++}
++
++/*
++ * add_timer, del_timer
++ * This should go into sched.c, but we have it split for different archs.
++ */
++struct timer_list_head {
++	struct timer_list *head, *tail;
++};
++
++static struct timer_list_head timers;		/* Anonymous heap of timers */
++
++void add_timer(struct timer_list *timer) {
++	struct timer_list *p;
++	if (timer->prev != NULL || timer->next != NULL) {
++		printk("bug: kernel timer added twice at 0x%x.\n",
++		    __builtin_return_address(0));
++		return;
++	}
++	if ((p = timers.tail) != NULL) {
++		timer->prev = p;
++		p->next = timer;
++		timers.tail = timer;
++	} else {
++		timers.head = timer;
++		timers.tail = timer;
++	}
++	return;
++}
++
++int del_timer(struct timer_list *timer) {
++	struct timer_list *p;
++	int ret;
++
++	if (timers.head == timer) timers.head = timer->next;
++	if (timers.tail == timer) timers.tail = timer->prev;
++	if ((p = timer->prev) != NULL) p->next = timer->next;
++	if ((p = timer->next) != NULL) p->prev = timer->prev;
++	ret = timer->next != 0 || timer->prev != 0;
++	timer->next = NULL;
++	timer->prev = NULL;
++	return ret;
++}
++
++void run_timers() {
++	struct timer_list *p;
++
++	p = timers.head;
++	while (p != NULL) {
++		if (p->expires < jiffies) {
++			del_timer(p);		/* XXX make nonstatic member */
++			(*p->function)(p->data);
++			p = timers.head;
++		} else {
++			p = p->next;
++		}
++	}
++}
++
++/*
++ * Allocate memory. This is reusable.
++ */
++void mem_init(struct mem *t, char *begin, char *limit)
++{
++	t->start = begin;
++	t->uplim = limit;
++	t->curp = begin;
++}
++
++void mem_fini(struct mem *t)
++{
++	t->curp = 0;
++}
++
++void *mem_alloc(struct mem *t, int size, int align)
++{
++	char *p;
++
++	p = (char *)((((unsigned int)t->curp) + (align-1)) & ~(align-1));
++	if (p >= t->uplim || p + size > t->uplim) return 0;
++	t->curp = p + size;
++	return p;
++}
++
++void *mem_zalloc(struct mem *t, int size, int align)
++{
++	char *p;
++
++	if ((p = mem_alloc(t, size, align)) != 0) bzero(p, size);
++	return p;
++}
++
++/*
++ * Library functions
++ */
++void bzero(void *s, int len) {
++	while (len--) *((char *)s)++ = 0;
++}
++
++void bcopy(const void *f, void *t, int len) {
++	while (len--) *((char *)t)++ = *((char *)f)++;
++}
++
++/* Comparison is 7-bit */
++int bcmp(const void *s1, const void *s2, int len)
++{
++	int i;
++	char ch;
++
++	while (len--) {
++		ch = *((char *)s1)++;
++		if ((i = ch - *((char *)s2)++) != 0)
++			return i;
++		if (ch == 0)
++			return 0;
++	}
++	return 0;
++}
++
++int strlen(const char *s) {
++	const char *p;
++	for (p = s; *p != 0; p++) { }
++	return p - s;
++}
++
++extern void *printk_fn;
++
++void printk(char *fmt, ...)
++{
++	struct prf_fp {
++		void *xfp;
++		void (*write)(void *, char *, int);
++	} prfa;
++	extern void prf(struct prf_fp *, char *fmt, va_list adx);
++	va_list x1;
++
++	va_start(x1, fmt);
++	prfa.xfp = &dp0;
++	prfa.write = printk_fn;
++	prf(&prfa, fmt, x1);
++	va_end(x1);
++}
++
++void fatal()
++{
++	printk("fatal.");
++loop: goto loop;
++}
++
++/*
++ * Get the highest bit number from the mask.
++ */
++int highc(int mask, int size)
++{
++	int m1;
++
++	m1 = 1 << size;
++	while (size != 0) {
++		size--;
++		m1 >>= 1;
++		if (m1 & mask) break;
++	}
++	return size;
++}
++
++/*
++ */
++unsigned int ld_bp_swap(unsigned int ptr) {
++	unsigned int n;
++	n = ld_bypass(ptr);
++	n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24);
++	return n;
++}
++
++void st_bp_swap(unsigned int ptr, unsigned int n) {
++	n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24);
++	st_bypass(ptr, n);
++};
+diff -ruN proll_18.orig/src/arp.c proll-patch7/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
++++ proll-patch7/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	*/
@@ -1475,9 +1967,9 @@ diff -ruN proll_18.orig/src/arp.c proll-patch4/src/arp.c
 +  def_gw = IP_ANY;
    return(TRUE);
  }
-diff -ruN proll_18.orig/src/arp.h proll-patch4/src/arp.h
+diff -ruN proll_18.orig/src/arp.h proll-patch7/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
++++ proll-patch7/src/arp.h	2004-11-13 15:50:49.000000000 +0000
 @@ -104,7 +104,7 @@
  extern int init_arp __P((void));
  
@@ -1487,24 +1979,35 @@ diff -ruN proll_18.orig/src/arp.h proll-patch4/src/arp.h
  
  /* 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
+diff -ruN proll_18.orig/src/hconsole.c proll-patch7/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 @@
++++ proll-patch7/src/hconsole.c	2005-03-02 17:03:09.000000000 +0000
+@@ -29,6 +29,10 @@
+        struct raster r_master;	/* For a case of resize, whole fb */
+        struct raster r_0;	/* malloc() erzatz */
+ 
++#ifdef QEMU
++extern unsigned int q_height, q_width;
++#endif
++
+ int hcon_init(struct hconsole *t, unsigned int a0)
+ {
+ 	struct raster *q, *r;
+@@ -42,7 +46,11 @@
   	 * No probing sequence or argument passing, hardcode everything. XXX
  	 */
  	raster8_cons_a(q, 768, 1024, (char *)a0);
-+#if 1
++#ifndef QEMU
  	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);
++	raster_cons_2(r, q, 0, 0, q_height, q_width);
 +#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
+diff -ruN proll_18.orig/src/lat7_2.bm proll-patch7/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
++++ proll-patch7/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
@@ -1513,9 +2016,9 @@ diff -ruN proll_18.orig/src/lat7_2.bm proll-patch4/src/lat7_2.bm
     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
+diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch7/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
++++ proll-patch7/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
@@ -1638,9 +2141,9 @@ diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch4/src/lat7_2_swapped.bm
 +   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
+diff -ruN proll_18.orig/src/le.c proll-patch7/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
++++ proll-patch7/src/le.c	2004-11-13 15:50:49.000000000 +0000
 @@ -185,8 +185,6 @@
  	unsigned short rap;			/* register address port */
  };
@@ -1650,9 +2153,9 @@ diff -ruN proll_18.orig/src/le.c proll-patch4/src/le.c
  /* 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
+diff -ruN proll_18.orig/src/netinit.c proll-patch7/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
++++ proll-patch7/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	*/
@@ -1696,9 +2199,9 @@ diff -ruN proll_18.orig/src/netinit.c proll-patch4/src/netinit.c
  	fatal();
    }
  }
-diff -ruN proll_18.orig/src/netpriv.h proll-patch4/src/netpriv.h
+diff -ruN proll_18.orig/src/netpriv.h proll-patch7/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
++++ proll-patch7/src/netpriv.h	2004-11-13 15:50:49.000000000 +0000
 @@ -130,10 +130,9 @@
   *
   */
@@ -1720,9 +2223,9 @@ diff -ruN proll_18.orig/src/netpriv.h proll-patch4/src/netpriv.h
  
  /* Empty read buffer */
  extern void empty_buf __P((void));
-diff -ruN proll_18.orig/src/openprom.h proll-patch4/src/openprom.h
+diff -ruN proll_18.orig/src/openprom.h proll-patch7/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
++++ proll-patch7/src/openprom.h	2004-11-13 15:50:49.000000000 +0000
 @@ -54,20 +54,20 @@
  };
  
@@ -1784,9 +2287,9 @@ diff -ruN proll_18.orig/src/openprom.h proll-patch4/src/openprom.h
  };
  
  /* More fun PROM structures for device probing. */
-diff -ruN proll_18.orig/src/packet.c proll-patch4/src/packet.c
+diff -ruN proll_18.orig/src/packet.c proll-patch7/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
++++ proll-patch7/src/packet.c	2004-11-13 15:50:49.000000000 +0000
 @@ -41,7 +41,7 @@
  	int aligner;
  } wbuf;
@@ -1814,9 +2317,9 @@ diff -ruN proll_18.orig/src/packet.c proll-patch4/src/packet.c
  {
  	struct sk_buff *skb;
  	unsigned char *s;
-diff -ruN proll_18.orig/src/printf.c proll-patch4/src/printf.c
+diff -ruN proll_18.orig/src/printf.c proll-patch7/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
++++ proll-patch7/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 *);
@@ -1844,9 +2347,9 @@ diff -ruN proll_18.orig/src/printf.c proll-patch4/src/printf.c
                          	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
+diff -ruN proll_18.orig/src/rconsole.c proll-patch7/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
++++ proll-patch7/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
@@ -1901,9 +2404,9 @@ diff -ruN proll_18.orig/src/rconsole.c proll-patch4/src/rconsole.c
    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
+diff -ruN proll_18.orig/src/rconsole.h proll-patch7/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
++++ proll-patch7/src/rconsole.h	2004-11-13 15:50:49.000000000 +0000
 @@ -13,10 +13,10 @@
   */
  
@@ -1917,9 +2420,9 @@ diff -ruN proll_18.orig/src/rconsole.h proll-patch4/src/rconsole.h
    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
+diff -ruN proll_18.orig/src/romlib.h proll-patch7/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
++++ proll-patch7/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)
@@ -1936,9 +2439,9 @@ diff -ruN proll_18.orig/src/romlib.h proll-patch4/src/romlib.h
  
  
  /*
-diff -ruN proll_18.orig/src/sched_4m.c proll-patch4/src/sched_4m.c
+diff -ruN proll_18.orig/src/sched_4m.c proll-patch7/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
++++ proll-patch7/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];
@@ -1948,9 +2451,9 @@ diff -ruN proll_18.orig/src/sched_4m.c proll-patch4/src/sched_4m.c
  	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
+diff -ruN proll_18.orig/src/swap.c proll-patch7/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
++++ proll-patch7/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
@@ -1973,9 +2476,9 @@ diff -ruN proll_18.orig/src/swap.c proll-patch4/src/swap.c
 +    }
 +    printf("\n");
 +}
-diff -ruN proll_18.orig/src/system.c proll-patch4/src/system.c
+diff -ruN proll_18.orig/src/system.c proll-patch7/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
++++ proll-patch7/src/system.c	2004-11-13 15:50:49.000000000 +0000
 @@ -298,8 +298,8 @@
  	}
  
@@ -2028,9 +2531,9 @@ diff -ruN proll_18.orig/src/system.c proll-patch4/src/system.c
  void fatal()
  {
  	printk("fatal.");
-diff -ruN proll_18.orig/src/system.h proll-patch4/src/system.h
+diff -ruN proll_18.orig/src/system.h proll-patch7/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
++++ proll-patch7/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
@@ -2040,9 +2543,9 @@ diff -ruN proll_18.orig/src/system.h proll-patch4/src/system.h
  
  #ifndef __ASSEMBLY__
  struct bank {
-diff -ruN proll_18.orig/src/udp.c proll-patch4/src/udp.c
+diff -ruN proll_18.orig/src/udp.c proll-patch7/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
++++ proll-patch7/src/udp.c	2004-11-13 15:50:49.000000000 +0000
 @@ -81,7 +81,7 @@
  int      source;
  int      dest;
@@ -2062,3 +2565,263 @@ diff -ruN proll_18.orig/src/udp.c proll-patch4/src/udp.c
    /* Register IP packet type and set write buffer pointer */
    if ((writebuf = reg_type(htons(ETH_P_IP), ip_recv)) == NULL)
  	return(FALSE);
+diff -ruN proll_18.orig/src/vcons_zs.c proll-patch7/src/vcons_zs.c
+--- proll_18.orig/src/vcons_zs.c	1970-01-01 00:00:00.000000000 +0000
++++ proll-patch7/src/vcons_zs.c	2005-03-02 12:07:41.000000000 +0000
+@@ -0,0 +1,68 @@
++/**
++ ** Console over 'zs' (Zilog serial port)
++ ** Copyright 1999 Pete Zaitcev
++ ** This code is licensed under GNU General Public License.
++ **/
++
++#include "vconsole.h"
++#include <system.h>
++
++#define ZS_DATA 0x02
++
++int vcon_zs_init(struct vconterm *t, unsigned int a0)
++{
++
++	t->impl = (void *) a0;
++
++	t->vc_x = 0;    t->vc_y = 0;
++	t->backp = 0;    t->backc = 0;
++
++	stb_bypass(a0, 3); // reg 3
++	stb_bypass(a0, 1); // enable rx
++
++	stb_bypass(a0, 5); // reg 5
++	stb_bypass(a0, 8); // enable tx
++
++	return 0;
++}
++
++int vcon_zs_putch(struct vconterm *t, char c)
++{
++	unsigned zs_ptr = (unsigned) t->impl;
++
++	//while ((ldb_bypass(zs_ptr + ZS_LSR) & 0x60) != 0x60) { }
++	stb_bypass(zs_ptr + ZS_DATA, c);
++	return 0;
++}
++
++int vcon_zs_write(struct vconterm *t, char *data, int leng)
++{
++	while (leng != 0) {
++		leng--;
++		vcon_zs_putch(t, *data++);
++	}
++	return leng;
++}
++
++int vcon_zs_read(struct vconterm *t, char *data, int leng)
++{
++	unsigned zs_ptr = (unsigned) t->impl;
++
++	while ((ldb_bypass(zs_ptr) & 1) != 1) { }
++	*data = ldb_bypass(zs_ptr + ZS_DATA);
++	return 0;
++}
++
++int vcon_zs_getch(struct vconterm *t)
++{
++	unsigned zs_ptr = (unsigned) t->impl;
++
++	while ((ldb_bypass(zs_ptr) & 1) != 1) { }
++	return ldb_bypass(zs_ptr + ZS_DATA);
++}
++
++void vcon_zs_fini(struct vconterm *t)
++{
++	/* violent crash in the end */
++	;
++}
+diff -ruN proll_18.orig/src/vconsole.c proll-patch7/src/vconsole.c
+--- proll_18.orig/src/vconsole.c	1999-11-08 03:10:28.000000000 +0000
++++ proll-patch7/src/vconsole.c	2005-03-02 14:29:05.000000000 +0000
+@@ -13,6 +13,10 @@
+ 
+ struct hconsole hcons0;
+ 
++enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
++	EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
++	ESpalette };
++
+ int vcon_init(struct vconterm *t, unsigned int a0)
+ {
+ 	struct hconsole *hconp;
+@@ -25,11 +29,49 @@
+ 
+ 	t->vc_x = 0;    t->vc_y = 0;
+ 	t->backp = 0;    t->backc = 0;
++	t->vc_state = ESnormal;
+ 
+ 	hcon_clear(hconp, 0, 0, hconp->ydim_, hconp->xdim_);
+ 	return 0;
+ }
+ 
++/*
++ * gotoxy() must verify all boundaries, because the arguments
++ * might also be negative. If the given position is out of
++ * bounds, the cursor is placed at the nearest margin.
++ */
++static void gotoxy(struct vconterm *vc, int new_x, int new_y)
++{
++	int max_x, max_y;
++	struct hconsole *hconp = vc->impl;
++
++	max_x = hcon_qxdim(hconp);
++	max_y = hcon_qydim(hconp);
++
++	if (new_x < 0)
++		vc->vc_x = 0;
++	else {
++		if (new_x >= max_x)
++			vc->vc_x = max_x - 1;
++		else
++			vc->vc_x = new_x;
++	}
++
++	if (new_y < 0)
++		vc->vc_y = 0;
++	else if (new_y >= max_y)
++		vc->vc_y = max_y - 1;
++	else
++		vc->vc_y = new_y;
++
++}
++
++/* for absolute user moves, when decom is set */
++static void gotoxay(struct vconterm *t, int new_x, int new_y)
++{
++	gotoxy(t, new_x, new_y);
++}
++
+ int vcon_write(struct vconterm *t, char *data, int leng)
+ {
+ 	int l = leng;
+@@ -40,29 +82,84 @@
+ 		if (l <= 0) break;
+ 		c = *data++;    --l;
+ 
+-		switch (c) {
+-		case 0x07:		/* Bell */
+-			vcon_i_backflush(t);
+-			break;
+-		case 0x0A:		/* Linefeed */
+-			vcon_i_backflush(t);
+-			vcon_i_cursfeed(t);
++		switch(t->vc_state) {
++		case ESesc:
++			t->vc_state = ESnormal;
++			switch (c) {
++			case '[':
++				t->vc_state = ESsquare;
++				break;
++			case 'M':
++				hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1);
++				break;
++			}
+ 			break;
+-		case 0x0D:		/* Return */
+-			vcon_i_backflush(t);
+-			t->vc_x = 0;
++		case ESsquare:
++			for(t->vc_npar = 0 ; t->vc_npar < NPAR ; t->vc_npar++)
++				t->vc_par[t->vc_npar] = 0;
++			t->vc_npar = 0;
++			t->vc_state = ESgetpars;
++		case ESgetpars:
++			if (c==';' && t->vc_npar<NPAR-1) {
++				t->vc_npar++;
++				break;
++			} else if (c>='0' && c<='9') {
++				t->vc_par[t->vc_npar] *= 10;
++				t->vc_par[t->vc_npar] += c-'0';
++				break;
++			} else t->vc_state=ESgotpars;
++		case ESgotpars:
++			t->vc_state = ESnormal;
++			switch(c) {
++			case 'H': case 'f':
++				if (t->vc_par[0]) t->vc_par[0]--;
++				if (t->vc_par[1]) t->vc_par[1]--;
++				gotoxay(t, t->vc_par[1], t->vc_par[0]);
++				break;
++			case 'M':
++				hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1);
++				break;
++			}
+ 			break;
+ 		default:
+-			if (t->backp == 0) {
+-				t->backc = 1;
+-				t->backp = data-1;
+-			} else {
+-				t->backc++;
+-			}
+-			if (t->vc_x + t->backc >= hcon_qxdim(hconp)) {
++			t->vc_state = ESnormal;
++			switch (c) {
++			case 0x07:		/* Bell */
++				vcon_i_backflush(t);
++				break;
++			case 0x08:		/* BS */
++				vcon_i_backflush(t);
++				if (t->vc_x > 0)
++					t->vc_x--;
++				break;
++			case 0x0A:		/* Linefeed */
+ 				vcon_i_backflush(t);
+-				t->vc_x = 0;
+ 				vcon_i_cursfeed(t);
++				break;
++			case 0x0D:		/* Return */
++				vcon_i_backflush(t);
++				t->vc_x = 0;
++				break;
++			case 24: case 26:
++				vcon_i_backflush(t);
++				t->vc_state = ESnormal;
++				break;
++			case 27:
++				vcon_i_backflush(t);
++				t->vc_state = ESesc;
++				break;
++			default:
++				if (t->backp == 0) {
++					t->backc = 1;
++					t->backp = data-1;
++				} else {
++					t->backc++;
++				}
++				if (t->vc_x + t->backc >= hcon_qxdim(hconp)) {
++					vcon_i_backflush(t);
++					t->vc_x = 0;
++					vcon_i_cursfeed(t);
++				}
+ 			}
+ 		}
+ 	}
+diff -ruN proll_18.orig/src/vconsole.h proll-patch7/src/vconsole.h
+--- proll_18.orig/src/vconsole.h	1999-11-08 00:58:13.000000000 +0000
++++ proll-patch7/src/vconsole.h	2005-03-02 12:40:12.000000000 +0000
+@@ -6,6 +6,8 @@
+ #ifndef VCONSOLE_H
+ #define VCONSOLE_H
+ 
++#define NPAR 16
++
+ struct vconterm {
+ 	void *impl;
+ 
+@@ -13,6 +15,8 @@
+ 	int backc;		/* Same, count */
+ 
+ 	int vc_x, vc_y;		/* XXX Make vcon_xxx() to use cellmap->xpos_ */
++	int vc_state;
++	unsigned int	vc_npar,vc_par[NPAR];	/* Parameters of current escape sequence */
+ };
+ 
+ int vcon_init(struct vconterm *t, unsigned int a0);
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index bf28a36756..e6891ccbb1 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -138,6 +138,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot
     }
 
     *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
+    *physical = 0xfffff000;
 
     /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
     /* Context base + context number */
@@ -210,7 +211,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot
     /* check access */
     access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
     error_code = access_table[*access_index][access_perms];
-    if (error_code)
+    if (error_code && !(env->mmuregs[0] & MMU_NF))
 	return error_code;
 
     /* the page can be put in the TLB */
@@ -225,7 +226,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot
     /* Even if large ptes, we map only one 4KB page in the cache to
        avoid filling it too fast */
     *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
-    return 0;
+    return error_code;
 }
 
 /* Perform address translation */
@@ -251,17 +252,14 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
     env->mmuregs[4] = address; /* Fault address register */
 
     if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
-#if 0
-        // No fault
+        // No fault mode: if a mapping is available, just override
+        // permissions. If no mapping is available, redirect accesses to
+        // neverland. Fake/overridden mappings will be flushed when
+        // switching to normal mode.
 	vaddr = address & TARGET_PAGE_MASK;
-        paddr = 0xfffff000;
         prot = PAGE_READ | PAGE_WRITE;
         ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
 	return ret;
-#else
-        cpu_abort(env, "MMU no fault case no handled");
-        return 0;
-#endif
     } else {
         if (rw & 2)
             env->exception_index = TT_TFAULT;
@@ -316,8 +314,8 @@ void do_interrupt(int intno)
                 count, intno,
                 env->pc,
                 env->npc, env->regwptr[6]);
-#if 1
 	cpu_dump_state(env, logfile, fprintf, 0);
+#if 0
 	{
 	    int i;
 	    uint8_t *ptr;
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 4c65c64d67..9cb3de49ac 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -164,7 +164,9 @@ void helper_st_asi(int asi, int size, int sign)
             case 0:
 		env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
 		env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
-                if ((oldreg & MMU_E) != (env->mmuregs[reg] & MMU_E))
+		// Mappings generated during no-fault mode or MMU
+		// disabled mode are invalid in normal mode
+                if (oldreg != env->mmuregs[reg])
                     tlb_flush(env, 1);
                 break;
             case 2:
diff --git a/vl.c b/vl.c
index 9efb4f7daa..a815a50fa8 100644
--- a/vl.c
+++ b/vl.c
@@ -2733,7 +2733,9 @@ void help(void)
            "-full-screen    start in full screen\n"
 #ifdef TARGET_PPC
            "-prep           Simulate a PREP system (default is PowerMAC)\n"
-           "-g WxH[xDEPTH]  Set the initial VGA graphic mode\n"
+#endif
+#if defined(TARGET_PPC) || defined(TARGET_SPARC)
+           "-g WxH[xDEPTH]  Set the initial graphical resolution and depth\n"
 #endif
            "\n"
            "Network options:\n"
@@ -2916,6 +2918,8 @@ const QEMUOption qemu_options[] = {
 #endif
 #ifdef TARGET_PPC
     { "prep", 0, QEMU_OPTION_prep },
+#endif
+#if defined(TARGET_PPC) || defined(TARGET_SPARC)
     { "g", 1, QEMU_OPTION_g },
 #endif
     { "localtime", 0, QEMU_OPTION_localtime },
@@ -3179,6 +3183,10 @@ int main(int argc, char **argv)
             case QEMU_OPTION_boot:
                 boot_device = optarg[0];
                 if (boot_device != 'a' && 
+#ifdef TARGET_SPARC
+		    // Network boot
+		    boot_device != 'n' &&
+#endif
                     boot_device != 'c' && boot_device != 'd') {
                     fprintf(stderr, "qemu: invalid boot device '%c'\n", boot_device);
                     exit(1);
diff --git a/vl.h b/vl.h
index c8404e10e5..5091ca14e7 100644
--- a/vl.h
+++ b/vl.h
@@ -714,7 +714,7 @@ void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr);
 
 /* tcx.c */
 void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
-	      unsigned long vram_offset, int vram_size);
+	       unsigned long vram_offset, int vram_size, int width, int height);
 void tcx_update_display(void *opaque);
 void tcx_invalidate_display(void *opaque);
 void tcx_screen_dump(void *opaque, const char *filename);
@@ -736,6 +736,9 @@ void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2);
 SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2);
 void slavio_serial_ms_kbd_init(int base, int irq);
 
+/* esp.c */
+void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr);
+
 /* NVRAM helpers */
 #include "hw/m48t59.h"