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