1 |
106 |
markom |
/* This file is part of the program psim.
|
2 |
|
|
|
3 |
|
|
Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
|
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");
|
220 |
|
|
for (n = htab_nr_bytes; n > 1; n = n / 2) {
|
221 |
|
|
if (n % 2 != 0)
|
222 |
|
|
device_error(parent, "htab size 0x%x not a power of two",
|
223 |
|
|
htab_nr_bytes);
|
224 |
|
|
}
|
225 |
|
|
*htaborg = htab_ra;
|
226 |
|
|
*htabmask = MASKED32(htab_nr_bytes - 1, 7, 31-6);
|
227 |
|
|
if ((htab_ra & INSERTED32(*htabmask, 7, 15)) != 0) {
|
228 |
|
|
device_error(parent, "htaborg 0x%lx not aligned to htabmask 0x%lx",
|
229 |
|
|
(unsigned long)*htaborg, (unsigned long)*htabmask);
|
230 |
|
|
}
|
231 |
|
|
DTRACE(htab, ("htab - htaborg=0x%lx htabmask=0x%lx\n",
|
232 |
|
|
(unsigned long)*htaborg, (unsigned long)*htabmask));
|
233 |
|
|
}
|
234 |
|
|
|
235 |
|
|
static void
|
236 |
|
|
htab_map_page(device *me,
|
237 |
|
|
unsigned_word ra,
|
238 |
|
|
unsigned64 va,
|
239 |
|
|
unsigned wimg,
|
240 |
|
|
unsigned pp,
|
241 |
|
|
unsigned32 htaborg,
|
242 |
|
|
unsigned32 htabmask)
|
243 |
|
|
{
|
244 |
|
|
/* keep everything left shifted so that the numbering is easier */
|
245 |
|
|
unsigned64 vpn = va << 12;
|
246 |
|
|
unsigned32 vsid = INSERTED32(EXTRACTED64(vpn, 0, 23), 0, 23);
|
247 |
|
|
unsigned32 vpage = INSERTED32(EXTRACTED64(vpn, 24, 39), 0, 15);
|
248 |
|
|
unsigned32 hash = INSERTED32(EXTRACTED32(vsid, 5, 23)
|
249 |
|
|
^ EXTRACTED32(vpage, 0, 15),
|
250 |
|
|
7, 31-6);
|
251 |
|
|
int h;
|
252 |
|
|
for (h = 0; h < 2; h++) {
|
253 |
|
|
unsigned32 pteg = (htaborg | (hash & htabmask));
|
254 |
|
|
int pti;
|
255 |
|
|
for (pti = 0; pti < 8; pti++) {
|
256 |
|
|
unsigned32 pte = pteg + 8 * pti;
|
257 |
|
|
unsigned32 current_target_pte0;
|
258 |
|
|
unsigned32 current_pte0;
|
259 |
|
|
if (device_dma_read_buffer(device_parent(me),
|
260 |
|
|
¤t_target_pte0,
|
261 |
|
|
0, /*space*/
|
262 |
|
|
pte,
|
263 |
|
|
sizeof(current_target_pte0)) != 4)
|
264 |
|
|
device_error(me, "failed to read a pte at 0x%lx", (unsigned long)pte);
|
265 |
|
|
current_pte0 = T2H_4(current_target_pte0);
|
266 |
|
|
if (MASKED32(current_pte0, 0, 0)) {
|
267 |
|
|
/* full pte, check it isn't already mapping the same virtual
|
268 |
|
|
address */
|
269 |
|
|
unsigned32 curr_vsid = INSERTED32(EXTRACTED32(current_pte0, 1, 24), 0, 23);
|
270 |
|
|
unsigned32 curr_api = INSERTED32(EXTRACTED32(current_pte0, 26, 31), 0, 5);
|
271 |
|
|
unsigned32 curr_h = EXTRACTED32(current_pte0, 25, 25);
|
272 |
|
|
if (curr_h == h
|
273 |
|
|
&& curr_vsid == vsid
|
274 |
|
|
&& curr_api == MASKED32(vpage, 0, 5))
|
275 |
|
|
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",
|
276 |
|
|
(unsigned long)va,
|
277 |
|
|
(unsigned long)ra,
|
278 |
|
|
(unsigned long)vsid,
|
279 |
|
|
h,
|
280 |
|
|
(unsigned long)vpage,
|
281 |
|
|
(unsigned long)hash,
|
282 |
|
|
(unsigned long)pteg,
|
283 |
|
|
pti * 8,
|
284 |
|
|
(unsigned long)current_pte0);
|
285 |
|
|
}
|
286 |
|
|
else {
|
287 |
|
|
/* empty pte fill it */
|
288 |
|
|
unsigned32 pte0 = (MASK32(0, 0)
|
289 |
|
|
| INSERTED32(EXTRACTED32(vsid, 0, 23), 1, 24)
|
290 |
|
|
| INSERTED32(h, 25, 25)
|
291 |
|
|
| INSERTED32(EXTRACTED32(vpage, 0, 5), 26, 31));
|
292 |
|
|
unsigned32 target_pte0 = H2T_4(pte0);
|
293 |
|
|
unsigned32 pte1 = (INSERTED32(EXTRACTED32(ra, 0, 19), 0, 19)
|
294 |
|
|
| INSERTED32(wimg, 25, 28)
|
295 |
|
|
| INSERTED32(pp, 30, 31));
|
296 |
|
|
unsigned32 target_pte1 = H2T_4(pte1);
|
297 |
|
|
if (device_dma_write_buffer(device_parent(me),
|
298 |
|
|
&target_pte0,
|
299 |
|
|
0, /*space*/
|
300 |
|
|
pte,
|
301 |
|
|
sizeof(target_pte0),
|
302 |
|
|
1/*ro?*/) != 4
|
303 |
|
|
|| device_dma_write_buffer(device_parent(me),
|
304 |
|
|
&target_pte1,
|
305 |
|
|
0, /*space*/
|
306 |
|
|
pte + 4,
|
307 |
|
|
sizeof(target_pte1),
|
308 |
|
|
1/*ro?*/) != 4)
|
309 |
|
|
device_error(me, "failed to write a pte a 0x%lx", (unsigned long)pte);
|
310 |
|
|
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",
|
311 |
|
|
(unsigned long)va,
|
312 |
|
|
(unsigned long)ra,
|
313 |
|
|
(unsigned long)vsid,
|
314 |
|
|
h,
|
315 |
|
|
(unsigned long)vpage,
|
316 |
|
|
(unsigned long)hash,
|
317 |
|
|
(unsigned long)pteg,
|
318 |
|
|
pti * 8,
|
319 |
|
|
(unsigned long)pte0,
|
320 |
|
|
(unsigned long)pte1));
|
321 |
|
|
return;
|
322 |
|
|
}
|
323 |
|
|
}
|
324 |
|
|
/* re-hash */
|
325 |
|
|
hash = MASKED32(~hash, 0, 18);
|
326 |
|
|
}
|
327 |
|
|
}
|
328 |
|
|
|
329 |
|
|
static unsigned_word
|
330 |
|
|
claim_memory(device *me,
|
331 |
|
|
device_instance *memory,
|
332 |
|
|
unsigned_word ra,
|
333 |
|
|
unsigned_word size)
|
334 |
|
|
{
|
335 |
|
|
unsigned32 args[3];
|
336 |
|
|
unsigned32 results[1];
|
337 |
|
|
int status;
|
338 |
|
|
args[0] = 0; /* alignment */
|
339 |
|
|
args[1] = size;
|
340 |
|
|
args[2] = ra;
|
341 |
|
|
status = device_instance_call_method(memory, "claim", 3, args, 1, results);
|
342 |
|
|
if (status != 0)
|
343 |
|
|
device_error(me, "failed to claim memory");
|
344 |
|
|
return results[0];
|
345 |
|
|
}
|
346 |
|
|
|
347 |
|
|
static void
|
348 |
|
|
htab_map_region(device *me,
|
349 |
|
|
device_instance *memory,
|
350 |
|
|
unsigned_word pte_ra,
|
351 |
|
|
unsigned64 pte_va,
|
352 |
|
|
unsigned nr_bytes,
|
353 |
|
|
unsigned wimg,
|
354 |
|
|
unsigned pp,
|
355 |
|
|
unsigned32 htaborg,
|
356 |
|
|
unsigned32 htabmask)
|
357 |
|
|
{
|
358 |
|
|
unsigned_word ra;
|
359 |
|
|
unsigned64 va;
|
360 |
|
|
/* claim the memory */
|
361 |
|
|
if (memory != NULL)
|
362 |
|
|
claim_memory(me, memory, pte_ra, nr_bytes);
|
363 |
|
|
/* go through all pages and create a pte for each */
|
364 |
|
|
for (ra = pte_ra, va = pte_va;
|
365 |
|
|
ra < pte_ra + nr_bytes;
|
366 |
|
|
ra += 0x1000, va += 0x1000) {
|
367 |
|
|
htab_map_page(me, ra, va, wimg, pp, htaborg, htabmask);
|
368 |
|
|
}
|
369 |
|
|
}
|
370 |
|
|
|
371 |
|
|
typedef struct _htab_binary_sizes {
|
372 |
|
|
unsigned_word text_ra;
|
373 |
|
|
unsigned_word text_base;
|
374 |
|
|
unsigned_word text_bound;
|
375 |
|
|
unsigned_word data_ra;
|
376 |
|
|
unsigned_word data_base;
|
377 |
|
|
unsigned data_bound;
|
378 |
|
|
device *me;
|
379 |
|
|
} htab_binary_sizes;
|
380 |
|
|
|
381 |
|
|
static void
|
382 |
|
|
htab_sum_binary(bfd *abfd,
|
383 |
|
|
sec_ptr sec,
|
384 |
|
|
PTR data)
|
385 |
|
|
{
|
386 |
|
|
htab_binary_sizes *sizes = (htab_binary_sizes*)data;
|
387 |
|
|
unsigned_word size = bfd_get_section_size_before_reloc (sec);
|
388 |
|
|
unsigned_word vma = bfd_get_section_vma (abfd, sec);
|
389 |
|
|
#define bfd_get_section_lma(abfd, sec) ((sec)->lma + 0)
|
390 |
|
|
unsigned_word ra = bfd_get_section_lma (abfd, sec);
|
391 |
|
|
|
392 |
|
|
/* skip the section if no memory to allocate */
|
393 |
|
|
if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
|
394 |
|
|
return;
|
395 |
|
|
|
396 |
|
|
if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
|
397 |
|
|
|| (bfd_get_section_flags (abfd, sec) & SEC_READONLY)) {
|
398 |
|
|
if (sizes->text_bound < vma + size)
|
399 |
|
|
sizes->text_bound = ALIGN_PAGE(vma + size);
|
400 |
|
|
if (sizes->text_base > vma)
|
401 |
|
|
sizes->text_base = FLOOR_PAGE(vma);
|
402 |
|
|
if (sizes->text_ra > ra)
|
403 |
|
|
sizes->text_ra = FLOOR_PAGE(ra);
|
404 |
|
|
}
|
405 |
|
|
else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA)
|
406 |
|
|
|| (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)) {
|
407 |
|
|
if (sizes->data_bound < vma + size)
|
408 |
|
|
sizes->data_bound = ALIGN_PAGE(vma + size);
|
409 |
|
|
if (sizes->data_base > vma)
|
410 |
|
|
sizes->data_base = FLOOR_PAGE(vma);
|
411 |
|
|
if (sizes->data_ra > ra)
|
412 |
|
|
sizes->data_ra = FLOOR_PAGE(ra);
|
413 |
|
|
}
|
414 |
|
|
}
|
415 |
|
|
|
416 |
|
|
static void
|
417 |
|
|
htab_dma_binary(bfd *abfd,
|
418 |
|
|
sec_ptr sec,
|
419 |
|
|
PTR data)
|
420 |
|
|
{
|
421 |
|
|
htab_binary_sizes *sizes = (htab_binary_sizes*)data;
|
422 |
|
|
void *section_init;
|
423 |
|
|
unsigned_word section_vma;
|
424 |
|
|
unsigned_word section_size;
|
425 |
|
|
unsigned_word section_ra;
|
426 |
|
|
device *me = sizes->me;
|
427 |
|
|
|
428 |
|
|
/* skip the section if no memory to allocate */
|
429 |
|
|
if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
|
430 |
|
|
return;
|
431 |
|
|
|
432 |
|
|
/* check/ignore any sections of size zero */
|
433 |
|
|
section_size = bfd_get_section_size_before_reloc(sec);
|
434 |
|
|
if (section_size == 0)
|
435 |
|
|
return;
|
436 |
|
|
|
437 |
|
|
/* if nothing to load, ignore this one */
|
438 |
|
|
if (! (bfd_get_section_flags(abfd, sec) & SEC_LOAD))
|
439 |
|
|
return;
|
440 |
|
|
|
441 |
|
|
/* find where it is to go */
|
442 |
|
|
section_vma = bfd_get_section_vma(abfd, sec);
|
443 |
|
|
section_ra = 0;
|
444 |
|
|
if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
|
445 |
|
|
|| (bfd_get_section_flags (abfd, sec) & SEC_READONLY))
|
446 |
|
|
section_ra = (section_vma - sizes->text_base + sizes->text_ra);
|
447 |
|
|
else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA))
|
448 |
|
|
section_ra = (section_vma - sizes->data_base + sizes->data_ra);
|
449 |
|
|
else
|
450 |
|
|
return; /* just ignore it */
|
451 |
|
|
|
452 |
|
|
DTRACE(htab,
|
453 |
|
|
("load - name=%-7s vma=0x%.8lx size=%6ld ra=0x%.8lx flags=%3lx(%s%s%s%s%s )\n",
|
454 |
|
|
bfd_get_section_name(abfd, sec),
|
455 |
|
|
(long)section_vma,
|
456 |
|
|
(long)section_size,
|
457 |
|
|
(long)section_ra,
|
458 |
|
|
(long)bfd_get_section_flags(abfd, sec),
|
459 |
|
|
bfd_get_section_flags(abfd, sec) & SEC_LOAD ? " LOAD" : "",
|
460 |
|
|
bfd_get_section_flags(abfd, sec) & SEC_CODE ? " CODE" : "",
|
461 |
|
|
bfd_get_section_flags(abfd, sec) & SEC_DATA ? " DATA" : "",
|
462 |
|
|
bfd_get_section_flags(abfd, sec) & SEC_ALLOC ? " ALLOC" : "",
|
463 |
|
|
bfd_get_section_flags(abfd, sec) & SEC_READONLY ? " READONLY" : ""
|
464 |
|
|
));
|
465 |
|
|
|
466 |
|
|
/* dma in the sections data */
|
467 |
|
|
section_init = zalloc(section_size);
|
468 |
|
|
if (!bfd_get_section_contents(abfd,
|
469 |
|
|
sec,
|
470 |
|
|
section_init, 0,
|
471 |
|
|
section_size)) {
|
472 |
|
|
bfd_perror("devices/pte");
|
473 |
|
|
device_error(me, "no data loaded");
|
474 |
|
|
}
|
475 |
|
|
if (device_dma_write_buffer(device_parent(me),
|
476 |
|
|
section_init,
|
477 |
|
|
|
478 |
|
|
section_ra,
|
479 |
|
|
section_size,
|
480 |
|
|
1 /*violate_read_only*/)
|
481 |
|
|
!= section_size)
|
482 |
|
|
device_error(me, "broken dma transfer");
|
483 |
|
|
zfree(section_init); /* only free if load */
|
484 |
|
|
}
|
485 |
|
|
|
486 |
|
|
/* create a memory map from a binaries virtual addresses to a copy of
|
487 |
|
|
the binary laid out linearly in memory */
|
488 |
|
|
|
489 |
|
|
static void
|
490 |
|
|
htab_map_binary(device *me,
|
491 |
|
|
device_instance *memory,
|
492 |
|
|
unsigned_word ra,
|
493 |
|
|
unsigned wimg,
|
494 |
|
|
unsigned pp,
|
495 |
|
|
const char *file_name,
|
496 |
|
|
unsigned32 htaborg,
|
497 |
|
|
unsigned32 htabmask)
|
498 |
|
|
{
|
499 |
|
|
htab_binary_sizes sizes;
|
500 |
|
|
bfd *image;
|
501 |
|
|
sizes.text_ra = -1;
|
502 |
|
|
sizes.data_ra = -1;
|
503 |
|
|
sizes.text_base = -1;
|
504 |
|
|
sizes.data_base = -1;
|
505 |
|
|
sizes.text_bound = 0;
|
506 |
|
|
sizes.data_bound = 0;
|
507 |
|
|
sizes.me = me;
|
508 |
|
|
|
509 |
|
|
/* open the file */
|
510 |
|
|
image = bfd_openr(file_name, NULL);
|
511 |
|
|
if (image == NULL) {
|
512 |
|
|
bfd_perror("devices/pte");
|
513 |
|
|
device_error(me, "the file %s not loaded", file_name);
|
514 |
|
|
}
|
515 |
|
|
|
516 |
|
|
/* check it is valid */
|
517 |
|
|
if (!bfd_check_format(image, bfd_object)) {
|
518 |
|
|
bfd_close(image);
|
519 |
|
|
device_error(me, "the file %s has an invalid binary format", file_name);
|
520 |
|
|
}
|
521 |
|
|
|
522 |
|
|
/* determine the size of each of the files regions */
|
523 |
|
|
bfd_map_over_sections (image, htab_sum_binary, (PTR) &sizes);
|
524 |
|
|
|
525 |
|
|
/* if needed, determine the real addresses of the sections */
|
526 |
|
|
if (ra != -1) {
|
527 |
|
|
sizes.text_ra = ra;
|
528 |
|
|
sizes.data_ra = ALIGN_PAGE(sizes.text_ra +
|
529 |
|
|
(sizes.text_bound - sizes.text_base));
|
530 |
|
|
}
|
531 |
|
|
|
532 |
|
|
DTRACE(htab, ("text map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
|
533 |
|
|
(unsigned long)sizes.text_base,
|
534 |
|
|
(unsigned long)sizes.text_bound,
|
535 |
|
|
(unsigned long)sizes.text_ra));
|
536 |
|
|
DTRACE(htab, ("data map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
|
537 |
|
|
(unsigned long)sizes.data_base,
|
538 |
|
|
(unsigned long)sizes.data_bound,
|
539 |
|
|
(unsigned long)sizes.data_ra));
|
540 |
|
|
|
541 |
|
|
/* check for and fix a botched image (text and data segments
|
542 |
|
|
overlap) */
|
543 |
|
|
if ((sizes.text_base <= sizes.data_base
|
544 |
|
|
&& sizes.text_bound >= sizes.data_bound)
|
545 |
|
|
|| (sizes.data_base <= sizes.text_base
|
546 |
|
|
&& sizes.data_bound >= sizes.data_bound)
|
547 |
|
|
|| (sizes.text_bound > sizes.data_base
|
548 |
|
|
&& sizes.text_bound <= sizes.data_bound)
|
549 |
|
|
|| (sizes.text_base >= sizes.data_base
|
550 |
|
|
&& sizes.text_base < sizes.data_bound)) {
|
551 |
|
|
DTRACE(htab, ("text and data segment overlaped - using just data segment\n"));
|
552 |
|
|
/* check va->ra linear */
|
553 |
|
|
if ((sizes.text_base - sizes.text_ra)
|
554 |
|
|
!= (sizes.data_base - sizes.data_ra))
|
555 |
|
|
device_error(me, "overlapping but missaligned text and data segments");
|
556 |
|
|
/* enlarge the data segment */
|
557 |
|
|
if (sizes.text_base < sizes.data_base)
|
558 |
|
|
sizes.data_base = sizes.text_base;
|
559 |
|
|
if (sizes.text_bound > sizes.data_bound)
|
560 |
|
|
sizes.data_bound = sizes.text_bound;
|
561 |
|
|
if (sizes.text_ra < sizes.data_ra)
|
562 |
|
|
sizes.data_ra = sizes.text_ra;
|
563 |
|
|
/* zap the text segment */
|
564 |
|
|
sizes.text_base = 0;
|
565 |
|
|
sizes.text_bound = 0;
|
566 |
|
|
sizes.text_ra = 0;
|
567 |
|
|
DTRACE(htab, ("common map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
|
568 |
|
|
(unsigned long)sizes.data_base,
|
569 |
|
|
(unsigned long)sizes.data_bound,
|
570 |
|
|
(unsigned long)sizes.data_ra));
|
571 |
|
|
}
|
572 |
|
|
|
573 |
|
|
/* set up virtual memory maps for each of the regions */
|
574 |
|
|
htab_map_region(me, memory, sizes.text_ra, sizes.text_base,
|
575 |
|
|
sizes.text_bound - sizes.text_base,
|
576 |
|
|
wimg, pp,
|
577 |
|
|
htaborg, htabmask);
|
578 |
|
|
|
579 |
|
|
htab_map_region(me, memory, sizes.data_ra, sizes.data_base,
|
580 |
|
|
sizes.data_bound - sizes.data_base,
|
581 |
|
|
wimg, pp,
|
582 |
|
|
htaborg, htabmask);
|
583 |
|
|
|
584 |
|
|
/* dma the sections into physical memory */
|
585 |
|
|
bfd_map_over_sections (image, htab_dma_binary, (PTR) &sizes);
|
586 |
|
|
}
|
587 |
|
|
|
588 |
|
|
static void
|
589 |
|
|
htab_init_data_callback(device *me)
|
590 |
|
|
{
|
591 |
|
|
device_instance *memory = NULL;
|
592 |
|
|
if (WITH_TARGET_WORD_BITSIZE != 32)
|
593 |
|
|
device_error(me, "only 32bit targets currently suported");
|
594 |
|
|
|
595 |
|
|
/* find memory device */
|
596 |
|
|
if (device_find_property(me, "claim") != NULL)
|
597 |
|
|
memory = tree_find_ihandle_property(me, "/chosen/memory");
|
598 |
|
|
|
599 |
|
|
/* for the htab, just allocate space for it */
|
600 |
|
|
if (strcmp(device_name(me), "htab") == 0) {
|
601 |
|
|
unsigned_word address = device_find_integer_property(me, "real-address");
|
602 |
|
|
unsigned_word length = device_find_integer_property(me, "nr-bytes");
|
603 |
|
|
unsigned_word base = claim_memory(me, memory, address, length);
|
604 |
|
|
if (base == -1 || base != address)
|
605 |
|
|
device_error(me, "cannot allocate hash table");
|
606 |
|
|
}
|
607 |
|
|
|
608 |
|
|
/* for the pte, do all the real work */
|
609 |
|
|
if (strcmp(device_name(me), "pte") == 0) {
|
610 |
|
|
unsigned32 htaborg;
|
611 |
|
|
unsigned32 htabmask;
|
612 |
|
|
|
613 |
|
|
htab_decode_hash_table(me, &htaborg, &htabmask);
|
614 |
|
|
|
615 |
|
|
if (device_find_property(me, "file-name") != NULL) {
|
616 |
|
|
/* map in a binary */
|
617 |
|
|
unsigned pte_wimg = device_find_integer_property(me, "wimg");
|
618 |
|
|
unsigned pte_pp = device_find_integer_property(me, "pp");
|
619 |
|
|
const char *file_name = device_find_string_property(me, "file-name");
|
620 |
|
|
if (device_find_property(me, "real-address") != NULL) {
|
621 |
|
|
unsigned32 pte_ra = device_find_integer_property(me, "real-address");
|
622 |
|
|
DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, file-name=%s\n",
|
623 |
|
|
(unsigned long)pte_ra,
|
624 |
|
|
(unsigned long)pte_wimg,
|
625 |
|
|
(long)pte_pp,
|
626 |
|
|
file_name));
|
627 |
|
|
htab_map_binary(me, memory, pte_ra, pte_wimg, pte_pp, file_name,
|
628 |
|
|
htaborg, htabmask);
|
629 |
|
|
}
|
630 |
|
|
else {
|
631 |
|
|
DTRACE(htab, ("pte - wimg=%ld, pp=%ld, file-name=%s\n",
|
632 |
|
|
(unsigned long)pte_wimg,
|
633 |
|
|
(long)pte_pp,
|
634 |
|
|
file_name));
|
635 |
|
|
htab_map_binary(me, memory, -1, pte_wimg, pte_pp, file_name,
|
636 |
|
|
htaborg, htabmask);
|
637 |
|
|
}
|
638 |
|
|
}
|
639 |
|
|
else {
|
640 |
|
|
/* handle a normal mapping definition */
|
641 |
|
|
unsigned64 pte_va = 0;
|
642 |
|
|
unsigned32 pte_ra = device_find_integer_property(me, "real-address");
|
643 |
|
|
unsigned pte_nr_bytes = device_find_integer_property(me, "nr-bytes");
|
644 |
|
|
unsigned pte_wimg = device_find_integer_property(me, "wimg");
|
645 |
|
|
unsigned pte_pp = device_find_integer_property(me, "pp");
|
646 |
|
|
signed_cell partial_va;
|
647 |
|
|
int i;
|
648 |
|
|
for (i = 0;
|
649 |
|
|
device_find_integer_array_property(me, "virtual-address", i, &partial_va);
|
650 |
|
|
i++) {
|
651 |
|
|
pte_va = (pte_va << WITH_TARGET_WORD_BITSIZE) | (unsigned_cell)partial_va;
|
652 |
|
|
}
|
653 |
|
|
DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, va=0x%lx, nr_bytes=%ld\n",
|
654 |
|
|
(unsigned long)pte_ra,
|
655 |
|
|
(long)pte_wimg,
|
656 |
|
|
(long)pte_pp,
|
657 |
|
|
(unsigned long)pte_va,
|
658 |
|
|
(long)pte_nr_bytes));
|
659 |
|
|
htab_map_region(me, memory, pte_ra, pte_va, pte_nr_bytes, pte_wimg, pte_pp,
|
660 |
|
|
htaborg, htabmask);
|
661 |
|
|
}
|
662 |
|
|
}
|
663 |
|
|
}
|
664 |
|
|
|
665 |
|
|
|
666 |
|
|
static device_callbacks const htab_callbacks = {
|
667 |
|
|
{ NULL, htab_init_data_callback, },
|
668 |
|
|
{ NULL, }, /* address */
|
669 |
|
|
{ NULL, }, /* IO */
|
670 |
|
|
{ passthrough_device_dma_read_buffer,
|
671 |
|
|
passthrough_device_dma_write_buffer, },
|
672 |
|
|
{ NULL, }, /* interrupt */
|
673 |
|
|
{ generic_device_unit_decode,
|
674 |
|
|
generic_device_unit_encode, },
|
675 |
|
|
};
|
676 |
|
|
|
677 |
|
|
const device_descriptor hw_htab_device_descriptor[] = {
|
678 |
|
|
{ "htab", NULL, &htab_callbacks },
|
679 |
|
|
{ "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */
|
680 |
|
|
{ NULL },
|
681 |
|
|
};
|
682 |
|
|
|
683 |
|
|
#endif /* _HW_HTAB_C_ */
|