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