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