Home | History | Annotate | Line # | Download | only in common
      1 /* The common simulator framework for GDB, the GNU Debugger.
      2 
      3    Copyright 2002-2024 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 <string.h>
     26 
     27 #include "hw-main.h"
     28 #include "hw-base.h"
     29 
     30 #include "sim-io.h"
     31 #include "sim-assert.h"
     32 
     33 /* property entries */
     34 
     35 struct hw_property_data
     36 {
     37   struct hw_property_data *next;
     38   struct hw_property *property;
     39   const void *init_array;
     40   unsigned sizeof_init_array;
     41 };
     42 
     43 void
     44 create_hw_property_data (struct hw *me)
     45 {
     46 }
     47 
     48 void
     49 delete_hw_property_data (struct hw *me)
     50 {
     51 }
     52 
     53 
     54 /* Device Properties: */
     55 
     56 static struct hw_property_data *
     57 find_property_data (struct hw *me,
     58 		    const char *property)
     59 {
     60   struct hw_property_data *entry;
     61   ASSERT (property != NULL);
     62   entry = me->properties_of_hw;
     63   while (entry != NULL)
     64     {
     65       if (strcmp (entry->property->name, property) == 0)
     66 	return entry;
     67       entry = entry->next;
     68     }
     69   return NULL;
     70 }
     71 
     72 
     73 static void
     74 hw_add_property (struct hw *me,
     75 		 const char *property,
     76 		 hw_property_type type,
     77 		 const void *init_array,
     78 		 unsigned sizeof_init_array,
     79 		 const void *array,
     80 		 unsigned sizeof_array,
     81 		 const struct hw_property *original,
     82 		 object_disposition disposition)
     83 {
     84   struct hw_property_data *new_entry = NULL;
     85   struct hw_property *new_value = NULL;
     86 
     87   /* find the list end */
     88   struct hw_property_data **insertion_point = &me->properties_of_hw;
     89   while (*insertion_point != NULL)
     90     {
     91       if (strcmp ((*insertion_point)->property->name, property) == 0)
     92 	return;
     93       insertion_point = &(*insertion_point)->next;
     94     }
     95 
     96   /* create a new value */
     97   new_value = HW_ZALLOC (me, struct hw_property);
     98   new_value->name = (char *) strdup (property);
     99   new_value->type = type;
    100   if (sizeof_array > 0)
    101     {
    102       void *new_array = hw_zalloc (me, sizeof_array);
    103       memcpy (new_array, array, sizeof_array);
    104       new_value->array = new_array;
    105       new_value->sizeof_array = sizeof_array;
    106     }
    107   new_value->owner = me;
    108   new_value->original = original;
    109   new_value->disposition = disposition;
    110 
    111   /* insert the value into the list */
    112   new_entry = HW_ZALLOC (me, struct hw_property_data);
    113   *insertion_point = new_entry;
    114   if (sizeof_init_array > 0)
    115     {
    116       void *new_init_array = hw_zalloc (me, sizeof_init_array);
    117       memcpy (new_init_array, init_array, sizeof_init_array);
    118       new_entry->init_array = new_init_array;
    119       new_entry->sizeof_init_array = sizeof_init_array;
    120     }
    121   new_entry->property = new_value;
    122 }
    123 
    124 
    125 static void
    126 hw_set_property (struct hw *me,
    127 		 const char *property,
    128 		 hw_property_type type,
    129 		 const void *array,
    130 		 int sizeof_array)
    131 {
    132   /* find the property */
    133   struct hw_property_data *entry = find_property_data (me, property);
    134   if (entry != NULL)
    135     {
    136       /* existing property - update it */
    137       void *new_array = 0;
    138       struct hw_property *value = entry->property;
    139       /* check the type matches */
    140       if (value->type != type)
    141 	hw_abort (me, "conflict between type of new and old value for property %s", property);
    142       /* replace its value */
    143       if (value->array != NULL)
    144 	hw_free (me, (void*)value->array);
    145       new_array = (sizeof_array > 0
    146 		   ? hw_zalloc (me, sizeof_array)
    147 		   : (void*)0);
    148       value->array = new_array;
    149       value->sizeof_array = sizeof_array;
    150       if (sizeof_array > 0)
    151 	memcpy (new_array, array, sizeof_array);
    152       return;
    153     }
    154   else
    155     {
    156       /* new property - create it */
    157       hw_add_property (me, property, type,
    158 		       NULL, 0, array, sizeof_array,
    159 		       NULL, temporary_object);
    160     }
    161 }
    162 
    163 
    164 #if 0
    165 static void
    166 clean_hw_properties (struct hw *me)
    167 {
    168   struct hw_property_data **delete_point = &me->properties_of_hw;
    169   while (*delete_point != NULL)
    170     {
    171       struct hw_property_data *current = *delete_point;
    172       switch (current->property->disposition)
    173 	{
    174 	case permanent_object:
    175 	  /* zap the current value, will be initialized later */
    176 	  ASSERT (current->init_array != NULL);
    177 	  if (current->property->array != NULL)
    178 	    {
    179 	      hw_free (me, (void*)current->property->array);
    180 	      current->property->array = NULL;
    181 	    }
    182 	  delete_point = &(*delete_point)->next;
    183 	  break;
    184 	case temporary_object:
    185 	  /* zap the actual property, was created during simulation run */
    186 	  ASSERT (current->init_array == NULL);
    187 	  *delete_point = current->next;
    188 	  if (current->property->array != NULL)
    189 	    hw_free (me, (void*)current->property->array);
    190 	  hw_free (me, current->property);
    191 	  hw_free (me, current);
    192 	  break;
    193 	}
    194     }
    195 }
    196 #endif
    197 
    198 #if 0
    199 void
    200 hw_init_static_properties (SIM_DESC sd,
    201 			   struct hw *me,
    202 			   void *data)
    203 {
    204   struct hw_property_data *property;
    205   for (property = me->properties_of_hw;
    206        property != NULL;
    207        property = property->next)
    208     {
    209       ASSERT (property->init_array != NULL);
    210       ASSERT (property->property->array == NULL);
    211       ASSERT (property->property->disposition == permanent_object);
    212       switch (property->property->type)
    213 	{
    214 	case array_property:
    215 	case boolean_property:
    216 	case range_array_property:
    217 	case reg_array_property:
    218 	case string_property:
    219 	case string_array_property:
    220 	case integer_property:
    221 	  /* delete the property, and replace it with the original */
    222 	  hw_set_property (me, property->property->name,
    223 			   property->property->type,
    224 			   property->init_array,
    225 			   property->sizeof_init_array);
    226 	  break;
    227 #if 0
    228 	case ihandle_property:
    229 	  break;
    230 #endif
    231 	}
    232     }
    233 }
    234 #endif
    235 
    236 
    237 #if 0
    238 void
    239 hw_init_runtime_properties (SIM_DESC sd,
    240 			    struct hw *me,
    241 			    void *data)
    242 {
    243   struct hw_property_data *property;
    244   for (property = me->properties_of_hw;
    245        property != NULL;
    246        property = property->next)
    247     {
    248       switch (property->property->disposition)
    249 	{
    250 	case permanent_object:
    251 	  switch (property->property->type)
    252 	    {
    253 #if 0
    254 	    case ihandle_property:
    255 	      {
    256 		struct hw_instance *ihandle;
    257 		ihandle_runtime_property_spec spec;
    258 		ASSERT (property->init_array != NULL);
    259 		ASSERT (property->property->array == NULL);
    260 		hw_find_ihandle_runtime_property (me, property->property->name, &spec);
    261 		ihandle = tree_instance (me, spec.full_path);
    262 		hw_set_ihandle_property (me, property->property->name, ihandle);
    263 		break;
    264 	      }
    265 #endif
    266 	    case array_property:
    267 	    case boolean_property:
    268 	    case range_array_property:
    269 	    case integer_property:
    270 	    case reg_array_property:
    271 	    case string_property:
    272 	    case string_array_property:
    273 	      ASSERT (property->init_array != NULL);
    274 	      ASSERT (property->property->array != NULL);
    275 	      break;
    276 	    }
    277 	  break;
    278 	case temporary_object:
    279 	  ASSERT (property->init_array == NULL);
    280 	  ASSERT (property->property->array != NULL);
    281 	  break;
    282 	}
    283     }
    284 }
    285 #endif
    286 
    287 
    288 
    289 const struct hw_property *
    290 hw_next_property (const struct hw_property *property)
    291 {
    292   /* find the property in the list */
    293   struct hw *owner = property->owner;
    294   struct hw_property_data *entry = owner->properties_of_hw;
    295   while (entry != NULL && entry->property != property)
    296     entry = entry->next;
    297   /* now return the following property */
    298   ASSERT (entry != NULL); /* must be a member! */
    299   if (entry->next != NULL)
    300     return entry->next->property;
    301   else
    302     return NULL;
    303 }
    304 
    305 
    306 const struct hw_property *
    307 hw_find_property (struct hw *me,
    308 		  const char *property)
    309 {
    310   if (me == NULL)
    311     {
    312       return NULL;
    313     }
    314   else if (property == NULL || strcmp (property, "") == 0)
    315     {
    316       if (me->properties_of_hw == NULL)
    317 	return NULL;
    318       else
    319 	return me->properties_of_hw->property;
    320     }
    321   else
    322     {
    323       struct hw_property_data *entry = find_property_data (me, property);
    324       if (entry != NULL)
    325 	return entry->property;
    326     }
    327   return NULL;
    328 }
    329 
    330 
    331 void
    332 hw_add_array_property (struct hw *me,
    333 		       const char *property,
    334 		       const void *array,
    335 		       int sizeof_array)
    336 {
    337   hw_add_property (me, property, array_property,
    338 		   array, sizeof_array, array, sizeof_array,
    339 		   NULL, permanent_object);
    340 }
    341 
    342 void
    343 hw_set_array_property (struct hw *me,
    344 		       const char *property,
    345 		       const void *array,
    346 		       int sizeof_array)
    347 {
    348   hw_set_property (me, property, array_property, array, sizeof_array);
    349 }
    350 
    351 const struct hw_property *
    352 hw_find_array_property (struct hw *me,
    353 			const char *property)
    354 {
    355   const struct hw_property *node;
    356   node = hw_find_property (me, property);
    357   if (node == NULL)
    358     hw_abort (me, "property \"%s\" not found", property);
    359   if (node->type != array_property)
    360     hw_abort (me, "property \"%s\" of wrong type (array)", property);
    361   return node;
    362 }
    363 
    364 
    365 
    366 void
    367 hw_add_boolean_property (struct hw *me,
    368 			 const char *property,
    369 			 int boolean)
    370 {
    371   int32_t new_boolean = (boolean ? -1 : 0);
    372   hw_add_property (me, property, boolean_property,
    373 		   &new_boolean, sizeof (new_boolean),
    374 		   &new_boolean, sizeof (new_boolean),
    375 		   NULL, permanent_object);
    376 }
    377 
    378 int
    379 hw_find_boolean_property (struct hw *me,
    380 			  const char *property)
    381 {
    382   const struct hw_property *node;
    383   unsigned_cell boolean;
    384   node = hw_find_property (me, property);
    385   if (node == NULL)
    386     hw_abort (me, "property \"%s\" not found", property);
    387   if (node->type != boolean_property)
    388     hw_abort (me, "property \"%s\" of wrong type (boolean)", property);
    389   ASSERT (sizeof (boolean) == node->sizeof_array);
    390   memcpy (&boolean, node->array, sizeof (boolean));
    391   return boolean;
    392 }
    393 
    394 
    395 
    396 #if 0
    397 void
    398 hw_add_ihandle_runtime_property (struct hw *me,
    399 				 const char *property,
    400 				 const ihandle_runtime_property_spec *ihandle)
    401 {
    402   /* enter the full path as the init array */
    403   hw_add_property (me, property, ihandle_property,
    404 		   ihandle->full_path, strlen (ihandle->full_path) + 1,
    405 		   NULL, 0,
    406 		   NULL, permanent_object);
    407 }
    408 #endif
    409 
    410 #if 0
    411 void
    412 hw_find_ihandle_runtime_property (struct hw *me,
    413 				  const char *property,
    414 				  ihandle_runtime_property_spec *ihandle)
    415 {
    416   struct hw_property_data *entry = find_property_data (me, property);
    417   if (entry == NULL)
    418     hw_abort (me, "property \"%s\" not found", property);
    419   if (entry->property->type != ihandle_property
    420       || entry->property->disposition != permanent_object)
    421     hw_abort (me, "property \"%s\" of wrong type", property);
    422   ASSERT (entry->init_array != NULL);
    423   /* the full path */
    424   ihandle->full_path = entry->init_array;
    425 }
    426 #endif
    427 
    428 
    429 
    430 #if 0
    431 void
    432 hw_set_ihandle_property (struct hw *me,
    433 			 const char *property,
    434 			 hw_instance *ihandle)
    435 {
    436   unsigned_cell cells;
    437   cells = H2BE_cell (hw_instance_to_external (ihandle));
    438   hw_set_property (me, property, ihandle_property,
    439 		   &cells, sizeof (cells));
    440 
    441 }
    442 #endif
    443 
    444 #if 0
    445 hw_instance *
    446 hw_find_ihandle_property (struct hw *me,
    447 			  const char *property)
    448 {
    449   const hw_property_data *node;
    450   unsigned_cell ihandle;
    451   hw_instance *instance;
    452 
    453   node = hw_find_property (me, property);
    454   if (node == NULL)
    455     hw_abort (me, "property \"%s\" not found", property);
    456   if (node->type != ihandle_property)
    457     hw_abort (me, "property \"%s\" of wrong type (ihandle)", property);
    458   if (node->array == NULL)
    459     hw_abort (me, "runtime property \"%s\" not yet initialized", property);
    460 
    461   ASSERT (sizeof (ihandle) == node->sizeof_array);
    462   memcpy (&ihandle, node->array, sizeof (ihandle));
    463   instance = external_to_hw_instance (me, BE2H_cell (ihandle));
    464   ASSERT (instance != NULL);
    465   return instance;
    466 }
    467 #endif
    468 
    469 
    470 void
    471 hw_add_integer_property (struct hw *me,
    472 			 const char *property,
    473 			 signed_cell integer)
    474 {
    475   H2BE (integer);
    476   hw_add_property (me, property, integer_property,
    477 		   &integer, sizeof (integer),
    478 		   &integer, sizeof (integer),
    479 		   NULL, permanent_object);
    480 }
    481 
    482 signed_cell
    483 hw_find_integer_property (struct hw *me,
    484 			  const char *property)
    485 {
    486   const struct hw_property *node;
    487   signed_cell integer;
    488   node = hw_find_property (me, property);
    489   if (node == NULL)
    490     hw_abort (me, "property \"%s\" not found", property);
    491   if (node->type != integer_property)
    492     hw_abort (me, "property \"%s\" of wrong type (integer)", property);
    493   ASSERT (sizeof (integer) == node->sizeof_array);
    494   memcpy (&integer, node->array, sizeof (integer));
    495   return BE2H_cell (integer);
    496 }
    497 
    498 int
    499 hw_find_integer_array_property (struct hw *me,
    500 				const char *property,
    501 				unsigned index,
    502 				signed_cell *integer)
    503 {
    504   const struct hw_property *node;
    505   int sizeof_integer = sizeof (*integer);
    506   signed_cell *cell;
    507 
    508   /* check things sane */
    509   node = hw_find_property (me, property);
    510   if (node == NULL)
    511     hw_abort (me, "property \"%s\" not found", property);
    512   if (node->type != integer_property
    513       && node->type != array_property)
    514     hw_abort (me, "property \"%s\" of wrong type (integer or array)", property);
    515   if ((node->sizeof_array % sizeof_integer) != 0)
    516     hw_abort (me, "property \"%s\" contains an incomplete number of cells", property);
    517   if (node->sizeof_array <= sizeof_integer * index)
    518     return 0;
    519 
    520   /* Find and convert the value */
    521   cell = ((signed_cell*)node->array) + index;
    522   *integer = BE2H_cell (*cell);
    523 
    524   return node->sizeof_array / sizeof_integer;
    525 }
    526 
    527 
    528 static unsigned_cell *
    529 unit_address_to_cells (const hw_unit *unit,
    530 		       unsigned_cell *cell,
    531 		       int nr_cells)
    532 {
    533   int i;
    534   ASSERT (nr_cells == unit->nr_cells);
    535   for (i = 0; i < unit->nr_cells; i++)
    536     {
    537       *cell = H2BE_cell (unit->cells[i]);
    538       cell += 1;
    539     }
    540   return cell;
    541 }
    542 
    543 
    544 static const unsigned_cell *
    545 cells_to_unit_address (const unsigned_cell *cell,
    546 		       hw_unit *unit,
    547 		       int nr_cells)
    548 {
    549   int i;
    550   memset (unit, 0, sizeof (*unit));
    551   unit->nr_cells = nr_cells;
    552   for (i = 0; i < unit->nr_cells; i++)
    553     {
    554       unit->cells[i] = BE2H_cell (*cell);
    555       cell += 1;
    556     }
    557   return cell;
    558 }
    559 
    560 
    561 static unsigned
    562 nr_range_property_cells (struct hw *me,
    563 			 int nr_ranges)
    564 {
    565   return ((hw_unit_nr_address_cells (me)
    566 	   + hw_unit_nr_address_cells (hw_parent (me))
    567 	   + hw_unit_nr_size_cells (me))
    568 	  ) * nr_ranges;
    569 }
    570 
    571 void
    572 hw_add_range_array_property (struct hw *me,
    573 			     const char *property,
    574 			     const range_property_spec *ranges,
    575 			     unsigned nr_ranges)
    576 {
    577   unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges)
    578 			   * sizeof (unsigned_cell));
    579   unsigned_cell *cells = hw_zalloc (me, sizeof_cells);
    580   unsigned_cell *cell;
    581   int i;
    582 
    583   /* copy the property elements over */
    584   cell = cells;
    585   for (i = 0; i < nr_ranges; i++)
    586     {
    587       const range_property_spec *range = &ranges[i];
    588       /* copy the child address */
    589       cell = unit_address_to_cells (&range->child_address, cell,
    590 				    hw_unit_nr_address_cells (me));
    591       /* copy the parent address */
    592       cell = unit_address_to_cells (&range->parent_address, cell,
    593 				    hw_unit_nr_address_cells (hw_parent (me)));
    594       /* copy the size */
    595       cell = unit_address_to_cells (&range->size, cell,
    596 				    hw_unit_nr_size_cells (me));
    597     }
    598   ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]);
    599 
    600   /* add it */
    601   hw_add_property (me, property, range_array_property,
    602 		   cells, sizeof_cells,
    603 		   cells, sizeof_cells,
    604 		   NULL, permanent_object);
    605 
    606   hw_free (me, cells);
    607 }
    608 
    609 int
    610 hw_find_range_array_property (struct hw *me,
    611 			      const char *property,
    612 			      unsigned index,
    613 			      range_property_spec *range)
    614 {
    615   const struct hw_property *node;
    616   unsigned sizeof_entry = (nr_range_property_cells (me, 1)
    617 			   * sizeof (unsigned_cell));
    618   const unsigned_cell *cells;
    619 
    620   /* locate the property */
    621   node = hw_find_property (me, property);
    622   if (node == NULL)
    623     hw_abort (me, "property \"%s\" not found", property);
    624   if (node->type != range_array_property)
    625     hw_abort (me, "property \"%s\" of wrong type (range array)", property);
    626 
    627   /* aligned ? */
    628   if ((node->sizeof_array % sizeof_entry) != 0)
    629     hw_abort (me, "property \"%s\" contains an incomplete number of entries",
    630 	      property);
    631 
    632   /* within bounds? */
    633   if (node->sizeof_array < sizeof_entry * (index + 1))
    634     return 0;
    635 
    636   /* find the range of interest */
    637   cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
    638 
    639   /* copy the child address out - converting as we go */
    640   cells = cells_to_unit_address (cells, &range->child_address,
    641 				 hw_unit_nr_address_cells (me));
    642 
    643   /* copy the parent address out - converting as we go */
    644   cells = cells_to_unit_address (cells, &range->parent_address,
    645 				 hw_unit_nr_address_cells (hw_parent (me)));
    646 
    647   /* copy the size - converting as we go */
    648   cells = cells_to_unit_address (cells, &range->size,
    649 				 hw_unit_nr_size_cells (me));
    650 
    651   return node->sizeof_array / sizeof_entry;
    652 }
    653 
    654 
    655 static unsigned
    656 nr_reg_property_cells (struct hw *me,
    657 		       int nr_regs)
    658 {
    659   return (hw_unit_nr_address_cells (hw_parent (me))
    660 	  + hw_unit_nr_size_cells (hw_parent (me))
    661 	  ) * nr_regs;
    662 }
    663 
    664 void
    665 hw_add_reg_array_property (struct hw *me,
    666 			   const char *property,
    667 			   const reg_property_spec *regs,
    668 			   unsigned nr_regs)
    669 {
    670   unsigned sizeof_cells = (nr_reg_property_cells (me, nr_regs)
    671 			   * sizeof (unsigned_cell));
    672   unsigned_cell *cells = hw_zalloc (me, sizeof_cells);
    673   unsigned_cell *cell;
    674   int i;
    675 
    676   /* copy the property elements over */
    677   cell = cells;
    678   for (i = 0; i < nr_regs; i++)
    679     {
    680       const reg_property_spec *reg = &regs[i];
    681       /* copy the address */
    682       cell = unit_address_to_cells (&reg->address, cell,
    683 				    hw_unit_nr_address_cells (hw_parent (me)));
    684       /* copy the size */
    685       cell = unit_address_to_cells (&reg->size, cell,
    686 				    hw_unit_nr_size_cells (hw_parent (me)));
    687     }
    688   ASSERT (cell == &cells[nr_reg_property_cells (me, nr_regs)]);
    689 
    690   /* add it */
    691   hw_add_property (me, property, reg_array_property,
    692 		   cells, sizeof_cells,
    693 		   cells, sizeof_cells,
    694 		   NULL, permanent_object);
    695 
    696   hw_free (me, cells);
    697 }
    698 
    699 int
    700 hw_find_reg_array_property (struct hw *me,
    701 			    const char *property,
    702 			    unsigned index,
    703 			    reg_property_spec *reg)
    704 {
    705   const struct hw_property *node;
    706   unsigned sizeof_entry = (nr_reg_property_cells (me, 1)
    707 			   * sizeof (unsigned_cell));
    708   const unsigned_cell *cells;
    709 
    710   /* locate the property */
    711   node = hw_find_property (me, property);
    712   if (node == NULL)
    713     hw_abort (me, "property \"%s\" not found", property);
    714   if (node->type != reg_array_property)
    715     hw_abort (me, "property \"%s\" of wrong type (reg array)", property);
    716 
    717   /* aligned ? */
    718   if ((node->sizeof_array % sizeof_entry) != 0)
    719     hw_abort (me, "property \"%s\" contains an incomplete number of entries",
    720 	      property);
    721 
    722   /* within bounds? */
    723   if (node->sizeof_array < sizeof_entry * (index + 1))
    724     return 0;
    725 
    726   /* find the range of interest */
    727   cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
    728 
    729   /* copy the address out - converting as we go */
    730   cells = cells_to_unit_address (cells, &reg->address,
    731 				 hw_unit_nr_address_cells (hw_parent (me)));
    732 
    733   /* copy the size out - converting as we go */
    734   cells = cells_to_unit_address (cells, &reg->size,
    735 				 hw_unit_nr_size_cells (hw_parent (me)));
    736 
    737   return node->sizeof_array / sizeof_entry;
    738 }
    739 
    740 
    741 void
    742 hw_add_string_property (struct hw *me,
    743 			const char *property,
    744 			const char *string)
    745 {
    746   hw_add_property (me, property, string_property,
    747 		   string, strlen (string) + 1,
    748 		   string, strlen (string) + 1,
    749 		   NULL, permanent_object);
    750 }
    751 
    752 const char *
    753 hw_find_string_property (struct hw *me,
    754 			 const char *property)
    755 {
    756   const struct hw_property *node;
    757   const char *string;
    758   node = hw_find_property (me, property);
    759   if (node == NULL)
    760     hw_abort (me, "property \"%s\" not found", property);
    761   if (node->type != string_property)
    762     hw_abort (me, "property \"%s\" of wrong type (string)", property);
    763   string = node->array;
    764   ASSERT (strlen (string) + 1 == node->sizeof_array);
    765   return string;
    766 }
    767 
    768 void
    769 hw_add_string_array_property (struct hw *me,
    770 			      const char *property,
    771 			      const string_property_spec *strings,
    772 			      unsigned nr_strings)
    773 {
    774   int sizeof_array;
    775   int string_nr;
    776   char *array;
    777   char *chp;
    778   if (nr_strings == 0)
    779     hw_abort (me, "property \"%s\" must be non-null", property);
    780   /* total up the size of the needed array */
    781   for (sizeof_array = 0, string_nr = 0;
    782        string_nr < nr_strings;
    783        string_nr ++)
    784     {
    785       sizeof_array += strlen (strings[string_nr]) + 1;
    786     }
    787   /* create the array */
    788   array = (char*) hw_zalloc (me, sizeof_array);
    789   chp = array;
    790   for (string_nr = 0;
    791        string_nr < nr_strings;
    792        string_nr++)
    793     {
    794       strcpy (chp, strings[string_nr]);
    795       chp += strlen (chp) + 1;
    796     }
    797   ASSERT (chp == array + sizeof_array);
    798   /* now enter it */
    799   hw_add_property (me, property, string_array_property,
    800 		   array, sizeof_array,
    801 		   array, sizeof_array,
    802 		   NULL, permanent_object);
    803 }
    804 
    805 int
    806 hw_find_string_array_property (struct hw *me,
    807 			       const char *property,
    808 			       unsigned index,
    809 			       string_property_spec *string)
    810 {
    811   const struct hw_property *node;
    812   node = hw_find_property (me, property);
    813   if (node == NULL)
    814     hw_abort (me, "property \"%s\" not found", property);
    815   switch (node->type)
    816     {
    817     default:
    818       hw_abort (me, "property \"%s\" of wrong type", property);
    819       break;
    820     case string_property:
    821       if (index == 0)
    822 	{
    823 	  *string = node->array;
    824 	  ASSERT (strlen (*string) + 1 == node->sizeof_array);
    825 	  return 1;
    826 	}
    827       break;
    828     case array_property:
    829       if (node->sizeof_array == 0
    830 	  || ((char*)node->array)[node->sizeof_array - 1] != '\0')
    831 	hw_abort (me, "property \"%s\" invalid for string array", property);
    832       ATTRIBUTE_FALLTHROUGH;
    833     case string_array_property:
    834       ASSERT (node->sizeof_array > 0);
    835       ASSERT (((char*)node->array)[node->sizeof_array - 1] == '\0');
    836       {
    837 	const char *chp = node->array;
    838 	int nr_entries = 0;
    839 	/* count the number of strings, keeping an eye out for the one
    840 	   we're looking for */
    841 	*string = chp;
    842 	do
    843 	  {
    844 	    if (*chp == '\0')
    845 	      {
    846 		/* next string */
    847 		nr_entries++;
    848 		chp++;
    849 		if (nr_entries == index)
    850 		  *string = chp;
    851 	      }
    852 	    else
    853 	      {
    854 		chp++;
    855 	      }
    856 	  } while (chp < (char*)node->array + node->sizeof_array);
    857 	if (index < nr_entries)
    858 	  return nr_entries;
    859 	else
    860 	  {
    861 	    *string = NULL;
    862 	    return 0;
    863 	  }
    864       }
    865       break;
    866     }
    867   return 0;
    868 }
    869 
    870 void
    871 hw_add_duplicate_property (struct hw *me,
    872 			   const char *property,
    873 			   const struct hw_property *original)
    874 {
    875   struct hw_property_data *master;
    876   if (original->disposition != permanent_object)
    877     hw_abort (me, "Can only duplicate permanent objects");
    878   /* find the original's master */
    879   master = original->owner->properties_of_hw;
    880   while (master->property != original)
    881     {
    882       master = master->next;
    883       ASSERT (master != NULL);
    884     }
    885   /* now duplicate it */
    886   hw_add_property (me, property,
    887 		   original->type,
    888 		   master->init_array, master->sizeof_init_array,
    889 		   original->array, original->sizeof_array,
    890 		   original, permanent_object);
    891 }
    892