1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * X86 simulator sparse memory File: X86MEM.C
6 * This module implements X86 memory for the X86 emulator
7 * used by the BIOS simulator. To avoid allocating the
8 * entire 1MB of PC's addressable memory, this is a "sparse"
9 * memory model, allocating chunks of storage as needed.
10 * VGA BIOSes seem to do all sorts of bizarre things to memory
11 * so this helps reduce the total amount we need to allocate
14 * In addition, this module lets the simulator "hook"
15 * ranges of memory to be handled by a callback
16 * routine. This is used so that we can redirect
17 * accesses to VGA memory space to the PCI bus handler.
19 * Author: Mitch Lichtenberg (mpl@broadcom.com)
21 *********************************************************************
23 * Copyright 2000,2001,2002,2003
24 * Broadcom Corporation. All rights reserved.
26 * This software is furnished under license and may be used and
27 * copied only in accordance with the following terms and
28 * conditions. Subject to these conditions, you may download,
29 * copy, install, use, modify and distribute modified or unmodified
30 * copies of this software in source and/or binary form. No title
31 * or ownership is transferred hereby.
33 * 1) Any source code used, modified or distributed must reproduce
34 * and retain this copyright notice and list of conditions
35 * as they appear in the source file.
37 * 2) No right is granted to use any trade name, trademark, or
38 * logo of Broadcom Corporation. The "Broadcom Corporation"
39 * name may not be used to endorse or promote products derived
40 * from this software without the prior written permission of
41 * Broadcom Corporation.
43 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
44 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
45 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
46 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
47 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
48 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
50 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
51 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
52 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
53 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
54 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
55 * THE POSSIBILITY OF SUCH DAMAGE.
56 ********************************************************************* */
59 #include "lib_types.h"
60 #include "lib_string.h"
61 #include "lib_malloc.h"
62 #include "lib_printf.h"
65 /* *********************************************************************
67 ********************************************************************* */
69 #define BSWAP_SHORT(s) ((((s) >> 8) & 0xFF) | (((s)&0xFF) << 8))
70 #define BSWAP_LONG(s) ((((s) & 0xFF000000) >> 24) | \
71 (((s) & 0x00FF0000) >> 8) | \
72 (((s) & 0x0000FF00) << 8) | \
73 (((s) & 0x000000FF) << 24))
76 /* *********************************************************************
79 * Initialize an X86mem object
86 ********************************************************************* */
88 void x86mem_init(x86mem_t
*mem
)
90 memset(mem
,0,sizeof(mem
));
93 /* *********************************************************************
96 * Uninitialize an X86mem object, freeing any storage
100 * mem - x86mem object
104 ********************************************************************* */
106 void x86mem_uninit(x86mem_t
*mem
)
110 for (idx
= 0; idx
< X86MEM_CHUNKS
; idx
++) {
111 if (mem
->data
[idx
]) {
112 KFREE(mem
->data
[idx
]);
113 mem
->data
[idx
] = NULL
;
118 /* *********************************************************************
119 * X86MEM_READB(mem,addr)
121 * Read a byte of memory from the X86mem object.
124 * mem - x86mem object
125 * addr - address of byte to read
129 ********************************************************************* */
131 uint8_t x86mem_readb(x86mem_t
*mem
,uint32_t addr
)
135 if (mem
->read
[X86MEM_REGION(addr
)]) {
136 return (uint8_t) (*(mem
->read
[X86MEM_REGION(addr
)]))(mem
,addr
,1);
139 p
= (mem
->data
[X86MEM_REGION(addr
)]);
142 return *(p
+ X86MEM_OFFSET(addr
));
149 /* *********************************************************************
150 * X86MEM_READW(mem,addr)
152 * Read a 16-bit word of memory from the X86mem object.
155 * mem - x86mem object
156 * addr - address of word to read
160 ********************************************************************* */
162 uint16_t x86mem_readw(x86mem_t
*mem
,uint32_t addr
)
167 if (mem
->read
[X86MEM_REGION(addr
)]) {
168 return (uint8_t) (*(mem
->read
[X86MEM_REGION(addr
)]))(mem
,addr
,2);
171 p
= (mem
->data
[X86MEM_REGION(addr
)]);
174 if ((addr
& 1) || (X86MEM_OFFSET(addr
) == X86MEM_CHUNKSIZE
-1)) {
176 ret
= ((uint16_t) x86mem_readb(mem
,addr
+0)) |
177 (((uint16_t) x86mem_readb(mem
,addr
+1)) << 8);
181 ret
= *((uint16_t *) (p
+X86MEM_OFFSET(addr
)));
183 ret
= BSWAP_SHORT(ret
);
190 /* *********************************************************************
191 * X86MEM_READL(mem,addr)
193 * Read a 32-bit dword of memory from the X86mem object.
196 * mem - x86mem object
197 * addr - address of dword to read
201 ********************************************************************* */
203 uint32_t x86mem_readl(x86mem_t
*mem
,uint32_t addr
)
208 if (mem
->read
[X86MEM_REGION(addr
)]) {
209 return (uint8_t) (*(mem
->read
[X86MEM_REGION(addr
)]))(mem
,addr
,4);
212 p
= (mem
->data
[X86MEM_REGION(addr
)]);
215 if ((addr
& 3) || (X86MEM_OFFSET(addr
) >= X86MEM_CHUNKSIZE
-3)) {
216 ret
= ((uint32_t) x86mem_readb(mem
,addr
+0)) |
217 (((uint32_t) x86mem_readb(mem
,addr
+1)) << 8) |
218 (((uint32_t) x86mem_readb(mem
,addr
+2)) << 16) |
219 (((uint32_t) x86mem_readb(mem
,addr
+3)) << 24);
222 ret
= *((uint32_t *) (p
+X86MEM_OFFSET(addr
)));
224 ret
= BSWAP_LONG(ret
);
231 /* *********************************************************************
232 * X86MEM_WRITEB(mem,addr,data)
234 * Write a byte to the X86mem object
237 * mem - x86mem object
238 * addr - address of byte to write
239 * data - data to write
243 ********************************************************************* */
244 void x86mem_writeb(x86mem_t
*mem
,uint32_t addr
,uint8_t data
)
248 if (mem
->write
[X86MEM_REGION(addr
)]) {
249 (*(mem
->write
[X86MEM_REGION(addr
)]))(mem
,addr
,data
,1);
253 p
= (mem
->data
[X86MEM_REGION(addr
)]);
256 *(p
+ X86MEM_OFFSET(addr
)) = data
;
259 p
= mem
->data
[X86MEM_REGION(addr
)] = KMALLOC(X86MEM_CHUNKSIZE
,sizeof(uint32_t));
261 memset(p
,0,X86MEM_CHUNKSIZE
);
262 *(p
+ X86MEM_OFFSET(addr
)) = data
;
267 /* *********************************************************************
268 * X86MEM_WRITEW(mem,addr,data)
270 * Write a 16-bit word to the X86mem object
273 * mem - x86mem object
274 * addr - address of word to write
275 * data - data to write
279 ********************************************************************* */
280 void x86mem_writew(x86mem_t
*mem
,uint32_t addr
,uint16_t data
)
284 if (mem
->write
[X86MEM_REGION(addr
)]) {
285 (*(mem
->write
[X86MEM_REGION(addr
)]))(mem
,addr
,data
,2);
289 p
= (mem
->data
[X86MEM_REGION(addr
)]);
291 if (!p
|| (addr
& 1) || (X86MEM_OFFSET(addr
) == X86MEM_CHUNKSIZE
-1)) {
292 x86mem_writeb(mem
,addr
+0,(data
& 0xFF));
293 x86mem_writeb(mem
,addr
+1,((data
>> 8) & 0xFF));
297 data
= BSWAP_SHORT(data
);
299 *((uint16_t *) (p
+X86MEM_OFFSET(addr
))) = data
;
303 /* *********************************************************************
304 * X86MEM_WRITEL(mem,addr,data)
306 * Write a 32-bit dword to the X86mem object
309 * mem - x86mem object
310 * addr - address of dword to write
311 * data - data to write
315 ********************************************************************* */
316 void x86mem_writel(x86mem_t
*mem
,uint32_t addr
,uint32_t data
)
320 if (mem
->write
[X86MEM_REGION(addr
)]) {
321 (*(mem
->write
[X86MEM_REGION(addr
)]))(mem
,addr
,data
,4);
325 p
= (mem
->data
[X86MEM_REGION(addr
)]);
327 if (!p
|| (addr
& 3) || (X86MEM_OFFSET(addr
) >= X86MEM_CHUNKSIZE
-3)) {
328 x86mem_writeb(mem
,addr
+0,(data
& 0xFF));
329 x86mem_writeb(mem
,addr
+1,((data
>> 8) & 0xFF));
330 x86mem_writeb(mem
,addr
+2,((data
>> 16) & 0xFF));
331 x86mem_writeb(mem
,addr
+3,((data
>> 24) & 0xFF));
335 data
= BSWAP_LONG(data
);
337 *((uint32_t *) (p
+X86MEM_OFFSET(addr
))) = data
;
341 /* *********************************************************************
342 * X86MEM_MEMCPY(mem,dest,src,cnt)
344 * memcpy data into the X86mem object
347 * mem - x86mem object
348 * destaddr - destination x86mem address
349 * src - source local address
350 * cnt - number of bytes to copy
354 ********************************************************************* */
356 void x86mem_memcpy(x86mem_t
*mem
,uint32_t destaddr
,uint8_t *src
,int count
)
359 x86mem_writeb(mem
,destaddr
,*src
);
367 /* *********************************************************************
368 * X86MEM_HOOK(mem,addr,readf,writef)
370 * Establish a hook for a block of simulated memory
373 * mem - x86mem object
374 * addr - address in memory, should be aligned on a "chunk"
376 * readf - function to call on READ accesses
377 * writef - function to call on WRITE accesses
381 ********************************************************************* */
383 void x86mem_hook(x86mem_t
*mem
,uint32_t chunkaddr
,
384 uint32_t (*readf
)(x86mem_t
*mem
,uint32_t addr
,int size
),
385 void (*writef
)(x86mem_t
*mem
,uint32_t addr
,uint32_t val
,int size
))
387 if (mem
->data
[X86MEM_REGION(chunkaddr
)]) {
388 KFREE(mem
->data
[X86MEM_REGION(chunkaddr
)]);
389 mem
->data
[X86MEM_REGION(chunkaddr
)] = NULL
;
391 mem
->read
[X86MEM_REGION(chunkaddr
)] = readf
;
392 mem
->write
[X86MEM_REGION(chunkaddr
)] = writef
;
395 /* *********************************************************************
396 * X86MEM_HOOK_RANGE(mem,addr,size,readf,writef)
398 * Establish a hook for a block of simulated memory
401 * mem - x86mem object
402 * addr - address in memory, should be aligned on a "chunk"
404 * size - size of region to hook. Should be a multiple
406 * readf - function to call on READ accesses
407 * writef - function to call on WRITE accesses
411 ********************************************************************* */
413 void x86mem_hook_range(x86mem_t
*mem
,uint32_t chunkaddr
,int size
,
414 uint32_t (*readf
)(x86mem_t
*mem
,uint32_t addr
,int size
),
415 void (*writef
)(x86mem_t
*mem
,uint32_t addr
,uint32_t val
,int size
))
418 x86mem_hook(mem
,chunkaddr
,readf
,writef
);
419 size
-= X86MEM_CHUNKSIZE
;
420 chunkaddr
+= X86MEM_CHUNKSIZE
;