xref: /netbsd/external/gpl3/gdb.old/dist/sim/ppc/hw_htab.c (revision 184b2d41)
16ca2c52aSchristos /*  This file is part of the program psim.
26ca2c52aSchristos 
36ca2c52aSchristos     Copyright 1994, 1995, 1996, 2003, 2004 Andrew Cagney
46ca2c52aSchristos 
56ca2c52aSchristos     This program is free software; you can redistribute it and/or modify
66ca2c52aSchristos     it under the terms of the GNU General Public License as published by
76ca2c52aSchristos     the Free Software Foundation; either version 3 of the License, or
86ca2c52aSchristos     (at your option) any later version.
96ca2c52aSchristos 
106ca2c52aSchristos     This program is distributed in the hope that it will be useful,
116ca2c52aSchristos     but WITHOUT ANY WARRANTY; without even the implied warranty of
126ca2c52aSchristos     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
136ca2c52aSchristos     GNU General Public License for more details.
146ca2c52aSchristos 
156ca2c52aSchristos     You should have received a copy of the GNU General Public License
166ca2c52aSchristos     along with this program; if not, see <http://www.gnu.org/licenses/>.
176ca2c52aSchristos 
186ca2c52aSchristos     */
196ca2c52aSchristos 
206ca2c52aSchristos 
216ca2c52aSchristos #ifndef _HW_HTAB_C_
226ca2c52aSchristos #define _HW_HTAB_C_
236ca2c52aSchristos 
246ca2c52aSchristos #include "device_table.h"
256ca2c52aSchristos #include "device.h"
266ca2c52aSchristos 
276ca2c52aSchristos #include "bfd.h"
286ca2c52aSchristos 
296ca2c52aSchristos 
306ca2c52aSchristos /* DEVICE
316ca2c52aSchristos 
326ca2c52aSchristos 
336ca2c52aSchristos    htab - pseudo-device describing a PowerPC hash table
346ca2c52aSchristos 
356ca2c52aSchristos 
366ca2c52aSchristos    DESCRIPTION
376ca2c52aSchristos 
386ca2c52aSchristos 
396ca2c52aSchristos    During the initialization of the device tree, the pseudo-device
406ca2c52aSchristos    <<htab>>, in conjunction with any child <<pte>> pseudo-devices,
416ca2c52aSchristos    will create a PowerPC hash table in memory.  The hash table values
426ca2c52aSchristos    are written using dma transfers.
436ca2c52aSchristos 
446ca2c52aSchristos    The size and address of the hash table are determined by properties
456ca2c52aSchristos    of the htab node.
466ca2c52aSchristos 
476ca2c52aSchristos    By convention, the htab device is made a child of the
486ca2c52aSchristos    <</openprom/init>> node.
496ca2c52aSchristos 
506ca2c52aSchristos    By convention, the real address of the htab is used as the htab
516ca2c52aSchristos    nodes unit address.
526ca2c52aSchristos 
536ca2c52aSchristos 
546ca2c52aSchristos    PROPERTIES
556ca2c52aSchristos 
566ca2c52aSchristos 
576ca2c52aSchristos    real-address = <address> (required)
586ca2c52aSchristos 
596ca2c52aSchristos    The physical address of the hash table.  The PowerPC architecture
606ca2c52aSchristos    places limitations on what is a valid hash table real-address.
616ca2c52aSchristos 
626ca2c52aSchristos 
636ca2c52aSchristos    nr-bytes = <size> (required)
646ca2c52aSchristos 
656ca2c52aSchristos    The size of the hash table (in bytes) that is to be created at
666ca2c52aSchristos    <<real-address>>.  The PowerPC architecture places limitations on
676ca2c52aSchristos    what is a valid hash table size.
686ca2c52aSchristos 
696ca2c52aSchristos 
706ca2c52aSchristos    claim = <anything> (optional)
716ca2c52aSchristos 
726ca2c52aSchristos    If this property is present, the memory used to construct the hash
736ca2c52aSchristos    table will be claimed from the memory device.  The memory device
746ca2c52aSchristos    being specified by the <</chosen/memory>> ihandle property.
756ca2c52aSchristos 
766ca2c52aSchristos 
776ca2c52aSchristos    EXAMPLES
786ca2c52aSchristos 
796ca2c52aSchristos    Enable tracing.
806ca2c52aSchristos 
816ca2c52aSchristos    |  $  psim -t htab-device \
826ca2c52aSchristos 
836ca2c52aSchristos 
846ca2c52aSchristos    Create a htab specifying the base address and minimum size.
856ca2c52aSchristos 
866ca2c52aSchristos    |    -o '/openprom/init/htab@0x10000/real-address 0x10000' \
876ca2c52aSchristos    |    -o '/openprom/init/htab@0x10000/claim 0' \
886ca2c52aSchristos    |    -o '/openprom/init/htab@0x10000/nr-bytes 65536' \
896ca2c52aSchristos 
906ca2c52aSchristos 
916ca2c52aSchristos    BUGS
926ca2c52aSchristos 
936ca2c52aSchristos 
946ca2c52aSchristos    See the <<pte>> device.
956ca2c52aSchristos 
966ca2c52aSchristos 
976ca2c52aSchristos    */
986ca2c52aSchristos 
996ca2c52aSchristos 
1006ca2c52aSchristos /* DEVICE
1016ca2c52aSchristos 
1026ca2c52aSchristos 
1036ca2c52aSchristos    pte - pseudo-device describing a htab entry
1046ca2c52aSchristos 
1056ca2c52aSchristos 
1066ca2c52aSchristos    DESCRIPTION
1076ca2c52aSchristos 
1086ca2c52aSchristos 
1096ca2c52aSchristos    The <<pte>> pseudo-device, which must be a child of a <<htabl>>
1106ca2c52aSchristos    node, describes a virtual to physical mapping that is to be entered
1116ca2c52aSchristos    into the parents hash table.
1126ca2c52aSchristos 
1136ca2c52aSchristos    Two alternative specifications of the mapping are allowed.  Either
1146ca2c52aSchristos    a section of physical memory can be mapped to a virtual address, or
1156ca2c52aSchristos    the header of an executible image can be used to define the
1166ca2c52aSchristos    mapping.
1176ca2c52aSchristos 
1186ca2c52aSchristos    By convention, the real address of the map is specified as the pte
1196ca2c52aSchristos    devices unit address.
1206ca2c52aSchristos 
1216ca2c52aSchristos 
1226ca2c52aSchristos    PROPERTIES
1236ca2c52aSchristos 
1246ca2c52aSchristos 
1256ca2c52aSchristos    real-address = <address> (required)
1266ca2c52aSchristos 
1276ca2c52aSchristos    The starting physical address that is to be mapped by the hash
1286ca2c52aSchristos    table.
1296ca2c52aSchristos 
1306ca2c52aSchristos 
1316ca2c52aSchristos    wimg = <int> (required)
1326ca2c52aSchristos    pp = <int> (required)
1336ca2c52aSchristos 
1346ca2c52aSchristos    The value of hash table protection bits that are to be used when
1356ca2c52aSchristos    creating the virtual to physical address map.
1366ca2c52aSchristos 
1376ca2c52aSchristos 
1386ca2c52aSchristos    claim = <anything> (optional)
1396ca2c52aSchristos 
1406ca2c52aSchristos    If this property is present, the real memory that is being mapped by the
1416ca2c52aSchristos    hash table will be claimed from the memory node (specified by the
1426ca2c52aSchristos    ihandle <</chosen/memory>>).
1436ca2c52aSchristos 
1446ca2c52aSchristos 
1456ca2c52aSchristos    virtual-address = <integer> [ <integer> ]  (option A)
1466ca2c52aSchristos    nr-bytes = <size>  (option A)
1476ca2c52aSchristos 
1486ca2c52aSchristos    Option A - Virtual virtual address (and size) at which the physical
1496ca2c52aSchristos    address is to be mapped.  If multiple values are specified for the
1506ca2c52aSchristos    virtual address then they are concatenated to gether to form a
1516ca2c52aSchristos    longer virtual address.
1526ca2c52aSchristos 
1536ca2c52aSchristos 
1546ca2c52aSchristos    file-name = <string>  (option B)
1556ca2c52aSchristos 
1566ca2c52aSchristos    Option B - An executable image that is to be loaded (starting at
1576ca2c52aSchristos    the physical address specified above) and then mapped in using
1586ca2c52aSchristos    informatioin taken from the executables header.  information found
1596ca2c52aSchristos    in the files header.
1606ca2c52aSchristos 
1616ca2c52aSchristos 
1626ca2c52aSchristos    EXAMPLES
1636ca2c52aSchristos 
1646ca2c52aSchristos 
1656ca2c52aSchristos    Enable tracing (note that both the <<htab>> and <<pte>> device use the
1666ca2c52aSchristos    same trace option).
1676ca2c52aSchristos 
1686ca2c52aSchristos    |   -t htab-device \
1696ca2c52aSchristos 
1706ca2c52aSchristos 
1716ca2c52aSchristos    Map a block of physical memory into a specified virtual address:
1726ca2c52aSchristos 
1736ca2c52aSchristos    |  -o '/openprom/init/htab/pte@0x0/real-address 0' \
1746ca2c52aSchristos    |  -o '/openprom/init/htab/pte@0x0/nr-bytes 4096' \
1756ca2c52aSchristos    |  -o '/openprom/init/htab/pte@0x0/virtual-address 0x1000000' \
1766ca2c52aSchristos    |  -o '/openprom/init/htab/pte@0x0/claim 0' \
1776ca2c52aSchristos    |  -o '/openprom/init/htab/pte@0x0/wimg 0x7' \
1786ca2c52aSchristos    |  -o '/openprom/init/htab/pte@0x0/pp 0x2' \
1796ca2c52aSchristos 
1806ca2c52aSchristos 
1816ca2c52aSchristos    Map a file into memory.
1826ca2c52aSchristos 
1836ca2c52aSchristos    |  -o '/openprom/init/htab/pte@0x10000/real-address 0x10000' \
1846ca2c52aSchristos    |  -o '/openprom/init/htab/pte@0x10000/file-name "netbsd.elf' \
1856ca2c52aSchristos    |  -o '/openprom/init/htab/pte@0x10000/wimg 0x7' \
1866ca2c52aSchristos    |  -o '/openprom/init/htab/pte@0x10000/pp 0x2' \
1876ca2c52aSchristos 
1886ca2c52aSchristos 
1896ca2c52aSchristos    BUGS
1906ca2c52aSchristos 
1916ca2c52aSchristos 
1926ca2c52aSchristos    For an ELF executable, the header defines both the virtual and real
1936ca2c52aSchristos    address at which each file section should be loaded.  At present, the
1946ca2c52aSchristos    real addresses that are specified in the header are ignored, the file
1956ca2c52aSchristos    instead being loaded in to physical memory in a linear fashion.
1966ca2c52aSchristos 
1976ca2c52aSchristos    When claiming memory, this device assumes that the #address-cells
1986ca2c52aSchristos    and #size-cells is one.  For future implementations, this may not
1996ca2c52aSchristos    be the case.
2006ca2c52aSchristos 
2016ca2c52aSchristos    */
2026ca2c52aSchristos 
2036ca2c52aSchristos 
2046ca2c52aSchristos 
2056ca2c52aSchristos static void
htab_decode_hash_table(device * me,unsigned32 * htaborg,unsigned32 * htabmask)2066ca2c52aSchristos htab_decode_hash_table(device *me,
2076ca2c52aSchristos 		       unsigned32 *htaborg,
2086ca2c52aSchristos 		       unsigned32 *htabmask)
2096ca2c52aSchristos {
2106ca2c52aSchristos   unsigned_word htab_ra;
2116ca2c52aSchristos   unsigned htab_nr_bytes;
2126ca2c52aSchristos   unsigned n;
2136ca2c52aSchristos   device *parent = device_parent(me);
2146ca2c52aSchristos   /* determine the location/size of the hash table */
2156ca2c52aSchristos   if (parent == NULL
2166ca2c52aSchristos       || strcmp(device_name(parent), "htab") != 0)
2176ca2c52aSchristos     device_error(parent, "must be a htab device");
2186ca2c52aSchristos   htab_ra = device_find_integer_property(parent, "real-address");
2196ca2c52aSchristos   htab_nr_bytes = device_find_integer_property(parent, "nr-bytes");
2206ca2c52aSchristos   if (htab_nr_bytes < 0x10000) {
2216ca2c52aSchristos     device_error(parent, "htab size 0x%x less than 0x1000",
2226ca2c52aSchristos 		 htab_nr_bytes);
2236ca2c52aSchristos   }
2246ca2c52aSchristos   for (n = htab_nr_bytes; n > 1; n = n / 2) {
2256ca2c52aSchristos     if (n % 2 != 0)
2266ca2c52aSchristos       device_error(parent, "htab size 0x%x not a power of two",
2276ca2c52aSchristos 		   htab_nr_bytes);
2286ca2c52aSchristos   }
2296ca2c52aSchristos   *htaborg = htab_ra;
2306ca2c52aSchristos   /* Position the HTABMASK ready for use against a hashed address and
2316ca2c52aSchristos      not ready for insertion into SDR1.HTABMASK.  */
2326ca2c52aSchristos   *htabmask = MASKED32(htab_nr_bytes - 1, 7, 31-6);
2336ca2c52aSchristos   /* Check that the MASK and ADDRESS do not overlap.  */
2346ca2c52aSchristos   if ((htab_ra & (*htabmask)) != 0) {
2356ca2c52aSchristos     device_error(parent, "htaborg 0x%lx not aligned to htabmask 0x%lx",
2366ca2c52aSchristos 		 (unsigned long)*htaborg, (unsigned long)*htabmask);
2376ca2c52aSchristos   }
2386ca2c52aSchristos   DTRACE(htab, ("htab - htaborg=0x%lx htabmask=0x%lx\n",
2396ca2c52aSchristos 		(unsigned long)*htaborg, (unsigned long)*htabmask));
2406ca2c52aSchristos }
2416ca2c52aSchristos 
2426ca2c52aSchristos static void
htab_map_page(device * me,unsigned_word ra,unsigned64 va,unsigned wimg,unsigned pp,unsigned32 htaborg,unsigned32 htabmask)2436ca2c52aSchristos htab_map_page(device *me,
2446ca2c52aSchristos 	      unsigned_word ra,
2456ca2c52aSchristos 	      unsigned64 va,
2466ca2c52aSchristos 	      unsigned wimg,
2476ca2c52aSchristos 	      unsigned pp,
2486ca2c52aSchristos 	      unsigned32 htaborg,
2496ca2c52aSchristos 	      unsigned32 htabmask)
2506ca2c52aSchristos {
2516ca2c52aSchristos   /* keep everything left shifted so that the numbering is easier */
2526ca2c52aSchristos   unsigned64 vpn = va << 12;
2536ca2c52aSchristos   unsigned32 vsid = INSERTED32(EXTRACTED64(vpn, 0, 23), 0, 23);
2546ca2c52aSchristos   unsigned32 vpage = INSERTED32(EXTRACTED64(vpn, 24, 39), 0, 15);
2556ca2c52aSchristos   unsigned32 hash = INSERTED32(EXTRACTED32(vsid, 5, 23)
2566ca2c52aSchristos 			       ^ EXTRACTED32(vpage, 0, 15),
2576ca2c52aSchristos 			       7, 31-6);
2586ca2c52aSchristos   int h;
2596ca2c52aSchristos   for (h = 0; h < 2; h++) {
2606ca2c52aSchristos     unsigned32 pteg = (htaborg | (hash & htabmask));
2616ca2c52aSchristos     int pti;
2626ca2c52aSchristos     for (pti = 0; pti < 8; pti++) {
2636ca2c52aSchristos       unsigned32 pte = pteg + 8 * pti;
2646ca2c52aSchristos       unsigned32 current_target_pte0;
2656ca2c52aSchristos       unsigned32 current_pte0;
2666ca2c52aSchristos       if (device_dma_read_buffer(device_parent(me),
2676ca2c52aSchristos 				 &current_target_pte0,
2686ca2c52aSchristos 				 0, /*space*/
2696ca2c52aSchristos 				 pte,
2706ca2c52aSchristos 				 sizeof(current_target_pte0)) != 4)
2716ca2c52aSchristos 	device_error(me, "failed to read a pte at 0x%lx", (unsigned long)pte);
2726ca2c52aSchristos       current_pte0 = T2H_4(current_target_pte0);
2736ca2c52aSchristos       if (MASKED32(current_pte0, 0, 0)) {
2746ca2c52aSchristos 	/* full pte, check it isn't already mapping the same virtual
2756ca2c52aSchristos            address */
2766ca2c52aSchristos 	unsigned32 curr_vsid = INSERTED32(EXTRACTED32(current_pte0, 1, 24), 0, 23);
2776ca2c52aSchristos 	unsigned32 curr_api = INSERTED32(EXTRACTED32(current_pte0, 26, 31), 0, 5);
2786ca2c52aSchristos 	unsigned32 curr_h = EXTRACTED32(current_pte0, 25, 25);
2796ca2c52aSchristos 	if (curr_h == h
2806ca2c52aSchristos 	    && curr_vsid == vsid
2816ca2c52aSchristos 	    && curr_api == MASKED32(vpage, 0, 5))
2826ca2c52aSchristos 	  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",
2836ca2c52aSchristos 		       (unsigned long)va,
2846ca2c52aSchristos 		       (unsigned long)ra,
2856ca2c52aSchristos 		       (unsigned long)vsid,
2866ca2c52aSchristos 		       h,
2876ca2c52aSchristos 		       (unsigned long)vpage,
2886ca2c52aSchristos 		       (unsigned long)hash,
2896ca2c52aSchristos 		       (unsigned long)pteg,
2906ca2c52aSchristos 		       pti * 8,
2916ca2c52aSchristos 		       (unsigned long)current_pte0);
2926ca2c52aSchristos       }
2936ca2c52aSchristos       else {
2946ca2c52aSchristos 	/* empty pte fill it */
2956ca2c52aSchristos 	unsigned32 pte0 = (MASK32(0, 0)
2966ca2c52aSchristos 			   | INSERTED32(EXTRACTED32(vsid, 0, 23), 1, 24)
2976ca2c52aSchristos 			   | INSERTED32(h, 25, 25)
2986ca2c52aSchristos 			   | INSERTED32(EXTRACTED32(vpage, 0, 5), 26, 31));
2996ca2c52aSchristos 	unsigned32 target_pte0 = H2T_4(pte0);
3006ca2c52aSchristos 	unsigned32 pte1 = (INSERTED32(EXTRACTED32(ra, 0, 19), 0, 19)
3016ca2c52aSchristos 			   | INSERTED32(wimg, 25, 28)
3026ca2c52aSchristos 			   | INSERTED32(pp, 30, 31));
3036ca2c52aSchristos 	unsigned32 target_pte1 = H2T_4(pte1);
3046ca2c52aSchristos 	if (device_dma_write_buffer(device_parent(me),
3056ca2c52aSchristos 				    &target_pte0,
3066ca2c52aSchristos 				    0, /*space*/
3076ca2c52aSchristos 				    pte,
3086ca2c52aSchristos 				    sizeof(target_pte0),
3096ca2c52aSchristos 				    1/*ro?*/) != 4
3106ca2c52aSchristos 	    || device_dma_write_buffer(device_parent(me),
3116ca2c52aSchristos 				       &target_pte1,
3126ca2c52aSchristos 				       0, /*space*/
3136ca2c52aSchristos 				       pte + 4,
3146ca2c52aSchristos 				       sizeof(target_pte1),
3156ca2c52aSchristos 				       1/*ro?*/) != 4)
3166ca2c52aSchristos 	  device_error(me, "failed to write a pte a 0x%lx", (unsigned long)pte);
3176ca2c52aSchristos 	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",
3186ca2c52aSchristos 		      (unsigned long)va,
3196ca2c52aSchristos 		      (unsigned long)ra,
3206ca2c52aSchristos 		      (unsigned long)vsid,
3216ca2c52aSchristos 		      h,
3226ca2c52aSchristos 		      (unsigned long)vpage,
3236ca2c52aSchristos 		      (unsigned long)hash,
3246ca2c52aSchristos 		      (unsigned long)pteg,
3256ca2c52aSchristos 		      pti * 8,
3266ca2c52aSchristos 		      (unsigned long)pte0,
3276ca2c52aSchristos 		      (unsigned long)pte1));
3286ca2c52aSchristos 	return;
3296ca2c52aSchristos       }
3306ca2c52aSchristos     }
3316ca2c52aSchristos     /* re-hash */
3326ca2c52aSchristos     hash = MASKED32(~hash, 0, 18);
3336ca2c52aSchristos   }
3346ca2c52aSchristos }
3356ca2c52aSchristos 
3366ca2c52aSchristos static unsigned_word
claim_memory(device * me,device_instance * memory,unsigned_word ra,unsigned_word size)3376ca2c52aSchristos claim_memory(device *me,
3386ca2c52aSchristos 	     device_instance *memory,
3396ca2c52aSchristos 	     unsigned_word ra,
3406ca2c52aSchristos 	     unsigned_word size)
3416ca2c52aSchristos {
3426ca2c52aSchristos   unsigned32 args[3];
3436ca2c52aSchristos   unsigned32 results[1];
3446ca2c52aSchristos   int status;
3456ca2c52aSchristos   args[0] = 0; /* alignment */
3466ca2c52aSchristos   args[1] = size;
3476ca2c52aSchristos   args[2] = ra;
3486ca2c52aSchristos   status = device_instance_call_method(memory, "claim", 3, args, 1, results);
3496ca2c52aSchristos   if (status != 0)
3506ca2c52aSchristos     device_error(me, "failed to claim memory");
3516ca2c52aSchristos   return results[0];
3526ca2c52aSchristos }
3536ca2c52aSchristos 
3546ca2c52aSchristos static void
htab_map_region(device * me,device_instance * memory,unsigned_word pte_ra,unsigned64 pte_va,unsigned nr_bytes,unsigned wimg,unsigned pp,unsigned32 htaborg,unsigned32 htabmask)3556ca2c52aSchristos htab_map_region(device *me,
3566ca2c52aSchristos 		device_instance *memory,
3576ca2c52aSchristos 		unsigned_word pte_ra,
3586ca2c52aSchristos 		unsigned64 pte_va,
3596ca2c52aSchristos 		unsigned nr_bytes,
3606ca2c52aSchristos 		unsigned wimg,
3616ca2c52aSchristos 		unsigned pp,
3626ca2c52aSchristos 		unsigned32 htaborg,
3636ca2c52aSchristos 		unsigned32 htabmask)
3646ca2c52aSchristos {
3656ca2c52aSchristos   unsigned_word ra;
3666ca2c52aSchristos   unsigned64 va;
3676ca2c52aSchristos   /* claim the memory */
3686ca2c52aSchristos   if (memory != NULL)
3696ca2c52aSchristos     claim_memory(me, memory, pte_ra, nr_bytes);
3706ca2c52aSchristos   /* go through all pages and create a pte for each */
3716ca2c52aSchristos   for (ra = pte_ra, va = pte_va;
3726ca2c52aSchristos        ra < pte_ra + nr_bytes;
3736ca2c52aSchristos        ra += 0x1000, va += 0x1000) {
3746ca2c52aSchristos     htab_map_page(me, ra, va, wimg, pp, htaborg, htabmask);
3756ca2c52aSchristos   }
3766ca2c52aSchristos }
3776ca2c52aSchristos 
3786ca2c52aSchristos typedef struct _htab_binary_sizes {
3796ca2c52aSchristos   unsigned_word text_ra;
3806ca2c52aSchristos   unsigned_word text_base;
3816ca2c52aSchristos   unsigned_word text_bound;
3826ca2c52aSchristos   unsigned_word data_ra;
3836ca2c52aSchristos   unsigned_word data_base;
3846ca2c52aSchristos   unsigned data_bound;
3856ca2c52aSchristos   device *me;
3866ca2c52aSchristos } htab_binary_sizes;
3876ca2c52aSchristos 
3886ca2c52aSchristos static void
htab_sum_binary(bfd * abfd,sec_ptr sec,PTR data)3896ca2c52aSchristos htab_sum_binary(bfd *abfd,
3906ca2c52aSchristos 		sec_ptr sec,
3916ca2c52aSchristos 		PTR data)
3926ca2c52aSchristos {
3936ca2c52aSchristos   htab_binary_sizes *sizes = (htab_binary_sizes*)data;
394*184b2d41Schristos   unsigned_word size = bfd_section_size (sec);
395*184b2d41Schristos   unsigned_word vma = bfd_section_vma (sec);
396*184b2d41Schristos   unsigned_word ra = bfd_section_lma (sec);
3976ca2c52aSchristos 
3986ca2c52aSchristos   /* skip the section if no memory to allocate */
399*184b2d41Schristos   if (! (bfd_section_flags (sec) & SEC_ALLOC))
4006ca2c52aSchristos     return;
4016ca2c52aSchristos 
402*184b2d41Schristos   if ((bfd_section_flags (sec) & SEC_CODE)
403*184b2d41Schristos       || (bfd_section_flags (sec) & SEC_READONLY)) {
4046ca2c52aSchristos     if (sizes->text_bound < vma + size)
4056ca2c52aSchristos       sizes->text_bound = ALIGN_PAGE(vma + size);
4066ca2c52aSchristos     if (sizes->text_base > vma)
4076ca2c52aSchristos       sizes->text_base = FLOOR_PAGE(vma);
4086ca2c52aSchristos     if (sizes->text_ra > ra)
4096ca2c52aSchristos       sizes->text_ra = FLOOR_PAGE(ra);
4106ca2c52aSchristos   }
411*184b2d41Schristos   else if ((bfd_section_flags (sec) & SEC_DATA)
412*184b2d41Schristos 	   || (bfd_section_flags (sec) & SEC_ALLOC)) {
4136ca2c52aSchristos     if (sizes->data_bound < vma + size)
4146ca2c52aSchristos       sizes->data_bound = ALIGN_PAGE(vma + size);
4156ca2c52aSchristos     if (sizes->data_base > vma)
4166ca2c52aSchristos       sizes->data_base = FLOOR_PAGE(vma);
4176ca2c52aSchristos     if (sizes->data_ra > ra)
4186ca2c52aSchristos       sizes->data_ra = FLOOR_PAGE(ra);
4196ca2c52aSchristos   }
4206ca2c52aSchristos }
4216ca2c52aSchristos 
4226ca2c52aSchristos static void
htab_dma_binary(bfd * abfd,sec_ptr sec,PTR data)4236ca2c52aSchristos htab_dma_binary(bfd *abfd,
4246ca2c52aSchristos 		sec_ptr sec,
4256ca2c52aSchristos 		PTR data)
4266ca2c52aSchristos {
4276ca2c52aSchristos   htab_binary_sizes *sizes = (htab_binary_sizes*)data;
4286ca2c52aSchristos   void *section_init;
4296ca2c52aSchristos   unsigned_word section_vma;
4306ca2c52aSchristos   unsigned_word section_size;
4316ca2c52aSchristos   unsigned_word section_ra;
4326ca2c52aSchristos   device *me = sizes->me;
4336ca2c52aSchristos 
4346ca2c52aSchristos   /* skip the section if no memory to allocate */
435*184b2d41Schristos   if (! (bfd_section_flags (sec) & SEC_ALLOC))
4366ca2c52aSchristos     return;
4376ca2c52aSchristos 
4386ca2c52aSchristos   /* check/ignore any sections of size zero */
439*184b2d41Schristos   section_size = bfd_section_size (sec);
4406ca2c52aSchristos   if (section_size == 0)
4416ca2c52aSchristos     return;
4426ca2c52aSchristos 
4436ca2c52aSchristos   /* if nothing to load, ignore this one */
444*184b2d41Schristos   if (! (bfd_section_flags (sec) & SEC_LOAD))
4456ca2c52aSchristos     return;
4466ca2c52aSchristos 
4476ca2c52aSchristos   /* find where it is to go */
448*184b2d41Schristos   section_vma = bfd_section_vma (sec);
4496ca2c52aSchristos   section_ra = 0;
450*184b2d41Schristos   if ((bfd_section_flags (sec) & SEC_CODE)
451*184b2d41Schristos       || (bfd_section_flags (sec) & SEC_READONLY))
4526ca2c52aSchristos     section_ra = (section_vma - sizes->text_base + sizes->text_ra);
453*184b2d41Schristos   else if ((bfd_section_flags (sec) & SEC_DATA))
4546ca2c52aSchristos     section_ra = (section_vma - sizes->data_base + sizes->data_ra);
4556ca2c52aSchristos   else
4566ca2c52aSchristos     return; /* just ignore it */
4576ca2c52aSchristos 
4586ca2c52aSchristos   DTRACE(htab,
4596ca2c52aSchristos 	 ("load - name=%-7s vma=0x%.8lx size=%6ld ra=0x%.8lx flags=%3lx(%s%s%s%s%s )\n",
460*184b2d41Schristos 	  bfd_section_name (sec),
4616ca2c52aSchristos 	  (long)section_vma,
4626ca2c52aSchristos 	  (long)section_size,
4636ca2c52aSchristos 	  (long)section_ra,
464*184b2d41Schristos 	  (long)bfd_section_flags (sec),
465*184b2d41Schristos 	  bfd_section_flags (sec) & SEC_LOAD ? " LOAD" : "",
466*184b2d41Schristos 	  bfd_section_flags (sec) & SEC_CODE ? " CODE" : "",
467*184b2d41Schristos 	  bfd_section_flags (sec) & SEC_DATA ? " DATA" : "",
468*184b2d41Schristos 	  bfd_section_flags (sec) & SEC_ALLOC ? " ALLOC" : "",
469*184b2d41Schristos 	  bfd_section_flags (sec) & SEC_READONLY ? " READONLY" : ""
4706ca2c52aSchristos 	  ));
4716ca2c52aSchristos 
4726ca2c52aSchristos   /* dma in the sections data */
4736ca2c52aSchristos   section_init = zalloc(section_size);
4746ca2c52aSchristos   if (!bfd_get_section_contents(abfd,
4756ca2c52aSchristos 				sec,
4766ca2c52aSchristos 				section_init, 0,
4776ca2c52aSchristos 				section_size)) {
4786ca2c52aSchristos     bfd_perror("devices/pte");
4796ca2c52aSchristos     device_error(me, "no data loaded");
4806ca2c52aSchristos   }
4816ca2c52aSchristos   if (device_dma_write_buffer(device_parent(me),
4826ca2c52aSchristos 			      section_init,
4836ca2c52aSchristos 			      0 /*space*/,
4846ca2c52aSchristos 			      section_ra,
4856ca2c52aSchristos 			      section_size,
4866ca2c52aSchristos 			      1 /*violate_read_only*/)
4876ca2c52aSchristos       != section_size)
4886ca2c52aSchristos     device_error(me, "broken dma transfer");
4896ca2c52aSchristos   free(section_init); /* only free if load */
4906ca2c52aSchristos }
4916ca2c52aSchristos 
4926ca2c52aSchristos /* create a memory map from a binaries virtual addresses to a copy of
4936ca2c52aSchristos    the binary laid out linearly in memory */
4946ca2c52aSchristos 
4956ca2c52aSchristos static void
htab_map_binary(device * me,device_instance * memory,unsigned_word ra,unsigned wimg,unsigned pp,const char * file_name,unsigned32 htaborg,unsigned32 htabmask)4966ca2c52aSchristos htab_map_binary(device *me,
4976ca2c52aSchristos 		device_instance *memory,
4986ca2c52aSchristos 		unsigned_word ra,
4996ca2c52aSchristos 		unsigned wimg,
5006ca2c52aSchristos 		unsigned pp,
5016ca2c52aSchristos 		const char *file_name,
5026ca2c52aSchristos 		unsigned32 htaborg,
5036ca2c52aSchristos 		unsigned32 htabmask)
5046ca2c52aSchristos {
5056ca2c52aSchristos   htab_binary_sizes sizes;
5066ca2c52aSchristos   bfd *image;
5076ca2c52aSchristos   sizes.text_ra = -1;
5086ca2c52aSchristos   sizes.data_ra = -1;
5096ca2c52aSchristos   sizes.text_base = -1;
5106ca2c52aSchristos   sizes.data_base = -1;
5116ca2c52aSchristos   sizes.text_bound = 0;
5126ca2c52aSchristos   sizes.data_bound = 0;
5136ca2c52aSchristos   sizes.me = me;
5146ca2c52aSchristos 
5156ca2c52aSchristos   /* open the file */
5166ca2c52aSchristos   image = bfd_openr(file_name, NULL);
5176ca2c52aSchristos   if (image == NULL) {
5186ca2c52aSchristos     bfd_perror("devices/pte");
5196ca2c52aSchristos     device_error(me, "the file %s not loaded", file_name);
5206ca2c52aSchristos   }
5216ca2c52aSchristos 
5226ca2c52aSchristos   /* check it is valid */
5236ca2c52aSchristos   if (!bfd_check_format(image, bfd_object)) {
5246ca2c52aSchristos     bfd_close(image);
5256ca2c52aSchristos     device_error(me, "the file %s has an invalid binary format", file_name);
5266ca2c52aSchristos   }
5276ca2c52aSchristos 
5286ca2c52aSchristos   /* determine the size of each of the files regions */
5296ca2c52aSchristos   bfd_map_over_sections (image, htab_sum_binary, (PTR) &sizes);
5306ca2c52aSchristos 
5316ca2c52aSchristos   /* if needed, determine the real addresses of the sections */
5326ca2c52aSchristos   if (ra != -1) {
5336ca2c52aSchristos     sizes.text_ra = ra;
5346ca2c52aSchristos     sizes.data_ra = ALIGN_PAGE(sizes.text_ra +
5356ca2c52aSchristos 			       (sizes.text_bound - sizes.text_base));
5366ca2c52aSchristos   }
5376ca2c52aSchristos 
5386ca2c52aSchristos   DTRACE(htab, ("text map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
5396ca2c52aSchristos 		(unsigned long)sizes.text_base,
5406ca2c52aSchristos 		(unsigned long)sizes.text_bound,
5416ca2c52aSchristos 		(unsigned long)sizes.text_ra));
5426ca2c52aSchristos   DTRACE(htab, ("data map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
5436ca2c52aSchristos 		(unsigned long)sizes.data_base,
5446ca2c52aSchristos 		(unsigned long)sizes.data_bound,
5456ca2c52aSchristos 		(unsigned long)sizes.data_ra));
5466ca2c52aSchristos 
5476ca2c52aSchristos   /* check for and fix a botched image (text and data segments
5486ca2c52aSchristos      overlap) */
5496ca2c52aSchristos   if ((sizes.text_base <= sizes.data_base
5506ca2c52aSchristos        && sizes.text_bound >= sizes.data_bound)
5516ca2c52aSchristos       || (sizes.data_base <= sizes.text_base
5526ca2c52aSchristos 	  && sizes.data_bound >= sizes.text_bound)
5536ca2c52aSchristos       || (sizes.text_bound > sizes.data_base
5546ca2c52aSchristos 	  && sizes.text_bound <= sizes.data_bound)
5556ca2c52aSchristos       || (sizes.text_base >= sizes.data_base
5566ca2c52aSchristos 	  && sizes.text_base < sizes.data_bound)) {
5576ca2c52aSchristos     DTRACE(htab, ("text and data segment overlaped - using just data segment\n"));
5586ca2c52aSchristos     /* check va->ra linear */
5596ca2c52aSchristos     if ((sizes.text_base - sizes.text_ra)
5606ca2c52aSchristos 	!= (sizes.data_base - sizes.data_ra))
5616ca2c52aSchristos       device_error(me, "overlapping but missaligned text and data segments");
5626ca2c52aSchristos     /* enlarge the data segment */
5636ca2c52aSchristos     if (sizes.text_base < sizes.data_base)
5646ca2c52aSchristos       sizes.data_base = sizes.text_base;
5656ca2c52aSchristos     if (sizes.text_bound > sizes.data_bound)
5666ca2c52aSchristos       sizes.data_bound = sizes.text_bound;
5676ca2c52aSchristos     if (sizes.text_ra < sizes.data_ra)
5686ca2c52aSchristos       sizes.data_ra = sizes.text_ra;
5696ca2c52aSchristos     /* zap the text segment */
5706ca2c52aSchristos     sizes.text_base = 0;
5716ca2c52aSchristos     sizes.text_bound = 0;
5726ca2c52aSchristos     sizes.text_ra = 0;
5736ca2c52aSchristos     DTRACE(htab, ("common map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
5746ca2c52aSchristos 		  (unsigned long)sizes.data_base,
5756ca2c52aSchristos 		  (unsigned long)sizes.data_bound,
5766ca2c52aSchristos 		  (unsigned long)sizes.data_ra));
5776ca2c52aSchristos   }
5786ca2c52aSchristos 
5796ca2c52aSchristos   /* set up virtual memory maps for each of the regions */
5806ca2c52aSchristos   if (sizes.text_bound - sizes.text_base > 0) {
5816ca2c52aSchristos     htab_map_region(me, memory, sizes.text_ra, sizes.text_base,
5826ca2c52aSchristos 		    sizes.text_bound - sizes.text_base,
5836ca2c52aSchristos 		    wimg, pp,
5846ca2c52aSchristos 		    htaborg, htabmask);
5856ca2c52aSchristos   }
5866ca2c52aSchristos 
5876ca2c52aSchristos   htab_map_region(me, memory, sizes.data_ra, sizes.data_base,
5886ca2c52aSchristos 		  sizes.data_bound - sizes.data_base,
5896ca2c52aSchristos 		  wimg, pp,
5906ca2c52aSchristos 		  htaborg, htabmask);
5916ca2c52aSchristos 
5926ca2c52aSchristos   /* dma the sections into physical memory */
5936ca2c52aSchristos   bfd_map_over_sections (image, htab_dma_binary, (PTR) &sizes);
5946ca2c52aSchristos }
5956ca2c52aSchristos 
5966ca2c52aSchristos static void
htab_init_data_callback(device * me)5976ca2c52aSchristos htab_init_data_callback(device *me)
5986ca2c52aSchristos {
5996ca2c52aSchristos   device_instance *memory = NULL;
6006ca2c52aSchristos   if (WITH_TARGET_WORD_BITSIZE != 32)
6016ca2c52aSchristos     device_error(me, "only 32bit targets currently suported");
6026ca2c52aSchristos 
6036ca2c52aSchristos   /* find memory device */
6046ca2c52aSchristos   if (device_find_property(me, "claim") != NULL)
6056ca2c52aSchristos     memory = tree_find_ihandle_property(me, "/chosen/memory");
6066ca2c52aSchristos 
6076ca2c52aSchristos   /* for the htab, just allocate space for it */
6086ca2c52aSchristos   if (strcmp(device_name(me), "htab") == 0) {
6096ca2c52aSchristos     unsigned_word address = device_find_integer_property(me, "real-address");
6106ca2c52aSchristos     unsigned_word length = device_find_integer_property(me, "nr-bytes");
6116ca2c52aSchristos     unsigned_word base = claim_memory(me, memory, address, length);
6126ca2c52aSchristos     if (base == -1 || base != address)
6136ca2c52aSchristos       device_error(me, "cannot allocate hash table");
6146ca2c52aSchristos   }
6156ca2c52aSchristos 
6166ca2c52aSchristos   /* for the pte, do all the real work */
6176ca2c52aSchristos   if (strcmp(device_name(me), "pte") == 0) {
6186ca2c52aSchristos     unsigned32 htaborg;
6196ca2c52aSchristos     unsigned32 htabmask;
6206ca2c52aSchristos 
6216ca2c52aSchristos     htab_decode_hash_table(me, &htaborg, &htabmask);
6226ca2c52aSchristos 
6236ca2c52aSchristos     if (device_find_property(me, "file-name") != NULL) {
6246ca2c52aSchristos       /* map in a binary */
6256ca2c52aSchristos       unsigned pte_wimg = device_find_integer_property(me, "wimg");
6266ca2c52aSchristos       unsigned pte_pp = device_find_integer_property(me, "pp");
6276ca2c52aSchristos       const char *file_name = device_find_string_property(me, "file-name");
6286ca2c52aSchristos       if (device_find_property(me, "real-address") != NULL) {
6296ca2c52aSchristos 	unsigned32 pte_ra = device_find_integer_property(me, "real-address");
6306ca2c52aSchristos 	DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, file-name=%s\n",
6316ca2c52aSchristos 		      (unsigned long)pte_ra,
6326ca2c52aSchristos 		      (unsigned long)pte_wimg,
6336ca2c52aSchristos 		      (long)pte_pp,
6346ca2c52aSchristos 		      file_name));
6356ca2c52aSchristos 	htab_map_binary(me, memory, pte_ra, pte_wimg, pte_pp, file_name,
6366ca2c52aSchristos 			htaborg, htabmask);
6376ca2c52aSchristos       }
6386ca2c52aSchristos       else {
6396ca2c52aSchristos 	DTRACE(htab, ("pte - wimg=%ld, pp=%ld, file-name=%s\n",
6406ca2c52aSchristos 		      (unsigned long)pte_wimg,
6416ca2c52aSchristos 		      (long)pte_pp,
6426ca2c52aSchristos 		      file_name));
6436ca2c52aSchristos 	htab_map_binary(me, memory, -1, pte_wimg, pte_pp, file_name,
6446ca2c52aSchristos 			htaborg, htabmask);
6456ca2c52aSchristos       }
6466ca2c52aSchristos     }
6476ca2c52aSchristos     else {
6486ca2c52aSchristos       /* handle a normal mapping definition */
6496ca2c52aSchristos       unsigned64 pte_va = 0;
6506ca2c52aSchristos       unsigned32 pte_ra = device_find_integer_property(me, "real-address");
6516ca2c52aSchristos       unsigned pte_nr_bytes = device_find_integer_property(me, "nr-bytes");
6526ca2c52aSchristos       unsigned pte_wimg = device_find_integer_property(me, "wimg");
6536ca2c52aSchristos       unsigned pte_pp = device_find_integer_property(me, "pp");
6546ca2c52aSchristos       signed_cell partial_va;
6556ca2c52aSchristos       int i;
6566ca2c52aSchristos       for (i = 0;
6576ca2c52aSchristos 	   device_find_integer_array_property(me, "virtual-address", i, &partial_va);
6586ca2c52aSchristos 	   i++) {
6596ca2c52aSchristos 	pte_va = (pte_va << WITH_TARGET_WORD_BITSIZE) | (unsigned_cell)partial_va;
6606ca2c52aSchristos       }
6616ca2c52aSchristos       DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, va=0x%lx, nr_bytes=%ld\n",
6626ca2c52aSchristos 		    (unsigned long)pte_ra,
6636ca2c52aSchristos 		    (long)pte_wimg,
6646ca2c52aSchristos 		    (long)pte_pp,
6656ca2c52aSchristos 		    (unsigned long)pte_va,
6666ca2c52aSchristos 		    (long)pte_nr_bytes));
6676ca2c52aSchristos       htab_map_region(me, memory, pte_ra, pte_va, pte_nr_bytes, pte_wimg, pte_pp,
6686ca2c52aSchristos 		      htaborg, htabmask);
6696ca2c52aSchristos     }
6706ca2c52aSchristos   }
6716ca2c52aSchristos }
6726ca2c52aSchristos 
6736ca2c52aSchristos 
6746ca2c52aSchristos static device_callbacks const htab_callbacks = {
6756ca2c52aSchristos   { NULL, htab_init_data_callback, },
6766ca2c52aSchristos   { NULL, }, /* address */
6776ca2c52aSchristos   { NULL, }, /* IO */
6786ca2c52aSchristos   { passthrough_device_dma_read_buffer,
6796ca2c52aSchristos     passthrough_device_dma_write_buffer, },
6806ca2c52aSchristos   { NULL, }, /* interrupt */
6816ca2c52aSchristos   { generic_device_unit_decode,
6826ca2c52aSchristos     generic_device_unit_encode, },
6836ca2c52aSchristos };
6846ca2c52aSchristos 
6856ca2c52aSchristos const device_descriptor hw_htab_device_descriptor[] = {
6866ca2c52aSchristos   { "htab", NULL, &htab_callbacks },
6876ca2c52aSchristos   { "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */
6886ca2c52aSchristos   { NULL },
6896ca2c52aSchristos };
6906ca2c52aSchristos 
6916ca2c52aSchristos #endif /* _HW_HTAB_C_ */
692