1 /////////////////////////////////////////////////////////////////////////
2 // $Id: paramtree.cc 14206 2021-03-28 06:31:03Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 //  Copyright (C) 2010-2021  The Bochs Project
6 //
7 //  This library is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU Lesser General Public
9 //  License as published by the Free Software Foundation; either
10 //  version 2 of the License, or (at your option) any later version.
11 //
12 //  This library is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 //  Lesser General Public License for more details.
16 //
17 //  You should have received a copy of the GNU Lesser General Public
18 //  License along with this library; if not, write to the Free Software
19 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20 //
21 /////////////////////////////////////////////////////////////////////////
22 
23 #include "bochs.h"
24 #include "siminterface.h"
25 #include "paramtree.h"
26 
27 /////////////////////////////////////////////////////////////////////////
28 // define methods of bx_param_* and family
29 /////////////////////////////////////////////////////////////////////////
30 
31 extern bx_simulator_interface_c *SIM;
32 extern logfunctions *siminterface_log;
33 extern bx_list_c *root_param;
34 #define LOG_THIS siminterface_log->
35 
36 const char* bx_param_c::default_text_format = NULL;
37 
bx_param_c(Bit32u id,const char * param_name,const char * param_desc)38 bx_param_c::bx_param_c(Bit32u id, const char *param_name, const char *param_desc)
39   : bx_object_c(id),
40     parent(NULL),
41     description(NULL),
42     label(NULL),
43     ask_format(NULL),
44     group_name(NULL)
45 {
46   set_type(BXT_PARAM);
47   this->name = new char[strlen(param_name)+1];
48   strcpy(this->name, param_name);
49   set_description(param_desc);
50   this->text_format = default_text_format;
51   this->long_text_format = default_text_format;
52   this->runtime_param = 0;
53   this->enabled = 1;
54   this->options = 0;
55   // dependent_list must be initialized before the set(),
56   // because set calls update_dependents().
57   dependent_list = NULL;
58 }
59 
bx_param_c(Bit32u id,const char * param_name,const char * param_label,const char * param_desc)60 bx_param_c::bx_param_c(Bit32u id, const char *param_name, const char *param_label, const char *param_desc)
61   : bx_object_c(id),
62     parent(NULL),
63     description(NULL),
64     label(NULL),
65     ask_format(NULL),
66     group_name(NULL)
67 {
68   set_type(BXT_PARAM);
69   this->name = new char[strlen(param_name)+1];
70   strcpy(this->name, param_name);
71   set_description(param_desc);
72   set_label(param_label);
73   this->text_format = default_text_format;
74   this->long_text_format = default_text_format;
75   this->runtime_param = 0;
76   this->enabled = 1;
77   this->options = 0;
78   // dependent_list must be initialized before the set(),
79   // because set calls update_dependents().
80   dependent_list = NULL;
81 }
82 
~bx_param_c()83 bx_param_c::~bx_param_c()
84 {
85   delete [] name;
86   delete [] label;
87   delete [] description;
88   delete [] ask_format;
89   delete [] group_name;
90   delete dependent_list;
91 }
92 
set_description(const char * text)93 void bx_param_c::set_description(const char *text)
94 {
95   delete [] this->description;
96   if (text) {
97     this->description = new char[strlen(text)+1];
98     strcpy(this->description, text);
99   } else {
100     this->description = NULL;
101   }
102 }
103 
set_label(const char * text)104 void bx_param_c::set_label(const char *text)
105 {
106   delete [] label;
107   if (text) {
108     label = new char[strlen(text)+1];
109     strcpy(label, text);
110   } else {
111     label = NULL;
112   }
113 }
114 
set_ask_format(const char * format)115 void bx_param_c::set_ask_format(const char *format)
116 {
117   delete [] ask_format;
118   if (format) {
119     ask_format = new char[strlen(format)+1];
120     strcpy(ask_format, format);
121   } else {
122     ask_format = NULL;
123   }
124 }
125 
set_group(const char * group)126 void bx_param_c::set_group(const char *group)
127 {
128   delete [] group_name;
129   if (group) {
130     group_name = new char[strlen(group)+1];
131     strcpy(group_name, group);
132   } else {
133     group_name = NULL;
134   }
135 }
136 
get_param_path(char * path_out,int maxlen)137 int bx_param_c::get_param_path(char *path_out, int maxlen)
138 {
139   if ((get_parent() == NULL) || (get_parent() == root_param)) {
140     // Start with an empty string.
141     // Never print the name of the root param.
142     path_out[0] = 0;
143   } else {
144     // build path of the parent, add a period, add path of this node
145     if (get_parent()->get_param_path(path_out, maxlen) > 0) {
146       strncat(path_out, ".", maxlen);
147     }
148   }
149   strncat(path_out, name, maxlen);
150   return strlen(path_out);
151 }
152 
set_default_format(const char * f)153 const char* bx_param_c::set_default_format(const char *f)
154 {
155   const char *old = default_text_format;
156   default_text_format = f;
157   return old;
158 }
159 
bx_param_num_c(bx_param_c * parent,const char * name,const char * label,const char * description,Bit64s min,Bit64s max,Bit64s initial_val,bool is_shadow)160 bx_param_num_c::bx_param_num_c(bx_param_c *parent,
161     const char *name,
162     const char *label,
163     const char *description,
164     Bit64s min, Bit64s max, Bit64s initial_val,
165     bool is_shadow)
166   : bx_param_c(SIM->gen_param_id(), name, label, description)
167 {
168   set_type(BXT_PARAM_NUM);
169   this->min = min;
170   this->max = max;
171   this->initial_val = initial_val;
172   this->val.number = initial_val;
173   this->handler = NULL;
174   this->save_handler = NULL;
175   this->restore_handler = NULL;
176   this->enable_handler = NULL;
177   this->base = default_base;
178   this->is_shadow = is_shadow;
179   if (!is_shadow) {
180     set(initial_val);
181   }
182   if (parent) {
183     BX_ASSERT(parent->get_type() == BXT_LIST);
184     this->parent = (bx_list_c *)parent;
185     this->parent->add(this);
186   }
187 }
188 
189 Bit32u bx_param_num_c::default_base = BASE_DEC;
190 
set_default_base(Bit32u val)191 Bit32u bx_param_num_c::set_default_base(Bit32u val)
192 {
193   Bit32u old = default_base;
194   default_base = val;
195   return old;
196 }
197 
set_handler(param_event_handler handler)198 void bx_param_num_c::set_handler(param_event_handler handler)
199 {
200   this->handler = handler;
201   // now that there's a handler, call set once to run the handler immediately
202   //set (get ());
203 }
204 
set_sr_handlers(void * devptr,param_save_handler save,param_restore_handler restore)205 void bx_param_num_c::set_sr_handlers(void *devptr, param_save_handler save, param_restore_handler restore)
206 {
207   sr_devptr = devptr;
208   save_handler = save;
209   restore_handler = restore;
210 }
211 
set_dependent_list(bx_list_c * l)212 void bx_param_num_c::set_dependent_list(bx_list_c *l)
213 {
214   dependent_list = l;
215   update_dependents();
216 }
217 
get64()218 Bit64s bx_param_num_c::get64()
219 {
220   if (save_handler) {
221     return (*save_handler)(sr_devptr, this);
222   }
223   if (handler) {
224     // the handler can decide what value to return and/or do some side effect
225     return (*handler)(this, 0, val.number);
226   } else {
227     // just return the value
228     return val.number;
229   }
230 }
231 
set(Bit64s newval)232 void bx_param_num_c::set(Bit64s newval)
233 {
234   if (!enabled) return;
235 
236   if (handler) {
237     // the handler can override the new value and/or perform some side effect
238     val.number = (*handler)(this, 1, newval);
239   } else {
240     // just set the value.  This code does not check max/min.
241     val.number = newval;
242   }
243   if (restore_handler) {
244     val.number = newval;
245     (*restore_handler)(sr_devptr, this, newval);
246   }
247   if ((val.number < min || val.number > max) && (Bit64u)max != BX_MAX_BIT64U)
248     BX_PANIC(("numerical parameter '%s' was set to " FMT_LL "d, which is out of range " FMT_LL "d to " FMT_LL "d", get_name (), val.number, min, max));
249   if (dependent_list != NULL) update_dependents();
250 }
251 
set_range(Bit64u min,Bit64u max)252 void bx_param_num_c::set_range(Bit64u min, Bit64u max)
253 {
254   this->min = min;
255   this->max = max;
256 }
257 
set_initial_val(Bit64s initial_val)258 void bx_param_num_c::set_initial_val(Bit64s initial_val)
259 {
260   this->val.number = this->initial_val = initial_val;
261 }
262 
update_dependents()263 void bx_param_num_c::update_dependents()
264 {
265   if (dependent_list) {
266     int en = val.number && enabled;
267     for (int i=0; i<dependent_list->get_size(); i++) {
268       bx_param_c *param = dependent_list->get(i);
269       if (param != this)
270         param->set_enabled(en);
271     }
272   }
273 }
274 
set_enabled(bool en)275 void bx_param_num_c::set_enabled(bool en)
276 {
277   // The enable handler may wish to allow/disallow the action
278   if (enable_handler) {
279     en = (*enable_handler)(this, en);
280   }
281   bx_param_c::set_enabled(en);
282   update_dependents();
283 }
284 
parse_param(const char * ptr)285 int bx_param_num_c::parse_param(const char *ptr)
286 {
287   if (ptr != NULL) {
288     Bit64u value;
289     if (get_base() == BASE_DOUBLE) {
290       double f2value = strtod(ptr, NULL);
291       memcpy(&value, &f2value, sizeof(double));
292       set(value);
293     } else if (get_base() == BASE_FLOAT) {
294       float f1value = (float)strtod(ptr, NULL);
295       memcpy(&value, &f1value, sizeof(float));
296       set(value);
297     } else if ((ptr[0] == '0') && (ptr[1] == 'x')) {
298       set(strtoull(ptr, NULL, 16));
299     } else {
300       if (ptr[strlen(ptr)-1] == 'K') {
301         set(1000 * strtoull(ptr, NULL, 10));
302       }
303       else if (ptr[strlen(ptr)-1] == 'M') {
304         set(1000000 * strtoull(ptr, NULL, 10));
305       }
306       else {
307         set(strtoull(ptr, NULL, 10));
308       }
309     }
310     return 1;
311   }
312 
313   return 0;
314 }
315 
dump_param(FILE * fp)316 void bx_param_num_c::dump_param(FILE *fp)
317 {
318   char tmpstr[BX_PATHNAME_LEN+1];
319   dump_param(tmpstr, BX_PATHNAME_LEN, 0);
320   fputs(tmpstr, fp);
321 }
322 
dump_param(char * buf,int len,bool dquotes)323 int bx_param_num_c::dump_param(char *buf, int len, bool dquotes)
324 {
325   Bit64s value = get64();
326   if (get_base() == BASE_DOUBLE) {
327     double f2value;
328     memcpy(&f2value, &value, sizeof(double));
329     snprintf(buf, len, "%f", f2value);
330   } else if (get_base() == BASE_FLOAT) {
331     float f1value;
332     memcpy(&f1value, &value, sizeof(float));
333     snprintf(buf, len, "%f", f1value);
334   } else if (get_base() == BASE_DEC) {
335     if (get_min() >= BX_MIN_BIT64U) {
336       if ((Bit64u) get_max() > BX_MAX_BIT32U) {
337         snprintf(buf, len, FMT_LL"u", value);
338       } else {
339         snprintf(buf, len, "%u", (Bit32u) value);
340       }
341     } else {
342       snprintf(buf, len, "%d", (Bit32s) value);
343     }
344   } else {
345     if (get_format()) {
346       snprintf(buf, len, get_format(), value);
347     } else {
348       if ((Bit64u)get_max() > BX_MAX_BIT32U) {
349         snprintf(buf, len, "0x" FMT_LL "x", (Bit64u) value);
350       } else {
351         snprintf(buf, len, "0x%x", (Bit32u) value);
352       }
353     }
354   }
355 
356   return strlen(buf);
357 }
358 
359 // Signed 64 bit
bx_shadow_num_c(bx_param_c * parent,const char * name,Bit64s * ptr_to_real_val,int base,Bit8u highbit,Bit8u lowbit)360 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
361     const char *name,
362     Bit64s *ptr_to_real_val,
363     int base,
364     Bit8u highbit,
365     Bit8u lowbit)
366 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT64S, BX_MAX_BIT64S, *ptr_to_real_val, 1)
367 {
368   this->varsize = 64;
369   this->lowbit = lowbit;
370   this->mask = ((BX_MAX_BIT64S >> (63 - (highbit - lowbit))) << lowbit);
371   val.p64bit = ptr_to_real_val;
372   if (base == BASE_HEX) {
373     this->base = base;
374     this->text_format = "0x" FMT_LL "x";
375   }
376 }
377 
378 // Unsigned 64 bit
bx_shadow_num_c(bx_param_c * parent,const char * name,Bit64u * ptr_to_real_val,int base,Bit8u highbit,Bit8u lowbit)379 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
380     const char *name,
381     Bit64u *ptr_to_real_val,
382     int base,
383     Bit8u highbit,
384     Bit8u lowbit)
385 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT64U, BX_MAX_BIT64U, *ptr_to_real_val, 1)
386 {
387   this->varsize = 64;
388   this->lowbit = lowbit;
389   this->mask = ((BX_MAX_BIT64U >> (63 - (highbit - lowbit))) << lowbit);
390   val.p64bit = (Bit64s*) ptr_to_real_val;
391   if (base == BASE_HEX) {
392     this->base = base;
393     this->text_format = "0x" FMT_LL "x";
394   }
395 }
396 
397 // Signed 32 bit
bx_shadow_num_c(bx_param_c * parent,const char * name,Bit32s * ptr_to_real_val,int base,Bit8u highbit,Bit8u lowbit)398 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
399     const char *name,
400     Bit32s *ptr_to_real_val,
401     int base,
402     Bit8u highbit,
403     Bit8u lowbit)
404 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT32S, BX_MAX_BIT32S, *ptr_to_real_val, 1)
405 {
406   this->varsize = 32;
407   this->lowbit = lowbit;
408   this->mask = ((BX_MAX_BIT32S >> (31 - (highbit - lowbit))) << lowbit);
409   val.p32bit = ptr_to_real_val;
410   if (base == BASE_HEX) {
411     this->base = base;
412     this->text_format = "0x%08x";
413   }
414 }
415 
416 // Unsigned 32 bit
bx_shadow_num_c(bx_param_c * parent,const char * name,Bit32u * ptr_to_real_val,int base,Bit8u highbit,Bit8u lowbit)417 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
418     const char *name,
419     Bit32u *ptr_to_real_val,
420     int base,
421     Bit8u highbit,
422     Bit8u lowbit)
423 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT32U, BX_MAX_BIT32U, *ptr_to_real_val, 1)
424 {
425   this->varsize = 32;
426   this->lowbit = lowbit;
427   this->mask = ((BX_MAX_BIT32U >> (31 - (highbit - lowbit))) << lowbit);
428   val.p32bit = (Bit32s*) ptr_to_real_val;
429   if (base == BASE_HEX) {
430     this->base = base;
431     this->text_format = "0x%08x";
432   }
433 }
434 
435 // Signed 16 bit
bx_shadow_num_c(bx_param_c * parent,const char * name,Bit16s * ptr_to_real_val,int base,Bit8u highbit,Bit8u lowbit)436 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
437     const char *name,
438     Bit16s *ptr_to_real_val,
439     int base,
440     Bit8u highbit,
441     Bit8u lowbit)
442 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT16S, BX_MAX_BIT16S, *ptr_to_real_val, 1)
443 {
444   this->varsize = 16;
445   this->lowbit = lowbit;
446   this->mask = ((BX_MAX_BIT16S >> (15 - (highbit - lowbit))) << lowbit);
447   val.p16bit = ptr_to_real_val;
448   if (base == BASE_HEX) {
449     this->base = base;
450     this->text_format = "0x%04x";
451   }
452 }
453 
454 // Unsigned 16 bit
bx_shadow_num_c(bx_param_c * parent,const char * name,Bit16u * ptr_to_real_val,int base,Bit8u highbit,Bit8u lowbit)455 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
456     const char *name,
457     Bit16u *ptr_to_real_val,
458     int base,
459     Bit8u highbit,
460     Bit8u lowbit)
461 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT16U, BX_MAX_BIT16U, *ptr_to_real_val, 1)
462 {
463   this->varsize = 16;
464   this->lowbit = lowbit;
465   this->mask = ((BX_MAX_BIT16U >> (15 - (highbit - lowbit))) << lowbit);
466   val.p16bit = (Bit16s*) ptr_to_real_val;
467   if (base == BASE_HEX) {
468     this->base = base;
469     this->text_format = "0x%04x";
470   }
471 }
472 
473 // Signed 8 bit
bx_shadow_num_c(bx_param_c * parent,const char * name,Bit8s * ptr_to_real_val,int base,Bit8u highbit,Bit8u lowbit)474 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
475     const char *name,
476     Bit8s *ptr_to_real_val,
477     int base,
478     Bit8u highbit,
479     Bit8u lowbit)
480 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT8S, BX_MAX_BIT8S, *ptr_to_real_val, 1)
481 {
482   this->varsize = 8;
483   this->lowbit = lowbit;
484   this->mask = ((BX_MAX_BIT8S >> (7 - (highbit - lowbit))) << lowbit);
485   this->mask = (1 << (highbit - lowbit)) - 1;
486   val.p8bit = ptr_to_real_val;
487   if (base == BASE_HEX) {
488     this->base = base;
489     this->text_format = "0x%02x";
490   }
491 }
492 
493 // Unsigned 8 bit
bx_shadow_num_c(bx_param_c * parent,const char * name,Bit8u * ptr_to_real_val,int base,Bit8u highbit,Bit8u lowbit)494 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
495     const char *name,
496     Bit8u *ptr_to_real_val,
497     int base,
498     Bit8u highbit,
499     Bit8u lowbit)
500 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT8U, BX_MAX_BIT8U, *ptr_to_real_val, 1)
501 {
502   this->varsize = 8;
503   this->lowbit = lowbit;
504   this->mask = ((BX_MAX_BIT8U >> (7 - (highbit - lowbit))) << lowbit);
505   val.p8bit = (Bit8s*) ptr_to_real_val;
506   if (base == BASE_HEX) {
507     this->base = base;
508     this->text_format = "0x%02x";
509   }
510 }
511 
512 // Float (floating point)
bx_shadow_num_c(bx_param_c * parent,const char * name,float * ptr_to_real_val)513 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
514     const char *name,
515     float *ptr_to_real_val)
516 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT64U, BX_MAX_BIT64U, 0, 1)
517 {
518   this->varsize = 32;
519   this->lowbit = 0;
520   this->mask = BX_MAX_BIT32U;
521   val.pfloat = ptr_to_real_val;
522   this->base = BASE_FLOAT;
523 }
524 
525 // Double (floating point)
bx_shadow_num_c(bx_param_c * parent,const char * name,double * ptr_to_real_val)526 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
527     const char *name,
528     double *ptr_to_real_val)
529 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT64U, BX_MAX_BIT64U, 0, 1)
530 {
531   this->varsize = 64;
532   this->lowbit = 0;
533   this->mask = BX_MAX_BIT64U;
534   val.pdouble = ptr_to_real_val;
535   this->base = BASE_DOUBLE;
536 }
537 
get64()538 Bit64s bx_shadow_num_c::get64()
539 {
540   Bit64u current = 0;
541   switch (varsize) {
542     case 8: current = *(val.p8bit);  break;
543     case 16: current = *(val.p16bit);  break;
544     case 32: current = *(val.p32bit);  break;
545     case 64: current = *(val.p64bit);  break;
546     default: BX_PANIC(("unsupported varsize %d", varsize));
547   }
548   current = (current >> lowbit) & mask;
549   if (handler) {
550     // the handler can decide what value to return and/or do some side effect
551     return (*handler)(this, 0, current) & mask;
552   } else {
553     // just return the value
554     return current;
555   }
556 }
557 
set(Bit64s newval)558 void bx_shadow_num_c::set(Bit64s newval)
559 {
560   Bit64u tmp = 0;
561   if (((newval < min) || (newval > max)) && (min != BX_MIN_BIT64S) && ((Bit64u)max != BX_MAX_BIT64U))
562     BX_PANIC(("numerical parameter %s was set to " FMT_LL "d, which is out of range " FMT_LL "d to " FMT_LL "d", get_name (), newval, min, max));
563   switch (varsize) {
564     case 8:
565       tmp = *(val.p8bit) & ~(mask << lowbit);
566       tmp |= (newval & mask) << lowbit;
567       *(val.p8bit) = (Bit8s)tmp;
568       break;
569     case 16:
570       tmp = *(val.p16bit) & ~(mask << lowbit);
571       tmp |= (newval & mask) << lowbit;
572       *(val.p16bit) = (Bit16s)tmp;
573       break;
574     case 32:
575       tmp = *(val.p32bit) & ~(mask << lowbit);
576       tmp |= (newval & mask) << lowbit;
577       *(val.p32bit) = (Bit32s)tmp;
578       break;
579     case 64:
580       tmp = *(val.p64bit) & ~(mask << lowbit);
581       tmp |= (newval & mask) << lowbit;
582       *(val.p64bit) = (Bit64s)tmp;
583       break;
584     default:
585       BX_PANIC(("unsupported varsize %d", varsize));
586   }
587   if (handler) {
588     // the handler can override the new value and/or perform some side effect
589     (*handler)(this, 1, tmp);
590   }
591 }
592 
reset()593 void bx_shadow_num_c::reset()
594 {
595   BX_PANIC(("reset not supported on bx_shadow_num_c yet"));
596 }
597 
bx_param_bool_c(bx_param_c * parent,const char * name,const char * label,const char * description,Bit64s initial_val,bool is_shadow)598 bx_param_bool_c::bx_param_bool_c(bx_param_c *parent,
599     const char *name,
600     const char *label,
601     const char *description,
602     Bit64s initial_val,
603     bool is_shadow)
604   : bx_param_num_c(parent, name, label, description, 0, 1, initial_val, is_shadow)
605 {
606   set_type(BXT_PARAM_BOOL);
607 }
608 
parse_param(const char * ptr)609 int bx_param_bool_c::parse_param(const char *ptr)
610 {
611   if (ptr != NULL) {
612     if (!strcmp(ptr, "0") || !stricmp(ptr, "false")) {
613       set(0); return 1;
614     }
615     if (!strcmp(ptr, "1") || !stricmp(ptr, "true")) {
616       set(1); return 1;
617     }
618   }
619 
620   return 0;
621 }
622 
dump_param(FILE * fp)623 void bx_param_bool_c::dump_param(FILE *fp)
624 {
625   fprintf(fp, "%s", get()?"true":"false");
626 }
627 
dump_param(char * buf,int len,bool dquotes)628 int bx_param_bool_c::dump_param(char *buf, int len, bool dquotes)
629 {
630   snprintf(buf, len, "%s", get()?"true":"false");
631   return strlen(buf);
632 }
633 
bx_shadow_bool_c(bx_param_c * parent,const char * name,const char * label,bool * ptr_to_real_val)634 bx_shadow_bool_c::bx_shadow_bool_c(bx_param_c *parent,
635       const char *name,
636       const char *label,
637       bool *ptr_to_real_val)
638   : bx_param_bool_c(parent, name, label, NULL, (Bit64s) *ptr_to_real_val, 1)
639 {
640   val.pbool = ptr_to_real_val;
641 }
642 
bx_shadow_bool_c(bx_param_c * parent,const char * name,bool * ptr_to_real_val)643 bx_shadow_bool_c::bx_shadow_bool_c(bx_param_c *parent,
644       const char *name,
645       bool *ptr_to_real_val)
646   : bx_param_bool_c(parent, name, NULL, NULL, (Bit64s) *ptr_to_real_val, 1)
647 {
648   val.pbool = ptr_to_real_val;
649 }
650 
get64()651 Bit64s bx_shadow_bool_c::get64()
652 {
653   if (handler) {
654     // the handler can decide what value to return and/or do some side effect
655     return (*handler)(this, 0, (Bit64s) *(val.pbool));
656   } else {
657     // just return the value
658     return (Bit64s)*(val.pbool);
659   }
660 }
661 
set(Bit64s newval)662 void bx_shadow_bool_c::set(Bit64s newval)
663 {
664   *(val.pbool) = (newval != 0);
665   if (handler) {
666     // the handler can override the new value and/or perform some side effect
667     (*handler)(this, 1, (Bit64s)newval);
668   }
669 }
670 
bx_param_enum_c(bx_param_c * parent,const char * name,const char * label,const char * description,const char ** choices,Bit64s initial_val,Bit64s value_base)671 bx_param_enum_c::bx_param_enum_c(bx_param_c *parent,
672       const char *name,
673       const char *label,
674       const char *description,
675       const char **choices,
676       Bit64s initial_val,
677       Bit64s value_base)
678   : bx_param_num_c(parent, name, label, description, value_base, BX_MAX_BIT64S, initial_val)
679 {
680   set_type(BXT_PARAM_ENUM);
681   this->choices = choices;
682   // count number of choices, set max
683   const char **p = choices;
684   while (*p != NULL) p++;
685   this->min = value_base;
686   // now that the max is known, replace the BX_MAX_BIT64S sent to the parent
687   // class constructor with the real max.
688   this->max = value_base + (p - choices - 1);
689   this->deps_bitmap = NULL;
690   set(initial_val);
691 }
692 
~bx_param_enum_c()693 bx_param_enum_c::~bx_param_enum_c()
694 {
695   delete [] deps_bitmap;
696 }
697 
698 
set(Bit64s val)699 void bx_param_enum_c::set(Bit64s val)
700 {
701   bx_param_num_c::set(val);
702   update_dependents();
703 }
704 
find_by_name(const char * s)705 int bx_param_enum_c::find_by_name(const char *s)
706 {
707   const char **p;
708   for (p=&choices[0]; *p; p++) {
709     if (!strcmp(s, *p))
710       return p-choices;
711   }
712   return -1;
713 }
714 
set_by_name(const char * s)715 bool bx_param_enum_c::set_by_name(const char *s)
716 {
717   int n = find_by_name(s);
718   if (n<0) return 0;
719   set(n + min);
720   return 1;
721 }
722 
set_dependent_list(bx_list_c * l,bool enable_all)723 void bx_param_enum_c::set_dependent_list(bx_list_c *l, bool enable_all)
724 {
725   dependent_list = l;
726   deps_bitmap = new Bit64u[(unsigned)(max - min + 1)];
727   for (int i=0; i<(max-min+1); i++) {
728     if (enable_all) {
729       deps_bitmap[i] = (1 << (l->get_size())) - 1;
730     } else {
731       deps_bitmap[i] = 0;
732     }
733   }
734   update_dependents();
735 }
736 
set_dependent_bitmap(Bit64s value,Bit64u bitmap)737 void bx_param_enum_c::set_dependent_bitmap(Bit64s value, Bit64u bitmap)
738 {
739   if (deps_bitmap != NULL) {
740     deps_bitmap[value - min] = bitmap;
741   }
742   update_dependents();
743 }
744 
get_dependent_bitmap(Bit64s value)745 Bit64u bx_param_enum_c::get_dependent_bitmap(Bit64s value)
746 {
747   if (deps_bitmap != NULL) {
748     return deps_bitmap[value - min];
749   }
750   return 0;
751 }
752 
update_dependents()753 void bx_param_enum_c::update_dependents()
754 {
755   if ((dependent_list != NULL) && (deps_bitmap != NULL)) {
756     Bit64u en_bmap = deps_bitmap[val.number - min];
757     Bit64u mask = 0x1;
758     for (int i=0; i<dependent_list->get_size(); i++) {
759       int en = (en_bmap & mask) && enabled;
760       bx_param_c *param = dependent_list->get(i);
761       if (param != this)
762         param->set_enabled(en);
763       mask <<= 1;
764     }
765   }
766 }
767 
set_enabled(bool en)768 void bx_param_enum_c::set_enabled(bool en)
769 {
770   // The enable handler may wish to allow/disallow the action
771   if (enable_handler) {
772     en = (*enable_handler)(this, en);
773   }
774   bx_param_c::set_enabled(en);
775   update_dependents();
776 }
777 
parse_param(const char * ptr)778 int bx_param_enum_c::parse_param(const char *ptr)
779 {
780   if (ptr != NULL) {
781     return set_by_name(ptr);
782   }
783 
784   return 0;
785 }
786 
dump_param(FILE * fp)787 void bx_param_enum_c::dump_param(FILE *fp)
788 {
789   fprintf(fp, "%s", get_selected());
790 }
791 
dump_param(char * buf,int len,bool dquotes)792 int bx_param_enum_c::dump_param(char *buf, int len, bool dquotes)
793 {
794   snprintf(buf, len, "%s", get_selected());
795   return strlen(buf);
796 }
797 
bx_param_string_c(bx_param_c * parent,const char * name,const char * label,const char * description,const char * initial_val,int maxsize)798 bx_param_string_c::bx_param_string_c(bx_param_c *parent,
799     const char *name,
800     const char *label,
801     const char *description,
802     const char *initial_val,
803     int maxsize)
804   : bx_param_c(SIM->gen_param_id(), name, label, description)
805 {
806   set_type(BXT_PARAM_STRING);
807   int initial_val_size = strlen(initial_val) + 1;
808   if (maxsize < 0) {
809     maxsize = initial_val_size;
810   } else if (initial_val_size > maxsize) {
811     initial_val_size = maxsize;
812   }
813   this->val = new char[maxsize];
814   this->initial_val = new char[maxsize];
815   this->handler = NULL;
816   this->enable_handler = NULL;
817   this->maxsize = maxsize;
818   strncpy(this->val, initial_val, initial_val_size);
819   if (maxsize > initial_val_size)
820     memset(this->val + initial_val_size, 0, maxsize - initial_val_size);
821   strncpy(this->initial_val, initial_val, maxsize);
822   this->options = 0;
823   set(initial_val);
824   if (parent) {
825     BX_ASSERT(parent->get_type() == BXT_LIST);
826     this->parent = (bx_list_c *)parent;
827     this->parent->add(this);
828   }
829 }
830 
~bx_param_string_c()831 bx_param_string_c::~bx_param_string_c()
832 {
833   delete [] val;
834   delete [] initial_val;
835 }
836 
reset()837 void bx_param_string_c::reset()
838 {
839   set(initial_val);
840 }
841 
set_handler(param_string_event_handler handler)842 void bx_param_string_c::set_handler(param_string_event_handler handler)
843 {
844   this->handler = handler;
845 }
846 
set_enable_handler(param_enable_handler handler)847 void bx_param_string_c::set_enable_handler(param_enable_handler handler)
848 {
849   this->enable_handler = handler;
850 }
851 
update_dependents()852 void bx_param_string_c::update_dependents()
853 {
854   if (dependent_list) {
855     int en = (strlen(val) > 0) && (strcmp(val, "none")) && enabled;
856     for (int i=0; i<dependent_list->get_size(); i++) {
857       bx_param_c *param = dependent_list->get(i);
858       if (param != this)
859         param->set_enabled(en);
860     }
861   }
862 }
863 
set_enabled(bool en)864 void bx_param_string_c::set_enabled(bool en)
865 {
866   // The enable handler may wish to allow/disallow the action
867   if (enable_handler) {
868     en = (*enable_handler)(this, en);
869   }
870   bx_param_c::set_enabled(en);
871   if (dependent_list != NULL) update_dependents();
872 }
873 
set_dependent_list(bx_list_c * l)874 void bx_param_string_c::set_dependent_list(bx_list_c *l)
875 {
876   dependent_list = l;
877   update_dependents();
878 }
879 
get(char * buf,int len)880 Bit32s bx_param_string_c::get(char *buf, int len)
881 {
882   strncpy(buf, val, len);
883   if (handler) {
884     // the handler can choose to replace the value in val/len.  Also its
885     // return value is passed back as the return value of get.
886     (*handler)(this, 0, buf, buf, len);
887   }
888   return 0;
889 }
890 
set(const char * buf)891 void bx_param_string_c::set(const char *buf)
892 {
893   char *oldval = new char[maxsize];
894 
895   strncpy(oldval, val, maxsize);
896   oldval[maxsize - 1] = 0;
897   if (handler) {
898     // the handler can return a different char* to be copied into the value
899     buf = (*handler)(this, 1, oldval, buf, -1);
900   }
901   strncpy(val, buf, maxsize);
902   val[maxsize - 1] = 0;
903   delete [] oldval;
904   if (dependent_list != NULL) update_dependents();
905 }
906 
equals(const char * buf) const907 bool bx_param_string_c::equals(const char *buf) const
908 {
909   return (strncmp(val, buf, maxsize) == 0);
910 }
911 
set_initial_val(const char * buf)912 void bx_param_string_c::set_initial_val(const char *buf)
913 {
914   strncpy(initial_val, buf, maxsize);
915   set(initial_val);
916 }
917 
isempty() const918 bool bx_param_string_c::isempty() const
919 {
920   return (strlen(val) == 0) || !strcmp(val, "none");
921 }
922 
parse_param(const char * ptr)923 int bx_param_string_c::parse_param(const char *ptr)
924 {
925   if (ptr != NULL) {
926     set(ptr);
927   } else {
928     set("");
929   }
930 
931   return 1;
932 }
933 
dump_param(FILE * fp)934 void bx_param_string_c::dump_param(FILE *fp)
935 {
936   char tmpstr[BX_PATHNAME_LEN+1];
937   dump_param(tmpstr, BX_PATHNAME_LEN, 0);
938   fputs(tmpstr, fp);
939 }
940 
dump_param(char * buf,int len,bool dquotes)941 int bx_param_string_c::dump_param(char *buf, int len, bool dquotes)
942 {
943   if (!isempty()) {
944     if (dquotes) {
945       snprintf(buf, len, "\"%s\"", val);
946     } else {
947       snprintf(buf, len, "%s", val);
948     }
949   } else {
950     strcpy(buf, "none");
951   }
952   return strlen(buf);
953 }
954 
get(char * buf,int len)955 Bit32s bx_param_bytestring_c::get(char *buf, int len)
956 {
957   memcpy(buf, val, len);
958   if (handler) {
959     // the handler can choose to replace the value in val/len.  Also its
960     // return value is passed back as the return value of get.
961     (*handler)(this, 0, buf, buf, len);
962   }
963   return 0;
964 }
965 
set(const char * buf)966 void bx_param_bytestring_c::set(const char *buf)
967 {
968   char *oldval = new char[maxsize];
969 
970   memcpy(oldval, val, maxsize);
971   if (handler) {
972     // the handler can return a different char* to be copied into the value
973     buf = (*handler)(this, 1, oldval, buf, -1);
974   }
975   memcpy(val, buf, maxsize);
976   delete [] oldval;
977   if (dependent_list != NULL) update_dependents();
978 }
979 
equals(const char * buf) const980 bool bx_param_bytestring_c::equals(const char *buf) const
981 {
982   return (memcmp(val, buf, maxsize) == 0);
983 }
984 
set_initial_val(const char * buf)985 void bx_param_bytestring_c::set_initial_val(const char *buf)
986 {
987   memcpy(initial_val, buf, maxsize);
988   set(initial_val);
989 }
990 
isempty() const991 bool bx_param_bytestring_c::isempty() const
992 {
993   return (memcmp(val, initial_val, maxsize) == 0);
994 }
995 
parse_param(const char * ptr)996 int bx_param_bytestring_c::parse_param(const char *ptr)
997 {
998   int j, p = 0, ret = 1;
999   unsigned n;
1000   char buf[512];
1001 
1002   memset(buf, 0, get_maxsize());
1003   for (j = 0; j < get_maxsize(); j++) {
1004     if (ptr[p] == get_separator()) {
1005       p++;
1006     }
1007     if (sscanf(ptr+p, "%02x", &n) == 1) {
1008       buf[j] = n;
1009       p += 2;
1010     } else {
1011       ret = 0;
1012     }
1013   }
1014   if (!equals(buf)) set(buf);
1015 
1016   return ret;
1017 }
1018 
dump_param(char * buf,int len,bool dquotes)1019 int bx_param_bytestring_c::dump_param(char *buf, int len, bool dquotes)
1020 {
1021   buf[0] = 0;
1022   for (int j = 0; j < maxsize; j++) {
1023     char tmpbyte[4];
1024     if (j > 0) {
1025       tmpbyte[0] = separator;
1026       tmpbyte[1] = 0;
1027       strcat(buf, tmpbyte);
1028     }
1029     sprintf(tmpbyte, "%02x", (Bit8u)val[j]);
1030     strcat(buf, tmpbyte);
1031   }
1032   return strlen(buf);
1033 }
1034 
bx_param_filename_c(bx_param_c * parent,const char * name,const char * label,const char * description,const char * initial_val,int maxsize)1035 bx_param_filename_c::bx_param_filename_c(bx_param_c *parent,
1036     const char *name,
1037     const char *label,
1038     const char *description,
1039     const char *initial_val,
1040     int maxsize)
1041   : bx_param_string_c(parent, name, label, description, initial_val, maxsize)
1042 {
1043   set_options(IS_FILENAME);
1044   int len = strlen(initial_val);
1045   if ((len > 4) && (initial_val[len - 4] == '.')) {
1046     ext = &initial_val[len - 3];
1047   } else {
1048     ext = NULL;
1049   }
1050 }
1051 
bx_shadow_data_c(bx_param_c * parent,const char * name,Bit8u * ptr_to_data,Bit32u data_size,bool is_text)1052 bx_shadow_data_c::bx_shadow_data_c(bx_param_c *parent,
1053     const char *name,
1054     Bit8u *ptr_to_data,
1055     Bit32u data_size,
1056     bool is_text)
1057   : bx_param_c(SIM->gen_param_id(), name, "")
1058 {
1059   set_type(BXT_PARAM_DATA);
1060   this->data_ptr = ptr_to_data;
1061   this->data_size = data_size;
1062   this->is_text = is_text;
1063   if (parent) {
1064     BX_ASSERT(parent->get_type() == BXT_LIST);
1065     this->parent = (bx_list_c *)parent;
1066     this->parent->add(this);
1067   }
1068 }
1069 
get(Bit32u index)1070 Bit8u bx_shadow_data_c::get(Bit32u index)
1071 {
1072   if (index < data_size) {
1073     return data_ptr[index];
1074   } else {
1075     return 0;
1076   }
1077 }
1078 
set(Bit32u index,Bit8u value)1079 void bx_shadow_data_c::set(Bit32u index, Bit8u value)
1080 {
1081   if (index < data_size) {
1082     data_ptr[index] = value;
1083   }
1084 }
1085 
bx_shadow_filedata_c(bx_param_c * parent,const char * name,FILE ** scratch_file_ptr_ptr)1086 bx_shadow_filedata_c::bx_shadow_filedata_c(bx_param_c *parent,
1087     const char *name, FILE **scratch_file_ptr_ptr)
1088   : bx_param_c(SIM->gen_param_id(), name, "")
1089 {
1090   set_type(BXT_PARAM_FILEDATA);
1091   this->scratch_fpp = scratch_file_ptr_ptr;
1092   this->save_handler = NULL;
1093   this->restore_handler = NULL;
1094   if (parent) {
1095     BX_ASSERT(parent->get_type() == BXT_LIST);
1096     this->parent = (bx_list_c *)parent;
1097     this->parent->add(this);
1098   }
1099 }
1100 
1101 // Save handler: called before file save, Restore handler: called after file restore
set_sr_handlers(void * devptr,filedata_save_handler save,filedata_restore_handler restore)1102 void bx_shadow_filedata_c::set_sr_handlers(void *devptr, filedata_save_handler save, filedata_restore_handler restore)
1103 {
1104   this->sr_devptr = devptr;
1105   this->save_handler = save;
1106   this->restore_handler = restore;
1107 }
1108 
save(FILE * save_fp)1109 void bx_shadow_filedata_c::save(FILE *save_fp)
1110 {
1111   if (save_handler)
1112     (*save_handler)(sr_devptr, save_fp);
1113 }
1114 
restore(FILE * save_fp)1115 void bx_shadow_filedata_c::restore(FILE *save_fp)
1116 {
1117   if (restore_handler)
1118     (*restore_handler)(sr_devptr, save_fp);
1119 }
1120 
bx_list_c(bx_param_c * parent)1121 bx_list_c::bx_list_c(bx_param_c *parent)
1122   : bx_param_c(SIM->gen_param_id(), "list", "")
1123 {
1124   set_type(BXT_LIST);
1125   this->size = 0;
1126   this->list = NULL;
1127   this->parent = NULL;
1128   if (parent) {
1129     BX_ASSERT(parent->get_type() == BXT_LIST);
1130     this->parent = (bx_list_c *)parent;
1131     this->parent->add(this);
1132   }
1133   init("");
1134 }
1135 
bx_list_c(bx_param_c * parent,const char * name)1136 bx_list_c::bx_list_c(bx_param_c *parent, const char *name)
1137   : bx_param_c(SIM->gen_param_id(), name, "")
1138 {
1139   set_type (BXT_LIST);
1140   this->size = 0;
1141   this->list = NULL;
1142   this->parent = NULL;
1143   if (parent) {
1144     BX_ASSERT(parent->get_type() == BXT_LIST);
1145     this->parent = (bx_list_c *)parent;
1146     this->parent->add(this);
1147   }
1148   this->restore_handler = NULL;
1149   init("");
1150 }
1151 
bx_list_c(bx_param_c * parent,const char * name,const char * title)1152 bx_list_c::bx_list_c(bx_param_c *parent, const char *name, const char *title)
1153   : bx_param_c(SIM->gen_param_id(), name, "")
1154 {
1155   set_type (BXT_LIST);
1156   this->size = 0;
1157   this->list = NULL;
1158   this->parent = NULL;
1159   if (parent) {
1160     BX_ASSERT(parent->get_type() == BXT_LIST);
1161     this->parent = (bx_list_c *)parent;
1162     this->parent->add(this);
1163   }
1164   this->restore_handler = NULL;
1165   init(title);
1166 }
1167 
bx_list_c(bx_param_c * parent,const char * name,const char * title,bx_param_c ** init_list)1168 bx_list_c::bx_list_c(bx_param_c *parent, const char *name, const char *title, bx_param_c **init_list)
1169   : bx_param_c(SIM->gen_param_id(), name, "")
1170 {
1171   set_type(BXT_LIST);
1172   this->size = 0;
1173   this->list = NULL;
1174   while (init_list[this->size] != NULL)
1175     add(init_list[this->size]);
1176   this->parent = NULL;
1177   if (parent) {
1178     BX_ASSERT(parent->get_type() == BXT_LIST);
1179     this->parent = (bx_list_c *)parent;
1180     this->parent->add(this);
1181   }
1182   this->restore_handler = NULL;
1183   init(title);
1184 }
1185 
~bx_list_c()1186 bx_list_c::~bx_list_c()
1187 {
1188   if (list != NULL) {
1189     clear();
1190   }
1191   delete [] title;
1192 }
1193 
init(const char * list_title)1194 void bx_list_c::init(const char *list_title)
1195 {
1196   if (list_title) {
1197     this->title = new char[strlen(list_title)+1];
1198     strcpy(this->title, list_title);
1199   } else {
1200     this->title = new char[1];
1201     this->title[0] = 0;
1202   }
1203   this->options = 0;
1204   this->choice = 1;
1205 }
1206 
set_parent(bx_param_c * newparent)1207 void bx_list_c::set_parent(bx_param_c *newparent)
1208 {
1209   if (parent) {
1210     // if this object already had a parent, the correct thing
1211     // to do would be to remove this object from the parent's
1212     // list of children.  Deleting children is currently
1213     // not supported.
1214     BX_PANIC(("bx_list_c::set_parent: changing from one parent to another is not supported"));
1215   }
1216   if (newparent) {
1217     BX_ASSERT(newparent->get_type() == BXT_LIST);
1218     parent = (bx_list_c *)newparent;
1219     parent->add(this);
1220   }
1221 }
1222 
clone()1223 bx_list_c* bx_list_c::clone()
1224 {
1225   bx_list_c *newlist = new bx_list_c(NULL, name, title);
1226   for (int i=0; i<get_size(); i++)
1227     newlist->add(get(i));
1228   newlist->set_options(options);
1229   return newlist;
1230 }
1231 
add(bx_param_c * param)1232 void bx_list_c::add(bx_param_c *param)
1233 {
1234   if ((get_by_name(param->get_name()) != NULL) && (param->get_parent() == this)) {
1235     BX_PANIC(("parameter '%s' already exists in list '%s'", param->get_name(), this->get_name()));
1236     return;
1237   }
1238   bx_listitem_t *item = new bx_listitem_t;
1239   item->param = param;
1240   item->next = NULL;
1241   if (list == NULL) {
1242     list = item;
1243   } else {
1244     bx_listitem_t *temp = list;
1245     while (temp->next)
1246       temp = temp->next;
1247     temp->next = item;
1248   }
1249   if (runtime_param) {
1250     param->set_runtime_param(1);
1251   }
1252   size++;
1253 }
1254 
get(int index)1255 bx_param_c* bx_list_c::get(int index)
1256 {
1257   BX_ASSERT(index >= 0 && index < size);
1258   int i = 0;
1259   bx_listitem_t *temp = list;
1260   while (temp != NULL) {
1261     if (i == index) {
1262       return temp->param;
1263     }
1264     temp = temp->next;
1265     i++;
1266   }
1267   return NULL;
1268 }
1269 
get_by_name(const char * name)1270 bx_param_c* bx_list_c::get_by_name(const char *name)
1271 {
1272   bx_listitem_t *temp = list;
1273   while (temp != NULL) {
1274     bx_param_c *p = temp->param;
1275     if (!stricmp(name, p->get_name())) {
1276       return p;
1277     }
1278     temp = temp->next;
1279   }
1280   return NULL;
1281 }
1282 
reset()1283 void bx_list_c::reset()
1284 {
1285   bx_listitem_t *temp = list;
1286   while (temp != NULL) {
1287     temp->param->reset();
1288     temp = temp->next;
1289   }
1290 }
1291 
clear()1292 void bx_list_c::clear()
1293 {
1294   bx_listitem_t *temp = list, *next;
1295   while (temp != NULL) {
1296     if (temp->param->get_parent() == this) {
1297       delete temp->param;
1298     }
1299     next = temp->next;
1300     delete temp;
1301     temp = next;
1302   }
1303   list = NULL;
1304   size = 0;
1305 }
1306 
remove(const char * name)1307 void bx_list_c::remove(const char *name)
1308 {
1309   bx_listitem_t *item, *prev = NULL;
1310 
1311   for (item = list; item; item = item->next) {
1312     bx_param_c *p = item->param;
1313     if (!stricmp(name, p->get_name())) {
1314       if (p->get_parent() == this) {
1315         delete p;
1316       }
1317       if (prev == NULL) {
1318         list = item->next;
1319       } else {
1320         prev->next = item->next;
1321       }
1322       delete item;
1323       size--;
1324       break;
1325     } else {
1326       prev = item;
1327     }
1328   }
1329 }
1330 
set_runtime_param(bool val)1331 void bx_list_c::set_runtime_param(bool val)
1332 {
1333   runtime_param = val;
1334   if (runtime_param) {
1335     for (bx_listitem_t * item = list; item; item = item->next) {
1336       item->param->set_runtime_param(1);
1337     }
1338   }
1339 }
1340 
set_restore_handler(void * devptr,list_restore_handler restore)1341 void bx_list_c::set_restore_handler(void *devptr, list_restore_handler restore)
1342 {
1343   sr_devptr = devptr;
1344   restore_handler = restore;
1345 }
1346 
restore()1347 void bx_list_c::restore()
1348 {
1349   if (restore_handler)
1350     (*restore_handler)(sr_devptr, this);
1351 }
1352