Latest changes from Andrew
[deliverable/binutils-gdb.git] / sim / ppc / hw_init.c
1 /* 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_INIT_C_
23 #define _HW_INIT_C_
24
25 #include "device_table.h"
26 #include "bfd.h"
27 #include "psim.h"
28
29
30 /* DMA a file into memory */
31 static int
32 dma_file(device *me,
33 const char *file_name,
34 unsigned_word addr)
35 {
36 int count;
37 int inc;
38 FILE *image;
39 char buf[1024];
40
41 /* get it open */
42 image = fopen(file_name, "r");
43 if (image == NULL)
44 return -1;
45
46 /* read it in slowly */
47 count = 0;
48 while (1) {
49 inc = fread(buf, 1, sizeof(buf), image);
50 if (feof(image) || ferror(image))
51 break;
52 if (device_dma_write_buffer(device_parent(me),
53 buf,
54 0 /*address-space*/,
55 addr+count,
56 inc /*nr-bytes*/,
57 1 /*violate ro*/) != inc) {
58 fclose(image);
59 return -1;
60 }
61 count += inc;
62 }
63
64 /* close down again */
65 fclose(image);
66
67 return count;
68 }
69
70
71 /* DEVICE
72
73 file - load a file into memory
74
75 DESCRIPTION
76
77 Loads the entire contents of <file-name> into memory at starting at
78 <real-address>. Assumes that memory exists for the load.
79
80 PROPERTIES
81
82 file-name = <string>
83
84 Name of the file to be loaded into memory
85
86 real-address = <integer>
87
88 Real address at which the file is to be loaded */
89
90 static void
91 hw_file_init_data_callback(device *me)
92 {
93 int count;
94 const char *file_name = device_find_string_property(me, "file-name");
95 unsigned_word addr = device_find_integer_property(me, "real-address");
96 /* load the file */
97 count = dma_file(me, file_name, addr);
98 if (count < 0)
99 device_error(me, "Problem loading file %s\n", file_name);
100 }
101
102
103 static device_callbacks const hw_file_callbacks = {
104 { NULL, hw_file_init_data_callback, },
105 { NULL, }, /* address */
106 { NULL, }, /* IO */
107 { NULL, }, /* DMA */
108 { NULL, }, /* interrupt */
109 { NULL, }, /* unit */
110 };
111
112
113 /* DEVICE
114
115 data - initialize a memory location
116
117 DESCRIPTION
118
119 A word sized quantity of data is written into memory, using the
120 targets byte ordering, at the specified memory location.
121
122 In the future this device will be extended so that it supports
123 initialization using other data types (eg array, ...)
124
125 PROPERTIES
126
127 data = <int>
128
129 Integer value to be loaded into memory
130
131 real-address = <integer>
132
133 Start address for the data. */
134
135
136 static void
137 hw_data_init_data_callback(device *me)
138 {
139 unsigned_word addr = device_find_integer_property(me, "real-address");
140 const device_property *data = device_find_property(me, "data");
141 if (data == NULL)
142 device_error(me, "missing property <data>\n");
143 switch (data->type) {
144 case integer_property:
145 {
146 unsigned32 buf = device_find_integer_property(me, "data");
147 H2T(buf);
148 if (device_dma_write_buffer(device_parent(me),
149 &buf,
150 0 /*address-space*/,
151 addr,
152 sizeof(buf), /*nr-bytes*/
153 1 /*violate ro*/) != sizeof(buf))
154 device_error(me, "Problem storing integer 0x%x at 0x%lx\n",
155 (unsigned)buf, (unsigned long)addr);
156 }
157 break;
158 default:
159 device_error(me, "Write of this data is not yet implemented\n");
160 break;
161 }
162 }
163
164
165 static device_callbacks const hw_data_callbacks = {
166 { NULL, hw_data_init_data_callback, },
167 { NULL, }, /* address */
168 { NULL, }, /* IO */
169 { NULL, }, /* DMA */
170 { NULL, }, /* interrupt */
171 { NULL, }, /* unit */
172 };
173
174
175 /* DEVICE
176
177 load-binary - load binary segments into memory
178
179 DESCRIPTION
180
181 Each loadable segment of the specified binary is loaded into memory
182 at its required address. It is assumed that the memory at those
183 addresses already exists.
184
185 This device is normally used to load an executable into memory as
186 part of real mode simulation.
187
188 PROPERTIES
189
190 file-name = <string>
191
192 Name of the binary to be loaded.
193
194 DEVICE
195
196 map-binary - map the binary into the users address space
197
198 DESCRIPTION
199
200 Similar to load-binary except that memory for each segment is
201 created before the corresponding data for the segment is loaded.
202
203 This device is normally used to load an executable into a user mode
204 simulation.
205
206 PROPERTIES
207
208 file-name = <string>
209
210 Name of the binary to be loaded.
211
212 */
213
214 static void
215 update_for_binary_section(bfd *abfd,
216 asection *the_section,
217 PTR obj)
218 {
219 unsigned_word section_vma;
220 unsigned_word section_size;
221 access_type access;
222 device *me = (device*)obj;
223
224 /* skip the section if no memory to allocate */
225 if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
226 return;
227
228 /* check/ignore any sections of size zero */
229 section_size = bfd_get_section_size_before_reloc(the_section);
230 if (section_size == 0)
231 return;
232
233 /* find where it is to go */
234 section_vma = bfd_get_section_vma(abfd, the_section);
235
236 DTRACE(binary,
237 ("name=%-7s, vma=0x%.8lx, size=%6ld, flags=%3lx(%s%s%s%s%s )\n",
238 bfd_get_section_name(abfd, the_section),
239 (long)section_vma,
240 (long)section_size,
241 (long)bfd_get_section_flags(abfd, the_section),
242 bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "",
243 bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "",
244 bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "",
245 bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "",
246 bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : ""
247 ));
248
249 /* If there is an .interp section, it means it needs a shared library interpreter. */
250 if (strcmp(".interp", bfd_get_section_name(abfd, the_section)) == 0)
251 error("Shared libraries are not yet supported.\n");
252
253 /* determine the devices access */
254 access = access_read;
255 if (bfd_get_section_flags(abfd, the_section) & SEC_CODE)
256 access |= access_exec;
257 if (!(bfd_get_section_flags(abfd, the_section) & SEC_READONLY))
258 access |= access_write;
259
260 /* if a map, pass up a request to create the memory in core */
261 if (strncmp(device_name(me), "map-binary", strlen("map-binary")) == 0)
262 device_attach_address(device_parent(me),
263 device_name(me),
264 attach_raw_memory,
265 0 /*address space*/,
266 section_vma,
267 section_size,
268 access,
269 me);
270
271 /* if a load dma in the required data */
272 if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) {
273 void *section_init = zalloc(section_size);
274 if (!bfd_get_section_contents(abfd,
275 the_section,
276 section_init, 0,
277 section_size)) {
278 bfd_perror("binary");
279 device_error(me, "load of data failed");
280 return;
281 }
282 if (device_dma_write_buffer(device_parent(me),
283 section_init,
284 0 /*space*/,
285 section_vma,
286 section_size,
287 1 /*violate_read_only*/)
288 != section_size)
289 device_error(me, "broken transfer\n");
290 zfree(section_init); /* only free if load */
291 }
292 }
293
294 static void
295 hw_binary_init_data_callback(device *me)
296 {
297 /* get the file name */
298 const char *file_name = device_find_string_property(me, "file-name");
299 bfd *image;
300
301 /* open the file */
302 image = bfd_openr(file_name, NULL);
303 if (image == NULL) {
304 bfd_perror("binary");
305 device_error(me, "Failed to open file %s\n", file_name);
306 }
307
308 /* check it is valid */
309 if (!bfd_check_format(image, bfd_object)) {
310 bfd_close(image);
311 device_error(me, "The file %s has an invalid binary format\n", file_name);
312 }
313
314 /* and the data sections */
315 bfd_map_over_sections(image,
316 update_for_binary_section,
317 (PTR)me);
318
319 bfd_close(image);
320 }
321
322
323 static device_callbacks const hw_binary_callbacks = {
324 { NULL, hw_binary_init_data_callback, },
325 { NULL, }, /* address */
326 { NULL, }, /* IO */
327 { NULL, }, /* DMA */
328 { NULL, }, /* interrupt */
329 { NULL, }, /* unit */
330 };
331
332
333 /* DEVICE
334
335 stack - create an initial stack frame in memory
336
337 DESCRIPTION
338
339 Creates a stack frame of the specified type in memory.
340
341 Due to the startup sequence gdb uses when commencing a simulation,
342 it is not possible for the data to be placed on the stack to be
343 specified as part of the device tree. Instead the arguments to be
344 pushed onto the stack are specified using an IOCTL call.
345
346 The IOCTL takes the additional arguments:
347
348 | unsigned_word stack_end -- where the stack should come down from
349 | char **argv -- ...
350 | char **envp -- ...
351
352 PROPERTIES
353
354 stack-type = <string>
355
356 The form of the stack frame that is to be created.
357
358 */
359
360 static int
361 sizeof_argument_strings(char **arg)
362 {
363 int sizeof_strings = 0;
364
365 /* robust */
366 if (arg == NULL)
367 return 0;
368
369 /* add up all the string sizes (padding as we go) */
370 for (; *arg != NULL; arg++) {
371 int len = strlen(*arg) + 1;
372 sizeof_strings += ALIGN_8(len);
373 }
374
375 return sizeof_strings;
376 }
377
378 static int
379 number_of_arguments(char **arg)
380 {
381 int nr;
382 if (arg == NULL)
383 return 0;
384 for (nr = 0; *arg != NULL; arg++, nr++);
385 return nr;
386 }
387
388 static int
389 sizeof_arguments(char **arg)
390 {
391 return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
392 }
393
394 static void
395 write_stack_arguments(device *me,
396 char **arg,
397 unsigned_word start_block,
398 unsigned_word end_block,
399 unsigned_word start_arg,
400 unsigned_word end_arg)
401 {
402 DTRACE(stack,
403 ("write_stack_arguments(device=%s, arg=0x%lx, start_block=0x%lx, end_block=0x%lx, start_arg=0x%lx, end_arg=0x%lx)\n",
404 device_name(me), (long)arg, (long)start_block, (long)end_block, (long)start_arg, (long)end_arg));
405 if (arg == NULL)
406 device_error(me, "Attempt to write a null array onto the stack\n");
407 /* only copy in arguments, memory is already zero */
408 for (; *arg != NULL; arg++) {
409 int len = strlen(*arg)+1;
410 unsigned_word target_start_block;
411 DTRACE(stack,
412 ("write_stack_arguments() write %s=%s at %s=0x%lx %s=0x%lx %s=0x%lx\n",
413 "**arg", *arg, "start_block", (long)start_block,
414 "len", (long)len, "start_arg", (long)start_arg));
415 if (psim_write_memory(device_system(me), 0, *arg,
416 start_block, len,
417 0/*violate_readonly*/) != len)
418 device_error(me, "Write of **arg (%s) at 0x%lx of stack failed\n",
419 *arg, (unsigned long)start_block);
420 target_start_block = H2T_word(start_block);
421 if (psim_write_memory(device_system(me), 0, &target_start_block,
422 start_arg, sizeof(target_start_block),
423 0) != sizeof(target_start_block))
424 device_error(me, "Write of *arg onto stack failed\n");
425 start_block += ALIGN_8(len);
426 start_arg += sizeof(start_block);
427 }
428 start_arg += sizeof(start_block); /*the null at the end*/
429 if (start_block != end_block
430 || ALIGN_8(start_arg) != end_arg)
431 device_error(me, "Probable corrpution of stack arguments\n");
432 DTRACE(stack, ("write_stack_arguments() = void\n"));
433 }
434
435 static void
436 create_ppc_elf_stack_frame(device *me,
437 unsigned_word bottom_of_stack,
438 char **argv,
439 char **envp)
440 {
441 /* fixme - this is over aligned */
442
443 /* information block */
444 const unsigned sizeof_envp_block = sizeof_argument_strings(envp);
445 const unsigned_word start_envp_block = bottom_of_stack - sizeof_envp_block;
446 const unsigned sizeof_argv_block = sizeof_argument_strings(argv);
447 const unsigned_word start_argv_block = start_envp_block - sizeof_argv_block;
448
449 /* auxiliary vector - contains only one entry */
450 const unsigned sizeof_aux_entry = 2*sizeof(unsigned_word); /* magic */
451 const unsigned_word start_aux = start_argv_block - ALIGN_8(sizeof_aux_entry);
452
453 /* environment points (including null sentinal) */
454 const unsigned sizeof_envp = sizeof_arguments(envp);
455 const unsigned_word start_envp = start_aux - sizeof_envp;
456
457 /* argument pointers (including null sentinal) */
458 const int argc = number_of_arguments(argv);
459 const unsigned sizeof_argv = sizeof_arguments(argv);
460 const unsigned_word start_argv = start_envp - sizeof_argv;
461
462 /* link register save address - alligned to a 16byte boundary */
463 const unsigned_word top_of_stack = ((start_argv
464 - 2 * sizeof(unsigned_word))
465 & ~0xf);
466
467 /* install arguments on stack */
468 write_stack_arguments(me, envp,
469 start_envp_block, bottom_of_stack,
470 start_envp, start_aux);
471 write_stack_arguments(me, argv,
472 start_argv_block, start_envp_block,
473 start_argv, start_envp);
474
475 /* set up the registers */
476 psim_write_register(device_system(me), -1,
477 &top_of_stack, "sp", cooked_transfer);
478 psim_write_register(device_system(me), -1,
479 &argc, "r3", cooked_transfer);
480 psim_write_register(device_system(me), -1,
481 &start_argv, "r4", cooked_transfer);
482 psim_write_register(device_system(me), -1,
483 &start_envp, "r5", cooked_transfer);
484 psim_write_register(device_system(me), -1,
485 &start_aux, "r6", cooked_transfer);
486 }
487
488 static void
489 create_ppc_aix_stack_frame(device *me,
490 unsigned_word bottom_of_stack,
491 char **argv,
492 char **envp)
493 {
494 unsigned_word core_envp;
495 unsigned_word core_argv;
496 unsigned_word core_argc;
497 unsigned_word core_aux;
498 unsigned_word top_of_stack;
499
500 /* cheat - create an elf stack frame */
501 create_ppc_elf_stack_frame(me, bottom_of_stack, argv, envp);
502
503 /* extract argument addresses from registers */
504 psim_read_register(device_system(me), 0,
505 &top_of_stack, "r1", cooked_transfer);
506 psim_read_register(device_system(me), 0,
507 &core_argc, "r3", cooked_transfer);
508 psim_read_register(device_system(me), 0,
509 &core_argv, "r4", cooked_transfer);
510 psim_read_register(device_system(me), 0,
511 &core_envp, "r5", cooked_transfer);
512 psim_read_register(device_system(me), 0,
513 &core_aux, "r6", cooked_transfer);
514
515 /* extract arguments from registers */
516 device_error(me, "Unfinished procedure create_ppc_aix_stack_frame\n");
517 }
518
519
520
521 static int
522 hw_stack_ioctl_callback(device *me,
523 cpu *processor,
524 unsigned_word cia,
525 va_list ap)
526 {
527 unsigned_word stack_pointer;
528 const char *stack_type;
529 char **argv;
530 char **envp;
531 stack_pointer = va_arg(ap, unsigned_word);
532 argv = va_arg(ap, char **);
533 envp = va_arg(ap, char **);
534 DTRACE(stack,
535 ("stack_ioctl_callback(me=0x%lx:%s processor=0x%lx cia=0x%lx argv=0x%lx envp=0x%lx)\n",
536 (long)me, device_name(me), (long)processor, (long)cia, (long)argv, (long)envp));
537 stack_type = device_find_string_property(me, "stack-type");
538 if (strcmp(stack_type, "ppc-elf") == 0)
539 create_ppc_elf_stack_frame(me, stack_pointer, argv, envp);
540 else if (strcmp(stack_type, "ppc-xcoff") == 0)
541 create_ppc_aix_stack_frame(me, stack_pointer, argv, envp);
542 else if (strcmp(stack_type, "none") != 0)
543 device_error(me, "Unknown initial stack frame type %s\n", stack_type);
544 DTRACE(stack,
545 ("stack_ioctl_callback() = void\n"));
546 return 0;
547 }
548
549 static device_callbacks const hw_stack_callbacks = {
550 { NULL, },
551 { NULL, }, /* address */
552 { NULL, }, /* IO */
553 { NULL, }, /* DMA */
554 { NULL, }, /* interrupt */
555 { NULL, }, /* unit */
556 NULL, /* instance */
557 hw_stack_ioctl_callback,
558 };
559
560 const device_descriptor hw_init_device_descriptor[] = {
561 { "file", NULL, &hw_file_callbacks },
562 { "data", NULL, &hw_data_callbacks },
563 { "load-binary", NULL, &hw_binary_callbacks },
564 { "map-binary", NULL, &hw_binary_callbacks },
565 { "stack", NULL, &hw_stack_callbacks },
566 { NULL },
567 };
568
569 #endif _HW_INIT_C_
This page took 0.044547 seconds and 5 git commands to generate.