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