Index: arm/ChangeLog
[platform/upstream/binutils.git] / sim / ppc / hw_init.c
1 /*  This file is part of the program psim.
2     
3     Copyright 1994, 1997, 2003, 2004 Andrew Cagney
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 (inc <= 0)
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
116    data - initialize a memory location with specified data
117
118
119    DESCRIPTION
120
121
122    The pseudo device <<data>> provides a mechanism specifying the
123    initialization of a small section of memory.
124
125    Normally, the data would be written using a dma operation.
126    However, for some addresses this will not result in the desired
127    result.  For instance, to initialize an address in an eeprom,
128    instead of a simple dma of the data, a sequence of writes (and then
129    real delays) that program the eeprom would be required.
130
131    For dma write initialization, the data device will write the
132    specified <<data>> to <<real-address>> using a normal dma.
133
134    For instance write initialization, the specified <<instance>> is
135    opened.  Then a seek to the <<real-address>> is performed followed
136    by a write of the data.
137
138
139    Integer properties are stored using the target's endian mode.
140
141
142    PROPERTIES
143
144
145    data = <any-valid-property> (required)
146
147    Data to be loaded into memory.  The property type determines how it
148    is loaded.
149
150
151    real-address = <integer> (required)
152
153    Start address at which the data is to be stored.
154
155
156    instance = <string> (optional)
157
158    Instance specification of the device that is to be opened so that
159    the specified data can be written to it.
160
161
162    EXAMPLES
163
164
165    The examples below illustrate the two alternative mechanisms that
166    can be used to store the value 0x12345678 at address 0xfff00c00,
167    which is normally part of the 512k system eeprom.
168
169
170    If the eeprom is being modeled by ram (<<memory>> device) then the
171    standard dma initialization can be used.  By convention: the data
172    devices are uniquely identified by argumenting them with the
173    destinations real address; and all data devices are put under the
174    node <</openprom/init>>.
175
176    | /openprom/memory@0xfff00000/reg 0xfff00000 0x80000
177    | /openprom/init/data@0x1000/data 0x12345678
178    | /openprom/init/data@0x1000/real-address 0x1000
179
180
181    If instead a real eeprom was being used the instance write method
182    would instead need to be used (storing just a single byte in an
183    eeprom requires a complex sequence of accesses).  The
184    <<real-address>> is specified as <<0x0c00>> which is the offset
185    into the eeprom.  For brevity, most of the eeprom properties have
186    been omited.
187
188    | /iobus/eeprom@0xfff00000/reg 0xfff00000 0x80000
189    | /openprom/init/data@0xfff00c00/real-address 0x0c00
190    | /openprom/init/data@0xfff00c00/data 0x12345667
191    | /openprom/init/data@0xfff00c00/instance /iobus/eeprom@0xfff00000/reg
192
193
194    BUGS
195
196
197    At present, only <<integer>> properties can be specified for an
198    initial data value.
199
200    */
201
202
203 static void
204 hw_data_init_data_callback(device *me)
205 {
206   unsigned_word addr = device_find_integer_property(me, "real-address");
207   const device_property *data = device_find_property(me, "data");
208   const char *instance_spec = (device_find_property(me, "instance") != NULL
209                                ? device_find_string_property(me, "instance")
210                                : NULL);
211   device_instance *instance = NULL;
212   if (data == NULL)
213     device_error(me, "missing property <data>\n");
214   if (instance_spec != NULL)
215     instance = tree_instance(me, instance_spec);
216   switch (data->type) {
217   case integer_property:
218     {
219       unsigned_cell buf = device_find_integer_property(me, "data");
220       H2T(buf);
221       if (instance == NULL) {
222         if (device_dma_write_buffer(device_parent(me),
223                                     &buf,
224                                     0 /*address-space*/,
225                                     addr,
226                                     sizeof(buf), /*nr-bytes*/
227                                     1 /*violate ro*/) != sizeof(buf))
228           device_error(me, "Problem storing integer 0x%x at 0x%lx\n",
229                        (unsigned)buf, (unsigned long)addr);
230       }
231       else {
232         if (device_instance_seek(instance, 0, addr) < 0
233             || device_instance_write(instance, &buf, sizeof(buf)) != sizeof(buf))
234           device_error(me, "Problem storing integer 0x%x at 0x%lx of instance %s\n",
235                        (unsigned)buf, (unsigned long)addr, instance_spec);
236       }
237     }
238     break;
239   default:
240     device_error(me, "Write of this data is not yet implemented\n");
241     break;
242   }
243   if (instance != NULL)
244     device_instance_delete(instance);
245 }
246
247
248 static device_callbacks const hw_data_callbacks = {
249   { NULL, hw_data_init_data_callback, },
250   { NULL, }, /* address */
251   { NULL, }, /* IO */
252   { NULL, }, /* DMA */
253   { NULL, }, /* interrupt */
254   { NULL, }, /* unit */
255 };
256
257
258 /* DEVICE
259
260
261    load-binary - load binary segments into memory
262
263
264    DESCRIPTION
265
266    Each loadable segment of the specified binary is loaded into memory
267    at its required address.  It is assumed that the memory at those
268    addresses already exists.
269
270    This device is normally used to load an executable into memory as
271    part of real mode simulation.
272
273
274    PROPERTIES
275
276
277    file-name = <string>
278
279    Name of the binary to be loaded.
280
281
282    claim = <anything> (optional)
283
284    If this property is present, the real memory that is to be used by
285    the image being loaded will be claimed from the memory node
286    (specified by the ihandle <</chosen/memory>>).
287
288
289    BUGS
290
291    
292    When loading the binary the bfd virtual-address is used.  It should
293    be using the bfd load-address.
294
295    */
296
297 /* DEVICE
298
299    map-binary - map the binary into the users address space
300
301    DESCRIPTION
302    
303    Similar to load-binary except that memory for each segment is
304    created before the corresponding data for the segment is loaded.
305
306    This device is normally used to load an executable into a user mode
307    simulation.
308
309    PROPERTIES
310
311    file-name = <string>
312
313    Name of the binary to be loaded.
314
315    */
316
317 static void
318 update_for_binary_section(bfd *abfd,
319                           asection *the_section,
320                           PTR obj)
321 {
322   unsigned_word section_vma;
323   unsigned_word section_size;
324   access_type access;
325   device *me = (device*)obj;
326
327   /* skip the section if no memory to allocate */
328   if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
329     return;
330
331   /* check/ignore any sections of size zero */
332   section_size = bfd_get_section_size (the_section);
333   if (section_size == 0)
334     return;
335
336   /* find where it is to go */
337   section_vma = bfd_get_section_vma(abfd, the_section);
338
339   DTRACE(binary,
340          ("name=%-7s, vma=0x%.8lx, size=%6ld, flags=%3lx(%s%s%s%s%s )\n",
341           bfd_get_section_name(abfd, the_section),
342           (long)section_vma,
343           (long)section_size,
344           (long)bfd_get_section_flags(abfd, the_section),
345           bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "",
346           bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "",
347           bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "",
348           bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "",
349           bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : ""
350           ));
351
352   /* If there is an .interp section, it means it needs a shared library interpreter.  */
353   if (strcmp(".interp", bfd_get_section_name(abfd, the_section)) == 0)
354     error("Shared libraries are not yet supported.\n");
355
356   /* determine the devices access */
357   access = access_read;
358   if (bfd_get_section_flags(abfd, the_section) & SEC_CODE)
359     access |= access_exec;
360   if (!(bfd_get_section_flags(abfd, the_section) & SEC_READONLY))
361     access |= access_write;
362
363   /* if claim specified, allocate region from the memory device */
364   if (device_find_property(me, "claim") != NULL) {
365     device_instance *memory = tree_find_ihandle_property(me, "/chosen/memory");
366     unsigned_cell mem_in[3];
367     unsigned_cell mem_out[1];
368     mem_in[0] = 0; /*alignment - top-of-stack*/
369     mem_in[1] = section_size;
370     mem_in[2] = section_vma;
371     if (device_instance_call_method(memory, "claim", 3, mem_in, 1, mem_out) < 0)
372       device_error(me, "failed to claim memory for section at 0x%lx (0x%lx",
373                    section_vma,
374                    section_size);
375     if (mem_out[0] != section_vma)
376       device_error(me, "section address not as requested");
377   }
378
379   /* if a map, pass up a request to create the memory in core */
380   if (strncmp(device_name(me), "map-binary", strlen("map-binary")) == 0)
381     device_attach_address(device_parent(me),
382                           attach_raw_memory,
383                           0 /*address space*/,
384                           section_vma,
385                           section_size,
386                           access,
387                           me);
388
389   /* if a load dma in the required data */
390   if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) {
391     void *section_init = zalloc(section_size);
392     if (!bfd_get_section_contents(abfd,
393                                   the_section,
394                                   section_init, 0,
395                                   section_size)) {
396       bfd_perror("binary");
397       device_error(me, "load of data failed");
398       return;
399     }
400     if (device_dma_write_buffer(device_parent(me),
401                                 section_init,
402                                 0 /*space*/,
403                                 section_vma,
404                                 section_size,
405                                 1 /*violate_read_only*/)
406         != section_size)
407       device_error(me, "broken transfer\n");
408     zfree(section_init); /* only free if load */
409   }
410 }
411
412 static void
413 hw_binary_init_data_callback(device *me)
414 {
415   /* get the file name */
416   const char *file_name = device_find_string_property(me, "file-name");
417   bfd *image;
418
419   /* open the file */
420   image = bfd_openr(file_name, NULL);
421   if (image == NULL) {
422     bfd_perror("binary");
423     device_error(me, "Failed to open file %s\n", file_name);
424   }
425
426   /* check it is valid */
427   if (!bfd_check_format(image, bfd_object)) {
428     bfd_close(image);
429     device_error(me, "The file %s has an invalid binary format\n", file_name);
430   }
431
432   /* and the data sections */
433   bfd_map_over_sections(image,
434                         update_for_binary_section,
435                         (PTR)me);
436
437   bfd_close(image);
438 }
439
440
441 static device_callbacks const hw_binary_callbacks = {
442   { NULL, hw_binary_init_data_callback, },
443   { NULL, }, /* address */
444   { NULL, }, /* IO */
445   { NULL, }, /* DMA */
446   { NULL, }, /* interrupt */
447   { NULL, }, /* unit */
448 };
449
450
451 /* DEVICE
452
453    stack - create an initial stack frame in memory
454
455    DESCRIPTION
456
457    Creates a stack frame of the specified type in memory.
458
459    Due to the startup sequence gdb uses when commencing a simulation,
460    it is not possible for the data to be placed on the stack to be
461    specified as part of the device tree.  Instead the arguments to be
462    pushed onto the stack are specified using an IOCTL call.
463
464    The IOCTL takes the additional arguments:
465
466    | unsigned_word stack_end -- where the stack should come down from
467    | char **argv -- ...
468    | char **envp -- ...
469
470    PROPERTIES
471
472    stack-type = <string>
473
474    The form of the stack frame that is to be created.
475
476    */
477
478 static int
479 sizeof_argument_strings(char **arg)
480 {
481   int sizeof_strings = 0;
482
483   /* robust */
484   if (arg == NULL)
485     return 0;
486
487   /* add up all the string sizes (padding as we go) */
488   for (; *arg != NULL; arg++) {
489     int len = strlen(*arg) + 1;
490     sizeof_strings += ALIGN_8(len);
491   }
492
493   return sizeof_strings;
494 }
495
496 static int
497 number_of_arguments(char **arg)
498 {
499   int nr;
500   if (arg == NULL)
501     return 0;
502   for (nr = 0; *arg != NULL; arg++, nr++);
503   return nr;
504 }
505
506 static int
507 sizeof_arguments(char **arg)
508 {
509   return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
510 }
511
512 static void
513 write_stack_arguments(device *me,
514                       char **arg,
515                       unsigned_word start_block,
516                       unsigned_word end_block,
517                       unsigned_word start_arg,
518                       unsigned_word end_arg)
519 {
520   DTRACE(stack,
521         ("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",
522          device_name(me), (long)arg, (long)start_block, (long)end_block, (long)start_arg, (long)end_arg));
523   if (arg == NULL)
524     device_error(me, "Attempt to write a null array onto the stack\n");
525   /* only copy in arguments, memory is already zero */
526   for (; *arg != NULL; arg++) {
527     int len = strlen(*arg)+1;
528     unsigned_word target_start_block;
529     DTRACE(stack,
530           ("write_stack_arguments() write %s=%s at %s=0x%lx %s=0x%lx %s=0x%lx\n",
531            "**arg", *arg, "start_block", (long)start_block,
532            "len", (long)len, "start_arg", (long)start_arg));
533     if (psim_write_memory(device_system(me), 0, *arg,
534                           start_block, len,
535                           0/*violate_readonly*/) != len)
536       device_error(me, "Write of **arg (%s) at 0x%lx of stack failed\n",
537                    *arg, (unsigned long)start_block);
538     target_start_block = H2T_word(start_block);
539     if (psim_write_memory(device_system(me), 0, &target_start_block,
540                           start_arg, sizeof(target_start_block),
541                           0) != sizeof(target_start_block))
542       device_error(me, "Write of *arg onto stack failed\n");
543     start_block += ALIGN_8(len);
544     start_arg += sizeof(start_block);
545   }
546   start_arg += sizeof(start_block); /*the null at the end*/
547   if (start_block != end_block
548       || ALIGN_8(start_arg) != end_arg)
549     device_error(me, "Probable corrpution of stack arguments\n");
550   DTRACE(stack, ("write_stack_arguments() = void\n"));
551 }
552
553 static void
554 create_ppc_elf_stack_frame(device *me,
555                            unsigned_word bottom_of_stack,
556                            char **argv,
557                            char **envp)
558 {
559   /* fixme - this is over aligned */
560
561   /* information block */
562   const unsigned sizeof_envp_block = sizeof_argument_strings(envp);
563   const unsigned_word start_envp_block = bottom_of_stack - sizeof_envp_block;
564   const unsigned sizeof_argv_block = sizeof_argument_strings(argv);
565   const unsigned_word start_argv_block = start_envp_block - sizeof_argv_block;
566
567   /* auxiliary vector - contains only one entry */
568   const unsigned sizeof_aux_entry = 2*sizeof(unsigned_word); /* magic */
569   const unsigned_word start_aux = start_argv_block - ALIGN_8(sizeof_aux_entry);
570
571   /* environment points (including null sentinal) */
572   const unsigned sizeof_envp = sizeof_arguments(envp);
573   const unsigned_word start_envp = start_aux - sizeof_envp;
574
575   /* argument pointers (including null sentinal) */
576   const int argc = number_of_arguments(argv);
577   const unsigned sizeof_argv = sizeof_arguments(argv);
578   const unsigned_word start_argv = start_envp - sizeof_argv;
579
580   /* link register save address - alligned to a 16byte boundary */
581   const unsigned_word top_of_stack = ((start_argv
582                                        - 2 * sizeof(unsigned_word))
583                                       & ~0xf);
584
585   /* install arguments on stack */
586   write_stack_arguments(me, envp,
587                         start_envp_block, bottom_of_stack,
588                         start_envp, start_aux);
589   write_stack_arguments(me, argv,
590                         start_argv_block, start_envp_block,
591                         start_argv, start_envp);
592
593   /* set up the registers */
594   ASSERT (psim_write_register(device_system(me), -1,
595                               &top_of_stack, "sp", cooked_transfer) > 0);
596   ASSERT (psim_write_register(device_system(me), -1,
597                               &argc, "r3", cooked_transfer) > 0);
598   ASSERT (psim_write_register(device_system(me), -1,
599                               &start_argv, "r4", cooked_transfer) > 0);
600   ASSERT (psim_write_register(device_system(me), -1,
601                               &start_envp, "r5", cooked_transfer) > 0);
602   ASSERT (psim_write_register(device_system(me), -1,
603                               &start_aux, "r6", cooked_transfer) > 0);
604 }
605
606 static void
607 create_ppc_aix_stack_frame(device *me,
608                            unsigned_word bottom_of_stack,
609                            char **argv,
610                            char **envp)
611 {
612   unsigned_word core_envp;
613   unsigned_word core_argv;
614   unsigned_word core_argc;
615   unsigned_word core_aux;
616   unsigned_word top_of_stack;
617
618   /* cheat - create an elf stack frame */
619   create_ppc_elf_stack_frame(me, bottom_of_stack, argv, envp);
620   
621   /* extract argument addresses from registers */
622   ASSERT (psim_read_register(device_system(me), 0,
623                              &top_of_stack, "r1", cooked_transfer) > 0);
624   ASSERT (psim_read_register(device_system(me), 0,
625                              &core_argc, "r3", cooked_transfer) > 0);
626   ASSERT (psim_read_register(device_system(me), 0,
627                              &core_argv, "r4", cooked_transfer) > 0);
628   ASSERT (psim_read_register(device_system(me), 0,
629                              &core_envp, "r5", cooked_transfer) > 0);
630   ASSERT (psim_read_register(device_system(me), 0,
631                              &core_aux, "r6", cooked_transfer) > 0);
632
633   /* extract arguments from registers */
634   device_error(me, "Unfinished procedure create_ppc_aix_stack_frame\n");
635 }
636
637
638 static void
639 create_ppc_chirp_bootargs(device *me,
640                           char **argv)
641 {
642   /* concat the arguments */
643   char args[1024];
644   char **chp = argv + 1;
645   args[0] = '\0';
646   while (*chp != NULL) {
647     if (strlen(args) > 0)
648       strcat(args, " ");
649     if (strlen(args) + strlen(*chp) >= sizeof(args))
650       device_error(me, "buffer overflow");
651     strcat(args, *chp);
652     chp++;
653   }
654
655   /* set the arguments property */
656   tree_parse(me, "/chosen/bootargs \"%s", args);
657 }
658
659
660 static int
661 hw_stack_ioctl(device *me,
662                cpu *processor,
663                unsigned_word cia,
664                device_ioctl_request request,
665                va_list ap)
666 {
667   switch (request) {
668   case device_ioctl_create_stack:
669     {
670       unsigned_word stack_pointer = va_arg(ap, unsigned_word);
671       char **argv = va_arg(ap, char **);
672       char **envp = va_arg(ap, char **);
673       const char *stack_type;
674       DTRACE(stack,
675              ("stack_ioctl_callback(me=0x%lx:%s processor=0x%lx cia=0x%lx argv=0x%lx envp=0x%lx)\n",
676               (long)me, device_name(me),
677               (long)processor,
678               (long)cia,
679               (long)argv,
680               (long)envp));
681       stack_type = device_find_string_property(me, "stack-type");
682       if (strcmp(stack_type, "ppc-elf") == 0)
683         create_ppc_elf_stack_frame(me, stack_pointer, argv, envp);
684       else if (strcmp(stack_type, "ppc-xcoff") == 0)
685         create_ppc_aix_stack_frame(me, stack_pointer, argv, envp);
686       else if (strcmp(stack_type, "chirp") == 0)
687         create_ppc_chirp_bootargs(me, argv);
688       else if (strcmp(stack_type, "none") != 0)
689         device_error(me, "Unknown initial stack frame type %s", stack_type);
690       DTRACE(stack, 
691              ("stack_ioctl_callback() = void\n"));
692       break;
693     }
694   default:
695     device_error(me, "Unsupported ioctl requested");
696     break;
697   }
698   return 0;
699 }
700
701 static device_callbacks const hw_stack_callbacks = {
702   { NULL, },
703   { NULL, }, /* address */
704   { NULL, }, /* IO */
705   { NULL, }, /* DMA */
706   { NULL, }, /* interrupt */
707   { NULL, }, /* unit */
708   NULL, /* instance */
709   hw_stack_ioctl,
710 };
711
712 const device_descriptor hw_init_device_descriptor[] = {
713   { "file", NULL, &hw_file_callbacks },
714   { "data", NULL, &hw_data_callbacks },
715   { "load-binary", NULL, &hw_binary_callbacks },
716   { "map-binary", NULL, &hw_binary_callbacks },
717   { "stack", NULL, &hw_stack_callbacks },
718   { NULL },
719 };
720
721 #endif _HW_INIT_C_