| /* This file is part of the program psim. | |
| Copyright 1994, 1995, 1996, 2003, 2004 Andrew Cagney | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 3 of the License, or | |
| (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program; if not, see <http://www.gnu.org/licenses/>. | |
| */ | |
| #ifndef _HW_HTAB_C_ | |
| #define _HW_HTAB_C_ | |
| #include "device_table.h" | |
| #include "device.h" | |
| #include "bfd.h" | |
| /* DEVICE | |
| htab - pseudo-device describing a PowerPC hash table | |
| DESCRIPTION | |
| During the initialization of the device tree, the pseudo-device | |
| <<htab>>, in conjunction with any child <<pte>> pseudo-devices, | |
| will create a PowerPC hash table in memory. The hash table values | |
| are written using dma transfers. | |
| The size and address of the hash table are determined by properties | |
| of the htab node. | |
| By convention, the htab device is made a child of the | |
| <</openprom/init>> node. | |
| By convention, the real address of the htab is used as the htab | |
| nodes unit address. | |
| PROPERTIES | |
| real-address = <address> (required) | |
| The physical address of the hash table. The PowerPC architecture | |
| places limitations on what is a valid hash table real-address. | |
| nr-bytes = <size> (required) | |
| The size of the hash table (in bytes) that is to be created at | |
| <<real-address>>. The PowerPC architecture places limitations on | |
| what is a valid hash table size. | |
| claim = <anything> (optional) | |
| If this property is present, the memory used to construct the hash | |
| table will be claimed from the memory device. The memory device | |
| being specified by the <</chosen/memory>> ihandle property. | |
| EXAMPLES | |
| Enable tracing. | |
| | $ psim -t htab-device \ | |
| Create a htab specifying the base address and minimum size. | |
| | -o '/openprom/init/htab@0x10000/real-address 0x10000' \ | |
| | -o '/openprom/init/htab@0x10000/claim 0' \ | |
| | -o '/openprom/init/htab@0x10000/nr-bytes 65536' \ | |
| BUGS | |
| See the <<pte>> device. | |
| */ | |
| /* DEVICE | |
| pte - pseudo-device describing a htab entry | |
| DESCRIPTION | |
| The <<pte>> pseudo-device, which must be a child of a <<htabl>> | |
| node, describes a virtual to physical mapping that is to be entered | |
| into the parents hash table. | |
| Two alternative specifications of the mapping are allowed. Either | |
| a section of physical memory can be mapped to a virtual address, or | |
| the header of an executible image can be used to define the | |
| mapping. | |
| By convention, the real address of the map is specified as the pte | |
| devices unit address. | |
| PROPERTIES | |
| real-address = <address> (required) | |
| The starting physical address that is to be mapped by the hash | |
| table. | |
| wimg = <int> (required) | |
| pp = <int> (required) | |
| The value of hash table protection bits that are to be used when | |
| creating the virtual to physical address map. | |
| claim = <anything> (optional) | |
| If this property is present, the real memory that is being mapped by the | |
| hash table will be claimed from the memory node (specified by the | |
| ihandle <</chosen/memory>>). | |
| virtual-address = <integer> [ <integer> ] (option A) | |
| nr-bytes = <size> (option A) | |
| Option A - Virtual virtual address (and size) at which the physical | |
| address is to be mapped. If multiple values are specified for the | |
| virtual address then they are concatenated to gether to form a | |
| longer virtual address. | |
| file-name = <string> (option B) | |
| Option B - An executable image that is to be loaded (starting at | |
| the physical address specified above) and then mapped in using | |
| informatioin taken from the executables header. information found | |
| in the files header. | |
| EXAMPLES | |
| Enable tracing (note that both the <<htab>> and <<pte>> device use the | |
| same trace option). | |
| | -t htab-device \ | |
| Map a block of physical memory into a specified virtual address: | |
| | -o '/openprom/init/htab/pte@0x0/real-address 0' \ | |
| | -o '/openprom/init/htab/pte@0x0/nr-bytes 4096' \ | |
| | -o '/openprom/init/htab/pte@0x0/virtual-address 0x1000000' \ | |
| | -o '/openprom/init/htab/pte@0x0/claim 0' \ | |
| | -o '/openprom/init/htab/pte@0x0/wimg 0x7' \ | |
| | -o '/openprom/init/htab/pte@0x0/pp 0x2' \ | |
| Map a file into memory. | |
| | -o '/openprom/init/htab/pte@0x10000/real-address 0x10000' \ | |
| | -o '/openprom/init/htab/pte@0x10000/file-name "netbsd.elf' \ | |
| | -o '/openprom/init/htab/pte@0x10000/wimg 0x7' \ | |
| | -o '/openprom/init/htab/pte@0x10000/pp 0x2' \ | |
| BUGS | |
| For an ELF executable, the header defines both the virtual and real | |
| address at which each file section should be loaded. At present, the | |
| real addresses that are specified in the header are ignored, the file | |
| instead being loaded in to physical memory in a linear fashion. | |
| When claiming memory, this device assumes that the #address-cells | |
| and #size-cells is one. For future implementations, this may not | |
| be the case. | |
| */ | |
| static void | |
| htab_decode_hash_table(device *me, | |
| uint32_t *htaborg, | |
| uint32_t *htabmask) | |
| { | |
| unsigned_word htab_ra; | |
| unsigned htab_nr_bytes; | |
| unsigned n; | |
| device *parent = device_parent(me); | |
| /* determine the location/size of the hash table */ | |
| if (parent == NULL | |
| || strcmp(device_name(parent), "htab") != 0) | |
| device_error(parent, "must be a htab device"); | |
| htab_ra = device_find_integer_property(parent, "real-address"); | |
| htab_nr_bytes = device_find_integer_property(parent, "nr-bytes"); | |
| if (htab_nr_bytes < 0x10000) { | |
| device_error(parent, "htab size 0x%x less than 0x1000", | |
| htab_nr_bytes); | |
| } | |
| for (n = htab_nr_bytes; n > 1; n = n / 2) { | |
| if (n % 2 != 0) | |
| device_error(parent, "htab size 0x%x not a power of two", | |
| htab_nr_bytes); | |
| } | |
| *htaborg = htab_ra; | |
| /* Position the HTABMASK ready for use against a hashed address and | |
| not ready for insertion into SDR1.HTABMASK. */ | |
| *htabmask = MASKED32(htab_nr_bytes - 1, 7, 31-6); | |
| /* Check that the MASK and ADDRESS do not overlap. */ | |
| if ((htab_ra & (*htabmask)) != 0) { | |
| device_error(parent, "htaborg 0x%lx not aligned to htabmask 0x%lx", | |
| (unsigned long)*htaborg, (unsigned long)*htabmask); | |
| } | |
| DTRACE(htab, ("htab - htaborg=0x%lx htabmask=0x%lx\n", | |
| (unsigned long)*htaborg, (unsigned long)*htabmask)); | |
| } | |
| static void | |
| htab_map_page(device *me, | |
| unsigned_word ra, | |
| uint64_t va, | |
| unsigned wimg, | |
| unsigned pp, | |
| uint32_t htaborg, | |
| uint32_t htabmask) | |
| { | |
| /* keep everything left shifted so that the numbering is easier */ | |
| uint64_t vpn = va << 12; | |
| uint32_t vsid = INSERTED32(EXTRACTED64(vpn, 0, 23), 0, 23); | |
| uint32_t vpage = INSERTED32(EXTRACTED64(vpn, 24, 39), 0, 15); | |
| uint32_t hash = INSERTED32(EXTRACTED32(vsid, 5, 23) | |
| ^ EXTRACTED32(vpage, 0, 15), | |
| 7, 31-6); | |
| int h; | |
| for (h = 0; h < 2; h++) { | |
| uint32_t pteg = (htaborg | (hash & htabmask)); | |
| int pti; | |
| for (pti = 0; pti < 8; pti++) { | |
| uint32_t pte = pteg + 8 * pti; | |
| uint32_t current_target_pte0; | |
| uint32_t current_pte0; | |
| if (device_dma_read_buffer(device_parent(me), | |
| ¤t_target_pte0, | |
| 0, /*space*/ | |
| pte, | |
| sizeof(current_target_pte0)) != 4) | |
| device_error(me, "failed to read a pte at 0x%lx", (unsigned long)pte); | |
| current_pte0 = T2H_4(current_target_pte0); | |
| if (MASKED32(current_pte0, 0, 0)) { | |
| /* full pte, check it isn't already mapping the same virtual | |
| address */ | |
| uint32_t curr_vsid = INSERTED32(EXTRACTED32(current_pte0, 1, 24), 0, 23); | |
| uint32_t curr_api = INSERTED32(EXTRACTED32(current_pte0, 26, 31), 0, 5); | |
| uint32_t curr_h = EXTRACTED32(current_pte0, 25, 25); | |
| if (curr_h == h | |
| && curr_vsid == vsid | |
| && curr_api == MASKED32(vpage, 0, 5)) | |
| 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", | |
| (unsigned long)va, | |
| (unsigned long)ra, | |
| (unsigned long)vsid, | |
| h, | |
| (unsigned long)vpage, | |
| (unsigned long)hash, | |
| (unsigned long)pteg, | |
| pti * 8, | |
| (unsigned long)current_pte0); | |
| } | |
| else { | |
| /* empty pte fill it */ | |
| uint32_t pte0 = (MASK32(0, 0) | |
| | INSERTED32(EXTRACTED32(vsid, 0, 23), 1, 24) | |
| | INSERTED32(h, 25, 25) | |
| | INSERTED32(EXTRACTED32(vpage, 0, 5), 26, 31)); | |
| uint32_t target_pte0 = H2T_4(pte0); | |
| uint32_t pte1 = (INSERTED32(EXTRACTED32(ra, 0, 19), 0, 19) | |
| | INSERTED32(wimg, 25, 28) | |
| | INSERTED32(pp, 30, 31)); | |
| uint32_t target_pte1 = H2T_4(pte1); | |
| if (device_dma_write_buffer(device_parent(me), | |
| &target_pte0, | |
| 0, /*space*/ | |
| pte, | |
| sizeof(target_pte0), | |
| 1/*ro?*/) != 4 | |
| || device_dma_write_buffer(device_parent(me), | |
| &target_pte1, | |
| 0, /*space*/ | |
| pte + 4, | |
| sizeof(target_pte1), | |
| 1/*ro?*/) != 4) | |
| device_error(me, "failed to write a pte a 0x%lx", (unsigned long)pte); | |
| 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", | |
| (unsigned long)va, | |
| (unsigned long)ra, | |
| (unsigned long)vsid, | |
| h, | |
| (unsigned long)vpage, | |
| (unsigned long)hash, | |
| (unsigned long)pteg, | |
| pti * 8, | |
| (unsigned long)pte0, | |
| (unsigned long)pte1)); | |
| return; | |
| } | |
| } | |
| /* re-hash */ | |
| hash = MASKED32(~hash, 0, 18); | |
| } | |
| } | |
| static unsigned_word | |
| claim_memory(device *me, | |
| device_instance *memory, | |
| unsigned_word ra, | |
| unsigned_word size) | |
| { | |
| uint32_t args[3]; | |
| uint32_t results[1]; | |
| int status; | |
| args[0] = 0; /* alignment */ | |
| args[1] = size; | |
| args[2] = ra; | |
| status = device_instance_call_method(memory, "claim", 3, args, 1, results); | |
| if (status != 0) | |
| device_error(me, "failed to claim memory"); | |
| return results[0]; | |
| } | |
| static void | |
| htab_map_region(device *me, | |
| device_instance *memory, | |
| unsigned_word pte_ra, | |
| uint64_t pte_va, | |
| unsigned nr_bytes, | |
| unsigned wimg, | |
| unsigned pp, | |
| uint32_t htaborg, | |
| uint32_t htabmask) | |
| { | |
| unsigned_word ra; | |
| uint64_t va; | |
| /* claim the memory */ | |
| if (memory != NULL) | |
| claim_memory(me, memory, pte_ra, nr_bytes); | |
| /* go through all pages and create a pte for each */ | |
| for (ra = pte_ra, va = pte_va; | |
| ra < pte_ra + nr_bytes; | |
| ra += 0x1000, va += 0x1000) { | |
| htab_map_page(me, ra, va, wimg, pp, htaborg, htabmask); | |
| } | |
| } | |
| typedef struct _htab_binary_sizes { | |
| unsigned_word text_ra; | |
| unsigned_word text_base; | |
| unsigned_word text_bound; | |
| unsigned_word data_ra; | |
| unsigned_word data_base; | |
| unsigned data_bound; | |
| device *me; | |
| } htab_binary_sizes; | |
| static void | |
| htab_sum_binary(bfd *abfd, | |
| sec_ptr sec, | |
| void *data) | |
| { | |
| htab_binary_sizes *sizes = (htab_binary_sizes*)data; | |
| unsigned_word size = bfd_section_size (sec); | |
| unsigned_word vma = bfd_section_vma (sec); | |
| unsigned_word ra = bfd_section_lma (sec); | |
| /* skip the section if no memory to allocate */ | |
| if (! (bfd_section_flags (sec) & SEC_ALLOC)) | |
| return; | |
| if ((bfd_section_flags (sec) & SEC_CODE) | |
| || (bfd_section_flags (sec) & SEC_READONLY)) { | |
| if (sizes->text_bound < vma + size) | |
| sizes->text_bound = ALIGN_PAGE(vma + size); | |
| if (sizes->text_base > vma) | |
| sizes->text_base = FLOOR_PAGE(vma); | |
| if (sizes->text_ra > ra) | |
| sizes->text_ra = FLOOR_PAGE(ra); | |
| } | |
| else if ((bfd_section_flags (sec) & SEC_DATA) | |
| || (bfd_section_flags (sec) & SEC_ALLOC)) { | |
| if (sizes->data_bound < vma + size) | |
| sizes->data_bound = ALIGN_PAGE(vma + size); | |
| if (sizes->data_base > vma) | |
| sizes->data_base = FLOOR_PAGE(vma); | |
| if (sizes->data_ra > ra) | |
| sizes->data_ra = FLOOR_PAGE(ra); | |
| } | |
| } | |
| static void | |
| htab_dma_binary(bfd *abfd, | |
| sec_ptr sec, | |
| void *data) | |
| { | |
| htab_binary_sizes *sizes = (htab_binary_sizes*)data; | |
| void *section_init; | |
| unsigned_word section_vma; | |
| unsigned_word section_size; | |
| unsigned_word section_ra; | |
| device *me = sizes->me; | |
| /* skip the section if no memory to allocate */ | |
| if (! (bfd_section_flags (sec) & SEC_ALLOC)) | |
| return; | |
| /* check/ignore any sections of size zero */ | |
| section_size = bfd_section_size (sec); | |
| if (section_size == 0) | |
| return; | |
| /* if nothing to load, ignore this one */ | |
| if (! (bfd_section_flags (sec) & SEC_LOAD)) | |
| return; | |
| /* find where it is to go */ | |
| section_vma = bfd_section_vma (sec); | |
| section_ra = 0; | |
| if ((bfd_section_flags (sec) & SEC_CODE) | |
| || (bfd_section_flags (sec) & SEC_READONLY)) | |
| section_ra = (section_vma - sizes->text_base + sizes->text_ra); | |
| else if ((bfd_section_flags (sec) & SEC_DATA)) | |
| section_ra = (section_vma - sizes->data_base + sizes->data_ra); | |
| else | |
| return; /* just ignore it */ | |
| DTRACE(htab, | |
| ("load - name=%-7s vma=0x%.8lx size=%6ld ra=0x%.8lx flags=%3lx(%s%s%s%s%s )\n", | |
| bfd_section_name (sec), | |
| (long)section_vma, | |
| (long)section_size, | |
| (long)section_ra, | |
| (long)bfd_section_flags (sec), | |
| bfd_section_flags (sec) & SEC_LOAD ? " LOAD" : "", | |
| bfd_section_flags (sec) & SEC_CODE ? " CODE" : "", | |
| bfd_section_flags (sec) & SEC_DATA ? " DATA" : "", | |
| bfd_section_flags (sec) & SEC_ALLOC ? " ALLOC" : "", | |
| bfd_section_flags (sec) & SEC_READONLY ? " READONLY" : "" | |
| )); | |
| /* dma in the sections data */ | |
| section_init = zalloc(section_size); | |
| if (!bfd_get_section_contents(abfd, | |
| sec, | |
| section_init, 0, | |
| section_size)) { | |
| bfd_perror("devices/pte"); | |
| device_error(me, "no data loaded"); | |
| } | |
| if (device_dma_write_buffer(device_parent(me), | |
| section_init, | |
| 0 /*space*/, | |
| section_ra, | |
| section_size, | |
| 1 /*violate_read_only*/) | |
| != section_size) | |
| device_error(me, "broken dma transfer"); | |
| free(section_init); /* only free if load */ | |
| } | |
| /* create a memory map from a binaries virtual addresses to a copy of | |
| the binary laid out linearly in memory */ | |
| static void | |
| htab_map_binary(device *me, | |
| device_instance *memory, | |
| unsigned_word ra, | |
| unsigned wimg, | |
| unsigned pp, | |
| const char *file_name, | |
| uint32_t htaborg, | |
| uint32_t htabmask) | |
| { | |
| htab_binary_sizes sizes; | |
| bfd *image; | |
| sizes.text_ra = -1; | |
| sizes.data_ra = -1; | |
| sizes.text_base = -1; | |
| sizes.data_base = -1; | |
| sizes.text_bound = 0; | |
| sizes.data_bound = 0; | |
| sizes.me = me; | |
| /* open the file */ | |
| image = bfd_openr(file_name, NULL); | |
| if (image == NULL) { | |
| bfd_perror("devices/pte"); | |
| device_error(me, "the file %s not loaded", file_name); | |
| } | |
| /* check it is valid */ | |
| if (!bfd_check_format(image, bfd_object)) { | |
| bfd_close(image); | |
| device_error(me, "the file %s has an invalid binary format", file_name); | |
| } | |
| /* determine the size of each of the files regions */ | |
| bfd_map_over_sections (image, htab_sum_binary, &sizes); | |
| /* if needed, determine the real addresses of the sections */ | |
| if (ra != -1) { | |
| sizes.text_ra = ra; | |
| sizes.data_ra = ALIGN_PAGE(sizes.text_ra + | |
| (sizes.text_bound - sizes.text_base)); | |
| } | |
| DTRACE(htab, ("text map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n", | |
| (unsigned long)sizes.text_base, | |
| (unsigned long)sizes.text_bound, | |
| (unsigned long)sizes.text_ra)); | |
| DTRACE(htab, ("data map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n", | |
| (unsigned long)sizes.data_base, | |
| (unsigned long)sizes.data_bound, | |
| (unsigned long)sizes.data_ra)); | |
| /* check for and fix a botched image (text and data segments | |
| overlap) */ | |
| if ((sizes.text_base <= sizes.data_base | |
| && sizes.text_bound >= sizes.data_bound) | |
| || (sizes.data_base <= sizes.text_base | |
| && sizes.data_bound >= sizes.text_bound) | |
| || (sizes.text_bound > sizes.data_base | |
| && sizes.text_bound <= sizes.data_bound) | |
| || (sizes.text_base >= sizes.data_base | |
| && sizes.text_base < sizes.data_bound)) { | |
| DTRACE(htab, ("text and data segment overlaped - using just data segment\n")); | |
| /* check va->ra linear */ | |
| if ((sizes.text_base - sizes.text_ra) | |
| != (sizes.data_base - sizes.data_ra)) | |
| device_error(me, "overlapping but missaligned text and data segments"); | |
| /* enlarge the data segment */ | |
| if (sizes.text_base < sizes.data_base) | |
| sizes.data_base = sizes.text_base; | |
| if (sizes.text_bound > sizes.data_bound) | |
| sizes.data_bound = sizes.text_bound; | |
| if (sizes.text_ra < sizes.data_ra) | |
| sizes.data_ra = sizes.text_ra; | |
| /* zap the text segment */ | |
| sizes.text_base = 0; | |
| sizes.text_bound = 0; | |
| sizes.text_ra = 0; | |
| DTRACE(htab, ("common map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n", | |
| (unsigned long)sizes.data_base, | |
| (unsigned long)sizes.data_bound, | |
| (unsigned long)sizes.data_ra)); | |
| } | |
| /* set up virtual memory maps for each of the regions */ | |
| if (sizes.text_bound - sizes.text_base > 0) { | |
| htab_map_region(me, memory, sizes.text_ra, sizes.text_base, | |
| sizes.text_bound - sizes.text_base, | |
| wimg, pp, | |
| htaborg, htabmask); | |
| } | |
| htab_map_region(me, memory, sizes.data_ra, sizes.data_base, | |
| sizes.data_bound - sizes.data_base, | |
| wimg, pp, | |
| htaborg, htabmask); | |
| /* dma the sections into physical memory */ | |
| bfd_map_over_sections (image, htab_dma_binary, &sizes); | |
| } | |
| static void | |
| htab_init_data_callback(device *me) | |
| { | |
| device_instance *memory = NULL; | |
| if (WITH_TARGET_WORD_BITSIZE != 32) | |
| device_error(me, "only 32bit targets currently suported"); | |
| /* find memory device */ | |
| if (device_find_property(me, "claim") != NULL) | |
| memory = tree_find_ihandle_property(me, "/chosen/memory"); | |
| /* for the htab, just allocate space for it */ | |
| if (strcmp(device_name(me), "htab") == 0) { | |
| unsigned_word address = device_find_integer_property(me, "real-address"); | |
| unsigned_word length = device_find_integer_property(me, "nr-bytes"); | |
| unsigned_word base = claim_memory(me, memory, address, length); | |
| if (base == -1 || base != address) | |
| device_error(me, "cannot allocate hash table"); | |
| } | |
| /* for the pte, do all the real work */ | |
| if (strcmp(device_name(me), "pte") == 0) { | |
| uint32_t htaborg; | |
| uint32_t htabmask; | |
| htab_decode_hash_table(me, &htaborg, &htabmask); | |
| if (device_find_property(me, "file-name") != NULL) { | |
| /* map in a binary */ | |
| unsigned pte_wimg = device_find_integer_property(me, "wimg"); | |
| unsigned pte_pp = device_find_integer_property(me, "pp"); | |
| const char *file_name = device_find_string_property(me, "file-name"); | |
| if (device_find_property(me, "real-address") != NULL) { | |
| uint32_t pte_ra = device_find_integer_property(me, "real-address"); | |
| DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, file-name=%s\n", | |
| (unsigned long)pte_ra, | |
| (unsigned long)pte_wimg, | |
| (long)pte_pp, | |
| file_name)); | |
| htab_map_binary(me, memory, pte_ra, pte_wimg, pte_pp, file_name, | |
| htaborg, htabmask); | |
| } | |
| else { | |
| DTRACE(htab, ("pte - wimg=%ld, pp=%ld, file-name=%s\n", | |
| (unsigned long)pte_wimg, | |
| (long)pte_pp, | |
| file_name)); | |
| htab_map_binary(me, memory, -1, pte_wimg, pte_pp, file_name, | |
| htaborg, htabmask); | |
| } | |
| } | |
| else { | |
| /* handle a normal mapping definition */ | |
| uint64_t pte_va = 0; | |
| uint32_t pte_ra = device_find_integer_property(me, "real-address"); | |
| unsigned pte_nr_bytes = device_find_integer_property(me, "nr-bytes"); | |
| unsigned pte_wimg = device_find_integer_property(me, "wimg"); | |
| unsigned pte_pp = device_find_integer_property(me, "pp"); | |
| signed_cell partial_va; | |
| int i; | |
| for (i = 0; | |
| device_find_integer_array_property(me, "virtual-address", i, &partial_va); | |
| i++) { | |
| pte_va = (pte_va << WITH_TARGET_WORD_BITSIZE) | (unsigned_cell)partial_va; | |
| } | |
| DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, va=0x%lx, nr_bytes=%ld\n", | |
| (unsigned long)pte_ra, | |
| (long)pte_wimg, | |
| (long)pte_pp, | |
| (unsigned long)pte_va, | |
| (long)pte_nr_bytes)); | |
| htab_map_region(me, memory, pte_ra, pte_va, pte_nr_bytes, pte_wimg, pte_pp, | |
| htaborg, htabmask); | |
| } | |
| } | |
| } | |
| static device_callbacks const htab_callbacks = { | |
| { NULL, htab_init_data_callback, }, | |
| { NULL, }, /* address */ | |
| { NULL, }, /* IO */ | |
| { passthrough_device_dma_read_buffer, | |
| passthrough_device_dma_write_buffer, }, | |
| { NULL, }, /* interrupt */ | |
| { generic_device_unit_decode, | |
| generic_device_unit_encode, }, | |
| }; | |
| const device_descriptor hw_htab_device_descriptor[] = { | |
| { "htab", NULL, &htab_callbacks }, | |
| { "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */ | |
| { NULL }, | |
| }; | |
| #endif /* _HW_HTAB_C_ */ |