Latest changes from Andrew
[platform/upstream/binutils.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_