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 | + |