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