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