]> git.proxmox.com Git - qemu.git/commitdiff
full system SPARC emulation (Blue Swirl)
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 30 Sep 2004 22:13:50 +0000 (22:13 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 30 Sep 2004 22:13:50 +0000 (22:13 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1085 c046a42c-6fe2-441c-8c8c-71466251a162

hw/iommu.c [new file with mode: 0644]
hw/lance.c [new file with mode: 0644]
hw/m48t08.c [new file with mode: 0644]
hw/m48t08.h [new file with mode: 0644]
hw/magic-load.c [new file with mode: 0644]
hw/sched.c [new file with mode: 0644]
hw/sun4m.c [new file with mode: 0644]
hw/tcx.c [new file with mode: 0644]

diff --git a/hw/iommu.c b/hw/iommu.c
new file mode 100644 (file)
index 0000000..f00bb78
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * QEMU SPARC iommu emulation
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+/* debug iommu */
+//#define DEBUG_IOMMU
+
+/* The IOMMU registers occupy three pages in IO space. */
+struct iommu_regs {
+       /* First page */
+       volatile unsigned long control;    /* IOMMU control */
+       volatile unsigned long base;       /* Physical base of iopte page table */
+       volatile unsigned long _unused1[3];
+       volatile unsigned long tlbflush;   /* write only */
+       volatile unsigned long pageflush;  /* write only */
+       volatile unsigned long _unused2[1017];
+       /* Second page */
+       volatile unsigned long afsr;       /* Async-fault status register */
+       volatile unsigned long afar;       /* Async-fault physical address */
+       volatile unsigned long _unused3[2];
+       volatile unsigned long sbuscfg0;   /* SBUS configuration registers, per-slot */
+       volatile unsigned long sbuscfg1;
+       volatile unsigned long sbuscfg2;
+       volatile unsigned long sbuscfg3;
+       volatile unsigned long mfsr;       /* Memory-fault status register */
+       volatile unsigned long mfar;       /* Memory-fault physical address */
+       volatile unsigned long _unused4[1014];
+       /* Third page */
+       volatile unsigned long mid;        /* IOMMU module-id */
+};
+
+#define IOMMU_CTRL_IMPL     0xf0000000 /* Implementation */
+#define IOMMU_CTRL_VERS     0x0f000000 /* Version */
+#define IOMMU_CTRL_RNGE     0x0000001c /* Mapping RANGE */
+#define IOMMU_RNGE_16MB     0x00000000 /* 0xff000000 -> 0xffffffff */
+#define IOMMU_RNGE_32MB     0x00000004 /* 0xfe000000 -> 0xffffffff */
+#define IOMMU_RNGE_64MB     0x00000008 /* 0xfc000000 -> 0xffffffff */
+#define IOMMU_RNGE_128MB    0x0000000c /* 0xf8000000 -> 0xffffffff */
+#define IOMMU_RNGE_256MB    0x00000010 /* 0xf0000000 -> 0xffffffff */
+#define IOMMU_RNGE_512MB    0x00000014 /* 0xe0000000 -> 0xffffffff */
+#define IOMMU_RNGE_1GB      0x00000018 /* 0xc0000000 -> 0xffffffff */
+#define IOMMU_RNGE_2GB      0x0000001c /* 0x80000000 -> 0xffffffff */
+#define IOMMU_CTRL_ENAB     0x00000001 /* IOMMU Enable */
+
+#define IOMMU_AFSR_ERR      0x80000000 /* LE, TO, or BE asserted */
+#define IOMMU_AFSR_LE       0x40000000 /* SBUS reports error after transaction */
+#define IOMMU_AFSR_TO       0x20000000 /* Write access took more than 12.8 us. */
+#define IOMMU_AFSR_BE       0x10000000 /* Write access received error acknowledge */
+#define IOMMU_AFSR_SIZE     0x0e000000 /* Size of transaction causing error */
+#define IOMMU_AFSR_S        0x01000000 /* Sparc was in supervisor mode */
+#define IOMMU_AFSR_RESV     0x00f00000 /* Reserver, forced to 0x8 by hardware */
+#define IOMMU_AFSR_ME       0x00080000 /* Multiple errors occurred */
+#define IOMMU_AFSR_RD       0x00040000 /* A read operation was in progress */
+#define IOMMU_AFSR_FAV      0x00020000 /* IOMMU afar has valid contents */
+
+#define IOMMU_SBCFG_SAB30   0x00010000 /* Phys-address bit 30 when bypass enabled */
+#define IOMMU_SBCFG_BA16    0x00000004 /* Slave supports 16 byte bursts */
+#define IOMMU_SBCFG_BA8     0x00000002 /* Slave supports 8 byte bursts */
+#define IOMMU_SBCFG_BYPASS  0x00000001 /* Bypass IOMMU, treat all addresses
+                                         produced by this device as pure
+                                         physical. */
+
+#define IOMMU_MFSR_ERR      0x80000000 /* One or more of PERR1 or PERR0 */
+#define IOMMU_MFSR_S        0x01000000 /* Sparc was in supervisor mode */
+#define IOMMU_MFSR_CPU      0x00800000 /* CPU transaction caused parity error */
+#define IOMMU_MFSR_ME       0x00080000 /* Multiple parity errors occurred */
+#define IOMMU_MFSR_PERR     0x00006000 /* high bit indicates parity error occurred
+                                         on the even word of the access, low bit
+                                         indicated odd word caused the parity error */
+#define IOMMU_MFSR_BM       0x00001000 /* Error occurred while in boot mode */
+#define IOMMU_MFSR_C        0x00000800 /* Address causing error was marked cacheable */
+#define IOMMU_MFSR_RTYP     0x000000f0 /* Memory request transaction type */
+
+#define IOMMU_MID_SBAE      0x001f0000 /* SBus arbitration enable */
+#define IOMMU_MID_SE        0x00100000 /* Enables SCSI/ETHERNET arbitration */
+#define IOMMU_MID_SB3       0x00080000 /* Enable SBUS device 3 arbitration */
+#define IOMMU_MID_SB2       0x00040000 /* Enable SBUS device 2 arbitration */
+#define IOMMU_MID_SB1       0x00020000 /* Enable SBUS device 1 arbitration */
+#define IOMMU_MID_SB0       0x00010000 /* Enable SBUS device 0 arbitration */
+#define IOMMU_MID_MID       0x0000000f /* Module-id, hardcoded to 0x8 */
+
+/* The format of an iopte in the page tables */
+#define IOPTE_PAGE          0x07ffff00 /* Physical page number (PA[30:12]) */
+#define IOPTE_CACHE         0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */
+#define IOPTE_WRITE         0x00000004 /* Writeable */
+#define IOPTE_VALID         0x00000002 /* IOPTE is valid */
+#define IOPTE_WAZ           0x00000001 /* Write as zeros */
+
+#define PHYS_JJ_IOMMU  0x10000000      /* First page of sun4m IOMMU */
+#define PAGE_SHIFT      12
+#define PAGE_SIZE       (1 << PAGE_SHIFT)
+#define PAGE_MASK      (PAGE_SIZE - 1)
+
+typedef struct IOMMUState {
+    uint32_t regs[sizeof(struct iommu_regs)];
+} IOMMUState;
+
+static IOMMUState *ps;
+
+static int iommu_io_memory;
+
+static void iommu_reset(IOMMUState *s)
+{
+}
+
+static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    IOMMUState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr - PHYS_JJ_IOMMU) >> 2;
+    switch (saddr) {
+    default:
+       return s->regs[saddr];
+       break;
+    }
+    return 0;
+}
+
+static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    IOMMUState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr - PHYS_JJ_IOMMU) >> 2;
+    switch (saddr) {
+    default:
+       s->regs[saddr] = val;
+       break;
+    }
+}
+
+static CPUReadMemoryFunc *iommu_mem_read[3] = {
+    iommu_mem_readw,
+    iommu_mem_readw,
+    iommu_mem_readw,
+};
+
+static CPUWriteMemoryFunc *iommu_mem_write[3] = {
+    iommu_mem_writew,
+    iommu_mem_writew,
+    iommu_mem_writew,
+};
+
+uint32_t iommu_translate(uint32_t addr)
+{
+    uint32_t *iopte = (void *)(ps->regs[1] << 4), pa, iostart;
+
+    switch (ps->regs[0] & IOMMU_CTRL_RNGE) {
+    case IOMMU_RNGE_16MB:
+       iostart = 0xff000000;
+       break;
+    case IOMMU_RNGE_32MB:
+       iostart = 0xfe000000;
+       break;
+    case IOMMU_RNGE_64MB:
+       iostart = 0xfc000000;
+       break;
+    case IOMMU_RNGE_128MB:
+       iostart = 0xf8000000;
+       break;
+    case IOMMU_RNGE_256MB:
+       iostart = 0xf0000000;
+       break;
+    case IOMMU_RNGE_512MB:
+       iostart = 0xe0000000;
+       break;
+    case IOMMU_RNGE_1GB:
+       iostart = 0xc0000000;
+       break;
+    default:
+    case IOMMU_RNGE_2GB:
+       iostart = 0x80000000;
+       break;
+    }
+
+    iopte += ((addr - iostart) >> PAGE_SHIFT);
+    cpu_physical_memory_rw((uint32_t)iopte, (void *) &pa, 4, 0);
+    bswap32s(&pa);
+    pa = (pa & IOPTE_PAGE) << 4;               /* Loose higher bits of 36 */
+    //return pa + PAGE_SIZE;
+    return pa + (addr & PAGE_MASK);
+}
+
+void iommu_init()
+{
+    IOMMUState *s;
+
+    s = qemu_mallocz(sizeof(IOMMUState));
+    if (!s)
+        return;
+
+    iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s);
+    cpu_register_physical_memory(PHYS_JJ_IOMMU, sizeof(struct iommu_regs),
+                                 iommu_io_memory);
+    
+    iommu_reset(s);
+    ps = s;
+}
+
diff --git a/hw/lance.c b/hw/lance.c
new file mode 100644 (file)
index 0000000..e461ade
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * QEMU Lance 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"
+
+/* debug LANCE card */
+#define DEBUG_LANCE
+
+#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 */
+
+#ifndef LANCE_LOG_TX_BUFFERS
+#define LANCE_LOG_TX_BUFFERS 4
+#define LANCE_LOG_RX_BUFFERS 4
+#endif
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
+
+
+#define LE_CSR0 0
+#define LE_CSR1 1
+#define LE_CSR2 2
+#define LE_CSR3 3
+#define LE_MAXREG (LE_CSR3 + 1)
+
+#define LE_RDP  0
+#define LE_RAP  1
+
+#define LE_MO_PROM      0x8000  /* Enable promiscuous mode */
+
+#define        LE_C0_ERR       0x8000  /* Error: set if BAB, SQE, MISS or ME is set */
+#define        LE_C0_BABL      0x4000  /* BAB:  Babble: tx timeout. */
+#define        LE_C0_CERR      0x2000  /* SQE:  Signal quality error */
+#define        LE_C0_MISS      0x1000  /* MISS: Missed a packet */
+#define        LE_C0_MERR      0x0800  /* ME:   Memory error */
+#define        LE_C0_RINT      0x0400  /* Received interrupt */
+#define        LE_C0_TINT      0x0200  /* Transmitter Interrupt */
+#define        LE_C0_IDON      0x0100  /* IFIN: Init finished. */
+#define        LE_C0_INTR      0x0080  /* Interrupt or error */
+#define        LE_C0_INEA      0x0040  /* Interrupt enable */
+#define        LE_C0_RXON      0x0020  /* Receiver on */
+#define        LE_C0_TXON      0x0010  /* Transmitter on */
+#define        LE_C0_TDMD      0x0008  /* Transmitter demand */
+#define        LE_C0_STOP      0x0004  /* Stop the card */
+#define        LE_C0_STRT      0x0002  /* Start the card */
+#define        LE_C0_INIT      0x0001  /* Init the card */
+
+#define        LE_C3_BSWP      0x4     /* SWAP */
+#define        LE_C3_ACON      0x2     /* ALE Control */
+#define        LE_C3_BCON      0x1     /* Byte control */
+
+/* Receive message descriptor 1 */
+#define LE_R1_OWN       0x80    /* Who owns the entry */
+#define LE_R1_ERR       0x40    /* Error: if FRA, OFL, CRC or BUF is set */
+#define LE_R1_FRA       0x20    /* FRA: Frame error */
+#define LE_R1_OFL       0x10    /* OFL: Frame overflow */
+#define LE_R1_CRC       0x08    /* CRC error */
+#define LE_R1_BUF       0x04    /* BUF: Buffer error */
+#define LE_R1_SOP       0x02    /* Start of packet */
+#define LE_R1_EOP       0x01    /* End of packet */
+#define LE_R1_POK       0x03    /* Packet is complete: SOP + EOP */
+
+#define LE_T1_OWN       0x80    /* Lance owns the packet */
+#define LE_T1_ERR       0x40    /* Error summary */
+#define LE_T1_EMORE     0x10    /* Error: more than one retry needed */
+#define LE_T1_EONE      0x08    /* Error: one retry needed */
+#define LE_T1_EDEF      0x04    /* Error: deferred */
+#define LE_T1_SOP       0x02    /* Start of packet */
+#define LE_T1_EOP       0x01    /* End of packet */
+#define LE_T1_POK      0x03    /* Packet is complete: SOP + EOP */
+
+#define LE_T3_BUF       0x8000  /* Buffer error */
+#define LE_T3_UFL       0x4000  /* Error underflow */
+#define LE_T3_LCOL      0x1000  /* Error late collision */
+#define LE_T3_CLOS      0x0800  /* Error carrier loss */
+#define LE_T3_RTY       0x0400  /* Error retry */
+#define LE_T3_TDR       0x03ff  /* Time Domain Reflectometry counter */
+
+#define TX_RING_SIZE                   (1 << (LANCE_LOG_TX_BUFFERS))
+#define TX_RING_MOD_MASK               (TX_RING_SIZE - 1)
+#define TX_RING_LEN_BITS               ((LANCE_LOG_TX_BUFFERS) << 29)
+
+#define RX_RING_SIZE                   (1 << (LANCE_LOG_RX_BUFFERS))
+#define RX_RING_MOD_MASK               (RX_RING_SIZE - 1)
+#define RX_RING_LEN_BITS               ((LANCE_LOG_RX_BUFFERS) << 29)
+
+#define PKT_BUF_SZ             1544
+#define RX_BUFF_SIZE            PKT_BUF_SZ
+#define TX_BUFF_SIZE            PKT_BUF_SZ
+
+struct lance_rx_desc {
+       unsigned short rmd0;        /* low address of packet */
+       unsigned char  rmd1_bits;   /* descriptor bits */
+       unsigned char  rmd1_hadr;   /* high address of packet */
+       short    length;            /* This length is 2s complement (negative)!
+                                    * Buffer length
+                                    */
+       unsigned short mblength;    /* This is the actual number of bytes received */
+};
+
+struct lance_tx_desc {
+       unsigned short tmd0;        /* low address of packet */
+       unsigned char  tmd1_bits;   /* descriptor bits */
+       unsigned char  tmd1_hadr;   /* high address of packet */
+       short length;               /* Length is 2s complement (negative)! */
+       unsigned short misc;
+};
+
+/* The LANCE initialization block, described in databook. */
+/* On the Sparc, this block should be on a DMA region     */
+struct lance_init_block {
+       unsigned short mode;            /* Pre-set mode (reg. 15) */
+       unsigned char phys_addr[6];     /* Physical ethernet address */
+       unsigned filter[2];             /* Multicast filter. */
+
+       /* Receive and transmit ring base, along with extra bits. */
+       unsigned short rx_ptr;          /* receive descriptor addr */
+       unsigned short rx_len;          /* receive len and high addr */
+       unsigned short tx_ptr;          /* transmit descriptor addr */
+       unsigned short tx_len;          /* transmit len and high addr */
+    
+       /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
+       struct lance_rx_desc brx_ring[RX_RING_SIZE];
+       struct lance_tx_desc btx_ring[TX_RING_SIZE];
+    
+       char   tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
+       char   pad[2];                  /* align rx_buf for copy_and_sum(). */
+       char   rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
+};
+
+#define LEDMA_REGS 4
+#if 0
+/* Structure to describe the current status of DMA registers on the Sparc */
+struct sparc_dma_registers {
+    uint32_t cond_reg; /* DMA condition register */
+    uint32_t st_addr;  /* Start address of this transfer */
+    uint32_t cnt;      /* How many bytes to transfer */
+    uint32_t dma_test; /* DMA test register */
+};
+#endif
+
+typedef struct LEDMAState {
+    uint32_t regs[LEDMA_REGS];
+} LEDMAState;
+
+typedef struct LANCEState {
+    NetDriverState *nd;
+    uint32_t leptr;
+    uint16_t addr;
+    uint16_t regs[LE_MAXREG];
+    uint8_t phys[6]; /* mac address */
+    int irq;
+    LEDMAState *ledma;
+} LANCEState;
+
+static int lance_io_memory;
+
+static unsigned int rxptr, txptr;
+
+static void lance_send(void *opaque);
+
+static void lance_reset(LANCEState *s)
+{
+    memcpy(s->phys, s->nd->macaddr, 6);
+    rxptr = 0;
+    txptr = 0;
+    s->regs[LE_CSR0] = LE_C0_STOP;
+}
+
+static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    LANCEState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr - PHYS_JJ_LE;
+    switch (saddr >> 1) {
+    case LE_RDP:
+       return s->regs[s->addr];
+    case LE_RAP:
+       return s->addr;
+    default:
+       break;
+    }
+    return 0;
+}
+
+static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    LANCEState *s = opaque;
+    uint32_t saddr;
+    uint16_t clear, reg;
+
+    saddr = addr - PHYS_JJ_LE;
+    switch (saddr >> 1) {
+    case LE_RDP:
+       switch(s->addr) {
+       case LE_CSR0:
+           if (val & LE_C0_STOP) {
+               s->regs[LE_CSR0] = LE_C0_STOP;
+               break;
+           }
+
+           reg = s->regs[LE_CSR0];
+
+           // 1 = clear for some bits
+           reg &= ~(val & 0x7f00);
+
+           // generated bits
+           reg &= ~(LE_C0_ERR | LE_C0_INTR);
+           if (reg & 0x7100)
+               reg |= LE_C0_ERR;
+           if (reg & 0x7f00)
+               reg |= LE_C0_INTR;
+
+           // direct bit
+           reg &= ~LE_C0_INEA;
+           reg |= val & LE_C0_INEA;
+
+           // exclusive bits
+           if (val & LE_C0_INIT) {
+               reg |= LE_C0_IDON | LE_C0_INIT;
+               reg &= ~LE_C0_STOP;
+           }
+           else if (val & LE_C0_STRT) {
+               reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON;
+               reg &= ~LE_C0_STOP;
+           }
+
+           s->regs[LE_CSR0] = reg;
+
+           // trigger bits
+           //if (val & LE_C0_TDMD)
+
+           if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
+               pic_set_irq(s->irq, 1);
+           break;
+       case LE_CSR1:
+           s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff);
+           s->regs[s->addr] = val;
+           break;
+       case LE_CSR2:
+           s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16);
+           s->regs[s->addr] = val;
+           break;
+       case LE_CSR3:
+           s->regs[s->addr] = val;
+           break;
+       }
+       break;
+    case LE_RAP:
+       if (val < LE_MAXREG)
+           s->addr = val;
+       break;
+    default:
+       break;
+    }
+    lance_send(s);
+}
+
+static CPUReadMemoryFunc *lance_mem_read[3] = {
+    lance_mem_readw,
+    lance_mem_readw,
+    lance_mem_readw,
+};
+
+static CPUWriteMemoryFunc *lance_mem_write[3] = {
+    lance_mem_writew,
+    lance_mem_writew,
+    lance_mem_writew,
+};
+
+
+/* return the max buffer size if the LANCE can receive more data */
+static int lance_can_receive(void *opaque)
+{
+    LANCEState *s = opaque;
+    void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
+    struct lance_init_block *ib;
+    int i;
+    uint16_t temp;
+
+    if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
+       return 0;
+
+    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);
+       temp &= 0xff;
+       if (temp == (LE_R1_OWN)) {
+#ifdef DEBUG_LANCE
+           fprintf(stderr, "lance: can receive %d\n", RX_BUFF_SIZE);
+#endif
+           return RX_BUFF_SIZE;
+       }
+    }
+#ifdef DEBUG_LANCE
+    fprintf(stderr, "lance: cannot receive\n");
+#endif
+    return 0;
+}
+
+#define MIN_BUF_SIZE 60
+
+static void lance_receive(void *opaque, const uint8_t *buf, int size)
+{
+    LANCEState *s = opaque;
+    void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
+    struct lance_init_block *ib;
+    unsigned int i, old_rxptr, j;
+    uint16_t temp;
+
+    if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
+       return;
+
+    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);
+       if (temp == (LE_R1_OWN)) {
+           rxptr = (rxptr + 1) & RX_RING_MOD_MASK;
+           temp = size;
+           bswap16s(&temp);
+           cpu_physical_memory_write(&ib->brx_ring[i].mblength, (void *) &temp, 2);
+#if 0
+           cpu_physical_memory_write(&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);
+           }
+#endif
+           temp = LE_R1_POK;
+           cpu_physical_memory_write(&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);
+#ifdef DEBUG_LANCE
+           fprintf(stderr, "lance: got packet, len %d\n", size);
+#endif
+           return;
+       }
+    }
+}
+
+static void lance_send(void *opaque)
+{
+    LANCEState *s = opaque;
+    void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
+    struct lance_init_block *ib;
+    unsigned int i, old_txptr, j;
+    uint16_t temp;
+    char pkt_buf[PKT_BUF_SZ];
+
+    if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
+       return;
+
+    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);
+       if (temp == (LE_T1_POK|LE_T1_OWN)) {
+           cpu_physical_memory_read(&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);
+#else
+           for (j = 0; j < temp; j++) {
+               cpu_physical_memory_read(((void *)&ib->tx_buf[i]) + j, &pkt_buf[j], 1);
+           }
+#endif
+
+#ifdef DEBUG_LANCE
+           fprintf(stderr, "lance: sending packet, len %d\n", temp);
+#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;
+           s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
+       }
+    }
+}
+
+static int ledma_io_memory;
+
+static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    LEDMAState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr - PHYS_JJ_LEDMA) >> 2;
+    if (saddr < LEDMA_REGS)
+       return s->regs[saddr];
+    else
+       return 0;
+}
+
+static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    LEDMAState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr - PHYS_JJ_LEDMA) >> 2;
+    if (saddr < LEDMA_REGS)
+       s->regs[saddr] = val;
+}
+
+static CPUReadMemoryFunc *ledma_mem_read[3] = {
+    ledma_mem_readl,
+    ledma_mem_readl,
+    ledma_mem_readl,
+};
+
+static CPUWriteMemoryFunc *ledma_mem_write[3] = {
+    ledma_mem_writel,
+    ledma_mem_writel,
+    ledma_mem_writel,
+};
+
+void lance_init(NetDriverState *nd, int irq)
+{
+    LANCEState *s;
+    LEDMAState *led;
+
+    s = qemu_mallocz(sizeof(LANCEState));
+    if (!s)
+        return;
+
+    lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
+    cpu_register_physical_memory(PHYS_JJ_LE, 8,
+                                 lance_io_memory);
+    led = qemu_mallocz(sizeof(LEDMAState));
+    if (!led)
+        return;
+
+    ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led);
+    cpu_register_physical_memory(PHYS_JJ_LEDMA, 16,
+                                 ledma_io_memory);
+
+    s->nd = nd;
+    s->ledma = led;
+    s->irq = irq;
+
+    lance_reset(s);
+    qemu_add_read_packet(nd, lance_can_receive, lance_receive, s);
+}
+
diff --git a/hw/m48t08.c b/hw/m48t08.c
new file mode 100644 (file)
index 0000000..c5b6e7a
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * QEMU M48T08 NVRAM emulation for Sparc platform
+ * 
+ * Copyright (c) 2003-2004 Jocelyn Mayer
+ * 
+ * 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"
+#include "m48t08.h"
+
+//#define DEBUG_NVRAM
+
+#if defined(DEBUG_NVRAM)
+#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
+#else
+#define NVRAM_PRINTF(fmt, args...) do { } while (0)
+#endif
+
+#define NVRAM_MAX_MEM 0xfff0
+
+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;
+};
+
+/* Fake timer functions */
+/* Generic helpers for BCD */
+static inline uint8_t toBCD (uint8_t value)
+{
+    return (((value / 10) % 10) << 4) | (value % 10);
+}
+
+static inline uint8_t fromBCD (uint8_t BCD)
+{
+    return ((BCD >> 4) * 10) + (BCD & 0x0F);
+}
+
+/* RTC management helpers */
+static void get_time (m48t08_t *NVRAM, struct tm *tm)
+{
+    time_t t;
+
+    t = time(NULL) + NVRAM->time_offset;
+#ifdef _WIN32
+    memcpy(tm,localtime(&t),sizeof(*tm));
+#else
+    localtime_r (&t, tm) ;
+#endif
+}
+
+static void set_time (m48t08_t *NVRAM, struct tm *tm)
+{
+    time_t now, new_time;
+    
+    new_time = mktime(tm);
+    now = time(NULL);
+    NVRAM->time_offset = new_time - now;
+}
+
+/* Direct access to NVRAM */
+void m48t08_write (m48t08_t *NVRAM, uint32_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) {
+    case 0x1FF8:
+        /* control */
+       NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
+        break;
+    case 0x1FF9:
+        /* seconds (BCD) */
+       tmp = fromBCD(val & 0x7F);
+       if (tmp >= 0 && tmp <= 59) {
+           get_time(NVRAM, &tm);
+           tm.tm_sec = tmp;
+           set_time(NVRAM, &tm);
+       }
+       if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
+           if (val & 0x80) {
+               NVRAM->stop_time = time(NULL);
+           } else {
+               NVRAM->time_offset += NVRAM->stop_time - time(NULL);
+               NVRAM->stop_time = 0;
+           }
+       }
+       NVRAM->buffer[0x1FF9] = val & 0x80;
+        break;
+    case 0x1FFA:
+        /* minutes (BCD) */
+       tmp = fromBCD(val & 0x7F);
+       if (tmp >= 0 && tmp <= 59) {
+           get_time(NVRAM, &tm);
+           tm.tm_min = tmp;
+           set_time(NVRAM, &tm);
+       }
+        break;
+    case 0x1FFB:
+        /* hours (BCD) */
+       tmp = fromBCD(val & 0x3F);
+       if (tmp >= 0 && tmp <= 23) {
+           get_time(NVRAM, &tm);
+           tm.tm_hour = tmp;
+           set_time(NVRAM, &tm);
+       }
+        break;
+    case 0x1FFC:
+        /* day of the week / century */
+       tmp = fromBCD(val & 0x07);
+       get_time(NVRAM, &tm);
+       tm.tm_wday = tmp;
+       set_time(NVRAM, &tm);
+        NVRAM->buffer[0x1FFC] = val & 0x40;
+        break;
+    case 0x1FFD:
+        /* date */
+       tmp = fromBCD(val & 0x1F);
+       if (tmp != 0) {
+           get_time(NVRAM, &tm);
+           tm.tm_mday = tmp;
+           set_time(NVRAM, &tm);
+       }
+        break;
+    case 0x1FFE:
+        /* month */
+       tmp = fromBCD(val & 0x1F);
+       if (tmp >= 1 && tmp <= 12) {
+           get_time(NVRAM, &tm);
+           tm.tm_mon = tmp - 1;
+           set_time(NVRAM, &tm);
+       }
+        break;
+    case 0x1FFF:
+        /* year */
+       tmp = fromBCD(val);
+       if (tmp >= 0 && tmp <= 99) {
+           get_time(NVRAM, &tm);
+           tm.tm_year = fromBCD(val);
+           set_time(NVRAM, &tm);
+       }
+        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;
+       }
+        break;
+    }
+}
+
+uint32_t m48t08_read (m48t08_t *NVRAM)
+{
+    struct tm tm;
+    uint32_t retval = 0xFF;
+
+    switch (NVRAM->addr) {
+    case 0x1FF8:
+        /* control */
+       goto do_read;
+    case 0x1FF9:
+        /* seconds (BCD) */
+        get_time(NVRAM, &tm);
+        retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
+        break;
+    case 0x1FFA:
+        /* minutes (BCD) */
+        get_time(NVRAM, &tm);
+        retval = toBCD(tm.tm_min);
+        break;
+    case 0x1FFB:
+        /* hours (BCD) */
+        get_time(NVRAM, &tm);
+        retval = toBCD(tm.tm_hour);
+        break;
+    case 0x1FFC:
+        /* day of the week / century */
+        get_time(NVRAM, &tm);
+        retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
+        break;
+    case 0x1FFD:
+        /* date */
+        get_time(NVRAM, &tm);
+        retval = toBCD(tm.tm_mday);
+        break;
+    case 0x1FFE:
+        /* month */
+        get_time(NVRAM, &tm);
+        retval = toBCD(tm.tm_mon + 1);
+        break;
+    case 0x1FFF:
+        /* year */
+        get_time(NVRAM, &tm);
+        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];
+       }
+        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;
+}
+
+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;
+    }
+}
+
+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;
+    }
+}
+
+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];
+
+    return retval;
+}
+
+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];
+    }
+
+    return retval;
+}
+
+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];
+    }
+
+    return retval;
+}
+
+static CPUWriteMemoryFunc *nvram_write[] = {
+    &nvram_writeb,
+    &nvram_writew,
+    &nvram_writel,
+};
+
+static CPUReadMemoryFunc *nvram_read[] = {
+    &nvram_readb,
+    &nvram_readw,
+    &nvram_readl,
+};
+
+/* Initialisation routine */
+m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size)
+{
+    m48t08_t *s;
+    int i;
+    unsigned char tmp = 0;
+
+    s = qemu_mallocz(sizeof(m48t08_t));
+    if (!s)
+       return NULL;
+    s->buffer = qemu_mallocz(size);
+    if (!s->buffer) {
+        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);
+    }
+    s->lock = 0;
+
+    i = 0x1fd8;
+    s->buffer[i++] = 0x01;
+    s->buffer[i++] = 0x80; /* Sun4m OBP */
+    /* XXX: Ethernet address, etc */
+
+    /* Calculate checksum */
+    for (i = 0x1fd8; i < 0x1fe7; i++) {
+       tmp ^= s->buffer[i];
+    }
+    s->buffer[0x1fe7] = tmp;
+    return s;
+}
+
+#if 0
+struct idprom
+{
+        unsigned char   id_format;      /* Format identifier (always 0x01) */
+        unsigned char   id_machtype;    /* Machine type */
+        unsigned char   id_ethaddr[6];  /* Hardware ethernet address */
+        long            id_date;        /* Date of manufacture */
+        unsigned int    id_sernum:24;   /* Unique serial number */
+        unsigned char   id_cksum;       /* Checksum - xor of the data bytes */
+        unsigned char   reserved[16];
+};
+#endif
diff --git a/hw/m48t08.h b/hw/m48t08.h
new file mode 100644 (file)
index 0000000..2a754b6
--- /dev/null
@@ -0,0 +1,12 @@
+#if !defined (__M48T08_H__)
+#define __M48T08_H__
+
+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);
+
+#endif /* !defined (__M48T08_H__) */
diff --git a/hw/magic-load.c b/hw/magic-load.c
new file mode 100644 (file)
index 0000000..7365183
--- /dev/null
@@ -0,0 +1,341 @@
+/* This is the Linux kernel elf-loading code, ported into user space */
+#include "vl.h"
+#include "disas.h"
+
+/* XXX: this code is not used as it is under the GPL license. Please
+   remove or recode it */
+//#define USE_ELF_LOADER
+
+#ifdef USE_ELF_LOADER
+/* should probably go in elf.h */
+#ifndef ELIBBAD
+#define ELIBBAD 80
+#endif
+
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_SPARC )
+
+#define ELF_CLASS   ELFCLASS32
+#define ELF_DATA    ELFDATA2MSB
+#define ELF_ARCH    EM_SPARC
+
+#include "elf.h"
+
+/*
+ * This structure is used to hold the arguments that are 
+ * used when loading binaries.
+ */
+struct linux_binprm {
+        char buf[128];
+       int fd;
+};
+
+#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
+#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
+
+#ifdef BSWAP_NEEDED
+static void bswap_ehdr(Elf32_Ehdr *ehdr)
+{
+    bswap16s(&ehdr->e_type);                   /* Object file type */
+    bswap16s(&ehdr->e_machine);                /* Architecture */
+    bswap32s(&ehdr->e_version);                /* Object file version */
+    bswap32s(&ehdr->e_entry);          /* Entry point virtual address */
+    bswap32s(&ehdr->e_phoff);          /* Program header table file offset */
+    bswap32s(&ehdr->e_shoff);          /* Section header table file offset */
+    bswap32s(&ehdr->e_flags);          /* Processor-specific flags */
+    bswap16s(&ehdr->e_ehsize);         /* ELF header size in bytes */
+    bswap16s(&ehdr->e_phentsize);              /* Program header table entry size */
+    bswap16s(&ehdr->e_phnum);          /* Program header table entry count */
+    bswap16s(&ehdr->e_shentsize);              /* Section header table entry size */
+    bswap16s(&ehdr->e_shnum);          /* Section header table entry count */
+    bswap16s(&ehdr->e_shstrndx);               /* Section header string table index */
+}
+
+static void bswap_phdr(Elf32_Phdr *phdr)
+{
+    bswap32s(&phdr->p_type);                   /* Segment type */
+    bswap32s(&phdr->p_offset);         /* Segment file offset */
+    bswap32s(&phdr->p_vaddr);          /* Segment virtual address */
+    bswap32s(&phdr->p_paddr);          /* Segment physical address */
+    bswap32s(&phdr->p_filesz);         /* Segment size in file */
+    bswap32s(&phdr->p_memsz);          /* Segment size in memory */
+    bswap32s(&phdr->p_flags);          /* Segment flags */
+    bswap32s(&phdr->p_align);          /* Segment alignment */
+}
+
+static void bswap_shdr(Elf32_Shdr *shdr)
+{
+    bswap32s(&shdr->sh_name);
+    bswap32s(&shdr->sh_type);
+    bswap32s(&shdr->sh_flags);
+    bswap32s(&shdr->sh_addr);
+    bswap32s(&shdr->sh_offset);
+    bswap32s(&shdr->sh_size);
+    bswap32s(&shdr->sh_link);
+    bswap32s(&shdr->sh_info);
+    bswap32s(&shdr->sh_addralign);
+    bswap32s(&shdr->sh_entsize);
+}
+
+static void bswap_sym(Elf32_Sym *sym)
+{
+    bswap32s(&sym->st_name);
+    bswap32s(&sym->st_value);
+    bswap32s(&sym->st_size);
+    bswap16s(&sym->st_shndx);
+}
+#endif
+
+static int prepare_binprm(struct linux_binprm *bprm)
+{
+    int retval;
+
+    memset(bprm->buf, 0, sizeof(bprm->buf));
+    retval = lseek(bprm->fd, 0L, SEEK_SET);
+    if(retval >= 0) {
+        retval = read(bprm->fd, bprm->buf, 128);
+    }
+    if(retval < 0) {
+       perror("prepare_binprm");
+       exit(-1);
+       /* return(-errno); */
+    }
+    else {
+       return(retval);
+    }
+}
+
+/* Best attempt to load symbols from this ELF object. */
+static void load_symbols(struct elfhdr *hdr, int fd)
+{
+    unsigned int i;
+    struct elf_shdr sechdr, symtab, strtab;
+    char *strings;
+
+    lseek(fd, hdr->e_shoff, SEEK_SET);
+    for (i = 0; i < hdr->e_shnum; i++) {
+       if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
+           return;
+#ifdef BSWAP_NEEDED
+       bswap_shdr(&sechdr);
+#endif
+       if (sechdr.sh_type == SHT_SYMTAB) {
+           symtab = sechdr;
+           lseek(fd, hdr->e_shoff
+                 + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
+           if (read(fd, &strtab, sizeof(strtab))
+               != sizeof(strtab))
+               return;
+#ifdef BSWAP_NEEDED
+           bswap_shdr(&strtab);
+#endif
+           goto found;
+       }
+    }
+    return; /* Shouldn't happen... */
+
+ found:
+    /* Now know where the strtab and symtab are.  Snarf them. */
+    disas_symtab = qemu_malloc(symtab.sh_size);
+    disas_strtab = strings = qemu_malloc(strtab.sh_size);
+    if (!disas_symtab || !disas_strtab)
+       return;
+       
+    lseek(fd, symtab.sh_offset, SEEK_SET);
+    if (read(fd, 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);
+#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);
+}
+
+static int load_elf_binary(struct linux_binprm * bprm, uint8_t *addr)
+{
+    struct elfhdr elf_ex;
+    unsigned long startaddr = addr;
+    int i;
+    struct elf_phdr * elf_ppnt;
+    struct elf_phdr *elf_phdata;
+    int retval;
+
+    elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
+#ifdef BSWAP_NEEDED
+    bswap_ehdr(&elf_ex);
+#endif
+
+    if (elf_ex.e_ident[0] != 0x7f ||
+       strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
+       return  -ENOEXEC;
+    }
+
+    /* First of all, some simple consistency checks */
+    if (! elf_check_arch(elf_ex.e_machine)) {
+       return -ENOEXEC;
+    }
+
+    /* Now read in all of the header information */
+    elf_phdata = (struct elf_phdr *)qemu_malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
+    if (elf_phdata == NULL) {
+       return -ENOMEM;
+    }
+
+    retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
+    if(retval > 0) {
+       retval = read(bprm->fd, (char *) elf_phdata, 
+                               elf_ex.e_phentsize * elf_ex.e_phnum);
+    }
+
+    if (retval < 0) {
+       perror("load_elf_binary");
+       exit(-1);
+       qemu_free (elf_phdata);
+       return -errno;
+    }
+
+#ifdef BSWAP_NEEDED
+    elf_ppnt = elf_phdata;
+    for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
+        bswap_phdr(elf_ppnt);
+    }
+#endif
+    elf_ppnt = elf_phdata;
+
+    /* Now we do a little grungy work by mmaping the ELF image into
+     * the correct location in memory.  At this point, we assume that
+     * the image should be loaded at fixed address, not at a variable
+     * address.
+     */
+
+    for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+        unsigned long error, offset, len;
+        
+       if (elf_ppnt->p_type != PT_LOAD)
+            continue;
+#if 0        
+        error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
+                            elf_prot,
+                            (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
+                            bprm->fd,
+                            (elf_ppnt->p_offset - 
+                             TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+#endif
+       //offset = elf_ppnt->p_offset - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr);
+       offset = 0x4000;
+       lseek(bprm->fd, offset, SEEK_SET);
+       len = elf_ppnt->p_filesz + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr);
+       error = read(bprm->fd, addr, len); 
+
+        if (error == -1) {
+            perror("mmap");
+            exit(-1);
+        }
+       addr += len;
+    }
+
+    qemu_free(elf_phdata);
+
+    load_symbols(&elf_ex, bprm->fd);
+
+    return addr-startaddr;
+}
+
+int elf_exec(const char * filename, uint8_t *addr)
+{
+        struct linux_binprm bprm;
+        int retval;
+
+        retval = open(filename, O_RDONLY);
+        if (retval < 0)
+            return retval;
+        bprm.fd = retval;
+
+        retval = prepare_binprm(&bprm);
+
+        if(retval>=0) {
+           retval = load_elf_binary(&bprm, addr);
+       }
+       return retval;
+}
+#endif
+
+int load_kernel(const char *filename, uint8_t *addr)
+{
+    int fd, size;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+    /* load 32 bit code */
+    size = read(fd, addr, 16 * 1024 * 1024);
+    if (size < 0)
+        goto fail;
+    close(fd);
+    return size;
+ fail:
+    close(fd);
+    return -1;
+}
+
+static char saved_kfn[1024];
+static uint32_t saved_addr;
+static int magic_state;
+
+static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    int ret;
+
+    if (magic_state == 0) {
+#ifdef USE_ELF_LOADER
+        ret = elf_exec(saved_kfn, saved_addr);
+#else
+        ret = load_kernel(saved_kfn, (uint8_t *)saved_addr);
+#endif
+        if (ret < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
+                    saved_kfn);
+        }
+       magic_state = 1; /* No more magic */
+       tb_flush();
+    }
+    return ret;
+}
+
+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)
+{
+    int magic_io_memory;
+
+    strcpy(saved_kfn, kfn);
+    saved_addr = kloadaddr;
+    magic_state = 0;
+    magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, 0);
+    cpu_register_physical_memory(0x20000000, 4,
+                                 magic_io_memory);
+}
+
diff --git a/hw/sched.c b/hw/sched.c
new file mode 100644 (file)
index 0000000..c9a685d
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * QEMU interrupt controller & timer 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 PHYS_JJ_CLOCK  0x71D00000
+#define PHYS_JJ_CLOCK1 0x71D10000
+#define PHYS_JJ_INTR0  0x71E00000      /* CPU0 interrupt control registers */
+#define PHYS_JJ_INTR_G 0x71E10000      /* Master interrupt control registers */
+
+/* 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. */
+};
+/*
+ * 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;
+};
+
+#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 intreg_pending;
+    uint32_t intreg_enabled;
+    uint32_t intregm_pending;
+    uint32_t intregm_enabled;
+    uint32_t timer_regs[2];
+    uint32_t timerm_regs[2];
+} SCHEDState;
+
+static SCHEDState *ps;
+
+static int intreg_io_memory, intregm_io_memory,
+    timer_io_memory, timerm_io_memory;
+
+static void sched_reset(SCHEDState *s)
+{
+}
+
+static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    SCHEDState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr - PHYS_JJ_INTR0) >> 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 - PHYS_JJ_INTR0) >> 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 - PHYS_JJ_INTR_G) >> 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 - PHYS_JJ_INTR_G) >> 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,
+};
+
+static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    SCHEDState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr - PHYS_JJ_CLOCK) >> 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)
+{
+    SCHEDState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr - PHYS_JJ_CLOCK) >> 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,
+};
+
+static uint32_t timerm_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    SCHEDState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr - PHYS_JJ_CLOCK1) >> 2;
+    switch (saddr) {
+    default:
+       return s->timerm_regs[saddr];
+       break;
+    }
+    return 0;
+}
+
+static void timerm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    SCHEDState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr - PHYS_JJ_CLOCK1) >> 2;
+    switch (saddr) {
+    default:
+       s->timerm_regs[saddr] = val;
+       break;
+    }
+}
+
+static CPUReadMemoryFunc *timerm_mem_read[3] = {
+    timerm_mem_readl,
+    timerm_mem_readl,
+    timerm_mem_readl,
+};
+
+static CPUWriteMemoryFunc *timerm_mem_write[3] = {
+    timerm_mem_writel,
+    timerm_mem_writel,
+    timerm_mem_writel,
+};
+
+void pic_info() {}
+void irq_info() {}
+
+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);
+       }
+    }
+}
+
+void sched_init()
+{
+    SCHEDState *s;
+
+    s = qemu_mallocz(sizeof(SCHEDState));
+    if (!s)
+        return;
+
+    intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s);
+    cpu_register_physical_memory(PHYS_JJ_INTR0, 3, intreg_io_memory);
+
+    intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s);
+    cpu_register_physical_memory(PHYS_JJ_INTR_G, 5, intregm_io_memory);
+
+    timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s);
+    cpu_register_physical_memory(PHYS_JJ_CLOCK, 2, timer_io_memory);
+
+    timerm_io_memory = cpu_register_io_memory(0, timerm_mem_read, timerm_mem_write, s);
+    cpu_register_physical_memory(PHYS_JJ_CLOCK1, 2, timerm_io_memory);
+
+    sched_reset(s);
+    ps = s;
+}
+
diff --git a/hw/sun4m.c b/hw/sun4m.c
new file mode 100644 (file)
index 0000000..05dbd56
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * QEMU Sun4m System Emulator
+ * 
+ * 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"
+#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 ROMVEC_DATA          (MMU_CONTEXT_TBL + 0x1800)
+#define PROM_ADDR           0xffd04000
+#define PROM_FILENAME       "proll.bin"
+#define PHYS_JJ_EEPROM 0x71200000      /* [2000] MK48T08 */
+#define PHYS_JJ_IDPROM_OFF     0x1FD8
+#define PHYS_JJ_EEPROM_SIZE    0x2000
+
+/* TSC handling */
+
+uint64_t cpu_get_tsc()
+{
+    return qemu_get_clock(vm_clock);
+}
+
+void DMA_run() {}
+void SB16_run() {}
+void vga_invalidate_display() {}
+void vga_screen_dump(const char *filename) {}
+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;
+
+/* Sun4m hardware initialisation */
+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)
+{
+    char buf[1024];
+    int ret, linux_boot, bios_size;
+    unsigned long bios_offset;
+
+    linux_boot = (kernel_filename != NULL);
+
+    /* allocate RAM */
+    cpu_register_physical_memory(0, ram_size, 0);
+    bios_offset = ram_size;
+
+    iommu_init();
+    sched_init();
+    tcx_init(ds);
+    lance_init(&nd_table[0], 6);
+    nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE);
+
+    magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+
+#if 0
+    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
+    bios_size = get_image_size(buf);
+    ret = load_image(buf, phys_ram_base + bios_offset);
+    if (ret != bios_size) {
+        fprintf(stderr, "qemu: could not load prom '%s'\n", buf);
+        exit(1);
+    }
+    cpu_register_physical_memory(PROM_ADDR, 
+                                 bios_size, bios_offset | IO_MEM_ROM);
+#endif
+
+    /* We load Proll as the kernel and start it. It will issue a magic
+       IO to load the real kernel */
+    if (linux_boot) {
+       snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
+        ret = load_kernel(buf, 
+                          phys_ram_base + KERNEL_LOAD_ADDR);
+        if (ret < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
+                    buf);
+            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);
+#if 0
+    stl_raw(phys_ram_base + MMU_L1PTP + (0x50 << 2), (MMU_L2PTP >> 4) | 1); // frame buffer at 50..
+#endif
+    stl_raw(phys_ram_base + MMU_L1PTP + (0xff << 2), (MMU_L2PTP >> 4) | 1); // ff.. == 00..
+    /* 3 = U:RWX S:RWX */
+    stl_raw(phys_ram_base + MMU_L2PTP, (3 << PTE_ACCESS_SHIFT) | 2);
+#if 0
+    stl_raw(phys_ram_base + MMU_L2PTP + 0x84, (PHYS_JJ_TCX_FB >> 4) \
+           | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf
+    stl_raw(phys_ram_base + MMU_L2PTP + 0x88, (PHYS_JJ_TCX_FB >> 4) \
+           | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf
+    stl_raw(phys_ram_base + MMU_L2PTP + 0x140, (PHYS_JJ_TCX_FB >> 4) \
+           | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf
+    // "Empirical constant"
+    stl_raw(phys_ram_base + ROMVEC_DATA, 0x10010407);
+
+    // Version: V3 prom
+    stl_raw(phys_ram_base + ROMVEC_DATA + 4, 3);
+
+    stl_raw(phys_ram_base + ROMVEC_DATA + 0x1c, ROMVEC_DATA+0x400);
+    stl_raw(phys_ram_base + ROMVEC_DATA + 0x400, ROMVEC_DATA+0x404);
+    stl_raw(phys_ram_base + ROMVEC_DATA + 0x404, 0x81c3e008); // retl
+    stl_raw(phys_ram_base + ROMVEC_DATA + 0x408, 0x01000000); // nop
+#endif
+}
diff --git a/hw/tcx.c b/hw/tcx.c
new file mode 100644 (file)
index 0000000..d9b91c6
--- /dev/null
+++ b/hw/tcx.c
@@ -0,0 +1,176 @@
+/*
+ * QEMU Sun4m System Emulator
+ * 
+ * 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 PHYS_JJ_TCX_FB 0x50800000      /* Start address, frame buffer body */
+#define PHYS_JJ_TCX_0E 0x5E000000      /* Top address, one byte used. */
+
+#define MAXX 1024
+#define MAXY 768
+#define XSZ (8*80)
+#define YSZ (24*11)
+#define XOFF (MAXX-XSZ)
+#define YOFF (MAXY-YSZ)
+
+#define DEBUG_VGA_MEM
+
+typedef struct TCXState {
+    uint8_t *vram_ptr;
+    unsigned long vram_offset;
+    unsigned int vram_size;
+    DisplayState *ds;
+} TCXState;
+
+static TCXState *ts;
+
+static int tcx_io_memory;
+
+void vga_update_display()
+{
+    dpy_update(ts->ds, 0, 0, XSZ, YSZ);
+}
+
+static uint32_t tcx_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    TCXState *s = opaque;
+    uint32_t saddr;
+    unsigned int x, y;
+    char *sptr;
+
+    saddr = addr - PHYS_JJ_TCX_FB - YOFF*MAXX - XOFF;
+    y = saddr / MAXX;
+    x = saddr - y * MAXX;
+    if (x < MAXX && y < MAXY) {
+       sptr =  s->ds->data;
+       if (sptr)
+           return sptr[y * s->ds->linesize + x*4];
+    }
+    return 0;
+}
+
+static uint32_t tcx_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+#ifdef TARGET_WORDS_BIGENDIAN
+    v = tcx_mem_readb(opaque, addr) << 8;
+    v |= tcx_mem_readb(opaque, addr + 1);
+#else
+    v = tcx_mem_readb(opaque, addr);
+    v |= tcx_mem_readb(opaque, addr + 1) << 8;
+#endif
+    return v;
+}
+
+static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+#ifdef TARGET_WORDS_BIGENDIAN
+    v = tcx_mem_readb(opaque, addr) << 24;
+    v |= tcx_mem_readb(opaque, addr + 1) << 16;
+    v |= tcx_mem_readb(opaque, addr + 2) << 8;
+    v |= tcx_mem_readb(opaque, addr + 3);
+#else
+    v = tcx_mem_readb(opaque, addr);
+    v |= tcx_mem_readb(opaque, addr + 1) << 8;
+    v |= tcx_mem_readb(opaque, addr + 2) << 16;
+    v |= tcx_mem_readb(opaque, addr + 3) << 24;
+#endif
+    return v;
+}
+
+/* called for accesses between 0xa0000 and 0xc0000 */
+static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    TCXState *s = opaque;
+    uint32_t saddr;
+    unsigned int x, y;
+    char *sptr;
+
+    saddr = addr - PHYS_JJ_TCX_FB - YOFF*MAXX - XOFF;
+    y = saddr / MAXX;
+    x = saddr - y * MAXX;
+    if (x < MAXX && y < MAXY) {
+       sptr =  s->ds->data;
+       if (sptr) {
+           sptr[y * s->ds->linesize + x*4] = val;
+           sptr[y * s->ds->linesize + x*4+1] = val;
+           sptr[y * s->ds->linesize + x*4+2] = val;
+           cpu_physical_memory_set_dirty(addr);
+       }
+    }
+}
+
+static void tcx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    tcx_mem_writeb(opaque, addr, (val >> 8) & 0xff);
+    tcx_mem_writeb(opaque, addr + 1, val & 0xff);
+#else
+    tcx_mem_writeb(opaque, addr, val & 0xff);
+    tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+#endif
+}
+
+static void tcx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    tcx_mem_writeb(opaque, addr, (val >> 24) & 0xff);
+    tcx_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
+    tcx_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
+    tcx_mem_writeb(opaque, addr + 3, val & 0xff);
+#else
+    tcx_mem_writeb(opaque, addr, val & 0xff);
+    tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+    tcx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+    tcx_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+#endif
+}
+
+static CPUReadMemoryFunc *tcx_mem_read[3] = {
+    tcx_mem_readb,
+    tcx_mem_readw,
+    tcx_mem_readl,
+};
+
+static CPUWriteMemoryFunc *tcx_mem_write[3] = {
+    tcx_mem_writeb,
+    tcx_mem_writew,
+    tcx_mem_writel,
+};
+
+void tcx_init(DisplayState *ds)
+{
+    TCXState *s;
+
+    s = qemu_mallocz(sizeof(TCXState));
+    if (!s)
+        return;
+    s->ds = ds;
+    ts = s;
+    tcx_io_memory = cpu_register_io_memory(0, tcx_mem_read, tcx_mem_write, s);
+    cpu_register_physical_memory(PHYS_JJ_TCX_FB, 0x100000, 
+                                 tcx_io_memory);
+    dpy_resize(s->ds, XSZ, YSZ);
+}
+