1 1.1 christos /* This file is part of the program psim. 2 1.1 christos 3 1.1 christos Copyright 1994, 1995, 1996, 2003, 2004 Andrew Cagney 4 1.1 christos 5 1.1 christos This program is free software; you can redistribute it and/or modify 6 1.1 christos it under the terms of the GNU General Public License as published by 7 1.1.1.2 christos the Free Software Foundation; either version 3 of the License, or 8 1.1 christos (at your option) any later version. 9 1.1 christos 10 1.1 christos This program is distributed in the hope that it will be useful, 11 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 12 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 1.1 christos GNU General Public License for more details. 14 1.1 christos 15 1.1 christos You should have received a copy of the GNU General Public License 16 1.1.1.2 christos along with this program; if not, see <http://www.gnu.org/licenses/>. 17 1.1 christos 18 1.1 christos */ 19 1.1 christos 20 1.1 christos 21 1.1 christos #ifndef _HW_HTAB_C_ 22 1.1 christos #define _HW_HTAB_C_ 23 1.1 christos 24 1.1 christos #include "device_table.h" 25 1.1.1.3 christos #include "device.h" 26 1.1 christos 27 1.1 christos #include "bfd.h" 28 1.1 christos 29 1.1 christos 30 1.1 christos /* DEVICE 31 1.1 christos 32 1.1 christos 33 1.1 christos htab - pseudo-device describing a PowerPC hash table 34 1.1 christos 35 1.1 christos 36 1.1 christos DESCRIPTION 37 1.1 christos 38 1.1 christos 39 1.1 christos During the initialization of the device tree, the pseudo-device 40 1.1 christos <<htab>>, in conjunction with any child <<pte>> pseudo-devices, 41 1.1 christos will create a PowerPC hash table in memory. The hash table values 42 1.1 christos are written using dma transfers. 43 1.1 christos 44 1.1 christos The size and address of the hash table are determined by properties 45 1.1 christos of the htab node. 46 1.1 christos 47 1.1 christos By convention, the htab device is made a child of the 48 1.1 christos <</openprom/init>> node. 49 1.1 christos 50 1.1 christos By convention, the real address of the htab is used as the htab 51 1.1 christos nodes unit address. 52 1.1 christos 53 1.1 christos 54 1.1 christos PROPERTIES 55 1.1 christos 56 1.1 christos 57 1.1 christos real-address = <address> (required) 58 1.1 christos 59 1.1 christos The physical address of the hash table. The PowerPC architecture 60 1.1 christos places limitations on what is a valid hash table real-address. 61 1.1 christos 62 1.1 christos 63 1.1 christos nr-bytes = <size> (required) 64 1.1 christos 65 1.1 christos The size of the hash table (in bytes) that is to be created at 66 1.1 christos <<real-address>>. The PowerPC architecture places limitations on 67 1.1 christos what is a valid hash table size. 68 1.1 christos 69 1.1 christos 70 1.1 christos claim = <anything> (optional) 71 1.1 christos 72 1.1 christos If this property is present, the memory used to construct the hash 73 1.1 christos table will be claimed from the memory device. The memory device 74 1.1 christos being specified by the <</chosen/memory>> ihandle property. 75 1.1 christos 76 1.1 christos 77 1.1 christos EXAMPLES 78 1.1 christos 79 1.1 christos Enable tracing. 80 1.1 christos 81 1.1 christos | $ psim -t htab-device \ 82 1.1 christos 83 1.1 christos 84 1.1 christos Create a htab specifying the base address and minimum size. 85 1.1 christos 86 1.1 christos | -o '/openprom/init/htab@0x10000/real-address 0x10000' \ 87 1.1 christos | -o '/openprom/init/htab@0x10000/claim 0' \ 88 1.1 christos | -o '/openprom/init/htab@0x10000/nr-bytes 65536' \ 89 1.1 christos 90 1.1 christos 91 1.1 christos BUGS 92 1.1 christos 93 1.1 christos 94 1.1 christos See the <<pte>> device. 95 1.1 christos 96 1.1 christos 97 1.1 christos */ 98 1.1 christos 99 1.1 christos 100 1.1 christos /* DEVICE 101 1.1 christos 102 1.1 christos 103 1.1 christos pte - pseudo-device describing a htab entry 104 1.1 christos 105 1.1 christos 106 1.1 christos DESCRIPTION 107 1.1 christos 108 1.1 christos 109 1.1 christos The <<pte>> pseudo-device, which must be a child of a <<htabl>> 110 1.1 christos node, describes a virtual to physical mapping that is to be entered 111 1.1 christos into the parents hash table. 112 1.1 christos 113 1.1 christos Two alternative specifications of the mapping are allowed. Either 114 1.1 christos a section of physical memory can be mapped to a virtual address, or 115 1.1 christos the header of an executible image can be used to define the 116 1.1 christos mapping. 117 1.1 christos 118 1.1 christos By convention, the real address of the map is specified as the pte 119 1.1 christos devices unit address. 120 1.1 christos 121 1.1 christos 122 1.1 christos PROPERTIES 123 1.1 christos 124 1.1 christos 125 1.1 christos real-address = <address> (required) 126 1.1 christos 127 1.1 christos The starting physical address that is to be mapped by the hash 128 1.1 christos table. 129 1.1 christos 130 1.1 christos 131 1.1 christos wimg = <int> (required) 132 1.1 christos pp = <int> (required) 133 1.1 christos 134 1.1 christos The value of hash table protection bits that are to be used when 135 1.1 christos creating the virtual to physical address map. 136 1.1 christos 137 1.1 christos 138 1.1 christos claim = <anything> (optional) 139 1.1 christos 140 1.1 christos If this property is present, the real memory that is being mapped by the 141 1.1 christos hash table will be claimed from the memory node (specified by the 142 1.1 christos ihandle <</chosen/memory>>). 143 1.1 christos 144 1.1 christos 145 1.1 christos virtual-address = <integer> [ <integer> ] (option A) 146 1.1 christos nr-bytes = <size> (option A) 147 1.1 christos 148 1.1 christos Option A - Virtual virtual address (and size) at which the physical 149 1.1 christos address is to be mapped. If multiple values are specified for the 150 1.1 christos virtual address then they are concatenated to gether to form a 151 1.1 christos longer virtual address. 152 1.1 christos 153 1.1 christos 154 1.1 christos file-name = <string> (option B) 155 1.1 christos 156 1.1 christos Option B - An executable image that is to be loaded (starting at 157 1.1 christos the physical address specified above) and then mapped in using 158 1.1 christos informatioin taken from the executables header. information found 159 1.1 christos in the files header. 160 1.1 christos 161 1.1 christos 162 1.1 christos EXAMPLES 163 1.1 christos 164 1.1 christos 165 1.1 christos Enable tracing (note that both the <<htab>> and <<pte>> device use the 166 1.1 christos same trace option). 167 1.1 christos 168 1.1 christos | -t htab-device \ 169 1.1 christos 170 1.1 christos 171 1.1 christos Map a block of physical memory into a specified virtual address: 172 1.1 christos 173 1.1 christos | -o '/openprom/init/htab/pte@0x0/real-address 0' \ 174 1.1 christos | -o '/openprom/init/htab/pte@0x0/nr-bytes 4096' \ 175 1.1 christos | -o '/openprom/init/htab/pte@0x0/virtual-address 0x1000000' \ 176 1.1 christos | -o '/openprom/init/htab/pte@0x0/claim 0' \ 177 1.1 christos | -o '/openprom/init/htab/pte@0x0/wimg 0x7' \ 178 1.1 christos | -o '/openprom/init/htab/pte@0x0/pp 0x2' \ 179 1.1 christos 180 1.1 christos 181 1.1 christos Map a file into memory. 182 1.1 christos 183 1.1 christos | -o '/openprom/init/htab/pte@0x10000/real-address 0x10000' \ 184 1.1 christos | -o '/openprom/init/htab/pte@0x10000/file-name "netbsd.elf' \ 185 1.1 christos | -o '/openprom/init/htab/pte@0x10000/wimg 0x7' \ 186 1.1 christos | -o '/openprom/init/htab/pte@0x10000/pp 0x2' \ 187 1.1 christos 188 1.1 christos 189 1.1 christos BUGS 190 1.1 christos 191 1.1 christos 192 1.1 christos For an ELF executable, the header defines both the virtual and real 193 1.1 christos address at which each file section should be loaded. At present, the 194 1.1 christos real addresses that are specified in the header are ignored, the file 195 1.1 christos instead being loaded in to physical memory in a linear fashion. 196 1.1 christos 197 1.1 christos When claiming memory, this device assumes that the #address-cells 198 1.1 christos and #size-cells is one. For future implementations, this may not 199 1.1 christos be the case. 200 1.1 christos 201 1.1 christos */ 202 1.1 christos 203 1.1 christos 204 1.1 christos 205 1.1 christos static void 206 1.1 christos htab_decode_hash_table(device *me, 207 1.1.1.6 christos uint32_t *htaborg, 208 1.1.1.6 christos uint32_t *htabmask) 209 1.1 christos { 210 1.1 christos unsigned_word htab_ra; 211 1.1 christos unsigned htab_nr_bytes; 212 1.1 christos unsigned n; 213 1.1 christos device *parent = device_parent(me); 214 1.1 christos /* determine the location/size of the hash table */ 215 1.1 christos if (parent == NULL 216 1.1 christos || strcmp(device_name(parent), "htab") != 0) 217 1.1 christos device_error(parent, "must be a htab device"); 218 1.1 christos htab_ra = device_find_integer_property(parent, "real-address"); 219 1.1 christos htab_nr_bytes = device_find_integer_property(parent, "nr-bytes"); 220 1.1 christos if (htab_nr_bytes < 0x10000) { 221 1.1 christos device_error(parent, "htab size 0x%x less than 0x1000", 222 1.1 christos htab_nr_bytes); 223 1.1 christos } 224 1.1 christos for (n = htab_nr_bytes; n > 1; n = n / 2) { 225 1.1 christos if (n % 2 != 0) 226 1.1 christos device_error(parent, "htab size 0x%x not a power of two", 227 1.1 christos htab_nr_bytes); 228 1.1 christos } 229 1.1 christos *htaborg = htab_ra; 230 1.1 christos /* Position the HTABMASK ready for use against a hashed address and 231 1.1 christos not ready for insertion into SDR1.HTABMASK. */ 232 1.1 christos *htabmask = MASKED32(htab_nr_bytes - 1, 7, 31-6); 233 1.1 christos /* Check that the MASK and ADDRESS do not overlap. */ 234 1.1 christos if ((htab_ra & (*htabmask)) != 0) { 235 1.1 christos device_error(parent, "htaborg 0x%lx not aligned to htabmask 0x%lx", 236 1.1 christos (unsigned long)*htaborg, (unsigned long)*htabmask); 237 1.1 christos } 238 1.1 christos DTRACE(htab, ("htab - htaborg=0x%lx htabmask=0x%lx\n", 239 1.1 christos (unsigned long)*htaborg, (unsigned long)*htabmask)); 240 1.1 christos } 241 1.1 christos 242 1.1 christos static void 243 1.1 christos htab_map_page(device *me, 244 1.1 christos unsigned_word ra, 245 1.1.1.6 christos uint64_t va, 246 1.1 christos unsigned wimg, 247 1.1 christos unsigned pp, 248 1.1.1.6 christos uint32_t htaborg, 249 1.1.1.6 christos uint32_t htabmask) 250 1.1 christos { 251 1.1 christos /* keep everything left shifted so that the numbering is easier */ 252 1.1.1.6 christos uint64_t vpn = va << 12; 253 1.1.1.6 christos uint32_t vsid = INSERTED32(EXTRACTED64(vpn, 0, 23), 0, 23); 254 1.1.1.6 christos uint32_t vpage = INSERTED32(EXTRACTED64(vpn, 24, 39), 0, 15); 255 1.1.1.6 christos uint32_t hash = INSERTED32(EXTRACTED32(vsid, 5, 23) 256 1.1 christos ^ EXTRACTED32(vpage, 0, 15), 257 1.1 christos 7, 31-6); 258 1.1 christos int h; 259 1.1 christos for (h = 0; h < 2; h++) { 260 1.1.1.6 christos uint32_t pteg = (htaborg | (hash & htabmask)); 261 1.1 christos int pti; 262 1.1 christos for (pti = 0; pti < 8; pti++) { 263 1.1.1.6 christos uint32_t pte = pteg + 8 * pti; 264 1.1.1.6 christos uint32_t current_target_pte0; 265 1.1.1.6 christos uint32_t current_pte0; 266 1.1 christos if (device_dma_read_buffer(device_parent(me), 267 1.1 christos ¤t_target_pte0, 268 1.1 christos 0, /*space*/ 269 1.1 christos pte, 270 1.1 christos sizeof(current_target_pte0)) != 4) 271 1.1 christos device_error(me, "failed to read a pte at 0x%lx", (unsigned long)pte); 272 1.1 christos current_pte0 = T2H_4(current_target_pte0); 273 1.1 christos if (MASKED32(current_pte0, 0, 0)) { 274 1.1 christos /* full pte, check it isn't already mapping the same virtual 275 1.1 christos address */ 276 1.1.1.6 christos uint32_t curr_vsid = INSERTED32(EXTRACTED32(current_pte0, 1, 24), 0, 23); 277 1.1.1.6 christos uint32_t curr_api = INSERTED32(EXTRACTED32(current_pte0, 26, 31), 0, 5); 278 1.1.1.6 christos uint32_t curr_h = EXTRACTED32(current_pte0, 25, 25); 279 1.1 christos if (curr_h == h 280 1.1 christos && curr_vsid == vsid 281 1.1 christos && curr_api == MASKED32(vpage, 0, 5)) 282 1.1 christos device_error(me, "duplicate map - va=0x%08lx ra=0x%lx vsid=0x%lx h=%d vpage=0x%lx hash=0x%lx pteg=0x%lx+%2d pte0=0x%lx", 283 1.1 christos (unsigned long)va, 284 1.1 christos (unsigned long)ra, 285 1.1 christos (unsigned long)vsid, 286 1.1 christos h, 287 1.1 christos (unsigned long)vpage, 288 1.1 christos (unsigned long)hash, 289 1.1 christos (unsigned long)pteg, 290 1.1 christos pti * 8, 291 1.1 christos (unsigned long)current_pte0); 292 1.1 christos } 293 1.1 christos else { 294 1.1 christos /* empty pte fill it */ 295 1.1.1.6 christos uint32_t pte0 = (MASK32(0, 0) 296 1.1 christos | INSERTED32(EXTRACTED32(vsid, 0, 23), 1, 24) 297 1.1 christos | INSERTED32(h, 25, 25) 298 1.1 christos | INSERTED32(EXTRACTED32(vpage, 0, 5), 26, 31)); 299 1.1.1.6 christos uint32_t target_pte0 = H2T_4(pte0); 300 1.1.1.6 christos uint32_t pte1 = (INSERTED32(EXTRACTED32(ra, 0, 19), 0, 19) 301 1.1 christos | INSERTED32(wimg, 25, 28) 302 1.1 christos | INSERTED32(pp, 30, 31)); 303 1.1.1.6 christos uint32_t target_pte1 = H2T_4(pte1); 304 1.1 christos if (device_dma_write_buffer(device_parent(me), 305 1.1 christos &target_pte0, 306 1.1 christos 0, /*space*/ 307 1.1 christos pte, 308 1.1 christos sizeof(target_pte0), 309 1.1 christos 1/*ro?*/) != 4 310 1.1 christos || device_dma_write_buffer(device_parent(me), 311 1.1 christos &target_pte1, 312 1.1 christos 0, /*space*/ 313 1.1 christos pte + 4, 314 1.1 christos sizeof(target_pte1), 315 1.1 christos 1/*ro?*/) != 4) 316 1.1 christos device_error(me, "failed to write a pte a 0x%lx", (unsigned long)pte); 317 1.1 christos DTRACE(htab, ("map - va=0x%08lx ra=0x%lx vsid=0x%lx h=%d vpage=0x%lx hash=0x%lx pteg=0x%lx+%2d pte0=0x%lx pte1=0x%lx\n", 318 1.1 christos (unsigned long)va, 319 1.1 christos (unsigned long)ra, 320 1.1 christos (unsigned long)vsid, 321 1.1 christos h, 322 1.1 christos (unsigned long)vpage, 323 1.1 christos (unsigned long)hash, 324 1.1 christos (unsigned long)pteg, 325 1.1 christos pti * 8, 326 1.1 christos (unsigned long)pte0, 327 1.1 christos (unsigned long)pte1)); 328 1.1 christos return; 329 1.1 christos } 330 1.1 christos } 331 1.1 christos /* re-hash */ 332 1.1 christos hash = MASKED32(~hash, 0, 18); 333 1.1 christos } 334 1.1 christos } 335 1.1 christos 336 1.1 christos static unsigned_word 337 1.1 christos claim_memory(device *me, 338 1.1 christos device_instance *memory, 339 1.1 christos unsigned_word ra, 340 1.1 christos unsigned_word size) 341 1.1 christos { 342 1.1.1.6 christos uint32_t args[3]; 343 1.1.1.6 christos uint32_t results[1]; 344 1.1 christos int status; 345 1.1 christos args[0] = 0; /* alignment */ 346 1.1 christos args[1] = size; 347 1.1 christos args[2] = ra; 348 1.1 christos status = device_instance_call_method(memory, "claim", 3, args, 1, results); 349 1.1 christos if (status != 0) 350 1.1 christos device_error(me, "failed to claim memory"); 351 1.1 christos return results[0]; 352 1.1 christos } 353 1.1 christos 354 1.1 christos static void 355 1.1 christos htab_map_region(device *me, 356 1.1 christos device_instance *memory, 357 1.1 christos unsigned_word pte_ra, 358 1.1.1.6 christos uint64_t pte_va, 359 1.1 christos unsigned nr_bytes, 360 1.1 christos unsigned wimg, 361 1.1 christos unsigned pp, 362 1.1.1.6 christos uint32_t htaborg, 363 1.1.1.6 christos uint32_t htabmask) 364 1.1 christos { 365 1.1 christos unsigned_word ra; 366 1.1.1.6 christos uint64_t va; 367 1.1 christos /* claim the memory */ 368 1.1 christos if (memory != NULL) 369 1.1 christos claim_memory(me, memory, pte_ra, nr_bytes); 370 1.1 christos /* go through all pages and create a pte for each */ 371 1.1 christos for (ra = pte_ra, va = pte_va; 372 1.1 christos ra < pte_ra + nr_bytes; 373 1.1 christos ra += 0x1000, va += 0x1000) { 374 1.1 christos htab_map_page(me, ra, va, wimg, pp, htaborg, htabmask); 375 1.1 christos } 376 1.1 christos } 377 1.1 christos 378 1.1 christos typedef struct _htab_binary_sizes { 379 1.1 christos unsigned_word text_ra; 380 1.1 christos unsigned_word text_base; 381 1.1 christos unsigned_word text_bound; 382 1.1 christos unsigned_word data_ra; 383 1.1 christos unsigned_word data_base; 384 1.1 christos unsigned data_bound; 385 1.1 christos device *me; 386 1.1 christos } htab_binary_sizes; 387 1.1 christos 388 1.1 christos static void 389 1.1 christos htab_sum_binary(bfd *abfd, 390 1.1 christos sec_ptr sec, 391 1.1.1.6 christos void *data) 392 1.1 christos { 393 1.1 christos htab_binary_sizes *sizes = (htab_binary_sizes*)data; 394 1.1.1.5 christos unsigned_word size = bfd_section_size (sec); 395 1.1.1.5 christos unsigned_word vma = bfd_section_vma (sec); 396 1.1.1.5 christos unsigned_word ra = bfd_section_lma (sec); 397 1.1 christos 398 1.1 christos /* skip the section if no memory to allocate */ 399 1.1.1.5 christos if (! (bfd_section_flags (sec) & SEC_ALLOC)) 400 1.1 christos return; 401 1.1 christos 402 1.1.1.5 christos if ((bfd_section_flags (sec) & SEC_CODE) 403 1.1.1.5 christos || (bfd_section_flags (sec) & SEC_READONLY)) { 404 1.1 christos if (sizes->text_bound < vma + size) 405 1.1 christos sizes->text_bound = ALIGN_PAGE(vma + size); 406 1.1 christos if (sizes->text_base > vma) 407 1.1 christos sizes->text_base = FLOOR_PAGE(vma); 408 1.1 christos if (sizes->text_ra > ra) 409 1.1 christos sizes->text_ra = FLOOR_PAGE(ra); 410 1.1 christos } 411 1.1.1.5 christos else if ((bfd_section_flags (sec) & SEC_DATA) 412 1.1.1.5 christos || (bfd_section_flags (sec) & SEC_ALLOC)) { 413 1.1 christos if (sizes->data_bound < vma + size) 414 1.1 christos sizes->data_bound = ALIGN_PAGE(vma + size); 415 1.1 christos if (sizes->data_base > vma) 416 1.1 christos sizes->data_base = FLOOR_PAGE(vma); 417 1.1 christos if (sizes->data_ra > ra) 418 1.1 christos sizes->data_ra = FLOOR_PAGE(ra); 419 1.1 christos } 420 1.1 christos } 421 1.1 christos 422 1.1 christos static void 423 1.1 christos htab_dma_binary(bfd *abfd, 424 1.1 christos sec_ptr sec, 425 1.1.1.6 christos void *data) 426 1.1 christos { 427 1.1 christos htab_binary_sizes *sizes = (htab_binary_sizes*)data; 428 1.1 christos void *section_init; 429 1.1 christos unsigned_word section_vma; 430 1.1 christos unsigned_word section_size; 431 1.1 christos unsigned_word section_ra; 432 1.1 christos device *me = sizes->me; 433 1.1 christos 434 1.1 christos /* skip the section if no memory to allocate */ 435 1.1.1.5 christos if (! (bfd_section_flags (sec) & SEC_ALLOC)) 436 1.1 christos return; 437 1.1 christos 438 1.1 christos /* check/ignore any sections of size zero */ 439 1.1.1.5 christos section_size = bfd_section_size (sec); 440 1.1 christos if (section_size == 0) 441 1.1 christos return; 442 1.1 christos 443 1.1 christos /* if nothing to load, ignore this one */ 444 1.1.1.5 christos if (! (bfd_section_flags (sec) & SEC_LOAD)) 445 1.1 christos return; 446 1.1 christos 447 1.1 christos /* find where it is to go */ 448 1.1.1.5 christos section_vma = bfd_section_vma (sec); 449 1.1 christos section_ra = 0; 450 1.1.1.5 christos if ((bfd_section_flags (sec) & SEC_CODE) 451 1.1.1.5 christos || (bfd_section_flags (sec) & SEC_READONLY)) 452 1.1 christos section_ra = (section_vma - sizes->text_base + sizes->text_ra); 453 1.1.1.5 christos else if ((bfd_section_flags (sec) & SEC_DATA)) 454 1.1 christos section_ra = (section_vma - sizes->data_base + sizes->data_ra); 455 1.1 christos else 456 1.1 christos return; /* just ignore it */ 457 1.1 christos 458 1.1 christos DTRACE(htab, 459 1.1 christos ("load - name=%-7s vma=0x%.8lx size=%6ld ra=0x%.8lx flags=%3lx(%s%s%s%s%s )\n", 460 1.1.1.5 christos bfd_section_name (sec), 461 1.1 christos (long)section_vma, 462 1.1 christos (long)section_size, 463 1.1 christos (long)section_ra, 464 1.1.1.5 christos (long)bfd_section_flags (sec), 465 1.1.1.5 christos bfd_section_flags (sec) & SEC_LOAD ? " LOAD" : "", 466 1.1.1.5 christos bfd_section_flags (sec) & SEC_CODE ? " CODE" : "", 467 1.1.1.5 christos bfd_section_flags (sec) & SEC_DATA ? " DATA" : "", 468 1.1.1.5 christos bfd_section_flags (sec) & SEC_ALLOC ? " ALLOC" : "", 469 1.1.1.5 christos bfd_section_flags (sec) & SEC_READONLY ? " READONLY" : "" 470 1.1 christos )); 471 1.1 christos 472 1.1 christos /* dma in the sections data */ 473 1.1 christos section_init = zalloc(section_size); 474 1.1 christos if (!bfd_get_section_contents(abfd, 475 1.1 christos sec, 476 1.1 christos section_init, 0, 477 1.1 christos section_size)) { 478 1.1 christos bfd_perror("devices/pte"); 479 1.1 christos device_error(me, "no data loaded"); 480 1.1 christos } 481 1.1 christos if (device_dma_write_buffer(device_parent(me), 482 1.1 christos section_init, 483 1.1 christos 0 /*space*/, 484 1.1 christos section_ra, 485 1.1 christos section_size, 486 1.1 christos 1 /*violate_read_only*/) 487 1.1 christos != section_size) 488 1.1 christos device_error(me, "broken dma transfer"); 489 1.1 christos free(section_init); /* only free if load */ 490 1.1 christos } 491 1.1 christos 492 1.1 christos /* create a memory map from a binaries virtual addresses to a copy of 493 1.1 christos the binary laid out linearly in memory */ 494 1.1 christos 495 1.1 christos static void 496 1.1 christos htab_map_binary(device *me, 497 1.1 christos device_instance *memory, 498 1.1 christos unsigned_word ra, 499 1.1 christos unsigned wimg, 500 1.1 christos unsigned pp, 501 1.1 christos const char *file_name, 502 1.1.1.6 christos uint32_t htaborg, 503 1.1.1.6 christos uint32_t htabmask) 504 1.1 christos { 505 1.1 christos htab_binary_sizes sizes; 506 1.1 christos bfd *image; 507 1.1 christos sizes.text_ra = -1; 508 1.1 christos sizes.data_ra = -1; 509 1.1 christos sizes.text_base = -1; 510 1.1 christos sizes.data_base = -1; 511 1.1 christos sizes.text_bound = 0; 512 1.1 christos sizes.data_bound = 0; 513 1.1 christos sizes.me = me; 514 1.1 christos 515 1.1 christos /* open the file */ 516 1.1 christos image = bfd_openr(file_name, NULL); 517 1.1 christos if (image == NULL) { 518 1.1 christos bfd_perror("devices/pte"); 519 1.1 christos device_error(me, "the file %s not loaded", file_name); 520 1.1 christos } 521 1.1 christos 522 1.1 christos /* check it is valid */ 523 1.1 christos if (!bfd_check_format(image, bfd_object)) { 524 1.1 christos bfd_close(image); 525 1.1 christos device_error(me, "the file %s has an invalid binary format", file_name); 526 1.1 christos } 527 1.1 christos 528 1.1 christos /* determine the size of each of the files regions */ 529 1.1.1.6 christos bfd_map_over_sections (image, htab_sum_binary, &sizes); 530 1.1 christos 531 1.1 christos /* if needed, determine the real addresses of the sections */ 532 1.1 christos if (ra != -1) { 533 1.1 christos sizes.text_ra = ra; 534 1.1 christos sizes.data_ra = ALIGN_PAGE(sizes.text_ra + 535 1.1 christos (sizes.text_bound - sizes.text_base)); 536 1.1 christos } 537 1.1 christos 538 1.1 christos DTRACE(htab, ("text map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n", 539 1.1 christos (unsigned long)sizes.text_base, 540 1.1 christos (unsigned long)sizes.text_bound, 541 1.1 christos (unsigned long)sizes.text_ra)); 542 1.1 christos DTRACE(htab, ("data map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n", 543 1.1 christos (unsigned long)sizes.data_base, 544 1.1 christos (unsigned long)sizes.data_bound, 545 1.1 christos (unsigned long)sizes.data_ra)); 546 1.1 christos 547 1.1 christos /* check for and fix a botched image (text and data segments 548 1.1 christos overlap) */ 549 1.1 christos if ((sizes.text_base <= sizes.data_base 550 1.1 christos && sizes.text_bound >= sizes.data_bound) 551 1.1 christos || (sizes.data_base <= sizes.text_base 552 1.1.1.4 christos && sizes.data_bound >= sizes.text_bound) 553 1.1 christos || (sizes.text_bound > sizes.data_base 554 1.1 christos && sizes.text_bound <= sizes.data_bound) 555 1.1 christos || (sizes.text_base >= sizes.data_base 556 1.1 christos && sizes.text_base < sizes.data_bound)) { 557 1.1 christos DTRACE(htab, ("text and data segment overlaped - using just data segment\n")); 558 1.1 christos /* check va->ra linear */ 559 1.1 christos if ((sizes.text_base - sizes.text_ra) 560 1.1 christos != (sizes.data_base - sizes.data_ra)) 561 1.1 christos device_error(me, "overlapping but missaligned text and data segments"); 562 1.1 christos /* enlarge the data segment */ 563 1.1 christos if (sizes.text_base < sizes.data_base) 564 1.1 christos sizes.data_base = sizes.text_base; 565 1.1 christos if (sizes.text_bound > sizes.data_bound) 566 1.1 christos sizes.data_bound = sizes.text_bound; 567 1.1 christos if (sizes.text_ra < sizes.data_ra) 568 1.1 christos sizes.data_ra = sizes.text_ra; 569 1.1 christos /* zap the text segment */ 570 1.1 christos sizes.text_base = 0; 571 1.1 christos sizes.text_bound = 0; 572 1.1 christos sizes.text_ra = 0; 573 1.1 christos DTRACE(htab, ("common map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n", 574 1.1 christos (unsigned long)sizes.data_base, 575 1.1 christos (unsigned long)sizes.data_bound, 576 1.1 christos (unsigned long)sizes.data_ra)); 577 1.1 christos } 578 1.1 christos 579 1.1 christos /* set up virtual memory maps for each of the regions */ 580 1.1 christos if (sizes.text_bound - sizes.text_base > 0) { 581 1.1 christos htab_map_region(me, memory, sizes.text_ra, sizes.text_base, 582 1.1 christos sizes.text_bound - sizes.text_base, 583 1.1 christos wimg, pp, 584 1.1 christos htaborg, htabmask); 585 1.1 christos } 586 1.1 christos 587 1.1 christos htab_map_region(me, memory, sizes.data_ra, sizes.data_base, 588 1.1 christos sizes.data_bound - sizes.data_base, 589 1.1 christos wimg, pp, 590 1.1 christos htaborg, htabmask); 591 1.1 christos 592 1.1 christos /* dma the sections into physical memory */ 593 1.1.1.6 christos bfd_map_over_sections (image, htab_dma_binary, &sizes); 594 1.1 christos } 595 1.1 christos 596 1.1 christos static void 597 1.1 christos htab_init_data_callback(device *me) 598 1.1 christos { 599 1.1 christos device_instance *memory = NULL; 600 1.1 christos if (WITH_TARGET_WORD_BITSIZE != 32) 601 1.1 christos device_error(me, "only 32bit targets currently suported"); 602 1.1 christos 603 1.1 christos /* find memory device */ 604 1.1 christos if (device_find_property(me, "claim") != NULL) 605 1.1 christos memory = tree_find_ihandle_property(me, "/chosen/memory"); 606 1.1 christos 607 1.1 christos /* for the htab, just allocate space for it */ 608 1.1 christos if (strcmp(device_name(me), "htab") == 0) { 609 1.1 christos unsigned_word address = device_find_integer_property(me, "real-address"); 610 1.1 christos unsigned_word length = device_find_integer_property(me, "nr-bytes"); 611 1.1 christos unsigned_word base = claim_memory(me, memory, address, length); 612 1.1 christos if (base == -1 || base != address) 613 1.1 christos device_error(me, "cannot allocate hash table"); 614 1.1 christos } 615 1.1 christos 616 1.1 christos /* for the pte, do all the real work */ 617 1.1 christos if (strcmp(device_name(me), "pte") == 0) { 618 1.1.1.6 christos uint32_t htaborg; 619 1.1.1.6 christos uint32_t htabmask; 620 1.1 christos 621 1.1 christos htab_decode_hash_table(me, &htaborg, &htabmask); 622 1.1 christos 623 1.1 christos if (device_find_property(me, "file-name") != NULL) { 624 1.1 christos /* map in a binary */ 625 1.1 christos unsigned pte_wimg = device_find_integer_property(me, "wimg"); 626 1.1 christos unsigned pte_pp = device_find_integer_property(me, "pp"); 627 1.1 christos const char *file_name = device_find_string_property(me, "file-name"); 628 1.1 christos if (device_find_property(me, "real-address") != NULL) { 629 1.1.1.6 christos uint32_t pte_ra = device_find_integer_property(me, "real-address"); 630 1.1 christos DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, file-name=%s\n", 631 1.1 christos (unsigned long)pte_ra, 632 1.1 christos (unsigned long)pte_wimg, 633 1.1 christos (long)pte_pp, 634 1.1 christos file_name)); 635 1.1 christos htab_map_binary(me, memory, pte_ra, pte_wimg, pte_pp, file_name, 636 1.1 christos htaborg, htabmask); 637 1.1 christos } 638 1.1 christos else { 639 1.1 christos DTRACE(htab, ("pte - wimg=%ld, pp=%ld, file-name=%s\n", 640 1.1 christos (unsigned long)pte_wimg, 641 1.1 christos (long)pte_pp, 642 1.1 christos file_name)); 643 1.1 christos htab_map_binary(me, memory, -1, pte_wimg, pte_pp, file_name, 644 1.1 christos htaborg, htabmask); 645 1.1 christos } 646 1.1 christos } 647 1.1 christos else { 648 1.1 christos /* handle a normal mapping definition */ 649 1.1.1.6 christos uint64_t pte_va = 0; 650 1.1.1.6 christos uint32_t pte_ra = device_find_integer_property(me, "real-address"); 651 1.1 christos unsigned pte_nr_bytes = device_find_integer_property(me, "nr-bytes"); 652 1.1 christos unsigned pte_wimg = device_find_integer_property(me, "wimg"); 653 1.1 christos unsigned pte_pp = device_find_integer_property(me, "pp"); 654 1.1 christos signed_cell partial_va; 655 1.1 christos int i; 656 1.1 christos for (i = 0; 657 1.1 christos device_find_integer_array_property(me, "virtual-address", i, &partial_va); 658 1.1 christos i++) { 659 1.1 christos pte_va = (pte_va << WITH_TARGET_WORD_BITSIZE) | (unsigned_cell)partial_va; 660 1.1 christos } 661 1.1 christos DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, va=0x%lx, nr_bytes=%ld\n", 662 1.1 christos (unsigned long)pte_ra, 663 1.1 christos (long)pte_wimg, 664 1.1 christos (long)pte_pp, 665 1.1 christos (unsigned long)pte_va, 666 1.1 christos (long)pte_nr_bytes)); 667 1.1 christos htab_map_region(me, memory, pte_ra, pte_va, pte_nr_bytes, pte_wimg, pte_pp, 668 1.1 christos htaborg, htabmask); 669 1.1 christos } 670 1.1 christos } 671 1.1 christos } 672 1.1 christos 673 1.1 christos 674 1.1 christos static device_callbacks const htab_callbacks = { 675 1.1 christos { NULL, htab_init_data_callback, }, 676 1.1 christos { NULL, }, /* address */ 677 1.1 christos { NULL, }, /* IO */ 678 1.1 christos { passthrough_device_dma_read_buffer, 679 1.1 christos passthrough_device_dma_write_buffer, }, 680 1.1 christos { NULL, }, /* interrupt */ 681 1.1 christos { generic_device_unit_decode, 682 1.1 christos generic_device_unit_encode, }, 683 1.1 christos }; 684 1.1 christos 685 1.1 christos const device_descriptor hw_htab_device_descriptor[] = { 686 1.1 christos { "htab", NULL, &htab_callbacks }, 687 1.1 christos { "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */ 688 1.1 christos { NULL }, 689 1.1 christos }; 690 1.1 christos 691 1.1 christos #endif /* _HW_HTAB_C_ */ 692