Commit 420557e8981347368427849ff89ecd3fe537dafa
1 parent
6d5e216d
full system SPARC emulation (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1085 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
8 changed files
with
2089 additions
and
0 deletions
hw/iommu.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU SPARC iommu emulation | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include "vl.h" | |
| 25 | + | |
| 26 | +/* debug iommu */ | |
| 27 | +//#define DEBUG_IOMMU | |
| 28 | + | |
| 29 | +/* The IOMMU registers occupy three pages in IO space. */ | |
| 30 | +struct iommu_regs { | |
| 31 | + /* First page */ | |
| 32 | + volatile unsigned long control; /* IOMMU control */ | |
| 33 | + volatile unsigned long base; /* Physical base of iopte page table */ | |
| 34 | + volatile unsigned long _unused1[3]; | |
| 35 | + volatile unsigned long tlbflush; /* write only */ | |
| 36 | + volatile unsigned long pageflush; /* write only */ | |
| 37 | + volatile unsigned long _unused2[1017]; | |
| 38 | + /* Second page */ | |
| 39 | + volatile unsigned long afsr; /* Async-fault status register */ | |
| 40 | + volatile unsigned long afar; /* Async-fault physical address */ | |
| 41 | + volatile unsigned long _unused3[2]; | |
| 42 | + volatile unsigned long sbuscfg0; /* SBUS configuration registers, per-slot */ | |
| 43 | + volatile unsigned long sbuscfg1; | |
| 44 | + volatile unsigned long sbuscfg2; | |
| 45 | + volatile unsigned long sbuscfg3; | |
| 46 | + volatile unsigned long mfsr; /* Memory-fault status register */ | |
| 47 | + volatile unsigned long mfar; /* Memory-fault physical address */ | |
| 48 | + volatile unsigned long _unused4[1014]; | |
| 49 | + /* Third page */ | |
| 50 | + volatile unsigned long mid; /* IOMMU module-id */ | |
| 51 | +}; | |
| 52 | + | |
| 53 | +#define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */ | |
| 54 | +#define IOMMU_CTRL_VERS 0x0f000000 /* Version */ | |
| 55 | +#define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */ | |
| 56 | +#define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */ | |
| 57 | +#define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */ | |
| 58 | +#define IOMMU_RNGE_64MB 0x00000008 /* 0xfc000000 -> 0xffffffff */ | |
| 59 | +#define IOMMU_RNGE_128MB 0x0000000c /* 0xf8000000 -> 0xffffffff */ | |
| 60 | +#define IOMMU_RNGE_256MB 0x00000010 /* 0xf0000000 -> 0xffffffff */ | |
| 61 | +#define IOMMU_RNGE_512MB 0x00000014 /* 0xe0000000 -> 0xffffffff */ | |
| 62 | +#define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */ | |
| 63 | +#define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */ | |
| 64 | +#define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */ | |
| 65 | + | |
| 66 | +#define IOMMU_AFSR_ERR 0x80000000 /* LE, TO, or BE asserted */ | |
| 67 | +#define IOMMU_AFSR_LE 0x40000000 /* SBUS reports error after transaction */ | |
| 68 | +#define IOMMU_AFSR_TO 0x20000000 /* Write access took more than 12.8 us. */ | |
| 69 | +#define IOMMU_AFSR_BE 0x10000000 /* Write access received error acknowledge */ | |
| 70 | +#define IOMMU_AFSR_SIZE 0x0e000000 /* Size of transaction causing error */ | |
| 71 | +#define IOMMU_AFSR_S 0x01000000 /* Sparc was in supervisor mode */ | |
| 72 | +#define IOMMU_AFSR_RESV 0x00f00000 /* Reserver, forced to 0x8 by hardware */ | |
| 73 | +#define IOMMU_AFSR_ME 0x00080000 /* Multiple errors occurred */ | |
| 74 | +#define IOMMU_AFSR_RD 0x00040000 /* A read operation was in progress */ | |
| 75 | +#define IOMMU_AFSR_FAV 0x00020000 /* IOMMU afar has valid contents */ | |
| 76 | + | |
| 77 | +#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when bypass enabled */ | |
| 78 | +#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */ | |
| 79 | +#define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */ | |
| 80 | +#define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses | |
| 81 | + produced by this device as pure | |
| 82 | + physical. */ | |
| 83 | + | |
| 84 | +#define IOMMU_MFSR_ERR 0x80000000 /* One or more of PERR1 or PERR0 */ | |
| 85 | +#define IOMMU_MFSR_S 0x01000000 /* Sparc was in supervisor mode */ | |
| 86 | +#define IOMMU_MFSR_CPU 0x00800000 /* CPU transaction caused parity error */ | |
| 87 | +#define IOMMU_MFSR_ME 0x00080000 /* Multiple parity errors occurred */ | |
| 88 | +#define IOMMU_MFSR_PERR 0x00006000 /* high bit indicates parity error occurred | |
| 89 | + on the even word of the access, low bit | |
| 90 | + indicated odd word caused the parity error */ | |
| 91 | +#define IOMMU_MFSR_BM 0x00001000 /* Error occurred while in boot mode */ | |
| 92 | +#define IOMMU_MFSR_C 0x00000800 /* Address causing error was marked cacheable */ | |
| 93 | +#define IOMMU_MFSR_RTYP 0x000000f0 /* Memory request transaction type */ | |
| 94 | + | |
| 95 | +#define IOMMU_MID_SBAE 0x001f0000 /* SBus arbitration enable */ | |
| 96 | +#define IOMMU_MID_SE 0x00100000 /* Enables SCSI/ETHERNET arbitration */ | |
| 97 | +#define IOMMU_MID_SB3 0x00080000 /* Enable SBUS device 3 arbitration */ | |
| 98 | +#define IOMMU_MID_SB2 0x00040000 /* Enable SBUS device 2 arbitration */ | |
| 99 | +#define IOMMU_MID_SB1 0x00020000 /* Enable SBUS device 1 arbitration */ | |
| 100 | +#define IOMMU_MID_SB0 0x00010000 /* Enable SBUS device 0 arbitration */ | |
| 101 | +#define IOMMU_MID_MID 0x0000000f /* Module-id, hardcoded to 0x8 */ | |
| 102 | + | |
| 103 | +/* The format of an iopte in the page tables */ | |
| 104 | +#define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */ | |
| 105 | +#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */ | |
| 106 | +#define IOPTE_WRITE 0x00000004 /* Writeable */ | |
| 107 | +#define IOPTE_VALID 0x00000002 /* IOPTE is valid */ | |
| 108 | +#define IOPTE_WAZ 0x00000001 /* Write as zeros */ | |
| 109 | + | |
| 110 | +#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ | |
| 111 | +#define PAGE_SHIFT 12 | |
| 112 | +#define PAGE_SIZE (1 << PAGE_SHIFT) | |
| 113 | +#define PAGE_MASK (PAGE_SIZE - 1) | |
| 114 | + | |
| 115 | +typedef struct IOMMUState { | |
| 116 | + uint32_t regs[sizeof(struct iommu_regs)]; | |
| 117 | +} IOMMUState; | |
| 118 | + | |
| 119 | +static IOMMUState *ps; | |
| 120 | + | |
| 121 | +static int iommu_io_memory; | |
| 122 | + | |
| 123 | +static void iommu_reset(IOMMUState *s) | |
| 124 | +{ | |
| 125 | +} | |
| 126 | + | |
| 127 | +static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) | |
| 128 | +{ | |
| 129 | + IOMMUState *s = opaque; | |
| 130 | + uint32_t saddr; | |
| 131 | + | |
| 132 | + saddr = (addr - PHYS_JJ_IOMMU) >> 2; | |
| 133 | + switch (saddr) { | |
| 134 | + default: | |
| 135 | + return s->regs[saddr]; | |
| 136 | + break; | |
| 137 | + } | |
| 138 | + return 0; | |
| 139 | +} | |
| 140 | + | |
| 141 | +static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 142 | +{ | |
| 143 | + IOMMUState *s = opaque; | |
| 144 | + uint32_t saddr; | |
| 145 | + | |
| 146 | + saddr = (addr - PHYS_JJ_IOMMU) >> 2; | |
| 147 | + switch (saddr) { | |
| 148 | + default: | |
| 149 | + s->regs[saddr] = val; | |
| 150 | + break; | |
| 151 | + } | |
| 152 | +} | |
| 153 | + | |
| 154 | +static CPUReadMemoryFunc *iommu_mem_read[3] = { | |
| 155 | + iommu_mem_readw, | |
| 156 | + iommu_mem_readw, | |
| 157 | + iommu_mem_readw, | |
| 158 | +}; | |
| 159 | + | |
| 160 | +static CPUWriteMemoryFunc *iommu_mem_write[3] = { | |
| 161 | + iommu_mem_writew, | |
| 162 | + iommu_mem_writew, | |
| 163 | + iommu_mem_writew, | |
| 164 | +}; | |
| 165 | + | |
| 166 | +uint32_t iommu_translate(uint32_t addr) | |
| 167 | +{ | |
| 168 | + uint32_t *iopte = (void *)(ps->regs[1] << 4), pa, iostart; | |
| 169 | + | |
| 170 | + switch (ps->regs[0] & IOMMU_CTRL_RNGE) { | |
| 171 | + case IOMMU_RNGE_16MB: | |
| 172 | + iostart = 0xff000000; | |
| 173 | + break; | |
| 174 | + case IOMMU_RNGE_32MB: | |
| 175 | + iostart = 0xfe000000; | |
| 176 | + break; | |
| 177 | + case IOMMU_RNGE_64MB: | |
| 178 | + iostart = 0xfc000000; | |
| 179 | + break; | |
| 180 | + case IOMMU_RNGE_128MB: | |
| 181 | + iostart = 0xf8000000; | |
| 182 | + break; | |
| 183 | + case IOMMU_RNGE_256MB: | |
| 184 | + iostart = 0xf0000000; | |
| 185 | + break; | |
| 186 | + case IOMMU_RNGE_512MB: | |
| 187 | + iostart = 0xe0000000; | |
| 188 | + break; | |
| 189 | + case IOMMU_RNGE_1GB: | |
| 190 | + iostart = 0xc0000000; | |
| 191 | + break; | |
| 192 | + default: | |
| 193 | + case IOMMU_RNGE_2GB: | |
| 194 | + iostart = 0x80000000; | |
| 195 | + break; | |
| 196 | + } | |
| 197 | + | |
| 198 | + iopte += ((addr - iostart) >> PAGE_SHIFT); | |
| 199 | + cpu_physical_memory_rw((uint32_t)iopte, (void *) &pa, 4, 0); | |
| 200 | + bswap32s(&pa); | |
| 201 | + pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */ | |
| 202 | + //return pa + PAGE_SIZE; | |
| 203 | + return pa + (addr & PAGE_MASK); | |
| 204 | +} | |
| 205 | + | |
| 206 | +void iommu_init() | |
| 207 | +{ | |
| 208 | + IOMMUState *s; | |
| 209 | + | |
| 210 | + s = qemu_mallocz(sizeof(IOMMUState)); | |
| 211 | + if (!s) | |
| 212 | + return; | |
| 213 | + | |
| 214 | + iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); | |
| 215 | + cpu_register_physical_memory(PHYS_JJ_IOMMU, sizeof(struct iommu_regs), | |
| 216 | + iommu_io_memory); | |
| 217 | + | |
| 218 | + iommu_reset(s); | |
| 219 | + ps = s; | |
| 220 | +} | |
| 221 | + | ... | ... |
hw/lance.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU Lance emulation | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include "vl.h" | |
| 25 | + | |
| 26 | +/* debug LANCE card */ | |
| 27 | +#define DEBUG_LANCE | |
| 28 | + | |
| 29 | +#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ | |
| 30 | +#define PHYS_JJ_LEDMA 0x78400010 /* ledma, off by 10 from unused SCSI */ | |
| 31 | +#define PHYS_JJ_LE 0x78C00000 /* LANCE, typical sun4m */ | |
| 32 | + | |
| 33 | +#ifndef LANCE_LOG_TX_BUFFERS | |
| 34 | +#define LANCE_LOG_TX_BUFFERS 4 | |
| 35 | +#define LANCE_LOG_RX_BUFFERS 4 | |
| 36 | +#endif | |
| 37 | + | |
| 38 | +#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ | |
| 39 | +#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ | |
| 40 | + | |
| 41 | + | |
| 42 | +#define LE_CSR0 0 | |
| 43 | +#define LE_CSR1 1 | |
| 44 | +#define LE_CSR2 2 | |
| 45 | +#define LE_CSR3 3 | |
| 46 | +#define LE_MAXREG (LE_CSR3 + 1) | |
| 47 | + | |
| 48 | +#define LE_RDP 0 | |
| 49 | +#define LE_RAP 1 | |
| 50 | + | |
| 51 | +#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ | |
| 52 | + | |
| 53 | +#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */ | |
| 54 | +#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */ | |
| 55 | +#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */ | |
| 56 | +#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */ | |
| 57 | +#define LE_C0_MERR 0x0800 /* ME: Memory error */ | |
| 58 | +#define LE_C0_RINT 0x0400 /* Received interrupt */ | |
| 59 | +#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */ | |
| 60 | +#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */ | |
| 61 | +#define LE_C0_INTR 0x0080 /* Interrupt or error */ | |
| 62 | +#define LE_C0_INEA 0x0040 /* Interrupt enable */ | |
| 63 | +#define LE_C0_RXON 0x0020 /* Receiver on */ | |
| 64 | +#define LE_C0_TXON 0x0010 /* Transmitter on */ | |
| 65 | +#define LE_C0_TDMD 0x0008 /* Transmitter demand */ | |
| 66 | +#define LE_C0_STOP 0x0004 /* Stop the card */ | |
| 67 | +#define LE_C0_STRT 0x0002 /* Start the card */ | |
| 68 | +#define LE_C0_INIT 0x0001 /* Init the card */ | |
| 69 | + | |
| 70 | +#define LE_C3_BSWP 0x4 /* SWAP */ | |
| 71 | +#define LE_C3_ACON 0x2 /* ALE Control */ | |
| 72 | +#define LE_C3_BCON 0x1 /* Byte control */ | |
| 73 | + | |
| 74 | +/* Receive message descriptor 1 */ | |
| 75 | +#define LE_R1_OWN 0x80 /* Who owns the entry */ | |
| 76 | +#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ | |
| 77 | +#define LE_R1_FRA 0x20 /* FRA: Frame error */ | |
| 78 | +#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ | |
| 79 | +#define LE_R1_CRC 0x08 /* CRC error */ | |
| 80 | +#define LE_R1_BUF 0x04 /* BUF: Buffer error */ | |
| 81 | +#define LE_R1_SOP 0x02 /* Start of packet */ | |
| 82 | +#define LE_R1_EOP 0x01 /* End of packet */ | |
| 83 | +#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ | |
| 84 | + | |
| 85 | +#define LE_T1_OWN 0x80 /* Lance owns the packet */ | |
| 86 | +#define LE_T1_ERR 0x40 /* Error summary */ | |
| 87 | +#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ | |
| 88 | +#define LE_T1_EONE 0x08 /* Error: one retry needed */ | |
| 89 | +#define LE_T1_EDEF 0x04 /* Error: deferred */ | |
| 90 | +#define LE_T1_SOP 0x02 /* Start of packet */ | |
| 91 | +#define LE_T1_EOP 0x01 /* End of packet */ | |
| 92 | +#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ | |
| 93 | + | |
| 94 | +#define LE_T3_BUF 0x8000 /* Buffer error */ | |
| 95 | +#define LE_T3_UFL 0x4000 /* Error underflow */ | |
| 96 | +#define LE_T3_LCOL 0x1000 /* Error late collision */ | |
| 97 | +#define LE_T3_CLOS 0x0800 /* Error carrier loss */ | |
| 98 | +#define LE_T3_RTY 0x0400 /* Error retry */ | |
| 99 | +#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ | |
| 100 | + | |
| 101 | +#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) | |
| 102 | +#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) | |
| 103 | +#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29) | |
| 104 | + | |
| 105 | +#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) | |
| 106 | +#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) | |
| 107 | +#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) | |
| 108 | + | |
| 109 | +#define PKT_BUF_SZ 1544 | |
| 110 | +#define RX_BUFF_SIZE PKT_BUF_SZ | |
| 111 | +#define TX_BUFF_SIZE PKT_BUF_SZ | |
| 112 | + | |
| 113 | +struct lance_rx_desc { | |
| 114 | + unsigned short rmd0; /* low address of packet */ | |
| 115 | + unsigned char rmd1_bits; /* descriptor bits */ | |
| 116 | + unsigned char rmd1_hadr; /* high address of packet */ | |
| 117 | + short length; /* This length is 2s complement (negative)! | |
| 118 | + * Buffer length | |
| 119 | + */ | |
| 120 | + unsigned short mblength; /* This is the actual number of bytes received */ | |
| 121 | +}; | |
| 122 | + | |
| 123 | +struct lance_tx_desc { | |
| 124 | + unsigned short tmd0; /* low address of packet */ | |
| 125 | + unsigned char tmd1_bits; /* descriptor bits */ | |
| 126 | + unsigned char tmd1_hadr; /* high address of packet */ | |
| 127 | + short length; /* Length is 2s complement (negative)! */ | |
| 128 | + unsigned short misc; | |
| 129 | +}; | |
| 130 | + | |
| 131 | +/* The LANCE initialization block, described in databook. */ | |
| 132 | +/* On the Sparc, this block should be on a DMA region */ | |
| 133 | +struct lance_init_block { | |
| 134 | + unsigned short mode; /* Pre-set mode (reg. 15) */ | |
| 135 | + unsigned char phys_addr[6]; /* Physical ethernet address */ | |
| 136 | + unsigned filter[2]; /* Multicast filter. */ | |
| 137 | + | |
| 138 | + /* Receive and transmit ring base, along with extra bits. */ | |
| 139 | + unsigned short rx_ptr; /* receive descriptor addr */ | |
| 140 | + unsigned short rx_len; /* receive len and high addr */ | |
| 141 | + unsigned short tx_ptr; /* transmit descriptor addr */ | |
| 142 | + unsigned short tx_len; /* transmit len and high addr */ | |
| 143 | + | |
| 144 | + /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ | |
| 145 | + struct lance_rx_desc brx_ring[RX_RING_SIZE]; | |
| 146 | + struct lance_tx_desc btx_ring[TX_RING_SIZE]; | |
| 147 | + | |
| 148 | + char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE]; | |
| 149 | + char pad[2]; /* align rx_buf for copy_and_sum(). */ | |
| 150 | + char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE]; | |
| 151 | +}; | |
| 152 | + | |
| 153 | +#define LEDMA_REGS 4 | |
| 154 | +#if 0 | |
| 155 | +/* Structure to describe the current status of DMA registers on the Sparc */ | |
| 156 | +struct sparc_dma_registers { | |
| 157 | + uint32_t cond_reg; /* DMA condition register */ | |
| 158 | + uint32_t st_addr; /* Start address of this transfer */ | |
| 159 | + uint32_t cnt; /* How many bytes to transfer */ | |
| 160 | + uint32_t dma_test; /* DMA test register */ | |
| 161 | +}; | |
| 162 | +#endif | |
| 163 | + | |
| 164 | +typedef struct LEDMAState { | |
| 165 | + uint32_t regs[LEDMA_REGS]; | |
| 166 | +} LEDMAState; | |
| 167 | + | |
| 168 | +typedef struct LANCEState { | |
| 169 | + NetDriverState *nd; | |
| 170 | + uint32_t leptr; | |
| 171 | + uint16_t addr; | |
| 172 | + uint16_t regs[LE_MAXREG]; | |
| 173 | + uint8_t phys[6]; /* mac address */ | |
| 174 | + int irq; | |
| 175 | + LEDMAState *ledma; | |
| 176 | +} LANCEState; | |
| 177 | + | |
| 178 | +static int lance_io_memory; | |
| 179 | + | |
| 180 | +static unsigned int rxptr, txptr; | |
| 181 | + | |
| 182 | +static void lance_send(void *opaque); | |
| 183 | + | |
| 184 | +static void lance_reset(LANCEState *s) | |
| 185 | +{ | |
| 186 | + memcpy(s->phys, s->nd->macaddr, 6); | |
| 187 | + rxptr = 0; | |
| 188 | + txptr = 0; | |
| 189 | + s->regs[LE_CSR0] = LE_C0_STOP; | |
| 190 | +} | |
| 191 | + | |
| 192 | +static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) | |
| 193 | +{ | |
| 194 | + LANCEState *s = opaque; | |
| 195 | + uint32_t saddr; | |
| 196 | + | |
| 197 | + saddr = addr - PHYS_JJ_LE; | |
| 198 | + switch (saddr >> 1) { | |
| 199 | + case LE_RDP: | |
| 200 | + return s->regs[s->addr]; | |
| 201 | + case LE_RAP: | |
| 202 | + return s->addr; | |
| 203 | + default: | |
| 204 | + break; | |
| 205 | + } | |
| 206 | + return 0; | |
| 207 | +} | |
| 208 | + | |
| 209 | +static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 210 | +{ | |
| 211 | + LANCEState *s = opaque; | |
| 212 | + uint32_t saddr; | |
| 213 | + uint16_t clear, reg; | |
| 214 | + | |
| 215 | + saddr = addr - PHYS_JJ_LE; | |
| 216 | + switch (saddr >> 1) { | |
| 217 | + case LE_RDP: | |
| 218 | + switch(s->addr) { | |
| 219 | + case LE_CSR0: | |
| 220 | + if (val & LE_C0_STOP) { | |
| 221 | + s->regs[LE_CSR0] = LE_C0_STOP; | |
| 222 | + break; | |
| 223 | + } | |
| 224 | + | |
| 225 | + reg = s->regs[LE_CSR0]; | |
| 226 | + | |
| 227 | + // 1 = clear for some bits | |
| 228 | + reg &= ~(val & 0x7f00); | |
| 229 | + | |
| 230 | + // generated bits | |
| 231 | + reg &= ~(LE_C0_ERR | LE_C0_INTR); | |
| 232 | + if (reg & 0x7100) | |
| 233 | + reg |= LE_C0_ERR; | |
| 234 | + if (reg & 0x7f00) | |
| 235 | + reg |= LE_C0_INTR; | |
| 236 | + | |
| 237 | + // direct bit | |
| 238 | + reg &= ~LE_C0_INEA; | |
| 239 | + reg |= val & LE_C0_INEA; | |
| 240 | + | |
| 241 | + // exclusive bits | |
| 242 | + if (val & LE_C0_INIT) { | |
| 243 | + reg |= LE_C0_IDON | LE_C0_INIT; | |
| 244 | + reg &= ~LE_C0_STOP; | |
| 245 | + } | |
| 246 | + else if (val & LE_C0_STRT) { | |
| 247 | + reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON; | |
| 248 | + reg &= ~LE_C0_STOP; | |
| 249 | + } | |
| 250 | + | |
| 251 | + s->regs[LE_CSR0] = reg; | |
| 252 | + | |
| 253 | + // trigger bits | |
| 254 | + //if (val & LE_C0_TDMD) | |
| 255 | + | |
| 256 | + if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) | |
| 257 | + pic_set_irq(s->irq, 1); | |
| 258 | + break; | |
| 259 | + case LE_CSR1: | |
| 260 | + s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff); | |
| 261 | + s->regs[s->addr] = val; | |
| 262 | + break; | |
| 263 | + case LE_CSR2: | |
| 264 | + s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16); | |
| 265 | + s->regs[s->addr] = val; | |
| 266 | + break; | |
| 267 | + case LE_CSR3: | |
| 268 | + s->regs[s->addr] = val; | |
| 269 | + break; | |
| 270 | + } | |
| 271 | + break; | |
| 272 | + case LE_RAP: | |
| 273 | + if (val < LE_MAXREG) | |
| 274 | + s->addr = val; | |
| 275 | + break; | |
| 276 | + default: | |
| 277 | + break; | |
| 278 | + } | |
| 279 | + lance_send(s); | |
| 280 | +} | |
| 281 | + | |
| 282 | +static CPUReadMemoryFunc *lance_mem_read[3] = { | |
| 283 | + lance_mem_readw, | |
| 284 | + lance_mem_readw, | |
| 285 | + lance_mem_readw, | |
| 286 | +}; | |
| 287 | + | |
| 288 | +static CPUWriteMemoryFunc *lance_mem_write[3] = { | |
| 289 | + lance_mem_writew, | |
| 290 | + lance_mem_writew, | |
| 291 | + lance_mem_writew, | |
| 292 | +}; | |
| 293 | + | |
| 294 | + | |
| 295 | +/* return the max buffer size if the LANCE can receive more data */ | |
| 296 | +static int lance_can_receive(void *opaque) | |
| 297 | +{ | |
| 298 | + LANCEState *s = opaque; | |
| 299 | + void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); | |
| 300 | + struct lance_init_block *ib; | |
| 301 | + int i; | |
| 302 | + uint16_t temp; | |
| 303 | + | |
| 304 | + if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) | |
| 305 | + return 0; | |
| 306 | + | |
| 307 | + ib = (void *) iommu_translate(dmaptr); | |
| 308 | + | |
| 309 | + for (i = 0; i < RX_RING_SIZE; i++) { | |
| 310 | + cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); | |
| 311 | + temp &= 0xff; | |
| 312 | + if (temp == (LE_R1_OWN)) { | |
| 313 | +#ifdef DEBUG_LANCE | |
| 314 | + fprintf(stderr, "lance: can receive %d\n", RX_BUFF_SIZE); | |
| 315 | +#endif | |
| 316 | + return RX_BUFF_SIZE; | |
| 317 | + } | |
| 318 | + } | |
| 319 | +#ifdef DEBUG_LANCE | |
| 320 | + fprintf(stderr, "lance: cannot receive\n"); | |
| 321 | +#endif | |
| 322 | + return 0; | |
| 323 | +} | |
| 324 | + | |
| 325 | +#define MIN_BUF_SIZE 60 | |
| 326 | + | |
| 327 | +static void lance_receive(void *opaque, const uint8_t *buf, int size) | |
| 328 | +{ | |
| 329 | + LANCEState *s = opaque; | |
| 330 | + void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); | |
| 331 | + struct lance_init_block *ib; | |
| 332 | + unsigned int i, old_rxptr, j; | |
| 333 | + uint16_t temp; | |
| 334 | + | |
| 335 | + if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) | |
| 336 | + return; | |
| 337 | + | |
| 338 | + ib = (void *) iommu_translate(dmaptr); | |
| 339 | + | |
| 340 | + old_rxptr = rxptr; | |
| 341 | + for (i = rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { | |
| 342 | + cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); | |
| 343 | + if (temp == (LE_R1_OWN)) { | |
| 344 | + rxptr = (rxptr + 1) & RX_RING_MOD_MASK; | |
| 345 | + temp = size; | |
| 346 | + bswap16s(&temp); | |
| 347 | + cpu_physical_memory_write(&ib->brx_ring[i].mblength, (void *) &temp, 2); | |
| 348 | +#if 0 | |
| 349 | + cpu_physical_memory_write(&ib->rx_buf[i], buf, size); | |
| 350 | +#else | |
| 351 | + for (j = 0; j < size; j++) { | |
| 352 | + cpu_physical_memory_write(((void *)&ib->rx_buf[i]) + j, &buf[j], 1); | |
| 353 | + } | |
| 354 | +#endif | |
| 355 | + temp = LE_R1_POK; | |
| 356 | + cpu_physical_memory_write(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); | |
| 357 | + s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; | |
| 358 | + if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) | |
| 359 | + pic_set_irq(s->irq, 1); | |
| 360 | +#ifdef DEBUG_LANCE | |
| 361 | + fprintf(stderr, "lance: got packet, len %d\n", size); | |
| 362 | +#endif | |
| 363 | + return; | |
| 364 | + } | |
| 365 | + } | |
| 366 | +} | |
| 367 | + | |
| 368 | +static void lance_send(void *opaque) | |
| 369 | +{ | |
| 370 | + LANCEState *s = opaque; | |
| 371 | + void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); | |
| 372 | + struct lance_init_block *ib; | |
| 373 | + unsigned int i, old_txptr, j; | |
| 374 | + uint16_t temp; | |
| 375 | + char pkt_buf[PKT_BUF_SZ]; | |
| 376 | + | |
| 377 | + if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) | |
| 378 | + return; | |
| 379 | + | |
| 380 | + ib = (void *) iommu_translate(dmaptr); | |
| 381 | + | |
| 382 | + old_txptr = txptr; | |
| 383 | + for (i = txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { | |
| 384 | + cpu_physical_memory_read(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); | |
| 385 | + if (temp == (LE_T1_POK|LE_T1_OWN)) { | |
| 386 | + cpu_physical_memory_read(&ib->btx_ring[i].length, (void *) &temp, 2); | |
| 387 | + bswap16s(&temp); | |
| 388 | + temp = (~temp) + 1; | |
| 389 | +#if 0 | |
| 390 | + cpu_physical_memory_read(&ib->tx_buf[i], pkt_buf, temp); | |
| 391 | +#else | |
| 392 | + for (j = 0; j < temp; j++) { | |
| 393 | + cpu_physical_memory_read(((void *)&ib->tx_buf[i]) + j, &pkt_buf[j], 1); | |
| 394 | + } | |
| 395 | +#endif | |
| 396 | + | |
| 397 | +#ifdef DEBUG_LANCE | |
| 398 | + fprintf(stderr, "lance: sending packet, len %d\n", temp); | |
| 399 | +#endif | |
| 400 | + qemu_send_packet(s->nd, pkt_buf, temp); | |
| 401 | + temp = LE_T1_POK; | |
| 402 | + cpu_physical_memory_write(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); | |
| 403 | + txptr = (txptr + 1) & TX_RING_MOD_MASK; | |
| 404 | + s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; | |
| 405 | + } | |
| 406 | + } | |
| 407 | +} | |
| 408 | + | |
| 409 | +static int ledma_io_memory; | |
| 410 | + | |
| 411 | +static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) | |
| 412 | +{ | |
| 413 | + LEDMAState *s = opaque; | |
| 414 | + uint32_t saddr; | |
| 415 | + | |
| 416 | + saddr = (addr - PHYS_JJ_LEDMA) >> 2; | |
| 417 | + if (saddr < LEDMA_REGS) | |
| 418 | + return s->regs[saddr]; | |
| 419 | + else | |
| 420 | + return 0; | |
| 421 | +} | |
| 422 | + | |
| 423 | +static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 424 | +{ | |
| 425 | + LEDMAState *s = opaque; | |
| 426 | + uint32_t saddr; | |
| 427 | + | |
| 428 | + saddr = (addr - PHYS_JJ_LEDMA) >> 2; | |
| 429 | + if (saddr < LEDMA_REGS) | |
| 430 | + s->regs[saddr] = val; | |
| 431 | +} | |
| 432 | + | |
| 433 | +static CPUReadMemoryFunc *ledma_mem_read[3] = { | |
| 434 | + ledma_mem_readl, | |
| 435 | + ledma_mem_readl, | |
| 436 | + ledma_mem_readl, | |
| 437 | +}; | |
| 438 | + | |
| 439 | +static CPUWriteMemoryFunc *ledma_mem_write[3] = { | |
| 440 | + ledma_mem_writel, | |
| 441 | + ledma_mem_writel, | |
| 442 | + ledma_mem_writel, | |
| 443 | +}; | |
| 444 | + | |
| 445 | +void lance_init(NetDriverState *nd, int irq) | |
| 446 | +{ | |
| 447 | + LANCEState *s; | |
| 448 | + LEDMAState *led; | |
| 449 | + | |
| 450 | + s = qemu_mallocz(sizeof(LANCEState)); | |
| 451 | + if (!s) | |
| 452 | + return; | |
| 453 | + | |
| 454 | + lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); | |
| 455 | + cpu_register_physical_memory(PHYS_JJ_LE, 8, | |
| 456 | + lance_io_memory); | |
| 457 | + led = qemu_mallocz(sizeof(LEDMAState)); | |
| 458 | + if (!led) | |
| 459 | + return; | |
| 460 | + | |
| 461 | + ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led); | |
| 462 | + cpu_register_physical_memory(PHYS_JJ_LEDMA, 16, | |
| 463 | + ledma_io_memory); | |
| 464 | + | |
| 465 | + s->nd = nd; | |
| 466 | + s->ledma = led; | |
| 467 | + s->irq = irq; | |
| 468 | + | |
| 469 | + lance_reset(s); | |
| 470 | + qemu_add_read_packet(nd, lance_can_receive, lance_receive, s); | |
| 471 | +} | |
| 472 | + | ... | ... |
hw/m48t08.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU M48T08 NVRAM emulation for Sparc platform | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003-2004 Jocelyn Mayer | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include "vl.h" | |
| 25 | +#include "m48t08.h" | |
| 26 | + | |
| 27 | +//#define DEBUG_NVRAM | |
| 28 | + | |
| 29 | +#if defined(DEBUG_NVRAM) | |
| 30 | +#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) | |
| 31 | +#else | |
| 32 | +#define NVRAM_PRINTF(fmt, args...) do { } while (0) | |
| 33 | +#endif | |
| 34 | + | |
| 35 | +#define NVRAM_MAX_MEM 0xfff0 | |
| 36 | + | |
| 37 | +struct m48t08_t { | |
| 38 | + /* Hardware parameters */ | |
| 39 | + int mem_index; | |
| 40 | + uint32_t mem_base; | |
| 41 | + uint16_t size; | |
| 42 | + /* RTC management */ | |
| 43 | + time_t time_offset; | |
| 44 | + time_t stop_time; | |
| 45 | + /* NVRAM storage */ | |
| 46 | + uint8_t lock; | |
| 47 | + uint16_t addr; | |
| 48 | + uint8_t *buffer; | |
| 49 | +}; | |
| 50 | + | |
| 51 | +/* Fake timer functions */ | |
| 52 | +/* Generic helpers for BCD */ | |
| 53 | +static inline uint8_t toBCD (uint8_t value) | |
| 54 | +{ | |
| 55 | + return (((value / 10) % 10) << 4) | (value % 10); | |
| 56 | +} | |
| 57 | + | |
| 58 | +static inline uint8_t fromBCD (uint8_t BCD) | |
| 59 | +{ | |
| 60 | + return ((BCD >> 4) * 10) + (BCD & 0x0F); | |
| 61 | +} | |
| 62 | + | |
| 63 | +/* RTC management helpers */ | |
| 64 | +static void get_time (m48t08_t *NVRAM, struct tm *tm) | |
| 65 | +{ | |
| 66 | + time_t t; | |
| 67 | + | |
| 68 | + t = time(NULL) + NVRAM->time_offset; | |
| 69 | +#ifdef _WIN32 | |
| 70 | + memcpy(tm,localtime(&t),sizeof(*tm)); | |
| 71 | +#else | |
| 72 | + localtime_r (&t, tm) ; | |
| 73 | +#endif | |
| 74 | +} | |
| 75 | + | |
| 76 | +static void set_time (m48t08_t *NVRAM, struct tm *tm) | |
| 77 | +{ | |
| 78 | + time_t now, new_time; | |
| 79 | + | |
| 80 | + new_time = mktime(tm); | |
| 81 | + now = time(NULL); | |
| 82 | + NVRAM->time_offset = new_time - now; | |
| 83 | +} | |
| 84 | + | |
| 85 | +/* Direct access to NVRAM */ | |
| 86 | +void m48t08_write (m48t08_t *NVRAM, uint32_t val) | |
| 87 | +{ | |
| 88 | + struct tm tm; | |
| 89 | + int tmp; | |
| 90 | + | |
| 91 | + if (NVRAM->addr > NVRAM_MAX_MEM && NVRAM->addr < 0x2000) | |
| 92 | + NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); | |
| 93 | + switch (NVRAM->addr) { | |
| 94 | + case 0x1FF8: | |
| 95 | + /* control */ | |
| 96 | + NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; | |
| 97 | + break; | |
| 98 | + case 0x1FF9: | |
| 99 | + /* seconds (BCD) */ | |
| 100 | + tmp = fromBCD(val & 0x7F); | |
| 101 | + if (tmp >= 0 && tmp <= 59) { | |
| 102 | + get_time(NVRAM, &tm); | |
| 103 | + tm.tm_sec = tmp; | |
| 104 | + set_time(NVRAM, &tm); | |
| 105 | + } | |
| 106 | + if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) { | |
| 107 | + if (val & 0x80) { | |
| 108 | + NVRAM->stop_time = time(NULL); | |
| 109 | + } else { | |
| 110 | + NVRAM->time_offset += NVRAM->stop_time - time(NULL); | |
| 111 | + NVRAM->stop_time = 0; | |
| 112 | + } | |
| 113 | + } | |
| 114 | + NVRAM->buffer[0x1FF9] = val & 0x80; | |
| 115 | + break; | |
| 116 | + case 0x1FFA: | |
| 117 | + /* minutes (BCD) */ | |
| 118 | + tmp = fromBCD(val & 0x7F); | |
| 119 | + if (tmp >= 0 && tmp <= 59) { | |
| 120 | + get_time(NVRAM, &tm); | |
| 121 | + tm.tm_min = tmp; | |
| 122 | + set_time(NVRAM, &tm); | |
| 123 | + } | |
| 124 | + break; | |
| 125 | + case 0x1FFB: | |
| 126 | + /* hours (BCD) */ | |
| 127 | + tmp = fromBCD(val & 0x3F); | |
| 128 | + if (tmp >= 0 && tmp <= 23) { | |
| 129 | + get_time(NVRAM, &tm); | |
| 130 | + tm.tm_hour = tmp; | |
| 131 | + set_time(NVRAM, &tm); | |
| 132 | + } | |
| 133 | + break; | |
| 134 | + case 0x1FFC: | |
| 135 | + /* day of the week / century */ | |
| 136 | + tmp = fromBCD(val & 0x07); | |
| 137 | + get_time(NVRAM, &tm); | |
| 138 | + tm.tm_wday = tmp; | |
| 139 | + set_time(NVRAM, &tm); | |
| 140 | + NVRAM->buffer[0x1FFC] = val & 0x40; | |
| 141 | + break; | |
| 142 | + case 0x1FFD: | |
| 143 | + /* date */ | |
| 144 | + tmp = fromBCD(val & 0x1F); | |
| 145 | + if (tmp != 0) { | |
| 146 | + get_time(NVRAM, &tm); | |
| 147 | + tm.tm_mday = tmp; | |
| 148 | + set_time(NVRAM, &tm); | |
| 149 | + } | |
| 150 | + break; | |
| 151 | + case 0x1FFE: | |
| 152 | + /* month */ | |
| 153 | + tmp = fromBCD(val & 0x1F); | |
| 154 | + if (tmp >= 1 && tmp <= 12) { | |
| 155 | + get_time(NVRAM, &tm); | |
| 156 | + tm.tm_mon = tmp - 1; | |
| 157 | + set_time(NVRAM, &tm); | |
| 158 | + } | |
| 159 | + break; | |
| 160 | + case 0x1FFF: | |
| 161 | + /* year */ | |
| 162 | + tmp = fromBCD(val); | |
| 163 | + if (tmp >= 0 && tmp <= 99) { | |
| 164 | + get_time(NVRAM, &tm); | |
| 165 | + tm.tm_year = fromBCD(val); | |
| 166 | + set_time(NVRAM, &tm); | |
| 167 | + } | |
| 168 | + break; | |
| 169 | + default: | |
| 170 | + /* Check lock registers state */ | |
| 171 | + if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) | |
| 172 | + break; | |
| 173 | + if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) | |
| 174 | + break; | |
| 175 | + if (NVRAM->addr < NVRAM_MAX_MEM || | |
| 176 | + (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { | |
| 177 | + NVRAM->buffer[NVRAM->addr] = val & 0xFF; | |
| 178 | + } | |
| 179 | + break; | |
| 180 | + } | |
| 181 | +} | |
| 182 | + | |
| 183 | +uint32_t m48t08_read (m48t08_t *NVRAM) | |
| 184 | +{ | |
| 185 | + struct tm tm; | |
| 186 | + uint32_t retval = 0xFF; | |
| 187 | + | |
| 188 | + switch (NVRAM->addr) { | |
| 189 | + case 0x1FF8: | |
| 190 | + /* control */ | |
| 191 | + goto do_read; | |
| 192 | + case 0x1FF9: | |
| 193 | + /* seconds (BCD) */ | |
| 194 | + get_time(NVRAM, &tm); | |
| 195 | + retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec); | |
| 196 | + break; | |
| 197 | + case 0x1FFA: | |
| 198 | + /* minutes (BCD) */ | |
| 199 | + get_time(NVRAM, &tm); | |
| 200 | + retval = toBCD(tm.tm_min); | |
| 201 | + break; | |
| 202 | + case 0x1FFB: | |
| 203 | + /* hours (BCD) */ | |
| 204 | + get_time(NVRAM, &tm); | |
| 205 | + retval = toBCD(tm.tm_hour); | |
| 206 | + break; | |
| 207 | + case 0x1FFC: | |
| 208 | + /* day of the week / century */ | |
| 209 | + get_time(NVRAM, &tm); | |
| 210 | + retval = NVRAM->buffer[0x1FFC] | tm.tm_wday; | |
| 211 | + break; | |
| 212 | + case 0x1FFD: | |
| 213 | + /* date */ | |
| 214 | + get_time(NVRAM, &tm); | |
| 215 | + retval = toBCD(tm.tm_mday); | |
| 216 | + break; | |
| 217 | + case 0x1FFE: | |
| 218 | + /* month */ | |
| 219 | + get_time(NVRAM, &tm); | |
| 220 | + retval = toBCD(tm.tm_mon + 1); | |
| 221 | + break; | |
| 222 | + case 0x1FFF: | |
| 223 | + /* year */ | |
| 224 | + get_time(NVRAM, &tm); | |
| 225 | + retval = toBCD(tm.tm_year); | |
| 226 | + break; | |
| 227 | + default: | |
| 228 | + /* Check lock registers state */ | |
| 229 | + if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) | |
| 230 | + break; | |
| 231 | + if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) | |
| 232 | + break; | |
| 233 | + if (NVRAM->addr < NVRAM_MAX_MEM || | |
| 234 | + (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { | |
| 235 | + do_read: | |
| 236 | + retval = NVRAM->buffer[NVRAM->addr]; | |
| 237 | + } | |
| 238 | + break; | |
| 239 | + } | |
| 240 | + if (NVRAM->addr > NVRAM_MAX_MEM + 1 && NVRAM->addr < 0x2000) | |
| 241 | + NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); | |
| 242 | + | |
| 243 | + return retval; | |
| 244 | +} | |
| 245 | + | |
| 246 | +void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr) | |
| 247 | +{ | |
| 248 | + NVRAM->addr = addr; | |
| 249 | +} | |
| 250 | + | |
| 251 | +void m48t08_toggle_lock (m48t08_t *NVRAM, int lock) | |
| 252 | +{ | |
| 253 | + NVRAM->lock ^= 1 << lock; | |
| 254 | +} | |
| 255 | + | |
| 256 | +static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) | |
| 257 | +{ | |
| 258 | + m48t08_t *NVRAM = opaque; | |
| 259 | + | |
| 260 | + addr -= NVRAM->mem_base; | |
| 261 | + if (addr < NVRAM_MAX_MEM) | |
| 262 | + NVRAM->buffer[addr] = value; | |
| 263 | +} | |
| 264 | + | |
| 265 | +static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) | |
| 266 | +{ | |
| 267 | + m48t08_t *NVRAM = opaque; | |
| 268 | + | |
| 269 | + addr -= NVRAM->mem_base; | |
| 270 | + if (addr < NVRAM_MAX_MEM) { | |
| 271 | + NVRAM->buffer[addr] = value >> 8; | |
| 272 | + NVRAM->buffer[addr + 1] = value; | |
| 273 | + } | |
| 274 | +} | |
| 275 | + | |
| 276 | +static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | |
| 277 | +{ | |
| 278 | + m48t08_t *NVRAM = opaque; | |
| 279 | + | |
| 280 | + addr -= NVRAM->mem_base; | |
| 281 | + if (addr < NVRAM_MAX_MEM) { | |
| 282 | + NVRAM->buffer[addr] = value >> 24; | |
| 283 | + NVRAM->buffer[addr + 1] = value >> 16; | |
| 284 | + NVRAM->buffer[addr + 2] = value >> 8; | |
| 285 | + NVRAM->buffer[addr + 3] = value; | |
| 286 | + } | |
| 287 | +} | |
| 288 | + | |
| 289 | +static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) | |
| 290 | +{ | |
| 291 | + m48t08_t *NVRAM = opaque; | |
| 292 | + uint32_t retval = 0; | |
| 293 | + | |
| 294 | + addr -= NVRAM->mem_base; | |
| 295 | + if (addr < NVRAM_MAX_MEM) | |
| 296 | + retval = NVRAM->buffer[addr]; | |
| 297 | + | |
| 298 | + return retval; | |
| 299 | +} | |
| 300 | + | |
| 301 | +static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) | |
| 302 | +{ | |
| 303 | + m48t08_t *NVRAM = opaque; | |
| 304 | + uint32_t retval = 0; | |
| 305 | + | |
| 306 | + addr -= NVRAM->mem_base; | |
| 307 | + if (addr < NVRAM_MAX_MEM) { | |
| 308 | + retval = NVRAM->buffer[addr] << 8; | |
| 309 | + retval |= NVRAM->buffer[addr + 1]; | |
| 310 | + } | |
| 311 | + | |
| 312 | + return retval; | |
| 313 | +} | |
| 314 | + | |
| 315 | +static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) | |
| 316 | +{ | |
| 317 | + m48t08_t *NVRAM = opaque; | |
| 318 | + uint32_t retval = 0; | |
| 319 | + | |
| 320 | + addr -= NVRAM->mem_base; | |
| 321 | + if (addr < NVRAM_MAX_MEM) { | |
| 322 | + retval = NVRAM->buffer[addr] << 24; | |
| 323 | + retval |= NVRAM->buffer[addr + 1] << 16; | |
| 324 | + retval |= NVRAM->buffer[addr + 2] << 8; | |
| 325 | + retval |= NVRAM->buffer[addr + 3]; | |
| 326 | + } | |
| 327 | + | |
| 328 | + return retval; | |
| 329 | +} | |
| 330 | + | |
| 331 | +static CPUWriteMemoryFunc *nvram_write[] = { | |
| 332 | + &nvram_writeb, | |
| 333 | + &nvram_writew, | |
| 334 | + &nvram_writel, | |
| 335 | +}; | |
| 336 | + | |
| 337 | +static CPUReadMemoryFunc *nvram_read[] = { | |
| 338 | + &nvram_readb, | |
| 339 | + &nvram_readw, | |
| 340 | + &nvram_readl, | |
| 341 | +}; | |
| 342 | + | |
| 343 | +/* Initialisation routine */ | |
| 344 | +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size) | |
| 345 | +{ | |
| 346 | + m48t08_t *s; | |
| 347 | + int i; | |
| 348 | + unsigned char tmp = 0; | |
| 349 | + | |
| 350 | + s = qemu_mallocz(sizeof(m48t08_t)); | |
| 351 | + if (!s) | |
| 352 | + return NULL; | |
| 353 | + s->buffer = qemu_mallocz(size); | |
| 354 | + if (!s->buffer) { | |
| 355 | + qemu_free(s); | |
| 356 | + return NULL; | |
| 357 | + } | |
| 358 | + s->size = size; | |
| 359 | + s->mem_base = mem_base; | |
| 360 | + s->addr = 0; | |
| 361 | + if (mem_base != 0) { | |
| 362 | + s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); | |
| 363 | + cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); | |
| 364 | + } | |
| 365 | + s->lock = 0; | |
| 366 | + | |
| 367 | + i = 0x1fd8; | |
| 368 | + s->buffer[i++] = 0x01; | |
| 369 | + s->buffer[i++] = 0x80; /* Sun4m OBP */ | |
| 370 | + /* XXX: Ethernet address, etc */ | |
| 371 | + | |
| 372 | + /* Calculate checksum */ | |
| 373 | + for (i = 0x1fd8; i < 0x1fe7; i++) { | |
| 374 | + tmp ^= s->buffer[i]; | |
| 375 | + } | |
| 376 | + s->buffer[0x1fe7] = tmp; | |
| 377 | + return s; | |
| 378 | +} | |
| 379 | + | |
| 380 | +#if 0 | |
| 381 | +struct idprom | |
| 382 | +{ | |
| 383 | + unsigned char id_format; /* Format identifier (always 0x01) */ | |
| 384 | + unsigned char id_machtype; /* Machine type */ | |
| 385 | + unsigned char id_ethaddr[6]; /* Hardware ethernet address */ | |
| 386 | + long id_date; /* Date of manufacture */ | |
| 387 | + unsigned int id_sernum:24; /* Unique serial number */ | |
| 388 | + unsigned char id_cksum; /* Checksum - xor of the data bytes */ | |
| 389 | + unsigned char reserved[16]; | |
| 390 | +}; | |
| 391 | +#endif | ... | ... |
hw/m48t08.h
0 → 100644
| 1 | +#if !defined (__M48T08_H__) | |
| 2 | +#define __M48T08_H__ | |
| 3 | + | |
| 4 | +typedef struct m48t08_t m48t08_t; | |
| 5 | + | |
| 6 | +void m48t08_write (m48t08_t *NVRAM, uint32_t val); | |
| 7 | +uint32_t m48t08_read (m48t08_t *NVRAM); | |
| 8 | +void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr); | |
| 9 | +void m48t08_toggle_lock (m48t08_t *NVRAM, int lock); | |
| 10 | +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size); | |
| 11 | + | |
| 12 | +#endif /* !defined (__M48T08_H__) */ | ... | ... |
hw/magic-load.c
0 → 100644
| 1 | +/* This is the Linux kernel elf-loading code, ported into user space */ | |
| 2 | +#include "vl.h" | |
| 3 | +#include "disas.h" | |
| 4 | + | |
| 5 | +/* XXX: this code is not used as it is under the GPL license. Please | |
| 6 | + remove or recode it */ | |
| 7 | +//#define USE_ELF_LOADER | |
| 8 | + | |
| 9 | +#ifdef USE_ELF_LOADER | |
| 10 | +/* should probably go in elf.h */ | |
| 11 | +#ifndef ELIBBAD | |
| 12 | +#define ELIBBAD 80 | |
| 13 | +#endif | |
| 14 | + | |
| 15 | + | |
| 16 | +#define ELF_START_MMAP 0x80000000 | |
| 17 | + | |
| 18 | +#define elf_check_arch(x) ( (x) == EM_SPARC ) | |
| 19 | + | |
| 20 | +#define ELF_CLASS ELFCLASS32 | |
| 21 | +#define ELF_DATA ELFDATA2MSB | |
| 22 | +#define ELF_ARCH EM_SPARC | |
| 23 | + | |
| 24 | +#include "elf.h" | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * This structure is used to hold the arguments that are | |
| 28 | + * used when loading binaries. | |
| 29 | + */ | |
| 30 | +struct linux_binprm { | |
| 31 | + char buf[128]; | |
| 32 | + int fd; | |
| 33 | +}; | |
| 34 | + | |
| 35 | +#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE | |
| 36 | +#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) | |
| 37 | +#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) | |
| 38 | + | |
| 39 | +#ifdef BSWAP_NEEDED | |
| 40 | +static void bswap_ehdr(Elf32_Ehdr *ehdr) | |
| 41 | +{ | |
| 42 | + bswap16s(&ehdr->e_type); /* Object file type */ | |
| 43 | + bswap16s(&ehdr->e_machine); /* Architecture */ | |
| 44 | + bswap32s(&ehdr->e_version); /* Object file version */ | |
| 45 | + bswap32s(&ehdr->e_entry); /* Entry point virtual address */ | |
| 46 | + bswap32s(&ehdr->e_phoff); /* Program header table file offset */ | |
| 47 | + bswap32s(&ehdr->e_shoff); /* Section header table file offset */ | |
| 48 | + bswap32s(&ehdr->e_flags); /* Processor-specific flags */ | |
| 49 | + bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ | |
| 50 | + bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ | |
| 51 | + bswap16s(&ehdr->e_phnum); /* Program header table entry count */ | |
| 52 | + bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ | |
| 53 | + bswap16s(&ehdr->e_shnum); /* Section header table entry count */ | |
| 54 | + bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ | |
| 55 | +} | |
| 56 | + | |
| 57 | +static void bswap_phdr(Elf32_Phdr *phdr) | |
| 58 | +{ | |
| 59 | + bswap32s(&phdr->p_type); /* Segment type */ | |
| 60 | + bswap32s(&phdr->p_offset); /* Segment file offset */ | |
| 61 | + bswap32s(&phdr->p_vaddr); /* Segment virtual address */ | |
| 62 | + bswap32s(&phdr->p_paddr); /* Segment physical address */ | |
| 63 | + bswap32s(&phdr->p_filesz); /* Segment size in file */ | |
| 64 | + bswap32s(&phdr->p_memsz); /* Segment size in memory */ | |
| 65 | + bswap32s(&phdr->p_flags); /* Segment flags */ | |
| 66 | + bswap32s(&phdr->p_align); /* Segment alignment */ | |
| 67 | +} | |
| 68 | + | |
| 69 | +static void bswap_shdr(Elf32_Shdr *shdr) | |
| 70 | +{ | |
| 71 | + bswap32s(&shdr->sh_name); | |
| 72 | + bswap32s(&shdr->sh_type); | |
| 73 | + bswap32s(&shdr->sh_flags); | |
| 74 | + bswap32s(&shdr->sh_addr); | |
| 75 | + bswap32s(&shdr->sh_offset); | |
| 76 | + bswap32s(&shdr->sh_size); | |
| 77 | + bswap32s(&shdr->sh_link); | |
| 78 | + bswap32s(&shdr->sh_info); | |
| 79 | + bswap32s(&shdr->sh_addralign); | |
| 80 | + bswap32s(&shdr->sh_entsize); | |
| 81 | +} | |
| 82 | + | |
| 83 | +static void bswap_sym(Elf32_Sym *sym) | |
| 84 | +{ | |
| 85 | + bswap32s(&sym->st_name); | |
| 86 | + bswap32s(&sym->st_value); | |
| 87 | + bswap32s(&sym->st_size); | |
| 88 | + bswap16s(&sym->st_shndx); | |
| 89 | +} | |
| 90 | +#endif | |
| 91 | + | |
| 92 | +static int prepare_binprm(struct linux_binprm *bprm) | |
| 93 | +{ | |
| 94 | + int retval; | |
| 95 | + | |
| 96 | + memset(bprm->buf, 0, sizeof(bprm->buf)); | |
| 97 | + retval = lseek(bprm->fd, 0L, SEEK_SET); | |
| 98 | + if(retval >= 0) { | |
| 99 | + retval = read(bprm->fd, bprm->buf, 128); | |
| 100 | + } | |
| 101 | + if(retval < 0) { | |
| 102 | + perror("prepare_binprm"); | |
| 103 | + exit(-1); | |
| 104 | + /* return(-errno); */ | |
| 105 | + } | |
| 106 | + else { | |
| 107 | + return(retval); | |
| 108 | + } | |
| 109 | +} | |
| 110 | + | |
| 111 | +/* Best attempt to load symbols from this ELF object. */ | |
| 112 | +static void load_symbols(struct elfhdr *hdr, int fd) | |
| 113 | +{ | |
| 114 | + unsigned int i; | |
| 115 | + struct elf_shdr sechdr, symtab, strtab; | |
| 116 | + char *strings; | |
| 117 | + | |
| 118 | + lseek(fd, hdr->e_shoff, SEEK_SET); | |
| 119 | + for (i = 0; i < hdr->e_shnum; i++) { | |
| 120 | + if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) | |
| 121 | + return; | |
| 122 | +#ifdef BSWAP_NEEDED | |
| 123 | + bswap_shdr(&sechdr); | |
| 124 | +#endif | |
| 125 | + if (sechdr.sh_type == SHT_SYMTAB) { | |
| 126 | + symtab = sechdr; | |
| 127 | + lseek(fd, hdr->e_shoff | |
| 128 | + + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); | |
| 129 | + if (read(fd, &strtab, sizeof(strtab)) | |
| 130 | + != sizeof(strtab)) | |
| 131 | + return; | |
| 132 | +#ifdef BSWAP_NEEDED | |
| 133 | + bswap_shdr(&strtab); | |
| 134 | +#endif | |
| 135 | + goto found; | |
| 136 | + } | |
| 137 | + } | |
| 138 | + return; /* Shouldn't happen... */ | |
| 139 | + | |
| 140 | + found: | |
| 141 | + /* Now know where the strtab and symtab are. Snarf them. */ | |
| 142 | + disas_symtab = qemu_malloc(symtab.sh_size); | |
| 143 | + disas_strtab = strings = qemu_malloc(strtab.sh_size); | |
| 144 | + if (!disas_symtab || !disas_strtab) | |
| 145 | + return; | |
| 146 | + | |
| 147 | + lseek(fd, symtab.sh_offset, SEEK_SET); | |
| 148 | + if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size) | |
| 149 | + return; | |
| 150 | + | |
| 151 | +#ifdef BSWAP_NEEDED | |
| 152 | + for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) | |
| 153 | + bswap_sym(disas_symtab + sizeof(struct elf_sym)*i); | |
| 154 | +#endif | |
| 155 | + | |
| 156 | + lseek(fd, strtab.sh_offset, SEEK_SET); | |
| 157 | + if (read(fd, strings, strtab.sh_size) != strtab.sh_size) | |
| 158 | + return; | |
| 159 | + disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); | |
| 160 | +} | |
| 161 | + | |
| 162 | +static int load_elf_binary(struct linux_binprm * bprm, uint8_t *addr) | |
| 163 | +{ | |
| 164 | + struct elfhdr elf_ex; | |
| 165 | + unsigned long startaddr = addr; | |
| 166 | + int i; | |
| 167 | + struct elf_phdr * elf_ppnt; | |
| 168 | + struct elf_phdr *elf_phdata; | |
| 169 | + int retval; | |
| 170 | + | |
| 171 | + elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ | |
| 172 | +#ifdef BSWAP_NEEDED | |
| 173 | + bswap_ehdr(&elf_ex); | |
| 174 | +#endif | |
| 175 | + | |
| 176 | + if (elf_ex.e_ident[0] != 0x7f || | |
| 177 | + strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { | |
| 178 | + return -ENOEXEC; | |
| 179 | + } | |
| 180 | + | |
| 181 | + /* First of all, some simple consistency checks */ | |
| 182 | + if (! elf_check_arch(elf_ex.e_machine)) { | |
| 183 | + return -ENOEXEC; | |
| 184 | + } | |
| 185 | + | |
| 186 | + /* Now read in all of the header information */ | |
| 187 | + elf_phdata = (struct elf_phdr *)qemu_malloc(elf_ex.e_phentsize*elf_ex.e_phnum); | |
| 188 | + if (elf_phdata == NULL) { | |
| 189 | + return -ENOMEM; | |
| 190 | + } | |
| 191 | + | |
| 192 | + retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); | |
| 193 | + if(retval > 0) { | |
| 194 | + retval = read(bprm->fd, (char *) elf_phdata, | |
| 195 | + elf_ex.e_phentsize * elf_ex.e_phnum); | |
| 196 | + } | |
| 197 | + | |
| 198 | + if (retval < 0) { | |
| 199 | + perror("load_elf_binary"); | |
| 200 | + exit(-1); | |
| 201 | + qemu_free (elf_phdata); | |
| 202 | + return -errno; | |
| 203 | + } | |
| 204 | + | |
| 205 | +#ifdef BSWAP_NEEDED | |
| 206 | + elf_ppnt = elf_phdata; | |
| 207 | + for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) { | |
| 208 | + bswap_phdr(elf_ppnt); | |
| 209 | + } | |
| 210 | +#endif | |
| 211 | + elf_ppnt = elf_phdata; | |
| 212 | + | |
| 213 | + /* Now we do a little grungy work by mmaping the ELF image into | |
| 214 | + * the correct location in memory. At this point, we assume that | |
| 215 | + * the image should be loaded at fixed address, not at a variable | |
| 216 | + * address. | |
| 217 | + */ | |
| 218 | + | |
| 219 | + for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { | |
| 220 | + unsigned long error, offset, len; | |
| 221 | + | |
| 222 | + if (elf_ppnt->p_type != PT_LOAD) | |
| 223 | + continue; | |
| 224 | +#if 0 | |
| 225 | + error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), | |
| 226 | + elf_prot, | |
| 227 | + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), | |
| 228 | + bprm->fd, | |
| 229 | + (elf_ppnt->p_offset - | |
| 230 | + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); | |
| 231 | +#endif | |
| 232 | + //offset = elf_ppnt->p_offset - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr); | |
| 233 | + offset = 0x4000; | |
| 234 | + lseek(bprm->fd, offset, SEEK_SET); | |
| 235 | + len = elf_ppnt->p_filesz + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr); | |
| 236 | + error = read(bprm->fd, addr, len); | |
| 237 | + | |
| 238 | + if (error == -1) { | |
| 239 | + perror("mmap"); | |
| 240 | + exit(-1); | |
| 241 | + } | |
| 242 | + addr += len; | |
| 243 | + } | |
| 244 | + | |
| 245 | + qemu_free(elf_phdata); | |
| 246 | + | |
| 247 | + load_symbols(&elf_ex, bprm->fd); | |
| 248 | + | |
| 249 | + return addr-startaddr; | |
| 250 | +} | |
| 251 | + | |
| 252 | +int elf_exec(const char * filename, uint8_t *addr) | |
| 253 | +{ | |
| 254 | + struct linux_binprm bprm; | |
| 255 | + int retval; | |
| 256 | + | |
| 257 | + retval = open(filename, O_RDONLY); | |
| 258 | + if (retval < 0) | |
| 259 | + return retval; | |
| 260 | + bprm.fd = retval; | |
| 261 | + | |
| 262 | + retval = prepare_binprm(&bprm); | |
| 263 | + | |
| 264 | + if(retval>=0) { | |
| 265 | + retval = load_elf_binary(&bprm, addr); | |
| 266 | + } | |
| 267 | + return retval; | |
| 268 | +} | |
| 269 | +#endif | |
| 270 | + | |
| 271 | +int load_kernel(const char *filename, uint8_t *addr) | |
| 272 | +{ | |
| 273 | + int fd, size; | |
| 274 | + | |
| 275 | + fd = open(filename, O_RDONLY | O_BINARY); | |
| 276 | + if (fd < 0) | |
| 277 | + return -1; | |
| 278 | + /* load 32 bit code */ | |
| 279 | + size = read(fd, addr, 16 * 1024 * 1024); | |
| 280 | + if (size < 0) | |
| 281 | + goto fail; | |
| 282 | + close(fd); | |
| 283 | + return size; | |
| 284 | + fail: | |
| 285 | + close(fd); | |
| 286 | + return -1; | |
| 287 | +} | |
| 288 | + | |
| 289 | +static char saved_kfn[1024]; | |
| 290 | +static uint32_t saved_addr; | |
| 291 | +static int magic_state; | |
| 292 | + | |
| 293 | +static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr) | |
| 294 | +{ | |
| 295 | + int ret; | |
| 296 | + | |
| 297 | + if (magic_state == 0) { | |
| 298 | +#ifdef USE_ELF_LOADER | |
| 299 | + ret = elf_exec(saved_kfn, saved_addr); | |
| 300 | +#else | |
| 301 | + ret = load_kernel(saved_kfn, (uint8_t *)saved_addr); | |
| 302 | +#endif | |
| 303 | + if (ret < 0) { | |
| 304 | + fprintf(stderr, "qemu: could not load kernel '%s'\n", | |
| 305 | + saved_kfn); | |
| 306 | + } | |
| 307 | + magic_state = 1; /* No more magic */ | |
| 308 | + tb_flush(); | |
| 309 | + } | |
| 310 | + return ret; | |
| 311 | +} | |
| 312 | + | |
| 313 | +static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 314 | +{ | |
| 315 | +} | |
| 316 | + | |
| 317 | + | |
| 318 | +static CPUReadMemoryFunc *magic_mem_read[3] = { | |
| 319 | + magic_mem_readl, | |
| 320 | + magic_mem_readl, | |
| 321 | + magic_mem_readl, | |
| 322 | +}; | |
| 323 | + | |
| 324 | +static CPUWriteMemoryFunc *magic_mem_write[3] = { | |
| 325 | + magic_mem_writel, | |
| 326 | + magic_mem_writel, | |
| 327 | + magic_mem_writel, | |
| 328 | +}; | |
| 329 | + | |
| 330 | +void magic_init(const char *kfn, int kloadaddr) | |
| 331 | +{ | |
| 332 | + int magic_io_memory; | |
| 333 | + | |
| 334 | + strcpy(saved_kfn, kfn); | |
| 335 | + saved_addr = kloadaddr; | |
| 336 | + magic_state = 0; | |
| 337 | + magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, 0); | |
| 338 | + cpu_register_physical_memory(0x20000000, 4, | |
| 339 | + magic_io_memory); | |
| 340 | +} | |
| 341 | + | ... | ... |
hw/sched.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU interrupt controller & timer emulation | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include "vl.h" | |
| 25 | + | |
| 26 | +#define PHYS_JJ_CLOCK 0x71D00000 | |
| 27 | +#define PHYS_JJ_CLOCK1 0x71D10000 | |
| 28 | +#define PHYS_JJ_INTR0 0x71E00000 /* CPU0 interrupt control registers */ | |
| 29 | +#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */ | |
| 30 | + | |
| 31 | +/* These registers are used for sending/receiving irqs from/to | |
| 32 | + * different cpu's. | |
| 33 | + */ | |
| 34 | +struct sun4m_intreg_percpu { | |
| 35 | + unsigned int tbt; /* Intrs pending for this cpu, by PIL. */ | |
| 36 | + /* These next two registers are WRITE-ONLY and are only | |
| 37 | + * "on bit" sensitive, "off bits" written have NO affect. | |
| 38 | + */ | |
| 39 | + unsigned int clear; /* Clear this cpus irqs here. */ | |
| 40 | + unsigned int set; /* Set this cpus irqs here. */ | |
| 41 | +}; | |
| 42 | +/* | |
| 43 | + * djhr | |
| 44 | + * Actually the clear and set fields in this struct are misleading.. | |
| 45 | + * according to the SLAVIO manual (and the same applies for the SEC) | |
| 46 | + * the clear field clears bits in the mask which will ENABLE that IRQ | |
| 47 | + * the set field sets bits in the mask to DISABLE the IRQ. | |
| 48 | + * | |
| 49 | + * Also the undirected_xx address in the SLAVIO is defined as | |
| 50 | + * RESERVED and write only.. | |
| 51 | + * | |
| 52 | + * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor | |
| 53 | + * sun4m machines, for MP the layout makes more sense. | |
| 54 | + */ | |
| 55 | +struct sun4m_intreg_master { | |
| 56 | + unsigned int tbt; /* IRQ's that are pending, see sun4m masks. */ | |
| 57 | + unsigned int irqs; /* Master IRQ bits. */ | |
| 58 | + | |
| 59 | + /* Again, like the above, two these registers are WRITE-ONLY. */ | |
| 60 | + unsigned int clear; /* Clear master IRQ's by setting bits here. */ | |
| 61 | + unsigned int set; /* Set master IRQ's by setting bits here. */ | |
| 62 | + | |
| 63 | + /* This register is both READ and WRITE. */ | |
| 64 | + unsigned int undirected_target; /* Which cpu gets undirected irqs. */ | |
| 65 | +}; | |
| 66 | +/* | |
| 67 | + * Registers of hardware timer in sun4m. | |
| 68 | + */ | |
| 69 | +struct sun4m_timer_percpu { | |
| 70 | + volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */ | |
| 71 | + volatile unsigned int l14_cur_count; | |
| 72 | +}; | |
| 73 | + | |
| 74 | +struct sun4m_timer_global { | |
| 75 | + volatile unsigned int l10_timer_limit; | |
| 76 | + volatile unsigned int l10_cur_count; | |
| 77 | +}; | |
| 78 | + | |
| 79 | +#define SUN4M_INT_ENABLE 0x80000000 | |
| 80 | +#define SUN4M_INT_E14 0x00000080 | |
| 81 | +#define SUN4M_INT_E10 0x00080000 | |
| 82 | + | |
| 83 | +#define SUN4M_HARD_INT(x) (0x000000001 << (x)) | |
| 84 | +#define SUN4M_SOFT_INT(x) (0x000010000 << (x)) | |
| 85 | + | |
| 86 | +#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ | |
| 87 | +#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ | |
| 88 | +#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ | |
| 89 | +#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ | |
| 90 | +#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ | |
| 91 | +#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ | |
| 92 | +#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ | |
| 93 | +#define SUN4M_INT_REALTIME 0x00080000 /* system timer */ | |
| 94 | +#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */ | |
| 95 | +#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */ | |
| 96 | +#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */ | |
| 97 | +#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ | |
| 98 | +#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ | |
| 99 | + | |
| 100 | +#define SUN4M_INT_SBUS(x) (1 << (x+7)) | |
| 101 | +#define SUN4M_INT_VME(x) (1 << (x)) | |
| 102 | + | |
| 103 | +typedef struct SCHEDState { | |
| 104 | + uint32_t intreg_pending; | |
| 105 | + uint32_t intreg_enabled; | |
| 106 | + uint32_t intregm_pending; | |
| 107 | + uint32_t intregm_enabled; | |
| 108 | + uint32_t timer_regs[2]; | |
| 109 | + uint32_t timerm_regs[2]; | |
| 110 | +} SCHEDState; | |
| 111 | + | |
| 112 | +static SCHEDState *ps; | |
| 113 | + | |
| 114 | +static int intreg_io_memory, intregm_io_memory, | |
| 115 | + timer_io_memory, timerm_io_memory; | |
| 116 | + | |
| 117 | +static void sched_reset(SCHEDState *s) | |
| 118 | +{ | |
| 119 | +} | |
| 120 | + | |
| 121 | +static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr) | |
| 122 | +{ | |
| 123 | + SCHEDState *s = opaque; | |
| 124 | + uint32_t saddr; | |
| 125 | + | |
| 126 | + saddr = (addr - PHYS_JJ_INTR0) >> 2; | |
| 127 | + switch (saddr) { | |
| 128 | + case 0: | |
| 129 | + return s->intreg_pending; | |
| 130 | + break; | |
| 131 | + default: | |
| 132 | + break; | |
| 133 | + } | |
| 134 | + return 0; | |
| 135 | +} | |
| 136 | + | |
| 137 | +static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 138 | +{ | |
| 139 | + SCHEDState *s = opaque; | |
| 140 | + uint32_t saddr; | |
| 141 | + | |
| 142 | + saddr = (addr - PHYS_JJ_INTR0) >> 2; | |
| 143 | + switch (saddr) { | |
| 144 | + case 0: | |
| 145 | + s->intreg_pending = val; | |
| 146 | + break; | |
| 147 | + case 1: // clear | |
| 148 | + s->intreg_enabled &= ~val; | |
| 149 | + break; | |
| 150 | + case 2: // set | |
| 151 | + s->intreg_enabled |= val; | |
| 152 | + break; | |
| 153 | + default: | |
| 154 | + break; | |
| 155 | + } | |
| 156 | +} | |
| 157 | + | |
| 158 | +static CPUReadMemoryFunc *intreg_mem_read[3] = { | |
| 159 | + intreg_mem_readl, | |
| 160 | + intreg_mem_readl, | |
| 161 | + intreg_mem_readl, | |
| 162 | +}; | |
| 163 | + | |
| 164 | +static CPUWriteMemoryFunc *intreg_mem_write[3] = { | |
| 165 | + intreg_mem_writel, | |
| 166 | + intreg_mem_writel, | |
| 167 | + intreg_mem_writel, | |
| 168 | +}; | |
| 169 | + | |
| 170 | +static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr) | |
| 171 | +{ | |
| 172 | + SCHEDState *s = opaque; | |
| 173 | + uint32_t saddr; | |
| 174 | + | |
| 175 | + saddr = (addr - PHYS_JJ_INTR_G) >> 2; | |
| 176 | + switch (saddr) { | |
| 177 | + case 0: | |
| 178 | + return s->intregm_pending; | |
| 179 | + break; | |
| 180 | + case 1: | |
| 181 | + return s->intregm_enabled; | |
| 182 | + break; | |
| 183 | + default: | |
| 184 | + break; | |
| 185 | + } | |
| 186 | + return 0; | |
| 187 | +} | |
| 188 | + | |
| 189 | +static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 190 | +{ | |
| 191 | + SCHEDState *s = opaque; | |
| 192 | + uint32_t saddr; | |
| 193 | + | |
| 194 | + saddr = (addr - PHYS_JJ_INTR_G) >> 2; | |
| 195 | + switch (saddr) { | |
| 196 | + case 0: | |
| 197 | + s->intregm_pending = val; | |
| 198 | + break; | |
| 199 | + case 1: | |
| 200 | + s->intregm_enabled = val; | |
| 201 | + break; | |
| 202 | + case 2: // clear | |
| 203 | + s->intregm_enabled &= ~val; | |
| 204 | + break; | |
| 205 | + case 3: // set | |
| 206 | + s->intregm_enabled |= val; | |
| 207 | + break; | |
| 208 | + default: | |
| 209 | + break; | |
| 210 | + } | |
| 211 | +} | |
| 212 | + | |
| 213 | +static CPUReadMemoryFunc *intregm_mem_read[3] = { | |
| 214 | + intregm_mem_readl, | |
| 215 | + intregm_mem_readl, | |
| 216 | + intregm_mem_readl, | |
| 217 | +}; | |
| 218 | + | |
| 219 | +static CPUWriteMemoryFunc *intregm_mem_write[3] = { | |
| 220 | + intregm_mem_writel, | |
| 221 | + intregm_mem_writel, | |
| 222 | + intregm_mem_writel, | |
| 223 | +}; | |
| 224 | + | |
| 225 | +static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr) | |
| 226 | +{ | |
| 227 | + SCHEDState *s = opaque; | |
| 228 | + uint32_t saddr; | |
| 229 | + | |
| 230 | + saddr = (addr - PHYS_JJ_CLOCK) >> 2; | |
| 231 | + switch (saddr) { | |
| 232 | + default: | |
| 233 | + return s->timer_regs[saddr]; | |
| 234 | + break; | |
| 235 | + } | |
| 236 | + return 0; | |
| 237 | +} | |
| 238 | + | |
| 239 | +static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 240 | +{ | |
| 241 | + SCHEDState *s = opaque; | |
| 242 | + uint32_t saddr; | |
| 243 | + | |
| 244 | + saddr = (addr - PHYS_JJ_CLOCK) >> 2; | |
| 245 | + switch (saddr) { | |
| 246 | + default: | |
| 247 | + s->timer_regs[saddr] = val; | |
| 248 | + break; | |
| 249 | + } | |
| 250 | +} | |
| 251 | + | |
| 252 | +static CPUReadMemoryFunc *timer_mem_read[3] = { | |
| 253 | + timer_mem_readl, | |
| 254 | + timer_mem_readl, | |
| 255 | + timer_mem_readl, | |
| 256 | +}; | |
| 257 | + | |
| 258 | +static CPUWriteMemoryFunc *timer_mem_write[3] = { | |
| 259 | + timer_mem_writel, | |
| 260 | + timer_mem_writel, | |
| 261 | + timer_mem_writel, | |
| 262 | +}; | |
| 263 | + | |
| 264 | +static uint32_t timerm_mem_readl(void *opaque, target_phys_addr_t addr) | |
| 265 | +{ | |
| 266 | + SCHEDState *s = opaque; | |
| 267 | + uint32_t saddr; | |
| 268 | + | |
| 269 | + saddr = (addr - PHYS_JJ_CLOCK1) >> 2; | |
| 270 | + switch (saddr) { | |
| 271 | + default: | |
| 272 | + return s->timerm_regs[saddr]; | |
| 273 | + break; | |
| 274 | + } | |
| 275 | + return 0; | |
| 276 | +} | |
| 277 | + | |
| 278 | +static void timerm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 279 | +{ | |
| 280 | + SCHEDState *s = opaque; | |
| 281 | + uint32_t saddr; | |
| 282 | + | |
| 283 | + saddr = (addr - PHYS_JJ_CLOCK1) >> 2; | |
| 284 | + switch (saddr) { | |
| 285 | + default: | |
| 286 | + s->timerm_regs[saddr] = val; | |
| 287 | + break; | |
| 288 | + } | |
| 289 | +} | |
| 290 | + | |
| 291 | +static CPUReadMemoryFunc *timerm_mem_read[3] = { | |
| 292 | + timerm_mem_readl, | |
| 293 | + timerm_mem_readl, | |
| 294 | + timerm_mem_readl, | |
| 295 | +}; | |
| 296 | + | |
| 297 | +static CPUWriteMemoryFunc *timerm_mem_write[3] = { | |
| 298 | + timerm_mem_writel, | |
| 299 | + timerm_mem_writel, | |
| 300 | + timerm_mem_writel, | |
| 301 | +}; | |
| 302 | + | |
| 303 | +void pic_info() {} | |
| 304 | +void irq_info() {} | |
| 305 | + | |
| 306 | +static const unsigned int intr_to_mask[16] = { | |
| 307 | + 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, | |
| 308 | + 0, 0, 0, 0, 0, 0, 0, 0, | |
| 309 | +}; | |
| 310 | + | |
| 311 | +void pic_set_irq(int irq, int level) | |
| 312 | +{ | |
| 313 | + if (irq < 16) { | |
| 314 | + unsigned int mask = intr_to_mask[irq]; | |
| 315 | + ps->intreg_pending |= 1 << irq; | |
| 316 | + if (ps->intregm_enabled & mask) { | |
| 317 | + cpu_single_env->interrupt_index = irq; | |
| 318 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); | |
| 319 | + } | |
| 320 | + } | |
| 321 | +} | |
| 322 | + | |
| 323 | +void sched_init() | |
| 324 | +{ | |
| 325 | + SCHEDState *s; | |
| 326 | + | |
| 327 | + s = qemu_mallocz(sizeof(SCHEDState)); | |
| 328 | + if (!s) | |
| 329 | + return; | |
| 330 | + | |
| 331 | + intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s); | |
| 332 | + cpu_register_physical_memory(PHYS_JJ_INTR0, 3, intreg_io_memory); | |
| 333 | + | |
| 334 | + intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s); | |
| 335 | + cpu_register_physical_memory(PHYS_JJ_INTR_G, 5, intregm_io_memory); | |
| 336 | + | |
| 337 | + timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s); | |
| 338 | + cpu_register_physical_memory(PHYS_JJ_CLOCK, 2, timer_io_memory); | |
| 339 | + | |
| 340 | + timerm_io_memory = cpu_register_io_memory(0, timerm_mem_read, timerm_mem_write, s); | |
| 341 | + cpu_register_physical_memory(PHYS_JJ_CLOCK1, 2, timerm_io_memory); | |
| 342 | + | |
| 343 | + sched_reset(s); | |
| 344 | + ps = s; | |
| 345 | +} | |
| 346 | + | ... | ... |
hw/sun4m.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU Sun4m System Emulator | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include "vl.h" | |
| 25 | +#include "m48t08.h" | |
| 26 | + | |
| 27 | +#define KERNEL_LOAD_ADDR 0x00004000 | |
| 28 | +#define MMU_CONTEXT_TBL 0x00003000 | |
| 29 | +#define MMU_L1PTP (MMU_CONTEXT_TBL + 0x0400) | |
| 30 | +#define MMU_L2PTP (MMU_CONTEXT_TBL + 0x0800) | |
| 31 | +#define ROMVEC_DATA (MMU_CONTEXT_TBL + 0x1800) | |
| 32 | +#define PROM_ADDR 0xffd04000 | |
| 33 | +#define PROM_FILENAME "proll.bin" | |
| 34 | +#define PHYS_JJ_EEPROM 0x71200000 /* [2000] MK48T08 */ | |
| 35 | +#define PHYS_JJ_IDPROM_OFF 0x1FD8 | |
| 36 | +#define PHYS_JJ_EEPROM_SIZE 0x2000 | |
| 37 | + | |
| 38 | +/* TSC handling */ | |
| 39 | + | |
| 40 | +uint64_t cpu_get_tsc() | |
| 41 | +{ | |
| 42 | + return qemu_get_clock(vm_clock); | |
| 43 | +} | |
| 44 | + | |
| 45 | +void DMA_run() {} | |
| 46 | +void SB16_run() {} | |
| 47 | +void vga_invalidate_display() {} | |
| 48 | +void vga_screen_dump(const char *filename) {} | |
| 49 | +int serial_can_receive(SerialState *s) { return 0; } | |
| 50 | +void serial_receive_byte(SerialState *s, int ch) {} | |
| 51 | +void serial_receive_break(SerialState *s) {} | |
| 52 | + | |
| 53 | +static m48t08_t *nvram; | |
| 54 | + | |
| 55 | +/* Sun4m hardware initialisation */ | |
| 56 | +void sun4m_init(int ram_size, int vga_ram_size, int boot_device, | |
| 57 | + DisplayState *ds, const char **fd_filename, int snapshot, | |
| 58 | + const char *kernel_filename, const char *kernel_cmdline, | |
| 59 | + const char *initrd_filename) | |
| 60 | +{ | |
| 61 | + char buf[1024]; | |
| 62 | + int ret, linux_boot, bios_size; | |
| 63 | + unsigned long bios_offset; | |
| 64 | + | |
| 65 | + linux_boot = (kernel_filename != NULL); | |
| 66 | + | |
| 67 | + /* allocate RAM */ | |
| 68 | + cpu_register_physical_memory(0, ram_size, 0); | |
| 69 | + bios_offset = ram_size; | |
| 70 | + | |
| 71 | + iommu_init(); | |
| 72 | + sched_init(); | |
| 73 | + tcx_init(ds); | |
| 74 | + lance_init(&nd_table[0], 6); | |
| 75 | + nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); | |
| 76 | + | |
| 77 | + magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); | |
| 78 | + | |
| 79 | +#if 0 | |
| 80 | + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); | |
| 81 | + bios_size = get_image_size(buf); | |
| 82 | + ret = load_image(buf, phys_ram_base + bios_offset); | |
| 83 | + if (ret != bios_size) { | |
| 84 | + fprintf(stderr, "qemu: could not load prom '%s'\n", buf); | |
| 85 | + exit(1); | |
| 86 | + } | |
| 87 | + cpu_register_physical_memory(PROM_ADDR, | |
| 88 | + bios_size, bios_offset | IO_MEM_ROM); | |
| 89 | +#endif | |
| 90 | + | |
| 91 | + /* We load Proll as the kernel and start it. It will issue a magic | |
| 92 | + IO to load the real kernel */ | |
| 93 | + if (linux_boot) { | |
| 94 | + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); | |
| 95 | + ret = load_kernel(buf, | |
| 96 | + phys_ram_base + KERNEL_LOAD_ADDR); | |
| 97 | + if (ret < 0) { | |
| 98 | + fprintf(stderr, "qemu: could not load kernel '%s'\n", | |
| 99 | + buf); | |
| 100 | + exit(1); | |
| 101 | + } | |
| 102 | + } | |
| 103 | + /* Setup a MMU entry for entire address space */ | |
| 104 | + stl_raw(phys_ram_base + MMU_CONTEXT_TBL, (MMU_L1PTP >> 4) | 1); | |
| 105 | + stl_raw(phys_ram_base + MMU_L1PTP, (MMU_L2PTP >> 4) | 1); | |
| 106 | +#if 0 | |
| 107 | + stl_raw(phys_ram_base + MMU_L1PTP + (0x50 << 2), (MMU_L2PTP >> 4) | 1); // frame buffer at 50.. | |
| 108 | +#endif | |
| 109 | + stl_raw(phys_ram_base + MMU_L1PTP + (0xff << 2), (MMU_L2PTP >> 4) | 1); // ff.. == 00.. | |
| 110 | + /* 3 = U:RWX S:RWX */ | |
| 111 | + stl_raw(phys_ram_base + MMU_L2PTP, (3 << PTE_ACCESS_SHIFT) | 2); | |
| 112 | +#if 0 | |
| 113 | + stl_raw(phys_ram_base + MMU_L2PTP + 0x84, (PHYS_JJ_TCX_FB >> 4) \ | |
| 114 | + | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf | |
| 115 | + stl_raw(phys_ram_base + MMU_L2PTP + 0x88, (PHYS_JJ_TCX_FB >> 4) \ | |
| 116 | + | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf | |
| 117 | + stl_raw(phys_ram_base + MMU_L2PTP + 0x140, (PHYS_JJ_TCX_FB >> 4) \ | |
| 118 | + | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf | |
| 119 | + // "Empirical constant" | |
| 120 | + stl_raw(phys_ram_base + ROMVEC_DATA, 0x10010407); | |
| 121 | + | |
| 122 | + // Version: V3 prom | |
| 123 | + stl_raw(phys_ram_base + ROMVEC_DATA + 4, 3); | |
| 124 | + | |
| 125 | + stl_raw(phys_ram_base + ROMVEC_DATA + 0x1c, ROMVEC_DATA+0x400); | |
| 126 | + stl_raw(phys_ram_base + ROMVEC_DATA + 0x400, ROMVEC_DATA+0x404); | |
| 127 | + stl_raw(phys_ram_base + ROMVEC_DATA + 0x404, 0x81c3e008); // retl | |
| 128 | + stl_raw(phys_ram_base + ROMVEC_DATA + 0x408, 0x01000000); // nop | |
| 129 | +#endif | |
| 130 | +} | ... | ... |
hw/tcx.c
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU Sun4m System Emulator | |
| 3 | + * | |
| 4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include "vl.h" | |
| 25 | + | |
| 26 | +#define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */ | |
| 27 | +#define PHYS_JJ_TCX_0E 0x5E000000 /* Top address, one byte used. */ | |
| 28 | + | |
| 29 | +#define MAXX 1024 | |
| 30 | +#define MAXY 768 | |
| 31 | +#define XSZ (8*80) | |
| 32 | +#define YSZ (24*11) | |
| 33 | +#define XOFF (MAXX-XSZ) | |
| 34 | +#define YOFF (MAXY-YSZ) | |
| 35 | + | |
| 36 | +#define DEBUG_VGA_MEM | |
| 37 | + | |
| 38 | +typedef struct TCXState { | |
| 39 | + uint8_t *vram_ptr; | |
| 40 | + unsigned long vram_offset; | |
| 41 | + unsigned int vram_size; | |
| 42 | + DisplayState *ds; | |
| 43 | +} TCXState; | |
| 44 | + | |
| 45 | +static TCXState *ts; | |
| 46 | + | |
| 47 | +static int tcx_io_memory; | |
| 48 | + | |
| 49 | +void vga_update_display() | |
| 50 | +{ | |
| 51 | + dpy_update(ts->ds, 0, 0, XSZ, YSZ); | |
| 52 | +} | |
| 53 | + | |
| 54 | +static uint32_t tcx_mem_readb(void *opaque, target_phys_addr_t addr) | |
| 55 | +{ | |
| 56 | + TCXState *s = opaque; | |
| 57 | + uint32_t saddr; | |
| 58 | + unsigned int x, y; | |
| 59 | + char *sptr; | |
| 60 | + | |
| 61 | + saddr = addr - PHYS_JJ_TCX_FB - YOFF*MAXX - XOFF; | |
| 62 | + y = saddr / MAXX; | |
| 63 | + x = saddr - y * MAXX; | |
| 64 | + if (x < MAXX && y < MAXY) { | |
| 65 | + sptr = s->ds->data; | |
| 66 | + if (sptr) | |
| 67 | + return sptr[y * s->ds->linesize + x*4]; | |
| 68 | + } | |
| 69 | + return 0; | |
| 70 | +} | |
| 71 | + | |
| 72 | +static uint32_t tcx_mem_readw(void *opaque, target_phys_addr_t addr) | |
| 73 | +{ | |
| 74 | + uint32_t v; | |
| 75 | +#ifdef TARGET_WORDS_BIGENDIAN | |
| 76 | + v = tcx_mem_readb(opaque, addr) << 8; | |
| 77 | + v |= tcx_mem_readb(opaque, addr + 1); | |
| 78 | +#else | |
| 79 | + v = tcx_mem_readb(opaque, addr); | |
| 80 | + v |= tcx_mem_readb(opaque, addr + 1) << 8; | |
| 81 | +#endif | |
| 82 | + return v; | |
| 83 | +} | |
| 84 | + | |
| 85 | +static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr) | |
| 86 | +{ | |
| 87 | + uint32_t v; | |
| 88 | +#ifdef TARGET_WORDS_BIGENDIAN | |
| 89 | + v = tcx_mem_readb(opaque, addr) << 24; | |
| 90 | + v |= tcx_mem_readb(opaque, addr + 1) << 16; | |
| 91 | + v |= tcx_mem_readb(opaque, addr + 2) << 8; | |
| 92 | + v |= tcx_mem_readb(opaque, addr + 3); | |
| 93 | +#else | |
| 94 | + v = tcx_mem_readb(opaque, addr); | |
| 95 | + v |= tcx_mem_readb(opaque, addr + 1) << 8; | |
| 96 | + v |= tcx_mem_readb(opaque, addr + 2) << 16; | |
| 97 | + v |= tcx_mem_readb(opaque, addr + 3) << 24; | |
| 98 | +#endif | |
| 99 | + return v; | |
| 100 | +} | |
| 101 | + | |
| 102 | +/* called for accesses between 0xa0000 and 0xc0000 */ | |
| 103 | +static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 104 | +{ | |
| 105 | + TCXState *s = opaque; | |
| 106 | + uint32_t saddr; | |
| 107 | + unsigned int x, y; | |
| 108 | + char *sptr; | |
| 109 | + | |
| 110 | + saddr = addr - PHYS_JJ_TCX_FB - YOFF*MAXX - XOFF; | |
| 111 | + y = saddr / MAXX; | |
| 112 | + x = saddr - y * MAXX; | |
| 113 | + if (x < MAXX && y < MAXY) { | |
| 114 | + sptr = s->ds->data; | |
| 115 | + if (sptr) { | |
| 116 | + sptr[y * s->ds->linesize + x*4] = val; | |
| 117 | + sptr[y * s->ds->linesize + x*4+1] = val; | |
| 118 | + sptr[y * s->ds->linesize + x*4+2] = val; | |
| 119 | + cpu_physical_memory_set_dirty(addr); | |
| 120 | + } | |
| 121 | + } | |
| 122 | +} | |
| 123 | + | |
| 124 | +static void tcx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 125 | +{ | |
| 126 | +#ifdef TARGET_WORDS_BIGENDIAN | |
| 127 | + tcx_mem_writeb(opaque, addr, (val >> 8) & 0xff); | |
| 128 | + tcx_mem_writeb(opaque, addr + 1, val & 0xff); | |
| 129 | +#else | |
| 130 | + tcx_mem_writeb(opaque, addr, val & 0xff); | |
| 131 | + tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); | |
| 132 | +#endif | |
| 133 | +} | |
| 134 | + | |
| 135 | +static void tcx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 136 | +{ | |
| 137 | +#ifdef TARGET_WORDS_BIGENDIAN | |
| 138 | + tcx_mem_writeb(opaque, addr, (val >> 24) & 0xff); | |
| 139 | + tcx_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff); | |
| 140 | + tcx_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff); | |
| 141 | + tcx_mem_writeb(opaque, addr + 3, val & 0xff); | |
| 142 | +#else | |
| 143 | + tcx_mem_writeb(opaque, addr, val & 0xff); | |
| 144 | + tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); | |
| 145 | + tcx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); | |
| 146 | + tcx_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); | |
| 147 | +#endif | |
| 148 | +} | |
| 149 | + | |
| 150 | +static CPUReadMemoryFunc *tcx_mem_read[3] = { | |
| 151 | + tcx_mem_readb, | |
| 152 | + tcx_mem_readw, | |
| 153 | + tcx_mem_readl, | |
| 154 | +}; | |
| 155 | + | |
| 156 | +static CPUWriteMemoryFunc *tcx_mem_write[3] = { | |
| 157 | + tcx_mem_writeb, | |
| 158 | + tcx_mem_writew, | |
| 159 | + tcx_mem_writel, | |
| 160 | +}; | |
| 161 | + | |
| 162 | +void tcx_init(DisplayState *ds) | |
| 163 | +{ | |
| 164 | + TCXState *s; | |
| 165 | + | |
| 166 | + s = qemu_mallocz(sizeof(TCXState)); | |
| 167 | + if (!s) | |
| 168 | + return; | |
| 169 | + s->ds = ds; | |
| 170 | + ts = s; | |
| 171 | + tcx_io_memory = cpu_register_io_memory(0, tcx_mem_read, tcx_mem_write, s); | |
| 172 | + cpu_register_physical_memory(PHYS_JJ_TCX_FB, 0x100000, | |
| 173 | + tcx_io_memory); | |
| 174 | + dpy_resize(s->ds, XSZ, YSZ); | |
| 175 | +} | |
| 176 | + | ... | ... |