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