1 /* The common simulator framework for GDB, the GNU Debugger.
2 
3    Copyright 2002-2013 Free Software Foundation, Inc.
4 
5    Contributed by Andrew Cagney and Red Hat.
6 
7    This file is part of GDB.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21 
22 
23 #include "hw-main.h"
24 #include "hw-base.h"
25 
26 
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #else
30 #ifdef HAVE_STRINGS_H
31 #include <strings.h>
32 #endif
33 #endif
34 
35 #if HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38 
39 #include <ctype.h>
40 
41 #include "hw-config.h"
42 
43 struct hw_base_data
44 {
45   int finished_p;
46   const struct hw_descriptor *descriptor;
47   hw_delete_callback *to_delete;
48 };
49 
50 static int
generic_hw_unit_decode(struct hw * bus,const char * unit,hw_unit * phys)51 generic_hw_unit_decode (struct hw *bus,
52 			const char *unit,
53 			hw_unit *phys)
54 {
55   memset (phys, 0, sizeof (*phys));
56   if (unit == NULL)
57     return 0;
58   else
59     {
60       int nr_cells = 0;
61       const int max_nr_cells = hw_unit_nr_address_cells (bus);
62       while (1)
63 	{
64 	  char *end = NULL;
65 	  unsigned long val;
66 	  val = strtoul (unit, &end, 0);
67 	  /* parse error? */
68 	  if (unit == end)
69 	    return -1;
70 	  /* two many cells? */
71 	  if (nr_cells >= max_nr_cells)
72 	    return -1;
73 	  /* save it */
74 	  phys->cells[nr_cells] = val;
75 	  nr_cells++;
76 	  unit = end;
77 	  /* more to follow? */
78 	  if (isspace (*unit) || *unit == '\0')
79 	    break;
80 	  if (*unit != ',')
81 	    return -1;
82 	  unit++;
83 	}
84       if (nr_cells < max_nr_cells)
85 	{
86 	  /* shift everything to correct position */
87 	  int i;
88 
89 	  for (i = 1; i <= nr_cells; i++)
90 	    phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i];
91 	  for (i = 0; i < (max_nr_cells - nr_cells); i++)
92 	    phys->cells[i] = 0;
93 	}
94       phys->nr_cells = max_nr_cells;
95       return max_nr_cells;
96   }
97 }
98 
99 static int
generic_hw_unit_encode(struct hw * bus,const hw_unit * phys,char * buf,int sizeof_buf)100 generic_hw_unit_encode (struct hw *bus,
101 			const hw_unit *phys,
102 			char *buf,
103 			int sizeof_buf)
104 {
105   int i;
106   int len;
107   char *pos = buf;
108   /* skip leading zero's */
109   for (i = 0; i < phys->nr_cells; i++)
110     {
111       if (phys->cells[i] != 0)
112 	break;
113     }
114   /* don't output anything if empty */
115   if (phys->nr_cells == 0)
116     {
117       strcpy (pos, "");
118       len = 0;
119     }
120   else if (i == phys->nr_cells)
121     {
122       /* all zero */
123       strcpy (pos, "0");
124       len = 1;
125     }
126   else
127     {
128       for (; i < phys->nr_cells; i++)
129 	{
130 	  if (pos != buf)
131 	    {
132 	      strcat (pos, ",");
133 	      pos = strchr (pos, '\0');
134 	    }
135 	  if (phys->cells[i] < 10)
136 	    sprintf (pos, "%ld", (unsigned long)phys->cells[i]);
137 	  else
138 	    sprintf (pos, "0x%lx", (unsigned long)phys->cells[i]);
139 	  pos = strchr (pos, '\0');
140 	}
141       len = pos - buf;
142     }
143   if (len >= sizeof_buf)
144     hw_abort (NULL, "generic_unit_encode - buffer overflow\n");
145   return len;
146 }
147 
148 static int
generic_hw_unit_address_to_attach_address(struct hw * me,const hw_unit * address,int * attach_space,unsigned_word * attach_address,struct hw * client)149 generic_hw_unit_address_to_attach_address (struct hw *me,
150 					   const hw_unit *address,
151 					   int *attach_space,
152 					   unsigned_word *attach_address,
153 					   struct hw *client)
154 {
155   int i;
156   for (i = 0; i < address->nr_cells - 2; i++)
157     {
158       if (address->cells[i] != 0)
159 	hw_abort (me, "Only 32bit addresses supported");
160     }
161   if (address->nr_cells >= 2)
162     *attach_space = address->cells[address->nr_cells - 2];
163   else
164     *attach_space = 0;
165   *attach_address = address->cells[address->nr_cells - 1];
166   return 1;
167 }
168 
169 static int
generic_hw_unit_size_to_attach_size(struct hw * me,const hw_unit * size,unsigned * nr_bytes,struct hw * client)170 generic_hw_unit_size_to_attach_size (struct hw *me,
171 				     const hw_unit *size,
172 				     unsigned *nr_bytes,
173 				     struct hw *client)
174 {
175   int i;
176   for (i = 0; i < size->nr_cells - 1; i++)
177     {
178       if (size->cells[i] != 0)
179 	hw_abort (me, "Only 32bit sizes supported");
180     }
181   *nr_bytes = size->cells[0];
182   return *nr_bytes;
183 }
184 
185 
186 /* ignore/passthrough versions of each function */
187 
188 static void
passthrough_hw_attach_address(struct hw * me,int level,int space,address_word addr,address_word nr_bytes,struct hw * client)189 passthrough_hw_attach_address (struct hw *me,
190 			       int level,
191 			       int space,
192 			       address_word addr,
193 			       address_word nr_bytes,
194 			       struct hw *client) /*callback/default*/
195 {
196   if (hw_parent (me) == NULL)
197     hw_abort (client, "hw_attach_address: no parent attach method");
198   hw_attach_address (hw_parent (me), level,
199 		     space, addr, nr_bytes,
200 		     client);
201 }
202 
203 static void
passthrough_hw_detach_address(struct hw * me,int level,int space,address_word addr,address_word nr_bytes,struct hw * client)204 passthrough_hw_detach_address (struct hw *me,
205 			       int level,
206 			       int space,
207 			       address_word addr,
208 			       address_word nr_bytes,
209 			       struct hw *client) /*callback/default*/
210 {
211   if (hw_parent (me) == NULL)
212     hw_abort (client, "hw_attach_address: no parent attach method");
213   hw_detach_address (hw_parent (me), level,
214 		     space, addr, nr_bytes,
215 		     client);
216 }
217 
218 static unsigned
panic_hw_io_read_buffer(struct hw * me,void * dest,int space,unsigned_word addr,unsigned nr_bytes)219 panic_hw_io_read_buffer (struct hw *me,
220 			 void *dest,
221 			 int space,
222 			 unsigned_word addr,
223 			 unsigned nr_bytes)
224 {
225   hw_abort (me, "no io-read method");
226   return 0;
227 }
228 
229 static unsigned
panic_hw_io_write_buffer(struct hw * me,const void * source,int space,unsigned_word addr,unsigned nr_bytes)230 panic_hw_io_write_buffer (struct hw *me,
231 			  const void *source,
232 			  int space,
233 			  unsigned_word addr,
234 			  unsigned nr_bytes)
235 {
236   hw_abort (me, "no io-write method");
237   return 0;
238 }
239 
240 static unsigned
passthrough_hw_dma_read_buffer(struct hw * me,void * dest,int space,unsigned_word addr,unsigned nr_bytes)241 passthrough_hw_dma_read_buffer (struct hw *me,
242 				void *dest,
243 				int space,
244 				unsigned_word addr,
245 				unsigned nr_bytes)
246 {
247   if (hw_parent (me) == NULL)
248     hw_abort (me, "no parent dma-read method");
249   return hw_dma_read_buffer (hw_parent (me), dest,
250 			     space, addr, nr_bytes);
251 }
252 
253 static unsigned
passthrough_hw_dma_write_buffer(struct hw * me,const void * source,int space,unsigned_word addr,unsigned nr_bytes,int violate_read_only_section)254 passthrough_hw_dma_write_buffer (struct hw *me,
255 				 const void *source,
256 				 int space,
257 				 unsigned_word addr,
258 				 unsigned nr_bytes,
259 				 int violate_read_only_section)
260 {
261   if (hw_parent (me) == NULL)
262     hw_abort (me, "no parent dma-write method");
263   return hw_dma_write_buffer (hw_parent (me), source,
264 			      space, addr,
265 			      nr_bytes,
266 			      violate_read_only_section);
267 }
268 
269 static void
ignore_hw_delete(struct hw * me)270 ignore_hw_delete (struct hw *me)
271 {
272   /* NOP */
273 }
274 
275 
276 
277 
278 static const char *
full_name_of_hw(struct hw * leaf,char * buf,unsigned sizeof_buf)279 full_name_of_hw (struct hw *leaf,
280 		 char *buf,
281 		 unsigned sizeof_buf)
282 {
283   /* get a buffer */
284   char full_name[1024];
285   if (buf == (char*)0)
286     {
287       buf = full_name;
288       sizeof_buf = sizeof (full_name);
289     }
290 
291   /* use head recursion to construct the path */
292 
293   if (hw_parent (leaf) == NULL)
294     /* root */
295     {
296       if (sizeof_buf < 1)
297 	hw_abort (leaf, "buffer overflow");
298       *buf = '\0';
299     }
300   else
301     /* sub node */
302     {
303       char unit[1024];
304       full_name_of_hw (hw_parent (leaf), buf, sizeof_buf);
305       if (hw_unit_encode (hw_parent (leaf),
306 			  hw_unit_address (leaf),
307 			  unit + 1,
308 			  sizeof (unit) - 1)
309 	  > 0)
310 	unit[0] = '@';
311       else
312 	unit[0] = '\0';
313       if (strlen (buf) + strlen ("/") + strlen (hw_name (leaf)) + strlen (unit)
314 	  >= sizeof_buf)
315 	hw_abort (leaf, "buffer overflow");
316       strcat (buf, "/");
317       strcat (buf, hw_name (leaf));
318       strcat (buf, unit);
319     }
320 
321   /* return it usefully */
322   if (buf == full_name)
323     buf = hw_strdup (leaf, full_name);
324   return buf;
325 }
326 
327 struct hw *
hw_create(struct sim_state * sd,struct hw * parent,const char * family,const char * name,const char * unit,const char * args)328 hw_create (struct sim_state *sd,
329 	   struct hw *parent,
330 	   const char *family,
331 	   const char *name,
332 	   const char *unit,
333 	   const char *args)
334 {
335  /* NOTE: HW must be allocated using ZALLOC, others use HW_ZALLOC */
336   struct hw *hw = ZALLOC (struct hw);
337 
338   /* our identity */
339   hw->family_of_hw = hw_strdup (hw, family);
340   hw->name_of_hw = hw_strdup (hw, name);
341   hw->args_of_hw = hw_strdup (hw, args);
342 
343   /* a hook into the system */
344   if (sd != NULL)
345     hw->system_of_hw = sd;
346   else if (parent != NULL)
347     hw->system_of_hw = hw_system (parent);
348   else
349     hw_abort (parent, "No system found");
350 
351   /* in a tree */
352   if (parent != NULL)
353     {
354       struct hw **sibling = &parent->child_of_hw;
355       while ((*sibling) != NULL)
356 	sibling = &(*sibling)->sibling_of_hw;
357       *sibling = hw;
358       hw->parent_of_hw = parent;
359     }
360 
361   /* top of tree */
362   if (parent != NULL)
363     {
364       struct hw *root = parent;
365       while (root->parent_of_hw != NULL)
366 	root = root->parent_of_hw;
367       hw->root_of_hw = root;
368     }
369 
370   /* a unique identifier for the device on the parents bus */
371   if (parent != NULL)
372     {
373       hw_unit_decode (parent, unit, &hw->unit_address_of_hw);
374     }
375 
376   /* Determine our path */
377   if (parent != NULL)
378     hw->path_of_hw = full_name_of_hw (hw, NULL, 0);
379   else
380     hw->path_of_hw = "/";
381 
382   /* create our base type */
383   hw->base_of_hw = HW_ZALLOC (hw, struct hw_base_data);
384   hw->base_of_hw->finished_p = 0;
385 
386   /* our callbacks */
387   set_hw_io_read_buffer (hw, panic_hw_io_read_buffer);
388   set_hw_io_write_buffer (hw, panic_hw_io_write_buffer);
389   set_hw_dma_read_buffer (hw, passthrough_hw_dma_read_buffer);
390   set_hw_dma_write_buffer (hw, passthrough_hw_dma_write_buffer);
391   set_hw_unit_decode (hw, generic_hw_unit_decode);
392   set_hw_unit_encode (hw, generic_hw_unit_encode);
393   set_hw_unit_address_to_attach_address (hw, generic_hw_unit_address_to_attach_address);
394   set_hw_unit_size_to_attach_size (hw, generic_hw_unit_size_to_attach_size);
395   set_hw_attach_address (hw, passthrough_hw_attach_address);
396   set_hw_detach_address (hw, passthrough_hw_detach_address);
397   set_hw_delete (hw, ignore_hw_delete);
398 
399   /* locate a descriptor */
400   {
401     const struct hw_descriptor **table;
402     for (table = hw_descriptors;
403 	 *table != NULL;
404 	 table++)
405       {
406 	const struct hw_descriptor *entry;
407 	for (entry = *table;
408 	     entry->family != NULL;
409 	     entry++)
410 	  {
411 	    if (strcmp (family, entry->family) == 0)
412 	      {
413 		hw->base_of_hw->descriptor = entry;
414 		break;
415 	      }
416 	  }
417       }
418     if (hw->base_of_hw->descriptor == NULL)
419       {
420 	hw_abort (parent, "Unknown device `%s'", family);
421       }
422   }
423 
424   /* Attach dummy ports */
425   create_hw_alloc_data (hw);
426   create_hw_property_data (hw);
427   create_hw_port_data (hw);
428   create_hw_event_data (hw);
429   create_hw_handle_data (hw);
430   create_hw_instance_data (hw);
431 
432   return hw;
433 }
434 
435 
436 int
hw_finished_p(struct hw * me)437 hw_finished_p (struct hw *me)
438 {
439   return (me->base_of_hw->finished_p);
440 }
441 
442 void
hw_finish(struct hw * me)443 hw_finish (struct hw *me)
444 {
445   if (hw_finished_p (me))
446     hw_abort (me, "Attempt to finish finished device");
447 
448   /* Fill in the (hopefully) defined address/size cells values */
449   if (hw_find_property (me, "#address-cells") != NULL)
450     me->nr_address_cells_of_hw_unit =
451       hw_find_integer_property (me, "#address-cells");
452   else
453     me->nr_address_cells_of_hw_unit = 2;
454   if (hw_find_property (me, "#size-cells") != NULL)
455     me->nr_size_cells_of_hw_unit =
456       hw_find_integer_property (me, "#size-cells");
457   else
458     me->nr_size_cells_of_hw_unit = 1;
459 
460   /* Fill in the (hopefully) defined trace variable */
461   if (hw_find_property (me, "trace?") != NULL)
462     me->trace_of_hw_p = hw_find_boolean_property (me, "trace?");
463   /* allow global variable to define default tracing */
464   else if (! hw_trace_p (me)
465 	   && hw_find_property (hw_root (me), "global-trace?") != NULL
466 	   && hw_find_boolean_property (hw_root (me), "global-trace?"))
467     me->trace_of_hw_p = 1;
468 
469 
470   /* Allow the real device to override any methods */
471   me->base_of_hw->descriptor->to_finish (me);
472   me->base_of_hw->finished_p = 1;
473 }
474 
475 
476 void
hw_delete(struct hw * me)477 hw_delete (struct hw *me)
478 {
479   /* give the object a chance to tidy up */
480   me->base_of_hw->to_delete (me);
481 
482   delete_hw_instance_data (me);
483   delete_hw_handle_data (me);
484   delete_hw_event_data (me);
485   delete_hw_port_data (me);
486   delete_hw_property_data (me);
487 
488   /* now unlink us from the tree */
489   if (hw_parent (me))
490     {
491       struct hw **sibling = &hw_parent (me)->child_of_hw;
492       while (*sibling != NULL)
493 	{
494 	  if (*sibling == me)
495 	    {
496 	      *sibling = me->sibling_of_hw;
497 	      me->sibling_of_hw = NULL;
498 	      me->parent_of_hw = NULL;
499 	      break;
500 	    }
501 	}
502     }
503 
504   /* some sanity checks */
505   if (hw_child (me) != NULL)
506     {
507       hw_abort (me, "attempt to delete device with children");
508     }
509   if (hw_sibling (me) != NULL)
510     {
511       hw_abort (me, "attempt to delete device with siblings");
512     }
513 
514   /* blow away all memory belonging to the device */
515   delete_hw_alloc_data (me);
516 
517   /* finally */
518   free (me);
519 }
520 
521 void
set_hw_delete(struct hw * hw,hw_delete_callback method)522 set_hw_delete (struct hw *hw, hw_delete_callback method)
523 {
524   hw->base_of_hw->to_delete = method;
525 }
526 
527 
528 /* Go through the devices various reg properties for those that
529    specify attach addresses */
530 
531 
532 void
do_hw_attach_regs(struct hw * hw)533 do_hw_attach_regs (struct hw *hw)
534 {
535   static const char *(reg_property_names[]) = {
536     "attach-addresses",
537     "assigned-addresses",
538     "reg",
539     "alternate-reg" ,
540     NULL
541   };
542   const char **reg_property_name;
543   int nr_valid_reg_properties = 0;
544   for (reg_property_name = reg_property_names;
545        *reg_property_name != NULL;
546        reg_property_name++)
547     {
548       if (hw_find_property (hw, *reg_property_name) != NULL)
549 	{
550 	  reg_property_spec reg;
551 	  int reg_entry;
552 	  for (reg_entry = 0;
553 	       hw_find_reg_array_property (hw, *reg_property_name, reg_entry,
554 					   &reg);
555 	       reg_entry++)
556 	    {
557 	      unsigned_word attach_address;
558 	      int attach_space;
559 	      unsigned attach_size;
560 	      if (!hw_unit_address_to_attach_address (hw_parent (hw),
561 						      &reg.address,
562 						      &attach_space,
563 						      &attach_address,
564 						      hw))
565 		continue;
566 	      if (!hw_unit_size_to_attach_size (hw_parent (hw),
567 						&reg.size,
568 						&attach_size, hw))
569 		continue;
570 	      hw_attach_address (hw_parent (hw),
571 				 0,
572 				 attach_space, attach_address, attach_size,
573 				 hw);
574 	      nr_valid_reg_properties++;
575 	    }
576 	  /* if first option matches don't try for any others */
577 	  if (reg_property_name == reg_property_names)
578 	    break;
579 	}
580     }
581 }
582