From 6f7e9aec5eb5bdfa57a9e458e391b785c283a007 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 09:43:36 +0000 Subject: [PATCH] sparc fixes (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1326 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- TODO | 1 - hw/esp.c | 192 +++++ hw/fdc.c | 37 +- hw/sun4m.c | 110 ++- hw/tcx.c | 129 +++- pc-bios/proll.elf | Bin 133338 -> 41236 bytes pc-bios/proll.patch | 1545 ++++++++++++++++++++++++++++---------- target-sparc/helper.c | 18 +- target-sparc/op_helper.c | 4 +- vl.c | 10 +- vl.h | 5 +- 12 files changed, 1564 insertions(+), 489 deletions(-) create mode 100644 hw/esp.c 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 e274b0d19361deb2959c9de7d7eb420ab4b14579..f960c83e61a3fea4336aecc7090dca5fb512db66 100644 GIT binary patch delta 8592 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 z. ++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 @@ -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 +#include /* 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 . -+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 +#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 ++#include ++#include ++#ifndef NULL ++#define NULL ((void*)0) ++#endif ++ ++#include "pgtsrmmu.h" ++ ++#include "vconsole.h" ++#include /* Local copy of 2.2 style include */ ++#include /* __P() */ ++#include /* init_net() */ ++#include /* we are a provider for part of this. */ ++#include /* myipaddr */ ++#include ++#include /* 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 ++ ++#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_nparvc_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"