1/* The common simulator framework for GDB, the GNU Debugger.
2
3   Copyright 2002, 2007, 2008, 2009, 2010, 2011 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{
45  int finished_p;
46  const struct hw_descriptor *descriptor;
47  hw_delete_callback *to_delete;
48};
49
50static int
51generic_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
99static int
100generic_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
148static int
149generic_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
169static int
170generic_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
188static void
189passthrough_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
203static void
204passthrough_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
218static unsigned
219panic_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
229static unsigned
230panic_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
240static unsigned
241passthrough_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
253static unsigned
254passthrough_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
269static void
270ignore_hw_delete (struct hw *me)
271{
272  /* NOP */
273}
274
275
276
277
278static const char *
279full_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
327struct hw *
328hw_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
436int
437hw_finished_p (struct hw *me)
438{
439  return (me->base_of_hw->finished_p);
440}
441
442void
443hw_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
476void
477hw_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
521void
522set_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
532void
533do_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