- added instructions how to update the online documentation
[bochs-mirror.git] / gui / siminterface.cc
blob2d3ceda9b460969d46ac283e030c38f0d53dbf0e
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: siminterface.cc,v 1.182 2008/09/19 21:31:08 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // See siminterface.h for description of the siminterface concept.
6 // Basically, the siminterface is visible from both the simulator and
7 // the configuration user interface, and allows them to talk to each other.
9 #include "bochs.h"
10 #include "iodev.h"
12 bx_simulator_interface_c *SIM = NULL;
13 logfunctions *siminterface_log = NULL;
14 bx_list_c *root_param = NULL;
15 #define LOG_THIS siminterface_log->
17 #define BX_MAX_USER_OPTIONS 16
19 // bx_simulator_interface just defines the interface that the Bochs simulator
20 // and the gui will use to talk to each other. None of the methods of
21 // bx_simulator_interface are implemented; they are all virtual. The
22 // bx_real_sim_c class is a child of bx_simulator_interface_c, and it
23 // implements all the methods. The idea is that a gui needs to know only
24 // definition of bx_simulator_interface to talk to Bochs. The gui should
25 // not need to include bochs.h.
27 // I made this separation to ensure that all guis use the siminterface to do
28 // access bochs internals, instead of accessing things like
29 // bx_keyboard.s.internal_buffer[4] (or whatever) directly. -Bryce
32 class bx_real_sim_c : public bx_simulator_interface_c {
33 bxevent_handler bxevent_callback;
34 void *bxevent_callback_data;
35 const char *registered_ci_name;
36 config_interface_callback_t ci_callback;
37 void *ci_callback_data;
38 int n_user_options;
39 user_option_parser_t user_option_parser[BX_MAX_USER_OPTIONS];
40 user_option_save_t user_option_save[BX_MAX_USER_OPTIONS];
41 const char *user_option_name[BX_MAX_USER_OPTIONS];
42 int init_done;
43 int enabled;
44 // save context to jump to if we must quit unexpectedly
45 jmp_buf *quit_context;
46 int exit_code;
47 unsigned param_id;
48 public:
49 bx_real_sim_c();
50 virtual ~bx_real_sim_c() {}
51 virtual void set_quit_context(jmp_buf *context) { quit_context = context; }
52 virtual int get_init_done() { return init_done; }
53 virtual int set_init_done(int n) { init_done = n; return 0;}
54 virtual void reset_all_param();
55 // new param methods
56 virtual bx_param_c *get_param(const char *pname, bx_param_c *base=NULL);
57 virtual bx_param_num_c *get_param_num(const char *pname, bx_param_c *base=NULL);
58 virtual bx_param_string_c *get_param_string(const char *pname, bx_param_c *base=NULL);
59 virtual bx_param_bool_c *get_param_bool(const char *pname, bx_param_c *base=NULL);
60 virtual bx_param_enum_c *get_param_enum(const char *pname, bx_param_c *base=NULL);
61 virtual Bit32u gen_param_id() { return param_id++; }
62 virtual int get_n_log_modules();
63 virtual char *get_prefix(int mod);
64 virtual int get_log_action(int mod, int level);
65 virtual void set_log_action(int mod, int level, int action);
66 virtual char *get_action_name(int action);
67 virtual int get_default_log_action(int level) {
68 return logfunctions::get_default_action(level);
70 virtual void set_default_log_action(int level, int action) {
71 logfunctions::set_default_action(level, action);
73 virtual const char *get_log_level_name(int level);
74 virtual int get_max_log_level() { return N_LOGLEV; }
75 virtual void quit_sim(int code);
76 virtual int get_exit_code() { return exit_code; }
77 virtual int get_default_rc(char *path, int len);
78 virtual int read_rc(const char *path);
79 virtual int write_rc(const char *path, int overwrite);
80 virtual int get_log_file(char *path, int len);
81 virtual int set_log_file(char *path);
82 virtual int get_log_prefix(char *prefix, int len);
83 virtual int set_log_prefix(char *prefix);
84 virtual int get_debugger_log_file(char *path, int len);
85 virtual int set_debugger_log_file(char *path);
86 virtual int get_cdrom_options(int drive, bx_list_c **out, int *device = NULL);
87 virtual void set_notify_callback(bxevent_handler func, void *arg);
88 virtual void get_notify_callback(bxevent_handler *func, void **arg);
89 virtual BxEvent* sim_to_ci_event(BxEvent *event);
90 virtual int log_msg(const char *prefix, int level, const char *msg);
91 virtual int ask_param(bx_param_c *param);
92 virtual int ask_param(const char *pname);
93 // ask the user for a pathname
94 virtual int ask_filename(const char *filename, int maxlen, const char *prompt, const char *the_default, int flags);
95 // yes/no dialog
96 virtual int ask_yes_no(const char *title, const char *prompt, bx_bool the_default);
97 // called at a regular interval, currently by the keyboard handler.
98 virtual void periodic ();
99 virtual int create_disk_image (const char *filename, int sectors, bx_bool overwrite);
100 virtual void refresh_ci ();
101 virtual void refresh_vga () {
102 // maybe need to check if something has been initialized yet?
103 DEV_vga_refresh();
105 virtual void handle_events () {
106 // maybe need to check if something has been initialized yet?
107 bx_gui->handle_events ();
109 // find first hard drive or cdrom
110 bx_param_c *get_first_atadevice(Bit32u search_type);
111 bx_param_c *get_first_cdrom() {
112 return get_first_atadevice(BX_ATA_DEVICE_CDROM);
114 bx_param_c *get_first_hd() {
115 return get_first_atadevice(BX_ATA_DEVICE_DISK);
117 #if BX_DEBUGGER
118 virtual void debug_break ();
119 virtual void debug_interpret_cmd (char *cmd);
120 virtual char *debug_get_next_command ();
121 virtual void debug_puts (const char *cmd);
122 #endif
123 virtual void register_configuration_interface (
124 const char* name,
125 config_interface_callback_t callback,
126 void *userdata);
127 virtual int configuration_interface(const char* name, ci_command_t command);
128 virtual int begin_simulation (int argc, char *argv[]);
129 virtual void set_sim_thread_func(is_sim_thread_func_t func) {}
130 virtual bx_bool is_sim_thread();
131 bx_bool debug_gui;
132 virtual void set_debug_gui(bx_bool val) { debug_gui = val; }
133 virtual bx_bool has_debug_gui() { return debug_gui; }
134 // provide interface to bx_gui->set_display_mode() method for config
135 // interfaces to use.
136 virtual void set_display_mode(disp_mode_t newmode) {
137 if (bx_gui != NULL)
138 bx_gui->set_display_mode(newmode);
140 virtual bx_bool test_for_text_console();
141 // user-defined option support
142 virtual int find_user_option(const char *keyword);
143 virtual bx_bool register_user_option(const char *keyword, user_option_parser_t parser, user_option_save_t save_func);
144 virtual Bit32s parse_user_option(int idx, const char *context, int num_params, char *params []);
145 virtual Bit32s save_user_options(FILE *fp);
147 // save/restore support
148 virtual void init_save_restore();
149 virtual bx_bool save_state(const char *checkpoint_path);
150 virtual bx_bool restore_config();
151 virtual bx_bool restore_logopts();
152 virtual bx_bool restore_hardware();
153 virtual bx_list_c *get_bochs_root() {
154 return (bx_list_c*)get_param("bochs", NULL);
156 virtual bx_bool restore_bochs_param(bx_list_c *root, const char *sr_path, const char *restore_name);
158 private:
159 bx_bool save_sr_param(FILE *fp, bx_param_c *node, const char *sr_path, int level);
162 // recursive function to find parameters from the path
163 static bx_param_c *find_param(const char *full_pname, const char *rest_of_pname, bx_param_c *base)
165 const char *from = rest_of_pname;
166 char component[BX_PATHNAME_LEN];
167 char *to = component;
168 // copy the first piece of pname into component, stopping at first separator
169 // or at the end of the string
170 while (*from != 0 && *from != '.') {
171 *to = *from;
172 to++;
173 from++;
175 *to = 0;
176 if (!component[0]) {
177 BX_PANIC(("find_param: found empty component in parameter name '%s'", full_pname));
178 // or does that mean that we're done?
180 if (base->get_type() != BXT_LIST) {
181 BX_PANIC(("find_param: base was not a list!"));
183 BX_DEBUG(("searching for component '%s' in list '%s'", component, base->get_name()));
185 // find the component in the list.
186 bx_list_c *list = (bx_list_c *)base;
187 bx_param_c *child = list->get_by_name(component);
188 // if child not found, there is nothing else that can be done. return NULL.
189 if (child == NULL) return NULL;
190 if (from[0] == 0) {
191 // that was the end of the path, we're done
192 return child;
194 // continue parsing the path
195 BX_ASSERT(from[0] == '.');
196 from++; // skip over the separator
197 return find_param(full_pname, from, child);
200 bx_param_c *bx_real_sim_c::get_param(const char *pname, bx_param_c *base)
202 if (base == NULL)
203 base = root_param;
204 // to access top level object, look for parameter "."
205 if (pname[0] == '.' && pname[1] == 0)
206 return base;
207 return find_param(pname, pname, base);
210 bx_param_num_c *bx_real_sim_c::get_param_num (const char *pname, bx_param_c *base)
212 bx_param_c *generic = get_param(pname, base);
213 if (generic==NULL) {
214 BX_ERROR(("get_param_num(%s) could not find a parameter", pname));
215 return NULL;
217 int type = generic->get_type();
218 if (type == BXT_PARAM_NUM || type == BXT_PARAM_BOOL || type == BXT_PARAM_ENUM)
219 return (bx_param_num_c *)generic;
220 BX_ERROR(("get_param_num(%s) could not find an integer parameter with that name", pname));
221 return NULL;
224 bx_param_string_c *bx_real_sim_c::get_param_string(const char *pname, bx_param_c *base)
226 bx_param_c *generic = get_param(pname, base);
227 if (generic==NULL) {
228 BX_ERROR(("get_param_string(%s) could not find a parameter", pname));
229 return NULL;
231 if (generic->get_type() == BXT_PARAM_STRING)
232 return (bx_param_string_c *)generic;
233 BX_ERROR(("get_param_string(%s) could not find an integer parameter with that name", pname));
234 return NULL;
237 bx_param_bool_c *bx_real_sim_c::get_param_bool(const char *pname, bx_param_c *base)
239 bx_param_c *generic = get_param(pname, base);
240 if (generic==NULL) {
241 BX_ERROR(("get_param_bool(%s) could not find a parameter", pname));
242 return NULL;
244 if (generic->get_type () == BXT_PARAM_BOOL)
245 return (bx_param_bool_c *)generic;
246 BX_ERROR(("get_param_bool(%s) could not find a bool parameter with that name", pname));
247 return NULL;
250 bx_param_enum_c *bx_real_sim_c::get_param_enum(const char *pname, bx_param_c *base)
252 bx_param_c *generic = get_param(pname, base);
253 if (generic==NULL) {
254 BX_ERROR(("get_param_enum(%s) could not find a parameter", pname));
255 return NULL;
257 if (generic->get_type() == BXT_PARAM_ENUM)
258 return (bx_param_enum_c *)generic;
259 BX_ERROR(("get_param_enum(%s) could not find a enum parameter with that name", pname));
260 return NULL;
263 void bx_init_siminterface()
265 siminterface_log = new logfunctions();
266 siminterface_log->put("CTRL");
267 siminterface_log->settype(CTRLLOG);
268 if (SIM == NULL)
269 SIM = new bx_real_sim_c();
270 if (root_param == NULL) {
271 root_param = new bx_list_c(NULL,
272 "bochs",
273 "list of top level bochs parameters",
274 30);
278 bx_real_sim_c::bx_real_sim_c()
280 bxevent_callback = NULL;
281 bxevent_callback_data = NULL;
282 ci_callback = NULL;
283 ci_callback_data = NULL;
284 is_sim_thread_func = NULL;
285 debug_gui = 0;
287 enabled = 1;
288 init_done = 0;
289 quit_context = NULL;
290 exit_code = 0;
291 param_id = BXP_NEW_PARAM_ID;
292 n_user_options = 0;
295 void bx_real_sim_c::reset_all_param()
297 bx_reset_options();
300 int bx_real_sim_c::get_n_log_modules()
302 return io->get_n_logfns();
305 char *bx_real_sim_c::get_prefix(int mod)
307 logfunc_t *logfn = io->get_logfn(mod);
308 return logfn->getprefix();
311 int bx_real_sim_c::get_log_action(int mod, int level)
313 logfunc_t *logfn = io->get_logfn(mod);
314 return logfn->getonoff(level);
317 void bx_real_sim_c::set_log_action(int mod, int level, int action)
319 // normal
320 if (mod >= 0) {
321 logfunc_t *logfn = io->get_logfn(mod);
322 logfn->setonoff(level, action);
323 return;
325 // if called with mod<0 loop over all
326 int nmod = get_n_log_modules ();
327 for (mod=0; mod<nmod; mod++)
328 set_log_action(mod, level, action);
331 char *bx_real_sim_c::get_action_name(int action)
333 return io->getaction(action);
336 const char *bx_real_sim_c::get_log_level_name(int level)
338 return io->getlevel(level);
341 void bx_real_sim_c::quit_sim(int code)
343 BX_INFO(("quit_sim called with exit code %d", code));
344 exit_code = code;
345 io->exit_log();
346 // use longjmp to quit cleanly, no matter where in the stack we are.
347 if (quit_context != NULL) {
348 longjmp(*quit_context, 1);
349 BX_PANIC(("in bx_real_sim_c::quit_sim, longjmp should never return"));
350 } else {
351 // use exit() to stop the application.
352 if (!code)
353 BX_PANIC(("Quit simulation command"));
354 ::exit(exit_code);
358 int bx_real_sim_c::get_default_rc(char *path, int len)
360 char *rc = bx_find_bochsrc();
361 if (rc == NULL) return -1;
362 strncpy(path, rc, len);
363 path[len-1] = 0;
364 return 0;
367 int bx_real_sim_c::read_rc(const char *rc)
369 return bx_read_configuration(rc);
372 // return values:
373 // 0: written ok
374 // -1: failed
375 // -2: already exists, and overwrite was off
376 int bx_real_sim_c::write_rc(const char *rc, int overwrite)
378 return bx_write_configuration(rc, overwrite);
381 int bx_real_sim_c::get_log_file(char *path, int len)
383 strncpy(path, SIM->get_param_string(BXPN_LOG_FILENAME)->getptr(), len);
384 return 0;
387 int bx_real_sim_c::set_log_file(char *path)
389 SIM->get_param_string(BXPN_LOG_FILENAME)->set(path);
390 return 0;
393 int bx_real_sim_c::get_log_prefix(char *prefix, int len)
395 strncpy(prefix, SIM->get_param_string(BXPN_LOG_PREFIX)->getptr(), len);
396 return 0;
399 int bx_real_sim_c::set_log_prefix(char *prefix)
401 SIM->get_param_string(BXPN_LOG_PREFIX)->set(prefix);
402 return 0;
405 int bx_real_sim_c::get_debugger_log_file(char *path, int len)
407 strncpy(path, SIM->get_param_string(BXPN_DEBUGGER_LOG_FILENAME)->getptr(), len);
408 return 0;
411 int bx_real_sim_c::set_debugger_log_file(char *path)
413 SIM->get_param_string(BXPN_DEBUGGER_LOG_FILENAME)->set(path);
414 return 0;
417 int bx_real_sim_c::get_cdrom_options(int level, bx_list_c **out, int *where)
419 char pname[80];
421 for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
422 for (Bit8u device=0; device<2; device++) {
423 sprintf(pname, "ata.%d.%s", channel, (device==0)?"master":"slave");
424 bx_list_c *devlist = (bx_list_c*) SIM->get_param(pname);
425 if (SIM->get_param_enum("type", devlist)->get() == BX_ATA_DEVICE_CDROM) {
426 if (level==0) {
427 *out = devlist;
428 if (where != NULL) *where = (channel * 2) + device;
429 return 1;
430 } else {
431 level--;
436 return 0;
439 const char *bochs_start_names[] = { "quick", "load", "edit", "run" };
441 const char *floppy_type_names[] = { "none", "1.2M", "1.44M", "2.88M", "720K", "360K", "160K", "180K", "320K", "auto", NULL };
442 int floppy_type_n_sectors[] = { -1, 80*2*15, 80*2*18, 80*2*36, 80*2*9, 40*2*9, 40*1*8, 40*1*9, 40*2*8, -1 };
443 const char *floppy_status_names[] = { "ejected", "inserted", NULL };
445 const char *bochs_bootdisk_names[] = { "none", "floppy", "disk","cdrom", "network", NULL };
446 const char *loader_os_names[] = { "none", "linux", "nullkernel", NULL };
447 const char *keyboard_type_names[] = { "xt", "at", "mf", NULL };
449 const char *atadevice_type_names[] = { "disk", "cdrom", NULL };
450 //const char *atadevice_mode_names[] = { "flat", "concat", "external", "dll", "sparse", "vmware3", "vmware4", "undoable", "growing", "volatile", "z-undoable", "z-volatile", NULL };
451 const char *atadevice_mode_names[] = { "flat", "concat", "external", "dll", "sparse", "vmware3", "vmware4", "undoable", "growing", "volatile", NULL };
452 const char *atadevice_status_names[] = { "ejected", "inserted", NULL };
453 const char *atadevice_biosdetect_names[] = { "none", "auto", "cmos", NULL };
454 const char *atadevice_translation_names[] = { "none", "lba", "large", "rechs", "auto", NULL };
455 const char *clock_sync_names[] = { "none", "realtime", "slowdown", "both", NULL };
458 void bx_real_sim_c::set_notify_callback(bxevent_handler func, void *arg)
460 bxevent_callback = func;
461 bxevent_callback_data = arg;
464 void bx_real_sim_c::get_notify_callback(bxevent_handler *func, void **arg)
466 *func = bxevent_callback;
467 *arg = bxevent_callback_data;
470 BxEvent *bx_real_sim_c::sim_to_ci_event(BxEvent *event)
472 if (bxevent_callback == NULL) {
473 BX_ERROR(("notify called, but no bxevent_callback function is registered"));
474 return NULL;
475 } else {
476 return (*bxevent_callback)(bxevent_callback_data, event);
480 // returns 0 for continue, 1 for alwayscontinue, 2 for die.
481 int bx_real_sim_c::log_msg(const char *prefix, int level, const char *msg)
483 BxEvent be;
484 be.type = BX_SYNC_EVT_LOG_ASK;
485 be.u.logmsg.prefix = prefix;
486 be.u.logmsg.level = level;
487 be.u.logmsg.msg = msg;
488 // default return value in case something goes wrong.
489 be.retcode = BX_LOG_NOTIFY_FAILED;
490 // calling notify
491 sim_to_ci_event (&be);
492 return be.retcode;
495 // Called by simulator whenever it needs the user to choose a new value
496 // for a registered parameter. Create a synchronous ASK_PARAM event,
497 // send it to the CI, and wait for the response. The CI will call the
498 // set() method on the parameter if the user changes the value.
499 int bx_real_sim_c::ask_param(bx_param_c *param)
501 BX_ASSERT(param != NULL);
502 // create appropriate event
503 BxEvent event;
504 event.type = BX_SYNC_EVT_ASK_PARAM;
505 event.u.param.param = param;
506 sim_to_ci_event(&event);
507 return event.retcode;
510 int bx_real_sim_c::ask_param(const char *pname)
512 bx_param_c *paramptr = SIM->get_param(pname);
513 BX_ASSERT(paramptr != NULL);
514 // create appropriate event
515 BxEvent event;
516 event.type = BX_SYNC_EVT_ASK_PARAM;
517 event.u.param.param = paramptr;
518 sim_to_ci_event(&event);
519 return event.retcode;
522 int bx_real_sim_c::ask_filename(const char *filename, int maxlen, const char *prompt, const char *the_default, int flags)
524 BxEvent event;
525 bx_param_string_c param(NULL, "filename", prompt, "", the_default, maxlen);
526 flags |= param.IS_FILENAME;
527 param.get_options()->set(flags);
528 event.type = BX_SYNC_EVT_ASK_PARAM;
529 event.u.param.param = &param;
530 sim_to_ci_event(&event);
531 if (event.retcode >= 0)
532 memcpy((char *)filename, param.getptr(), maxlen);
533 return event.retcode;
536 int bx_real_sim_c::ask_yes_no(const char *title, const char *prompt, bx_bool the_default)
538 BxEvent event;
539 char format[512];
541 bx_param_bool_c param(NULL, "yes_no", title, prompt, the_default);
542 sprintf(format, "%s\n\n%s [%%s] ", title, prompt);
543 param.set_ask_format(format);
544 event.type = BX_SYNC_EVT_ASK_PARAM;
545 event.u.param.param = &param;
546 sim_to_ci_event(&event);
547 if (event.retcode >= 0) {
548 return param.get();
550 else {
551 return event.retcode;
555 void bx_real_sim_c::periodic()
557 // give the GUI a chance to do periodic things on the bochs thread. in
558 // particular, notice if the thread has been asked to die.
559 BxEvent tick;
560 tick.type = BX_SYNC_EVT_TICK;
561 sim_to_ci_event (&tick);
562 if (tick.retcode < 0) {
563 BX_INFO(("Bochs thread has been asked to quit."));
564 #if !BX_DEBUGGER
565 bx_atexit();
566 quit_sim(0);
567 #else
568 bx_dbg_exit(0);
569 #endif
571 static int refresh_counter = 0;
572 if (++refresh_counter == 50) {
573 // only ask the CI to refresh every 50 times periodic() is called.
574 // This should obviously be configurable because system speeds and
575 // user preferences vary.
576 refresh_ci();
577 refresh_counter = 0;
581 // create a disk image file called filename, size=512 bytes * sectors.
582 // If overwrite is 0 and the file exists, returns -1 without changing it.
583 // Otherwise, opens up the image and starts writing. Returns -2 if
584 // the image could not be opened, or -3 if there are failures during
585 // write, e.g. disk full.
587 // wxWidgets: This may be called from the gui thread.
588 int bx_real_sim_c::create_disk_image(const char *filename, int sectors, bx_bool overwrite)
590 FILE *fp;
591 if (!overwrite) {
592 // check for existence first
593 fp = fopen(filename, "r");
594 if (fp) {
595 // yes it exists
596 fclose(fp);
597 return -1;
600 fp = fopen(filename, "w");
601 if (fp == NULL) {
602 #ifdef HAVE_PERROR
603 char buffer[1024];
604 sprintf(buffer, "while opening '%s' for writing", filename);
605 perror(buffer);
606 // not sure how to get this back into the CI
607 #endif
608 return -2;
610 int sec = sectors;
612 * seek to sec*512-1 and write a single character.
613 * can't just do: fseek(fp, 512*sec-1, SEEK_SET)
614 * because 512*sec may be too large for signed int.
616 while (sec > 0)
618 /* temp <-- min(sec, 4194303)
619 * 4194303 is (int)(0x7FFFFFFF/512)
621 int temp = ((sec < 4194303) ? sec : 4194303);
622 fseek(fp, 512*temp, SEEK_CUR);
623 sec -= temp;
626 fseek(fp, -1, SEEK_CUR);
627 if (fputc('\0', fp) == EOF)
629 fclose(fp);
630 return -3;
632 fclose(fp);
633 return 0;
636 void bx_real_sim_c::refresh_ci()
638 if (SIM->has_debug_gui()) {
639 // presently, only wxWidgets interface uses these events
640 // It's an async event, so allocate a pointer and send it.
641 // The event will be freed by the recipient.
642 BxEvent *event = new BxEvent();
643 event->type = BX_ASYNC_EVT_REFRESH;
644 sim_to_ci_event(event);
648 bx_param_c *bx_real_sim_c::get_first_atadevice(Bit32u search_type)
650 char pname[80];
651 for (int channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
652 sprintf(pname, "ata.%d.resources.enabled", channel);
653 if (!SIM->get_param_bool(pname)->get())
654 continue;
655 for (int slave=0; slave<2; slave++) {
656 sprintf(pname, "ata.%d.%s.present", channel, (slave==0)?"master":"slave");
657 Bit32u present = SIM->get_param_bool(pname)->get();
658 sprintf(pname, "ata.%d.%s.type", channel, (slave==0)?"master":"slave");
659 Bit32u type = SIM->get_param_enum(pname)->get();
660 if (present && (type == search_type)) {
661 sprintf(pname, "ata.%d.%s", channel, (slave==0)?"master":"slave");
662 return SIM->get_param(pname);
666 return NULL;
669 #if BX_DEBUGGER
671 // this can be safely called from either thread.
672 void bx_real_sim_c::debug_break()
674 bx_debug_break();
677 // this should only be called from the sim_thread.
678 void bx_real_sim_c::debug_interpret_cmd(char *cmd)
680 if (!is_sim_thread()) {
681 fprintf(stderr, "ERROR: debug_interpret_cmd called but not from sim_thread\n");
682 return;
684 bx_dbg_interpret_line(cmd);
687 char *bx_real_sim_c::debug_get_next_command()
689 BxEvent event;
690 event.type = BX_SYNC_EVT_GET_DBG_COMMAND;
691 BX_DEBUG(("asking for next debug command"));
692 sim_to_ci_event (&event);
693 BX_DEBUG(("received next debug command: '%s'", event.u.debugcmd.command));
694 if (event.retcode >= 0)
695 return event.u.debugcmd.command;
696 return NULL;
699 void bx_real_sim_c::debug_puts(const char *text)
701 if (SIM->has_debug_gui()) {
702 // send message to the wxWidgets debugger
703 BxEvent *event = new BxEvent();
704 event->type = BX_ASYNC_EVT_DBG_MSG;
705 event->u.logmsg.msg = text;
706 sim_to_ci_event(event);
707 // the event will be freed by the recipient
708 } else {
709 // text mode debugger: just write to console
710 fputs(text, stderr);
711 delete [] (char *)text;
714 #endif
716 void bx_real_sim_c::register_configuration_interface(
717 const char* name,
718 config_interface_callback_t callback,
719 void *userdata)
721 ci_callback = callback;
722 ci_callback_data = userdata;
723 registered_ci_name = name;
726 int bx_real_sim_c::configuration_interface(const char *ignore, ci_command_t command)
728 bx_param_enum_c *ci_param = SIM->get_param_enum(BXPN_SEL_CONFIG_INTERFACE);
729 const char *name = ci_param->get_selected();
730 if (!ci_callback) {
731 BX_PANIC(("no configuration interface was loaded"));
732 return -1;
734 if (strcmp(name, registered_ci_name) != 0) {
735 BX_PANIC(("siminterface does not support loading one configuration interface and then calling another"));
736 return -1;
738 if (!strcmp(name, "wx"))
739 debug_gui = 1;
740 else
741 debug_gui = 0;
742 // enter configuration mode, just while running the configuration interface
743 set_display_mode(DISP_MODE_CONFIG);
744 int retval = (*ci_callback)(ci_callback_data, command);
745 set_display_mode(DISP_MODE_SIM);
746 return retval;
749 int bx_real_sim_c::begin_simulation(int argc, char *argv[])
751 return bx_begin_simulation(argc, argv);
754 bx_bool bx_real_sim_c::is_sim_thread()
756 if (is_sim_thread_func == NULL) return 1;
757 return (*is_sim_thread_func)();
760 // check if the text console exists. On some platforms, if Bochs is
761 // started from the "Start Menu" or by double clicking on it on a Mac,
762 // there may be nothing attached to stdin/stdout/stderr. This function
763 // tests if stdin/stdout/stderr are usable and returns 0 if not.
764 bx_bool bx_real_sim_c::test_for_text_console()
766 #if BX_WITH_CARBON
767 // In a Carbon application, you have a text console if you run the app from
768 // the command line, but if you start it from the finder you don't.
769 if(!isatty(STDIN_FILENO)) return 0;
770 #endif
771 // default: yes
772 return 1;
775 int bx_real_sim_c::find_user_option(const char *keyword)
777 int i = 0;
778 while (i < n_user_options) {
779 if (!strcmp(keyword, user_option_name[i])) {
780 return i;
782 i++;
784 return -1;
787 bx_bool bx_real_sim_c::register_user_option(const char *keyword, user_option_parser_t parser,
788 user_option_save_t save_func)
790 if (n_user_options >= BX_MAX_USER_OPTIONS) {
791 return 0;
793 int idx = find_user_option(keyword);
794 if (idx >= 0) {
795 if (parser == user_option_parser[idx]) {
796 // parse handler already registered
797 return 1;
798 } else {
799 // keyword already exists
800 return 0;
802 } else {
803 user_option_name[n_user_options] = keyword;
804 user_option_parser[n_user_options] = parser;
805 user_option_save[n_user_options++] = save_func;
806 return 1;
810 Bit32s bx_real_sim_c::parse_user_option(int idx, const char *context, int num_params, char *params [])
812 if ((idx < 0) || (idx >= n_user_options)) {
813 return -1;
815 return (*user_option_parser[idx])(context, num_params, params);
818 Bit32s bx_real_sim_c::save_user_options(FILE *fp)
820 for (int i = 0; i < n_user_options; i++) {
821 if (user_option_save[i] != NULL) {
822 (*user_option_save[i])(fp);
825 return 0;
828 void bx_real_sim_c::init_save_restore()
830 bx_list_c *list;
832 if ((list = get_bochs_root()) != NULL) {
833 list->clear();
834 } else {
835 list = new bx_list_c(root_param,
836 "bochs",
837 "subtree for save/restore",
838 30 + BX_MAX_SMP_THREADS_SUPPORTED);
842 bx_bool bx_real_sim_c::save_state(const char *checkpoint_path)
844 char sr_file[BX_PATHNAME_LEN];
845 char prefix[8];
846 int i, dev, ndev = SIM->get_n_log_modules();
847 int type, ntype = SIM->get_max_log_level();
849 sprintf(sr_file, "%s/config", checkpoint_path);
850 if (write_rc(sr_file, 1) < 0)
851 return 0;
852 sprintf(sr_file, "%s/logopts", checkpoint_path);
853 FILE *fp = fopen(sr_file, "w");
854 if (fp != NULL) {
855 for (dev=0; dev<ndev; dev++) {
856 strcpy(prefix, get_prefix(dev));
857 strcpy(prefix, prefix+1);
858 prefix[strlen(prefix) - 1] = 0;
859 i = strlen(prefix) - 1;
860 while ((i >= 0) && (prefix[i] == ' ')) prefix[i--] = 0;
861 if (strlen(prefix) > 0) {
862 fprintf(fp, "%s: ", prefix);
863 for (type=0; type<ntype; type++) {
864 if (type > 0) fprintf(fp, ", ");
865 fprintf(fp, "%s=%s", get_log_level_name(type), get_action_name(get_log_action(dev, type)));
867 fprintf(fp, "\n");
870 fclose(fp);
871 } else {
872 return 0;
874 bx_list_c *sr_list = get_bochs_root();
875 ndev = sr_list->get_size();
876 for (dev=0; dev<ndev; dev++) {
877 sprintf(sr_file, "%s/%s", checkpoint_path, sr_list->get(dev)->get_name());
878 fp = fopen(sr_file, "w");
879 if (fp != NULL) {
880 save_sr_param(fp, sr_list->get(dev), checkpoint_path, 0);
881 fclose(fp);
882 } else {
883 return 0;
886 return 1;
889 bx_bool bx_real_sim_c::restore_config()
891 char config[BX_PATHNAME_LEN];
892 sprintf(config, "%s/config", get_param_string(BXPN_RESTORE_PATH)->getptr());
893 BX_INFO(("restoring '%s'", config));
894 return (read_rc(config) >= 0);
897 bx_bool bx_real_sim_c::restore_logopts()
899 char logopts[BX_PATHNAME_LEN];
900 char line[512], string[512], prefix[8];
901 char *ret, *ptr;
902 int d, i, j, dev = 0, type = 0, action = 0;
903 int ndev = SIM->get_n_log_modules();
904 FILE *fp;
906 sprintf(logopts, "%s/logopts", get_param_string(BXPN_RESTORE_PATH)->getptr());
907 BX_INFO(("restoring '%s'", logopts));
908 fp = fopen(logopts, "r");
909 if (fp != NULL) {
910 do {
911 ret = fgets(line, sizeof(line)-1, fp);
912 line[sizeof(line) - 1] = '\0';
913 int len = strlen(line);
914 if ((len>0) && (line[len-1] < ' '))
915 line[len-1] = '\0';
916 i = 0;
917 if ((ret != NULL) && strlen(line)) {
918 ptr = strtok(line, ":");
919 while (ptr) {
920 strcpy(string, ptr);
921 while (isspace(string[0])) strcpy(string, string+1);
922 while (isspace(string[strlen(string)-1])) string[strlen(string)-1] = 0;
923 if (i == 0) {
924 sprintf(prefix, "[%-5s]", string);
925 dev = -1;
926 for (d = 0; d < ndev; d++) {
927 if (!strcmp(prefix, get_prefix(d))) {
928 dev = d;
931 } else if (dev >= 0) {
932 j = 6;
933 if (!strncmp(string, "DEBUG=", 6)) {
934 type = LOGLEV_DEBUG;
935 } else if (!strncmp(string, "INFO=", 5)) {
936 type = LOGLEV_INFO;
937 j = 5;
938 } else if (!strncmp(string, "ERROR=", 6)) {
939 type = LOGLEV_ERROR;
940 } else if (!strncmp(string, "PANIC=", 6)) {
941 type = LOGLEV_PANIC;
942 } else if (!strncmp(string, "PASS=", 5)) {
943 type = LOGLEV_PASS;
944 j = 5;
946 if (!strcmp(string+j, "ignore")) {
947 action = ACT_IGNORE;
948 } else if (!strcmp(string+j, "report")) {
949 action = ACT_REPORT;
950 } else if (!strcmp(string+j, "ask")) {
951 action = ACT_ASK;
952 } else if (!strcmp(string+j, "fatal")) {
953 action = ACT_FATAL;
955 set_log_action(dev, type, action);
956 } else {
957 if (i == 1) {
958 BX_ERROR(("restore_logopts(): log module '%s' not found", prefix));
961 i++;
962 ptr = strtok(NULL, ",");
965 } while (!feof(fp));
966 fclose(fp);
967 } else {
968 return 0;
970 return 1;
973 bx_bool bx_real_sim_c::restore_bochs_param(bx_list_c *root, const char *sr_path, const char *restore_name)
975 char devstate[BX_PATHNAME_LEN], devdata[BX_PATHNAME_LEN];
976 char line[512], buf[512], pname[80];
977 char *ret, *ptr;
978 int i, j, p;
979 unsigned n;
980 bx_param_c *param = NULL;
981 FILE *fp, *fp2;
983 if (root->get_by_name(restore_name) == NULL) {
984 BX_ERROR(("restore_bochs_param(): unknown parameter to restore"));
985 return 0;
988 sprintf(devstate, "%s/%s", sr_path, restore_name);
989 BX_INFO(("restoring '%s'", devstate));
990 bx_list_c *base = root;
991 fp = fopen(devstate, "r");
992 if (fp != NULL) {
993 do {
994 ret = fgets(line, sizeof(line)-1, fp);
995 line[sizeof(line) - 1] = '\0';
996 int len = strlen(line);
997 if ((len>0) && (line[len-1] < ' '))
998 line[len-1] = '\0';
999 i = 0;
1000 if ((ret != NULL) && strlen(line)) {
1001 ptr = strtok(line, " ");
1002 while (ptr) {
1003 if (i == 0) {
1004 if (!strcmp(ptr, "}")) {
1005 base = (bx_list_c*)base->get_parent();
1006 break;
1007 } else {
1008 param = get_param(ptr, base);
1010 } else if (i == 2) {
1011 if (param->get_type() != BXT_LIST) {
1012 param->get_param_path(pname, 80);
1013 BX_DEBUG(("restoring parameter '%s'", pname));
1015 switch (param->get_type()) {
1016 case BXT_PARAM_NUM:
1017 if ((ptr[0] == '0') && (ptr[1] == 'x')) {
1018 ((bx_param_num_c*)param)->set(strtoull(ptr, NULL, 16));
1019 } else {
1020 ((bx_param_num_c*)param)->set(strtoull(ptr, NULL, 10));
1022 break;
1023 case BXT_PARAM_BOOL:
1024 ((bx_param_bool_c*)param)->set(!strcmp(ptr, "true"));
1025 break;
1026 case BXT_PARAM_ENUM:
1027 ((bx_param_enum_c*)param)->set_by_name(ptr);
1028 break;
1029 case BXT_PARAM_STRING:
1030 if (((bx_param_string_c*)param)->get_options()->get() & bx_param_string_c::RAW_BYTES) {
1031 p = 0;
1032 for (j = 0; j < ((bx_param_string_c*)param)->get_maxsize(); j++) {
1033 if (ptr[p] == ((bx_param_string_c*)param)->get_separator()) {
1034 p++;
1036 if (sscanf(ptr+p, "%02x", &n) == 1) {
1037 buf[j] = n;
1038 p += 2;
1041 ((bx_param_string_c*)param)->set(buf);
1042 } else {
1043 ((bx_param_string_c*)param)->set(ptr);
1045 break;
1046 case BXT_PARAM_DATA:
1047 sprintf(devdata, "%s/%s", sr_path, ptr);
1048 fp2 = fopen(devdata, "rb");
1049 if (fp2 != NULL) {
1050 fread(((bx_shadow_data_c*)param)->getptr(), 1, ((bx_shadow_data_c*)param)->get_size(), fp2);
1051 fclose(fp2);
1053 break;
1054 case BXT_LIST:
1055 base = (bx_list_c*)param;
1056 break;
1057 default:
1058 BX_ERROR(("restore_sr_param(): unknown parameter type"));
1061 i++;
1062 ptr = strtok(NULL, " ");
1065 } while (!feof(fp));
1066 fclose(fp);
1067 } else {
1068 BX_ERROR(("restore_bochs_param(): error in file open"));
1069 return 0;
1072 return 1;
1075 bx_bool bx_real_sim_c::restore_hardware()
1077 bx_list_c *sr_list = get_bochs_root();
1078 int ndev = sr_list->get_size();
1079 for (int dev=0; dev<ndev; dev++) {
1080 if (!restore_bochs_param(sr_list, get_param_string(BXPN_RESTORE_PATH)->getptr(), sr_list->get(dev)->get_name()))
1081 return 0;
1083 return 1;
1086 bx_bool bx_real_sim_c::save_sr_param(FILE *fp, bx_param_c *node, const char *sr_path, int level)
1088 int i;
1089 Bit64s value;
1090 char tmpstr[BX_PATHNAME_LEN], tmpbyte[4];
1091 FILE *fp2;
1093 for (i=0; i<level; i++)
1094 fprintf(fp, " ");
1095 if (node == NULL) {
1096 BX_ERROR(("NULL pointer"));
1097 return 0;
1099 fprintf(fp, "%s = ", node->get_name());
1100 switch (node->get_type()) {
1101 case BXT_PARAM_NUM:
1102 value = ((bx_param_num_c*)node)->get64();
1103 if (((bx_param_num_c*)node)->get_base() == BASE_DEC) {
1104 if (((bx_param_num_c*)node)->get_min() >= BX_MIN_BIT64U) {
1105 if ((Bit64u)((bx_param_num_c*)node)->get_max() > BX_MAX_BIT32U) {
1106 fprintf(fp, FMT_LL"u\n", value);
1107 } else {
1108 fprintf(fp, "%u\n", (Bit32u) value);
1110 } else {
1111 fprintf(fp, "%d\n", (Bit32s) value);
1113 } else {
1114 if (node->get_format()) {
1115 fprintf(fp, node->get_format(), value);
1116 } else {
1117 if ((Bit64u)((bx_param_num_c*)node)->get_max() > BX_MAX_BIT32U) {
1118 fprintf(fp, "0x"FMT_LL"x", (Bit64u) value);
1119 } else {
1120 fprintf(fp, "0x%x", (Bit32u) value);
1123 fprintf(fp, "\n");
1125 break;
1126 case BXT_PARAM_BOOL:
1127 fprintf(fp, "%s\n", ((bx_param_bool_c*)node)->get()?"true":"false");
1128 break;
1129 case BXT_PARAM_ENUM:
1130 fprintf(fp, "%s\n", ((bx_param_enum_c*)node)->get_selected());
1131 break;
1132 case BXT_PARAM_STRING:
1133 if (((bx_param_string_c*)node)->get_options()->get() & bx_param_string_c::RAW_BYTES) {
1134 tmpstr[0] = 0;
1135 for (i = 0; i < ((bx_param_string_c*)node)->get_maxsize(); i++) {
1136 if (i > 0) {
1137 tmpbyte[0] = ((bx_param_string_c*)node)->get_separator();
1138 tmpbyte[1] = 0;
1139 strcat(tmpstr, tmpbyte);
1141 sprintf(tmpbyte, "%02x", (Bit8u)((bx_param_string_c*)node)->getptr()[i]);
1142 strcat(tmpstr, tmpbyte);
1144 fprintf(fp, "%s\n", tmpstr);
1145 } else {
1146 fprintf(fp, "%s\n", ((bx_param_string_c*)node)->getptr());
1148 break;
1149 case BXT_PARAM_DATA:
1150 fprintf(fp, "%s.%s\n", node->get_parent()->get_name(), node->get_name());
1151 if (sr_path)
1152 sprintf(tmpstr, "%s/%s.%s", sr_path, node->get_parent()->get_name(), node->get_name());
1153 else
1154 sprintf(tmpstr, "%s.%s", node->get_parent()->get_name(), node->get_name());
1155 fp2 = fopen(tmpstr, "wb");
1156 if (fp2 != NULL) {
1157 fwrite(((bx_shadow_data_c*)node)->getptr(), 1, ((bx_shadow_data_c*)node)->get_size(), fp2);
1158 fclose(fp2);
1160 break;
1161 case BXT_LIST:
1163 fprintf(fp, "{\n");
1164 bx_list_c *list = (bx_list_c*)node;
1165 for (i=0; i < list->get_size(); i++) {
1166 save_sr_param(fp, list->get(i), sr_path, level+1);
1168 for (i=0; i<level; i++)
1169 fprintf(fp, " ");
1170 fprintf(fp, "}\n");
1171 break;
1173 default:
1174 BX_ERROR(("save_sr_param(): unknown parameter type"));
1175 return 0;
1178 return 1;
1181 /////////////////////////////////////////////////////////////////////////
1182 // define methods of bx_param_* and family
1183 /////////////////////////////////////////////////////////////////////////
1185 const char* bx_param_c::default_text_format = NULL;
1187 bx_param_c::bx_param_c(Bit32u id, const char *param_name, const char *param_desc)
1188 : bx_object_c(id),
1189 parent(NULL),
1190 description(NULL),
1191 label(NULL),
1192 ask_format(NULL),
1193 group_name(NULL)
1195 set_type(BXT_PARAM);
1196 this->name = new char[strlen(param_name)+1];
1197 strcpy(this->name, param_name);
1198 set_description(param_desc);
1199 this->text_format = default_text_format;
1200 this->long_text_format = default_text_format;
1201 this->runtime_param = 0;
1202 this->enabled = 1;
1205 bx_param_c::bx_param_c(Bit32u id, const char *param_name, const char *param_label, const char *param_desc)
1206 : bx_object_c(id),
1207 parent(NULL),
1208 description(NULL),
1209 label(NULL),
1210 ask_format(NULL),
1211 group_name(NULL)
1213 set_type(BXT_PARAM);
1214 this->name = new char[strlen(param_name)+1];
1215 strcpy(this->name, param_name);
1216 set_description(param_desc);
1217 set_label(param_label);
1218 this->text_format = default_text_format;
1219 this->long_text_format = default_text_format;
1220 this->runtime_param = 0;
1221 this->enabled = 1;
1224 bx_param_c::~bx_param_c()
1226 delete [] name;
1227 delete [] label;
1228 delete [] description;
1229 delete [] ask_format;
1230 delete [] group_name;
1233 void bx_param_c::set_description(const char *text)
1235 delete [] this->description;
1236 if (text) {
1237 this->description = new char[strlen(text)+1];
1238 strcpy(this->description, text);
1239 } else {
1240 this->description = NULL;
1244 void bx_param_c::set_label(const char *text)
1246 delete [] this->label;
1247 if (text) {
1248 this->label = new char[strlen(text)+1];
1249 strcpy(this->label, text);
1250 } else {
1251 this->label = NULL;
1255 void bx_param_c::set_ask_format(const char *format)
1257 delete [] this->ask_format;
1258 if (format) {
1259 this->ask_format = new char[strlen(format)+1];
1260 strcpy(this->ask_format, format);
1261 } else {
1262 this->ask_format = NULL;
1266 void bx_param_c::set_group(const char *group)
1268 delete [] this->group_name;
1269 if (group) {
1270 this->group_name = new char[strlen(group)+1];
1271 strcpy(this->group_name, group);
1272 } else {
1273 this->group_name = NULL;
1277 int bx_param_c::get_param_path(char *path_out, int maxlen)
1279 if ((get_parent() == NULL) || (get_parent() == root_param)) {
1280 // Start with an empty string.
1281 // Never print the name of the root param.
1282 path_out[0] = 0;
1283 } else {
1284 // build path of the parent, add a period, add path of this node
1285 if (get_parent()->get_param_path(path_out, maxlen) > 0) {
1286 strncat(path_out, ".", maxlen);
1289 strncat(path_out, name, maxlen);
1290 return strlen(path_out);
1293 const char* bx_param_c::set_default_format(const char *f)
1295 const char *old = default_text_format;
1296 default_text_format = f;
1297 return old;
1300 bx_param_num_c::bx_param_num_c(bx_param_c *parent,
1301 const char *name,
1302 const char *label,
1303 const char *description,
1304 Bit64s min, Bit64s max, Bit64s initial_val,
1305 bx_bool is_shadow)
1306 : bx_param_c(SIM->gen_param_id(), name, label, description)
1308 set_type(BXT_PARAM_NUM);
1309 this->min = min;
1310 this->max = max;
1311 this->initial_val = initial_val;
1312 this->val.number = initial_val;
1313 this->handler = NULL;
1314 this->save_handler = NULL;
1315 this->restore_handler = NULL;
1316 this->enable_handler = NULL;
1317 this->base = default_base;
1318 this->is_shadow = is_shadow;
1319 // dependent_list must be initialized before the set(),
1320 // because set calls update_dependents().
1321 dependent_list = NULL;
1322 if (!is_shadow) {
1323 set(initial_val);
1325 if (parent) {
1326 BX_ASSERT(parent->get_type() == BXT_LIST);
1327 this->parent = (bx_list_c *)parent;
1328 this->parent->add(this);
1332 Bit32u bx_param_num_c::default_base = BASE_DEC;
1334 Bit32u bx_param_num_c::set_default_base(Bit32u val)
1336 Bit32u old = default_base;
1337 default_base = val;
1338 return old;
1341 void bx_param_num_c::set_handler(param_event_handler handler)
1343 this->handler = handler;
1344 // now that there's a handler, call set once to run the handler immediately
1345 //set (get ());
1348 void bx_param_num_c::set_sr_handlers(void *devptr, param_sr_handler save, param_sr_handler restore)
1350 this->sr_devptr = devptr;
1351 this->save_handler = save;
1352 this->restore_handler = restore;
1355 void bx_param_num_c::set_dependent_list(bx_list_c *l)
1357 dependent_list = l;
1358 update_dependents();
1361 Bit64s bx_param_num_c::get64()
1363 if (save_handler) {
1364 return (*save_handler)(sr_devptr, this, val.number);
1366 if (handler) {
1367 // the handler can decide what value to return and/or do some side effect
1368 return (*handler)(this, 0, val.number);
1369 } else {
1370 // just return the value
1371 return val.number;
1375 void bx_param_num_c::set(Bit64s newval)
1377 if (handler) {
1378 // the handler can override the new value and/or perform some side effect
1379 val.number = newval;
1380 (*handler)(this, 1, newval);
1381 } else {
1382 // just set the value. This code does not check max/min.
1383 val.number = newval;
1385 if (restore_handler) {
1386 val.number = newval;
1387 (*restore_handler)(sr_devptr, this, newval);
1389 if ((val.number < min || val.number > max) && (Bit64u)max != BX_MAX_BIT64U)
1390 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));
1391 if (dependent_list != NULL) update_dependents();
1394 void bx_param_num_c::set_range(Bit64u min, Bit64u max)
1396 this->min = min;
1397 this->max = max;
1400 void bx_param_num_c::set_initial_val(Bit64s initial_val)
1402 this->val.number = this->initial_val = initial_val;
1405 void bx_param_num_c::update_dependents()
1407 if (dependent_list) {
1408 int en = val.number && enabled;
1409 for (int i=0; i<dependent_list->get_size(); i++) {
1410 bx_param_c *param = dependent_list->get(i);
1411 if (param != this)
1412 param->set_enabled(en);
1417 void bx_param_num_c::set_enabled(int en)
1419 // The enable handler may wish to allow/disallow the action
1420 if (enable_handler) {
1421 en = (*enable_handler)(this, en);
1423 bx_param_c::set_enabled(en);
1424 update_dependents();
1427 // Signed 64 bit
1428 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
1429 const char *name,
1430 Bit64s *ptr_to_real_val,
1431 int base,
1432 Bit8u highbit,
1433 Bit8u lowbit)
1434 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT64S, BX_MAX_BIT64S, *ptr_to_real_val, 1)
1436 this->varsize = 64;
1437 this->lowbit = lowbit;
1438 this->mask = ((BX_MAX_BIT64S >> (63 - (highbit - lowbit))) << lowbit);
1439 val.p64bit = ptr_to_real_val;
1440 if (base == BASE_HEX) {
1441 this->base = base;
1442 this->text_format = "0x"FMT_LL"x";
1446 // Unsigned 64 bit
1447 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
1448 const char *name,
1449 Bit64u *ptr_to_real_val,
1450 int base,
1451 Bit8u highbit,
1452 Bit8u lowbit)
1453 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT64U, BX_MAX_BIT64U, *ptr_to_real_val, 1)
1455 this->varsize = 64;
1456 this->lowbit = lowbit;
1457 this->mask = ((BX_MAX_BIT64U >> (63 - (highbit - lowbit))) << lowbit);
1458 val.p64bit = (Bit64s*) ptr_to_real_val;
1459 if (base == BASE_HEX) {
1460 this->base = base;
1461 this->text_format = "0x"FMT_LL"x";
1465 // Signed 32 bit
1466 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
1467 const char *name,
1468 Bit32s *ptr_to_real_val,
1469 int base,
1470 Bit8u highbit,
1471 Bit8u lowbit)
1472 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT32S, BX_MAX_BIT32S, *ptr_to_real_val, 1)
1474 this->varsize = 32;
1475 this->lowbit = lowbit;
1476 this->mask = ((BX_MAX_BIT32S >> (31 - (highbit - lowbit))) << lowbit);
1477 val.p32bit = ptr_to_real_val;
1478 if (base == BASE_HEX) {
1479 this->base = base;
1480 this->text_format = "0x%08x";
1484 // Unsigned 32 bit
1485 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
1486 const char *name,
1487 Bit32u *ptr_to_real_val,
1488 int base,
1489 Bit8u highbit,
1490 Bit8u lowbit)
1491 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT32U, BX_MAX_BIT32U, *ptr_to_real_val, 1)
1493 this->varsize = 32;
1494 this->lowbit = lowbit;
1495 this->mask = ((BX_MAX_BIT32U >> (31 - (highbit - lowbit))) << lowbit);
1496 val.p32bit = (Bit32s*) ptr_to_real_val;
1497 if (base == BASE_HEX) {
1498 this->base = base;
1499 this->text_format = "0x%08x";
1503 // Signed 16 bit
1504 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
1505 const char *name,
1506 Bit16s *ptr_to_real_val,
1507 int base,
1508 Bit8u highbit,
1509 Bit8u lowbit)
1510 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT16S, BX_MAX_BIT16S, *ptr_to_real_val, 1)
1512 this->varsize = 16;
1513 this->lowbit = lowbit;
1514 this->mask = ((BX_MAX_BIT16S >> (15 - (highbit - lowbit))) << lowbit);
1515 val.p16bit = ptr_to_real_val;
1516 if (base == BASE_HEX) {
1517 this->base = base;
1518 this->text_format = "0x%04x";
1522 // Unsigned 16 bit
1523 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
1524 const char *name,
1525 Bit16u *ptr_to_real_val,
1526 int base,
1527 Bit8u highbit,
1528 Bit8u lowbit)
1529 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT16U, BX_MAX_BIT16U, *ptr_to_real_val, 1)
1531 this->varsize = 16;
1532 this->lowbit = lowbit;
1533 this->mask = ((BX_MAX_BIT16U >> (15 - (highbit - lowbit))) << lowbit);
1534 val.p16bit = (Bit16s*) ptr_to_real_val;
1535 if (base == BASE_HEX) {
1536 this->base = base;
1537 this->text_format = "0x%04x";
1541 // Signed 8 bit
1542 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
1543 const char *name,
1544 Bit8s *ptr_to_real_val,
1545 int base,
1546 Bit8u highbit,
1547 Bit8u lowbit)
1548 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT8S, BX_MAX_BIT8S, *ptr_to_real_val, 1)
1550 this->varsize = 8;
1551 this->lowbit = lowbit;
1552 this->mask = ((BX_MAX_BIT8S >> (7 - (highbit - lowbit))) << lowbit);
1553 this->mask = (1 << (highbit - lowbit)) - 1;
1554 val.p8bit = ptr_to_real_val;
1555 if (base == BASE_HEX) {
1556 this->base = base;
1557 this->text_format = "0x%02x";
1561 // Unsigned 8 bit
1562 bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent,
1563 const char *name,
1564 Bit8u *ptr_to_real_val,
1565 int base,
1566 Bit8u highbit,
1567 Bit8u lowbit)
1568 : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT8U, BX_MAX_BIT8U, *ptr_to_real_val, 1)
1570 this->varsize = 8;
1571 this->lowbit = lowbit;
1572 this->mask = ((BX_MAX_BIT8U >> (7 - (highbit - lowbit))) << lowbit);
1573 val.p8bit = (Bit8s*) ptr_to_real_val;
1574 if (base == BASE_HEX) {
1575 this->base = base;
1576 this->text_format = "0x%02x";
1580 Bit64s bx_shadow_num_c::get64()
1582 Bit64u current = 0;
1583 switch (varsize) {
1584 case 8: current = *(val.p8bit); break;
1585 case 16: current = *(val.p16bit); break;
1586 case 32: current = *(val.p32bit); break;
1587 case 64: current = *(val.p64bit); break;
1588 default: BX_PANIC(("unsupported varsize %d", varsize));
1590 current = (current >> lowbit) & mask;
1591 if (handler) {
1592 // the handler can decide what value to return and/or do some side effect
1593 return (*handler)(this, 0, current) & mask;
1594 } else {
1595 // just return the value
1596 return current;
1600 void bx_shadow_num_c::set(Bit64s newval)
1602 Bit64u tmp = 0;
1603 if (((newval < min) || (newval > max)) && (min != BX_MIN_BIT64S) && ((Bit64u)max != BX_MAX_BIT64U))
1604 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));
1605 switch (varsize) {
1606 case 8:
1607 tmp = *(val.p8bit) & ~(mask << lowbit);
1608 tmp |= (newval & mask) << lowbit;
1609 *(val.p8bit) = (Bit8s)tmp;
1610 break;
1611 case 16:
1612 tmp = *(val.p16bit) & ~(mask << lowbit);
1613 tmp |= (newval & mask) << lowbit;
1614 *(val.p16bit) = (Bit16s)tmp;
1615 break;
1616 case 32:
1617 tmp = *(val.p32bit) & ~(mask << lowbit);
1618 tmp |= (newval & mask) << lowbit;
1619 *(val.p32bit) = (Bit32s)tmp;
1620 break;
1621 case 64:
1622 tmp = *(val.p64bit) & ~(mask << lowbit);
1623 tmp |= (newval & mask) << lowbit;
1624 *(val.p64bit) = (Bit64s)tmp;
1625 break;
1626 default:
1627 BX_PANIC(("unsupported varsize %d", varsize));
1629 if (handler) {
1630 // the handler can override the new value and/or perform some side effect
1631 (*handler)(this, 1, tmp);
1635 void bx_shadow_num_c::reset()
1637 BX_PANIC(("reset not supported on bx_shadow_num_c yet"));
1640 bx_param_bool_c::bx_param_bool_c(bx_param_c *parent,
1641 const char *name,
1642 const char *label,
1643 const char *description,
1644 Bit64s initial_val,
1645 bx_bool is_shadow)
1646 : bx_param_num_c(parent, name, label, description, 0, 1, initial_val, is_shadow)
1648 set_type(BXT_PARAM_BOOL);
1651 bx_shadow_bool_c::bx_shadow_bool_c(bx_param_c *parent,
1652 const char *name,
1653 const char *label,
1654 bx_bool *ptr_to_real_val,
1655 Bit8u bitnum)
1656 : bx_param_bool_c(parent, name, label, NULL, (Bit64s) *ptr_to_real_val, 1)
1658 val.pbool = ptr_to_real_val;
1659 this->bitnum = bitnum;
1662 bx_shadow_bool_c::bx_shadow_bool_c(bx_param_c *parent,
1663 const char *name,
1664 bx_bool *ptr_to_real_val,
1665 Bit8u bitnum)
1666 : bx_param_bool_c(parent, name, NULL, NULL, (Bit64s) *ptr_to_real_val, 1)
1668 val.pbool = ptr_to_real_val;
1669 this->bitnum = bitnum;
1672 Bit64s bx_shadow_bool_c::get64()
1674 if (handler) {
1675 // the handler can decide what value to return and/or do some side effect
1676 Bit64s ret = (*handler)(this, 0, (Bit64s) *(val.pbool));
1677 return (ret>>bitnum) & 1;
1678 } else {
1679 // just return the value
1680 return (*(val.pbool)) & 1;
1684 void bx_shadow_bool_c::set(Bit64s newval)
1686 // only change the bitnum bit
1687 Bit64s tmp = (newval&1) << bitnum;
1688 *(val.pbool) &= ~tmp;
1689 *(val.pbool) |= tmp;
1690 if (handler) {
1691 // the handler can override the new value and/or perform some side effect
1692 (*handler)(this, 1, newval&1);
1696 bx_param_enum_c::bx_param_enum_c(bx_param_c *parent,
1697 const char *name,
1698 const char *label,
1699 const char *description,
1700 const char **choices,
1701 Bit64s initial_val,
1702 Bit64s value_base)
1703 : bx_param_num_c(parent, name, label, description, value_base, BX_MAX_BIT64S, initial_val)
1705 set_type(BXT_PARAM_ENUM);
1706 this->choices = choices;
1707 // count number of choices, set max
1708 const char **p = choices;
1709 while (*p != NULL) p++;
1710 this->min = value_base;
1711 // now that the max is known, replace the BX_MAX_BIT64S sent to the parent
1712 // class constructor with the real max.
1713 this->max = value_base + (p - choices - 1);
1714 set(initial_val);
1717 int bx_param_enum_c::find_by_name(const char *string)
1719 const char **p;
1720 for (p=&choices[0]; *p; p++) {
1721 if (!strcmp(string, *p))
1722 return p-choices;
1724 return -1;
1727 bx_bool bx_param_enum_c::set_by_name(const char *string)
1729 int n = find_by_name(string);
1730 if (n<0) return 0;
1731 set(n + min);
1732 return 1;
1735 bx_param_string_c::bx_param_string_c(bx_param_c *parent,
1736 const char *name,
1737 const char *label,
1738 const char *description,
1739 const char *initial_val,
1740 int maxsize)
1741 : bx_param_c(SIM->gen_param_id(), name, label, description)
1743 set_type(BXT_PARAM_STRING);
1744 int initial_val_size = strlen(initial_val) + 1;
1745 if (maxsize < 0)
1746 maxsize = initial_val_size;
1747 this->val = new char[maxsize];
1748 this->initial_val = new char[maxsize];
1749 this->handler = NULL;
1750 this->enable_handler = NULL;
1751 this->maxsize = maxsize;
1752 strncpy(this->val, initial_val, initial_val_size);
1753 if (maxsize > initial_val_size)
1754 memset(this->val + initial_val_size, 0, maxsize - initial_val_size);
1755 strncpy(this->initial_val, initial_val, maxsize);
1756 this->options = new bx_param_num_c(NULL,
1757 "stringoptions", NULL, NULL, 0, BX_MAX_BIT64S, 0);
1758 set(initial_val);
1759 if (parent) {
1760 BX_ASSERT(parent->get_type() == BXT_LIST);
1761 this->parent = (bx_list_c *)parent;
1762 this->parent->add(this);
1766 bx_param_filename_c::bx_param_filename_c(bx_param_c *parent,
1767 const char *name,
1768 const char *label,
1769 const char *description,
1770 const char *initial_val,
1771 int maxsize)
1772 : bx_param_string_c(parent, name, label, description, initial_val, maxsize)
1774 get_options()->set(IS_FILENAME);
1777 bx_param_string_c::~bx_param_string_c()
1779 if (val != NULL) delete [] val;
1780 if (initial_val != NULL) delete [] initial_val;
1781 if (options != NULL) delete options;
1784 void bx_param_string_c::reset()
1786 strncpy(val, initial_val, maxsize);
1789 void bx_param_string_c::set_handler(param_string_event_handler handler)
1791 this->handler = handler;
1792 // now that there's a handler, call set once to run the handler immediately
1793 //set (getptr ());
1796 void bx_param_string_c::set_enable_handler(param_enable_handler handler)
1798 this->enable_handler = handler;
1801 void bx_param_string_c::set_enabled(int en)
1803 // The enable handler may wish to allow/disallow the action
1804 if (enable_handler) {
1805 en = (*enable_handler)(this, en);
1807 bx_param_c::set_enabled(en);
1810 Bit32s bx_param_string_c::get(char *buf, int len)
1812 if (options->get() & RAW_BYTES)
1813 memcpy(buf, val, len);
1814 else
1815 strncpy(buf, val, len);
1816 if (handler) {
1817 // the handler can choose to replace the value in val/len. Also its
1818 // return value is passed back as the return value of get.
1819 (*handler)(this, 0, buf, len);
1821 return 0;
1824 void bx_param_string_c::set(const char *buf)
1826 if (options->get() & RAW_BYTES)
1827 memcpy(val, buf, maxsize);
1828 else {
1829 strncpy(val, buf, maxsize);
1830 val[maxsize - 1] = 0;
1832 if (handler) {
1833 // the handler can return a different char* to be copied into the value
1834 buf = (*handler)(this, 1, buf, -1);
1838 bx_bool bx_param_string_c::equals(const char *buf)
1840 if (options->get() & RAW_BYTES)
1841 return (memcmp(val, buf, maxsize) == 0);
1842 else
1843 return (strncmp(val, buf, maxsize) == 0);
1846 void bx_param_string_c::set_initial_val(const char *buf)
1848 if (options->get() & RAW_BYTES)
1849 memcpy(initial_val, buf, maxsize);
1850 else
1851 strncpy(initial_val, buf, maxsize);
1852 set(initial_val);
1855 bx_shadow_data_c::bx_shadow_data_c(bx_param_c *parent,
1856 const char *name,
1857 Bit8u *ptr_to_data,
1858 Bit32u data_size)
1859 : bx_param_c(SIM->gen_param_id(), name, "")
1861 set_type(BXT_PARAM_DATA);
1862 this->data_ptr = ptr_to_data;
1863 this->data_size = data_size;
1864 if (parent) {
1865 BX_ASSERT(parent->get_type() == BXT_LIST);
1866 this->parent = (bx_list_c *)parent;
1867 this->parent->add(this);
1871 bx_list_c::bx_list_c(bx_param_c *parent, int maxsize)
1872 : bx_param_c(SIM->gen_param_id(), "list", "")
1874 set_type(BXT_LIST);
1875 this->size = 0;
1876 this->maxsize = maxsize;
1877 this->list = new bx_param_c* [maxsize];
1878 this->parent = NULL;
1879 if (parent) {
1880 BX_ASSERT(parent->get_type() == BXT_LIST);
1881 this->parent = (bx_list_c *)parent;
1882 this->parent->add(this);
1884 init("");
1887 bx_list_c::bx_list_c(bx_param_c *parent, const char *name, int maxsize)
1888 : bx_param_c(SIM->gen_param_id(), name, "")
1890 set_type (BXT_LIST);
1891 this->size = 0;
1892 this->maxsize = maxsize;
1893 this->list = new bx_param_c* [maxsize];
1894 this->parent = NULL;
1895 if (parent) {
1896 BX_ASSERT(parent->get_type() == BXT_LIST);
1897 this->parent = (bx_list_c *)parent;
1898 this->parent->add(this);
1900 init("");
1903 bx_list_c::bx_list_c(bx_param_c *parent, const char *name, const char *title,
1904 int maxsize)
1905 : bx_param_c(SIM->gen_param_id(), name, "")
1907 set_type (BXT_LIST);
1908 this->size = 0;
1909 this->maxsize = maxsize;
1910 this->list = new bx_param_c* [maxsize];
1911 this->parent = NULL;
1912 if (parent) {
1913 BX_ASSERT(parent->get_type() == BXT_LIST);
1914 this->parent = (bx_list_c *)parent;
1915 this->parent->add(this);
1917 init(title);
1920 bx_list_c::bx_list_c(bx_param_c *parent, const char *name, const char *title, bx_param_c **init_list)
1921 : bx_param_c(SIM->gen_param_id(), name, "")
1923 set_type(BXT_LIST);
1924 this->size = 0;
1925 while (init_list[this->size] != NULL)
1926 this->size++;
1927 this->maxsize = this->size;
1928 this->list = new bx_param_c* [maxsize];
1929 for (int i=0; i<this->size; i++)
1930 this->list[i] = init_list[i];
1931 this->parent = NULL;
1932 if (parent) {
1933 BX_ASSERT(parent->get_type() == BXT_LIST);
1934 this->parent = (bx_list_c *)parent;
1935 this->parent->add(this);
1937 init(title);
1940 bx_list_c::~bx_list_c()
1942 if (list != NULL) {
1943 for (int i=0; i<this->size; i++) {
1944 delete list[i];
1946 delete [] list;
1948 if (title != NULL) delete title;
1949 if (options != NULL) delete options;
1950 if (choice != NULL) delete choice;
1953 void bx_list_c::init(const char *list_title)
1955 // the title defaults to the name
1956 this->title = new bx_param_string_c(NULL,
1957 "list_title",
1958 "", "",
1959 get_name(), 80);
1960 if ((list_title != NULL) && (strlen(list_title) > 0)) {
1961 this->title->set((char *)list_title);
1963 this->options = new bx_param_num_c(NULL,
1964 "list_option", "", "", 0, BX_MAX_BIT64S, 0);
1965 this->choice = new bx_param_num_c(NULL,
1966 "list_choice", "", "", 0, BX_MAX_BIT64S, 1);
1969 void bx_list_c::set_parent(bx_param_c *newparent)
1971 if (parent) {
1972 // if this object already had a parent, the correct thing
1973 // to do would be to remove this object from the parent's
1974 // list of children. Deleting children is currently
1975 // not supported.
1976 BX_PANIC(("bx_list_c::set_parent: changing from one parent to another is not supported"));
1978 if (newparent) {
1979 BX_ASSERT(newparent->get_type() == BXT_LIST);
1980 this->parent = (bx_list_c *)newparent;
1981 this->parent->add(this);
1985 bx_list_c* bx_list_c::clone()
1987 bx_list_c *newlist = new bx_list_c(NULL, name, title->getptr(), maxsize);
1988 for (int i=0; i<get_size(); i++)
1989 newlist->add(get(i));
1990 newlist->get_options()->set(options->get());
1991 return newlist;
1994 void bx_list_c::add(bx_param_c *param)
1996 if (size >= maxsize)
1997 BX_PANIC(("add param '%s' to bx_list_c '%s': list capacity exceeded",
1998 param->get_name(), get_name()));
1999 list[size] = param;
2000 size++;
2003 bx_param_c* bx_list_c::get(int index)
2005 BX_ASSERT(index >= 0 && index < size);
2006 return list[index];
2009 bx_param_c* bx_list_c::get_by_name(const char *name)
2011 int imax = get_size();
2012 for (int i=0; i<imax; i++) {
2013 bx_param_c *p = get(i);
2014 if (0 == strcmp (name, p->get_name())) {
2015 return p;
2018 return NULL;
2021 void bx_list_c::reset()
2023 int imax = get_size();
2024 for (int i=0; i<imax; i++) {
2025 get(i)->reset();
2029 void bx_list_c::clear()
2031 int imax = get_size();
2032 for (int i=0; i<imax; i++) {
2033 bx_param_c *param = get(i);
2034 delete param;
2036 size = 0;