1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * X86 simulator sparse memory File: X86MEM.C 5 * 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 12 * significantly. 13 * 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. 18 * 19 * Author: Mitch Lichtenberg (mpl@broadcom.com) 20 * 21 ********************************************************************* 22 * 23 * Copyright 2000,2001,2002,2003 24 * Broadcom Corporation. All rights reserved. 25 * 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. 32 * 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. 36 * 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. 42 * 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 ********************************************************************* */ 57 58 59#include "lib_types.h" 60#include "lib_string.h" 61#include "lib_malloc.h" 62#include "lib_printf.h" 63#include "x86mem.h" 64 65/* ********************************************************************* 66 * Macros 67 ********************************************************************* */ 68 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)) 74 75 76/* ********************************************************************* 77 * X86MEM_INIT() 78 * 79 * Initialize an X86mem object 80 * 81 * Input parameters: 82 * mem - X86mem object 83 * 84 * Return value: 85 * nothing 86 ********************************************************************* */ 87 88void x86mem_init(x86mem_t *mem) 89{ 90 memset(mem,0,sizeof(mem)); 91} 92 93/* ********************************************************************* 94 * X86MEM_UNINIT(mem) 95 * 96 * Uninitialize an X86mem object, freeing any storage 97 * associated with it. 98 * 99 * Input parameters: 100 * mem - x86mem object 101 * 102 * Return value: 103 * nothing 104 ********************************************************************* */ 105 106void x86mem_uninit(x86mem_t *mem) 107{ 108 int idx; 109 110 for (idx = 0; idx < X86MEM_CHUNKS; idx++) { 111 if (mem->data[idx]) { 112 KFREE(mem->data[idx]); 113 mem->data[idx] = NULL; 114 } 115 } 116} 117 118/* ********************************************************************* 119 * X86MEM_READB(mem,addr) 120 * 121 * Read a byte of memory from the X86mem object. 122 * 123 * Input parameters: 124 * mem - x86mem object 125 * addr - address of byte to read 126 * 127 * Return value: 128 * byte read 129 ********************************************************************* */ 130 131uint8_t x86mem_readb(x86mem_t *mem,uint32_t addr) 132{ 133 uint8_t *p; 134 135 if (mem->read[X86MEM_REGION(addr)]) { 136 return (uint8_t) (*(mem->read[X86MEM_REGION(addr)]))(mem,addr,1); 137 } 138 139 p = (mem->data[X86MEM_REGION(addr)]); 140 141 if (p) { 142 return *(p + X86MEM_OFFSET(addr)); 143 } 144 else { 145 return 0; 146 } 147} 148 149/* ********************************************************************* 150 * X86MEM_READW(mem,addr) 151 * 152 * Read a 16-bit word of memory from the X86mem object. 153 * 154 * Input parameters: 155 * mem - x86mem object 156 * addr - address of word to read 157 * 158 * Return value: 159 * word read 160 ********************************************************************* */ 161 162uint16_t x86mem_readw(x86mem_t *mem,uint32_t addr) 163{ 164 uint8_t *p; 165 uint16_t ret; 166 167 if (mem->read[X86MEM_REGION(addr)]) { 168 return (uint8_t) (*(mem->read[X86MEM_REGION(addr)]))(mem,addr,2); 169 } 170 171 p = (mem->data[X86MEM_REGION(addr)]); 172 if (!p) return 0; 173 174 if ((addr & 1) || (X86MEM_OFFSET(addr) == X86MEM_CHUNKSIZE-1)) { 175 176 ret = ((uint16_t) x86mem_readb(mem,addr+0)) | 177 (((uint16_t) x86mem_readb(mem,addr+1)) << 8); 178 return ret; 179 } 180 else { 181 ret = *((uint16_t *) (p+X86MEM_OFFSET(addr))); 182#ifdef __MIPSEB 183 ret = BSWAP_SHORT(ret); 184#endif 185 } 186 187 return ret; 188} 189 190/* ********************************************************************* 191 * X86MEM_READL(mem,addr) 192 * 193 * Read a 32-bit dword of memory from the X86mem object. 194 * 195 * Input parameters: 196 * mem - x86mem object 197 * addr - address of dword to read 198 * 199 * Return value: 200 * dword read 201 ********************************************************************* */ 202 203uint32_t x86mem_readl(x86mem_t *mem,uint32_t addr) 204{ 205 uint8_t *p; 206 uint32_t ret; 207 208 if (mem->read[X86MEM_REGION(addr)]) { 209 return (uint8_t) (*(mem->read[X86MEM_REGION(addr)]))(mem,addr,4); 210 } 211 212 p = (mem->data[X86MEM_REGION(addr)]); 213 if (!p) return 0; 214 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); 220 } 221 else { 222 ret = *((uint32_t *) (p+X86MEM_OFFSET(addr))); 223#ifdef __MIPSEB 224 ret = BSWAP_LONG(ret); 225#endif 226 } 227 228 return ret; 229} 230 231/* ********************************************************************* 232 * X86MEM_WRITEB(mem,addr,data) 233 * 234 * Write a byte to the X86mem object 235 * 236 * Input parameters: 237 * mem - x86mem object 238 * addr - address of byte to write 239 * data - data to write 240 * 241 * Return value: 242 * nothing 243 ********************************************************************* */ 244void x86mem_writeb(x86mem_t *mem,uint32_t addr,uint8_t data) 245{ 246 uint8_t *p; 247 248 if (mem->write[X86MEM_REGION(addr)]) { 249 (*(mem->write[X86MEM_REGION(addr)]))(mem,addr,data,1); 250 return; 251 } 252 253 p = (mem->data[X86MEM_REGION(addr)]); 254 255 if (p) { 256 *(p + X86MEM_OFFSET(addr)) = data; 257 } 258 else { 259 p = mem->data[X86MEM_REGION(addr)] = KMALLOC(X86MEM_CHUNKSIZE,sizeof(uint32_t)); 260 if (p) { 261 memset(p,0,X86MEM_CHUNKSIZE); 262 *(p + X86MEM_OFFSET(addr)) = data; 263 } 264 } 265} 266 267/* ********************************************************************* 268 * X86MEM_WRITEW(mem,addr,data) 269 * 270 * Write a 16-bit word to the X86mem object 271 * 272 * Input parameters: 273 * mem - x86mem object 274 * addr - address of word to write 275 * data - data to write 276 * 277 * Return value: 278 * nothing 279 ********************************************************************* */ 280void x86mem_writew(x86mem_t *mem,uint32_t addr,uint16_t data) 281{ 282 uint8_t *p; 283 284 if (mem->write[X86MEM_REGION(addr)]) { 285 (*(mem->write[X86MEM_REGION(addr)]))(mem,addr,data,2); 286 return; 287 } 288 289 p = (mem->data[X86MEM_REGION(addr)]); 290 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)); 294 } 295 else { 296#ifdef __MIPSEB 297 data = BSWAP_SHORT(data); 298#endif 299 *((uint16_t *) (p+X86MEM_OFFSET(addr))) = data; 300 } 301} 302 303/* ********************************************************************* 304 * X86MEM_WRITEL(mem,addr,data) 305 * 306 * Write a 32-bit dword to the X86mem object 307 * 308 * Input parameters: 309 * mem - x86mem object 310 * addr - address of dword to write 311 * data - data to write 312 * 313 * Return value: 314 * nothing 315 ********************************************************************* */ 316void x86mem_writel(x86mem_t *mem,uint32_t addr,uint32_t data) 317{ 318 uint8_t *p; 319 320 if (mem->write[X86MEM_REGION(addr)]) { 321 (*(mem->write[X86MEM_REGION(addr)]))(mem,addr,data,4); 322 return; 323 } 324 325 p = (mem->data[X86MEM_REGION(addr)]); 326 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)); 332 } 333 else { 334#ifdef __MIPSEB 335 data = BSWAP_LONG(data); 336#endif 337 *((uint32_t *) (p+X86MEM_OFFSET(addr))) = data; 338 } 339} 340 341/* ********************************************************************* 342 * X86MEM_MEMCPY(mem,dest,src,cnt) 343 * 344 * memcpy data into the X86mem object 345 * 346 * Input parameters: 347 * mem - x86mem object 348 * destaddr - destination x86mem address 349 * src - source local address 350 * cnt - number of bytes to copy 351 * 352 * Return value: 353 * nothing 354 ********************************************************************* */ 355 356void x86mem_memcpy(x86mem_t *mem,uint32_t destaddr,uint8_t *src,int count) 357{ 358 while (count) { 359 x86mem_writeb(mem,destaddr,*src); 360 destaddr++; 361 src++; 362 count--; 363 } 364} 365 366 367/* ********************************************************************* 368 * X86MEM_HOOK(mem,addr,readf,writef) 369 * 370 * Establish a hook for a block of simulated memory 371 * 372 * Input parameters: 373 * mem - x86mem object 374 * addr - address in memory, should be aligned on a "chunk" 375 * boundary. 376 * readf - function to call on READ accesses 377 * writef - function to call on WRITE accesses 378 * 379 * Return value: 380 * nothing 381 ********************************************************************* */ 382 383void 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)) 386{ 387 if (mem->data[X86MEM_REGION(chunkaddr)]) { 388 KFREE(mem->data[X86MEM_REGION(chunkaddr)]); 389 mem->data[X86MEM_REGION(chunkaddr)] = NULL; 390 } 391 mem->read[X86MEM_REGION(chunkaddr)] = readf; 392 mem->write[X86MEM_REGION(chunkaddr)] = writef; 393} 394 395/* ********************************************************************* 396 * X86MEM_HOOK_RANGE(mem,addr,size,readf,writef) 397 * 398 * Establish a hook for a block of simulated memory 399 * 400 * Input parameters: 401 * mem - x86mem object 402 * addr - address in memory, should be aligned on a "chunk" 403 * boundary. 404 * size - size of region to hook. Should be a multiple 405 * of the chunk size 406 * readf - function to call on READ accesses 407 * writef - function to call on WRITE accesses 408 * 409 * Return value: 410 * nothing 411 ********************************************************************* */ 412 413void 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)) 416{ 417 while (size > 0) { 418 x86mem_hook(mem,chunkaddr,readf,writef); 419 size -= X86MEM_CHUNKSIZE; 420 chunkaddr += X86MEM_CHUNKSIZE; 421 } 422} 423 424