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 ¤t_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