Revision 420557e8
b/hw/iommu.c | ||
---|---|---|
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 |
|
b/hw/lance.c | ||
---|---|---|
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 |
|
b/hw/m48t08.c | ||
---|---|---|
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 |
b/hw/m48t08.h | ||
---|---|---|
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__) */ |
b/hw/magic-load.c | ||
---|---|---|
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 |
|
b/hw/sched.c | ||
---|---|---|
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 |
Also available in: Unified diff