PowerPC64 ld segfault with code in non-executable sections
[external/binutils.git] / sim / ppc / hw_pal.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 3 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, see <http://www.gnu.org/licenses/>.
17     
18     */
19
20
21 #ifndef _HW_PAL_C_
22 #define _HW_PAL_C_
23
24 #ifndef STATIC_INLINE_HW_PAL
25 #define STATIC_INLINE_HW_PAL STATIC_INLINE
26 #endif
27
28 #include "device_table.h"
29
30 #include "cpu.h"
31
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #else
35 #ifdef HAVE_STRINGS_H
36 #include <strings.h>
37 #endif
38 #endif
39
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #ifdef HAVE_STDLIB_H
44 #include <stdlib.h>
45 #endif
46
47
48 /* DEVICE
49
50    
51    pal - glue logic device containing assorted junk
52
53    
54    DESCRIPTION
55
56    
57    Typical hardware dependant hack.  This device allows the firmware
58    to gain access to all the things the firmware needs (but the OS
59    doesn't).
60
61    The pal contains the following registers.  Except for the interrupt
62    level register, each of the below is 8 bytes in size and must be
63    accessed using correct alignment.  For 16 and 32 bit accesses the
64    bytes not directed to the register are ignored:
65    
66    |0   reset register (write)
67    |4   processor id register (read)
68    |8   interrupt port (write)
69    |9   interrupt level (write)
70    |12  processor count register (read)
71    |16  tty input fifo register (read)
72    |20  tty input status register (read)
73    |24  tty output fifo register (write)
74    |28  tty output status register (read)
75
76    Reset register (write) halts the simulator exiting with the
77    value written.
78    
79    Processor id register (read) returns the processor number (0
80    .. N-1) of the processor performing the read.
81    
82    The interrupt registers should be accessed as a pair (using a 16 or
83    32 bit store).  The low byte specifies the interrupt port while the
84    high byte specifies the level to drive that port at.  By
85    convention, the pal's interrupt ports (int0, int1, ...) are wired
86    up to the corresponding processor's level sensative external
87    interrupt pin.  Eg: A two byte write to address 8 of 0x0102
88    (big-endian) will result in processor 2's external interrupt pin to
89    be asserted.
90
91    Processor count register (read) returns the total number of
92    processors active in the current simulation.
93
94    TTY input fifo register (read), if the TTY input status register
95    indicates a character is available by being nonzero, returns the
96    next available character from the pal's tty input port.
97
98    Similarly, the TTY output fifo register (write), if the TTY output
99    status register indicates the output fifo is not full by being
100    nonzero, outputs the character written to the tty's output port.
101
102
103    PROPERTIES
104    
105
106    reg = <address> <size> (required)
107
108    Specify the address (within the parent bus) that this device is to
109    live.
110
111
112    */
113
114
115 enum {
116   hw_pal_reset_register = 0x0,
117   hw_pal_cpu_nr_register = 0x4,
118   hw_pal_int_register = 0x8,
119   hw_pal_nr_cpu_register = 0xa,
120   hw_pal_read_fifo = 0x10,
121   hw_pal_read_status = 0x14,
122   hw_pal_write_fifo = 0x18,
123   hw_pal_write_status = 0x1a,
124   hw_pal_address_mask = 0x1f,
125 };
126
127
128 typedef struct _hw_pal_console_buffer {
129   char buffer;
130   int status;
131 } hw_pal_console_buffer;
132
133 typedef struct _hw_pal_device {
134   hw_pal_console_buffer input;
135   hw_pal_console_buffer output;
136   device *disk;
137 } hw_pal_device;
138
139
140 /* check the console for an available character */
141 static void
142 scan_hw_pal(hw_pal_device *hw_pal)
143 {
144   char c;
145   int count;
146   count = sim_io_read_stdin(&c, sizeof(c));
147   switch (count) {
148   case sim_io_not_ready:
149   case sim_io_eof:
150     hw_pal->input.buffer = 0;
151     hw_pal->input.status = 0;
152     break;
153   default:
154     hw_pal->input.buffer = c;
155     hw_pal->input.status = 1;
156   }
157 }
158
159 /* write the character to the hw_pal */
160 static void
161 write_hw_pal(hw_pal_device *hw_pal,
162              char val)
163 {
164   sim_io_write_stdout(&val, 1);
165   hw_pal->output.buffer = val;
166   hw_pal->output.status = 1;
167 }
168
169
170 static unsigned
171 hw_pal_io_read_buffer_callback(device *me,
172                                void *dest,
173                                int space,
174                                unsigned_word addr,
175                                unsigned nr_bytes,
176                                cpu *processor,
177                                unsigned_word cia)
178 {
179   hw_pal_device *hw_pal = (hw_pal_device*)device_data(me);
180   unsigned_1 val;
181   switch (addr & hw_pal_address_mask) {
182   case hw_pal_cpu_nr_register:
183     val = cpu_nr(processor);
184     DTRACE(pal, ("read - cpu-nr %d\n", val));
185     break;
186   case hw_pal_nr_cpu_register:
187     val = tree_find_integer_property(me, "/openprom/options/smp");
188     DTRACE(pal, ("read - nr-cpu %d\n", val));
189     break;
190   case hw_pal_read_fifo:
191     val = hw_pal->input.buffer;
192     DTRACE(pal, ("read - input-fifo %d\n", val));
193     break;
194   case hw_pal_read_status:
195     scan_hw_pal(hw_pal);
196     val = hw_pal->input.status;
197     DTRACE(pal, ("read - input-status %d\n", val));
198     break;
199   case hw_pal_write_fifo:
200     val = hw_pal->output.buffer;
201     DTRACE(pal, ("read - output-fifo %d\n", val));
202     break;
203   case hw_pal_write_status:
204     val = hw_pal->output.status;
205     DTRACE(pal, ("read - output-status %d\n", val));
206     break;
207   default:
208     val = 0;
209     DTRACE(pal, ("read - ???\n"));
210   }
211   memset(dest, 0, nr_bytes);
212   *(unsigned_1*)dest = val;
213   return nr_bytes;
214 }
215
216
217 static unsigned
218 hw_pal_io_write_buffer_callback(device *me,
219                                 const void *source,
220                                 int space,
221                                 unsigned_word addr,
222                                 unsigned nr_bytes,
223                                 cpu *processor,
224                                 unsigned_word cia)
225 {
226   hw_pal_device *hw_pal = (hw_pal_device*)device_data(me);
227   unsigned_1 *byte = (unsigned_1*)source;
228   
229   switch (addr & hw_pal_address_mask) {
230   case hw_pal_reset_register:
231     cpu_halt(processor, cia, was_exited, byte[0]);
232     break;
233   case hw_pal_int_register:
234     device_interrupt_event(me,
235                            byte[0], /*port*/
236                            (nr_bytes > 1 ? byte[1] : 0), /* val */
237                            processor, cia);
238     break;
239   case hw_pal_read_fifo:
240     hw_pal->input.buffer = byte[0];
241     DTRACE(pal, ("write - input-fifo %d\n", byte[0]));
242     break;
243   case hw_pal_read_status:
244     hw_pal->input.status = byte[0];
245     DTRACE(pal, ("write - input-status %d\n", byte[0]));
246     break;
247   case hw_pal_write_fifo:
248     write_hw_pal(hw_pal, byte[0]);
249     DTRACE(pal, ("write - output-fifo %d\n", byte[0]));
250     break;
251   case hw_pal_write_status:
252     hw_pal->output.status = byte[0];
253     DTRACE(pal, ("write - output-status %d\n", byte[0]));
254     break;
255   }
256   return nr_bytes;
257 }
258
259
260 /* instances of the hw_pal device */
261
262 static void
263 hw_pal_instance_delete_callback(device_instance *instance)
264 {
265   /* nothing to delete, the hw_pal is attached to the device */
266   return;
267 }
268
269 static int
270 hw_pal_instance_read_callback(device_instance *instance,
271                               void *buf,
272                               unsigned_word len)
273 {
274   DITRACE(pal, ("read - %s (%ld)", (const char*)buf, (long int)len));
275   return sim_io_read_stdin(buf, len);
276 }
277
278 static int
279 hw_pal_instance_write_callback(device_instance *instance,
280                                const void *buf,
281                                unsigned_word len)
282 {
283   int i;
284   const char *chp = buf;
285   hw_pal_device *hw_pal = device_instance_data(instance);
286   DITRACE(pal, ("write - %s (%ld)", (const char*)buf, (long int)len));
287   for (i = 0; i < len; i++)
288     write_hw_pal(hw_pal, chp[i]);
289   sim_io_flush_stdoutput();
290   return i;
291 }
292
293 static const device_instance_callbacks hw_pal_instance_callbacks = {
294   hw_pal_instance_delete_callback,
295   hw_pal_instance_read_callback,
296   hw_pal_instance_write_callback,
297 };
298
299 static device_instance *
300 hw_pal_create_instance(device *me,
301                        const char *path,
302                        const char *args)
303 {
304   return device_create_instance_from(me, NULL,
305                                      device_data(me),
306                                      path, args,
307                                      &hw_pal_instance_callbacks);
308 }
309
310 static const device_interrupt_port_descriptor hw_pal_interrupt_ports[] = {
311   { "int", 0, MAX_NR_PROCESSORS },
312   { NULL }
313 };
314
315
316 static void
317 hw_pal_attach_address(device *me,
318                       attach_type attach,
319                       int space,
320                       unsigned_word addr,
321                       unsigned nr_bytes,
322                       access_type access,
323                       device *client)
324 {
325   hw_pal_device *pal = (hw_pal_device*)device_data(me);
326   pal->disk = client;
327 }
328
329
330 static device_callbacks const hw_pal_callbacks = {
331   { generic_device_init_address, },
332   { hw_pal_attach_address, }, /* address */
333   { hw_pal_io_read_buffer_callback,
334       hw_pal_io_write_buffer_callback, },
335   { NULL, }, /* DMA */
336   { NULL, NULL, hw_pal_interrupt_ports }, /* interrupt */
337   { generic_device_unit_decode,
338     generic_device_unit_encode,
339     generic_device_address_to_attach_address,
340     generic_device_size_to_attach_size },
341   hw_pal_create_instance,
342 };
343
344
345 static void *
346 hw_pal_create(const char *name,
347               const device_unit *unit_address,
348               const char *args)
349 {
350   /* create the descriptor */
351   hw_pal_device *hw_pal = ZALLOC(hw_pal_device);
352   hw_pal->output.status = 1;
353   hw_pal->output.buffer = '\0';
354   hw_pal->input.status = 0;
355   hw_pal->input.buffer = '\0';
356   return hw_pal;
357 }
358
359
360 const device_descriptor hw_pal_device_descriptor[] = {
361   { "pal", hw_pal_create, &hw_pal_callbacks },
362   { NULL },
363 };
364
365 #endif /* _HW_PAL_C_ */