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