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