1 /////////////////////////////////////////////////////////////////////////
2 // $Id: siminterface.cc 14293 2021-06-27 14:50:26Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 //  Copyright (C) 2002-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 // See siminterface.h for description of the siminterface concept.
24 // Basically, the siminterface is visible from both the simulator and
25 // the configuration user interface, and allows them to talk to each other.
26 
27 #include "param_names.h"
28 #include "iodev.h"
29 #include "bx_debug/debug.h"
30 #include "virt_timer.h"
31 
32 bx_simulator_interface_c *SIM = NULL;
33 logfunctions *siminterface_log = NULL;
34 bx_list_c *root_param = NULL;
35 #define LOG_THIS siminterface_log->
36 
37 // bx_simulator_interface just defines the interface that the Bochs simulator
38 // and the gui will use to talk to each other.  None of the methods of
39 // bx_simulator_interface are implemented; they are all virtual.  The
40 // bx_real_sim_c class is a child of bx_simulator_interface_c, and it
41 // implements all the methods.  The idea is that a gui needs to know only
42 // definition of bx_simulator_interface to talk to Bochs.  The gui should
43 // not need to include bochs.h.
44 //
45 // I made this separation to ensure that all guis use the siminterface to do
46 // access bochs internals, instead of accessing things like
47 // bx_keyboard.s.internal_buffer[4] (or whatever) directly. -Bryce
48 //
49 
50 static int rt_conf_id = 0;
51 
52 typedef struct _rt_conf_entry_t {
53   int id;
54   void *device;
55   rt_conf_handler_t handler;
56   struct _rt_conf_entry_t *next;
57 } rt_conf_entry_t;
58 
59 typedef struct _addon_option_t {
60   const char *name;
61   addon_option_parser_t parser;
62   addon_option_save_t savefn;
63   struct _addon_option_t *next;
64 } addon_option_t;
65 
66 class bx_real_sim_c : public bx_simulator_interface_c {
67   bxevent_handler bxevent_callback;
68   void *bxevent_callback_data;
69   const char *registered_ci_name;
70   config_interface_callback_t ci_callback;
71   void *ci_callback_data;
72   rt_conf_entry_t *rt_conf_entries;
73   addon_option_t *addon_options;
74   bool init_done;
75   bool enabled;
76   // save context to jump to if we must quit unexpectedly
77   jmp_buf *quit_context;
78   int exit_code;
79   unsigned param_id;
80   bool bx_debug_gui;
81   bool bx_log_viewer;
82   bool wxsel;
83 public:
84   bx_real_sim_c();
~bx_real_sim_c()85   virtual ~bx_real_sim_c() {}
set_quit_context(jmp_buf * context)86   virtual void set_quit_context(jmp_buf *context) { quit_context = context; }
get_init_done()87   virtual bool get_init_done() { return init_done; }
88   virtual int set_init_done(bool n);
89   virtual void reset_all_param();
90   // new param methods
91   virtual bx_param_c *get_param(const char *pname, bx_param_c *base=NULL);
92   virtual bx_param_num_c *get_param_num(const char *pname, bx_param_c *base=NULL);
93   virtual bx_param_string_c *get_param_string(const char *pname, bx_param_c *base=NULL);
94   virtual bx_param_bool_c *get_param_bool(const char *pname, bx_param_c *base=NULL);
95   virtual bx_param_enum_c *get_param_enum(const char *pname, bx_param_c *base=NULL);
gen_param_id()96   virtual Bit32u gen_param_id() { return param_id++; }
97   virtual int get_n_log_modules();
98   virtual const char *get_logfn_name(int mod);
99   virtual int get_logfn_id(const char *name);
100   virtual const char *get_prefix(int mod);
101   virtual int get_log_action(int mod, int level);
102   virtual void set_log_action(int mod, int level, int action);
103   virtual const char *get_action_name(int action);
104   virtual int is_action_name(const char *val);
get_default_log_action(int level)105   virtual int get_default_log_action(int level) {
106     return logfunctions::get_default_action(level);
107   }
set_default_log_action(int level,int action)108   virtual void set_default_log_action(int level, int action) {
109     logfunctions::set_default_action(level, action);
110   }
111   virtual const char *get_log_level_name(int level);
get_max_log_level()112   virtual int get_max_log_level() { return N_LOGLEV; }
113   virtual void quit_sim(int code);
get_exit_code()114   virtual int get_exit_code() { return exit_code; }
115   virtual int get_default_rc(char *path, int len);
116   virtual int read_rc(const char *path);
117   virtual int write_rc(const char *path, int overwrite);
118   virtual int get_log_file(char *path, int len);
119   virtual int set_log_file(const char *path);
120   virtual int get_log_prefix(char *prefix, int len);
121   virtual int set_log_prefix(const char *prefix);
122   virtual int get_debugger_log_file(char *path, int len);
123   virtual int set_debugger_log_file(const char *path);
124   virtual void set_notify_callback(bxevent_handler func, void *arg);
125   virtual void get_notify_callback(bxevent_handler *func, void **arg);
126   virtual BxEvent* sim_to_ci_event(BxEvent *event);
127   virtual int log_dlg(const char *prefix, int level, const char *msg, int mode);
128   virtual void log_msg(const char *prefix, int level, const char *msg);
set_log_viewer(bool val)129   virtual void set_log_viewer(bool val) { bx_log_viewer = val; }
has_log_viewer() const130   virtual bool has_log_viewer() const { return bx_log_viewer; }
131   virtual int ask_param(bx_param_c *param);
132   virtual int ask_param(const char *pname);
133   // ask the user for a pathname
134   virtual int ask_filename(const char *filename, int maxlen, const char *prompt, const char *the_default, int flags);
135   // yes/no dialog
136   virtual int ask_yes_no(const char *title, const char *prompt, bool the_default);
137   // simple message box
138   virtual void message_box(const char *title, const char *message);
139   // called at a regular interval, currently by the keyboard handler.
140   virtual void periodic();
141   virtual int create_disk_image(const char *filename, int sectors, bool overwrite);
142   virtual void refresh_ci();
refresh_vga()143   virtual void refresh_vga() {
144     if (init_done) {
145       DEV_vga_refresh(0);
146     }
147   }
handle_events()148   virtual void handle_events() {
149     // maybe need to check if something has been initialized yet?
150     bx_gui->handle_events();
151   }
152   // find first hard drive or cdrom
153   bx_param_c *get_first_atadevice(Bit32u search_type);
get_first_cdrom()154   bx_param_c *get_first_cdrom() {
155     return get_first_atadevice(BX_ATA_DEVICE_CDROM);
156   }
get_first_hd()157   bx_param_c *get_first_hd() {
158     return get_first_atadevice(BX_ATA_DEVICE_DISK);
159   }
160   virtual bool is_pci_device(const char *name);
161   virtual bool is_agp_device(const char *name);
162 #if BX_DEBUGGER
163   virtual void debug_break();
164   virtual void debug_interpret_cmd(char *cmd);
165   virtual char *debug_get_next_command();
166   virtual void debug_puts(const char *cmd);
167 #endif
168   virtual void register_configuration_interface (
169     const char* name,
170     config_interface_callback_t callback,
171     void *userdata);
172   virtual int configuration_interface(const char* name, ci_command_t command);
173   virtual int begin_simulation(int argc, char *argv[]);
174   virtual int register_runtime_config_handler(void *dev, rt_conf_handler_t handler);
175   virtual void unregister_runtime_config_handler(int id);
176   virtual void update_runtime_options();
set_sim_thread_func(is_sim_thread_func_t func)177   virtual void set_sim_thread_func(is_sim_thread_func_t func) {}
178   virtual bool is_sim_thread();
set_debug_gui(bool val)179   virtual void set_debug_gui(bool val) { bx_debug_gui = val; }
has_debug_gui() const180   virtual bool has_debug_gui() const { return bx_debug_gui; }
is_wx_selected() const181   virtual bool is_wx_selected() const { return wxsel; }
182   // provide interface to bx_gui->set_display_mode() method for config
183   // interfaces to use.
set_display_mode(disp_mode_t newmode)184   virtual void set_display_mode(disp_mode_t newmode) {
185     if (bx_gui != NULL)
186       bx_gui->set_display_mode(newmode);
187   }
188   virtual bool test_for_text_console();
189   // add-on config option support
190   virtual bool register_addon_option(const char *keyword, addon_option_parser_t parser, addon_option_save_t save_func);
191   virtual bool unregister_addon_option(const char *keyword);
192   virtual bool is_addon_option(const char *keyword);
193   virtual Bit32s  parse_addon_option(const char *context, int num_params, char *params []);
194   virtual Bit32s  save_addon_options(FILE *fp);
195 
196   // statistics
197   virtual void init_statistics();
198   virtual void cleanup_statistics();
get_statistics_root()199   virtual bx_list_c *get_statistics_root() {
200     return (bx_list_c*)get_param("statistics", NULL);
201   }
202 
203   // save/restore support
204   virtual void init_save_restore();
205   virtual void cleanup_save_restore();
206   virtual bool save_state(const char *checkpoint_path);
207   virtual bool restore_config();
208   virtual bool restore_logopts();
209   virtual bool restore_hardware();
get_bochs_root()210   virtual bx_list_c *get_bochs_root() {
211     return (bx_list_c*)get_param("bochs", NULL);
212   }
213   virtual bool restore_bochs_param(bx_list_c *root, const char *sr_path, const char *restore_name);
214   // special config parameter and options functions for plugins
215   virtual bool opt_plugin_ctrl(const char *plugname, bool load);
216 #if BX_NETWORKING
217   virtual void init_std_nic_options(const char *name, bx_list_c *menu);
218 #endif
219 #if BX_SUPPORT_PCIUSB
220   virtual void init_usb_options(const char *usb_name, const char *pname, int maxports);
221 #endif
222   virtual int  parse_param_from_list(const char *context, const char *param, bx_list_c *base);
223   virtual int  parse_nic_params(const char *context, const char *param, bx_list_c *base);
224   virtual int  parse_usb_port_params(const char *context, const char *param,
225                                      int maxports, bx_list_c *base);
226   virtual int  split_option_list(const char *msg, const char *rawopt, char **argv, int max_argv);
227   virtual int  write_param_list(FILE *fp, bx_list_c *base, const char *optname, bool multiline);
228 #if BX_SUPPORT_PCIUSB
229   virtual int  write_usb_options(FILE *fp, int maxports, bx_list_c *base);
230 #endif
231 #if BX_USE_GUI_CONSOLE
232   virtual int  bx_printf(const char *fmt, ...);
233   virtual char* bx_gets(char *s, int size, FILE *stream);
234 #endif
235 
236 private:
237   bool save_sr_param(FILE *fp, bx_param_c *node, const char *sr_path, int level);
238 };
239 
240 // recursive function to find parameters from the path
find_param(const char * full_pname,const char * rest_of_pname,bx_param_c * base)241 static bx_param_c *find_param(const char *full_pname, const char *rest_of_pname, bx_param_c *base)
242 {
243   const char *from = rest_of_pname;
244   char component[BX_PATHNAME_LEN];
245   char *to = component;
246   // copy the first piece of pname into component, stopping at first separator
247   // or at the end of the string
248   while (*from != 0 && *from != '.') {
249     *to = *from;
250     to++;
251     from++;
252   }
253   *to = 0;
254   if (!component[0]) {
255     BX_PANIC(("find_param: found empty component in parameter name '%s'", full_pname));
256     // or does that mean that we're done?
257   }
258   if (base->get_type() != BXT_LIST) {
259     BX_PANIC(("find_param: base was not a list!"));
260   }
261   BX_DEBUG(("searching for component '%s' in list '%s'", component, base->get_name()));
262 
263   // find the component in the list.
264   bx_list_c *list = (bx_list_c *)base;
265   bx_param_c *child = list->get_by_name(component);
266   // if child not found, there is nothing else that can be done. return NULL.
267   if (child == NULL) return NULL;
268   if (from[0] == 0) {
269     // that was the end of the path, we're done
270     return child;
271   }
272   // continue parsing the path
273   BX_ASSERT(from[0] == '.');
274   from++;  // skip over the separator
275   return find_param(full_pname, from, child);
276 }
277 
get_param(const char * pname,bx_param_c * base)278 bx_param_c *bx_real_sim_c::get_param(const char *pname, bx_param_c *base)
279 {
280   if (base == NULL)
281     base = root_param;
282   // to access top level object, look for parameter "."
283   if (pname[0] == '.' && pname[1] == 0)
284     return base;
285   return find_param(pname, pname, base);
286 }
287 
get_param_num(const char * pname,bx_param_c * base)288 bx_param_num_c *bx_real_sim_c::get_param_num(const char *pname, bx_param_c *base)
289 {
290   bx_param_c *gen = get_param(pname, base);
291   if (gen==NULL) {
292     BX_ERROR(("get_param_num(%s) could not find a parameter", pname));
293     return NULL;
294   }
295   int type = gen->get_type();
296   if (type == BXT_PARAM_NUM || type == BXT_PARAM_BOOL || type == BXT_PARAM_ENUM)
297     return (bx_param_num_c *)gen;
298   BX_ERROR(("get_param_num(%s) could not find a number parameter with that name", pname));
299   return NULL;
300 }
301 
get_param_string(const char * pname,bx_param_c * base)302 bx_param_string_c *bx_real_sim_c::get_param_string(const char *pname, bx_param_c *base)
303 {
304   bx_param_c *gen = get_param(pname, base);
305   if (gen==NULL) {
306     BX_ERROR(("get_param_string(%s) could not find a parameter", pname));
307     return NULL;
308   }
309   if (gen->get_type() == BXT_PARAM_STRING || gen->get_type() == BXT_PARAM_BYTESTRING)
310     return (bx_param_string_c *)gen;
311   BX_ERROR(("get_param_string(%s) could not find a string parameter with that name", pname));
312   return NULL;
313 }
314 
get_param_bool(const char * pname,bx_param_c * base)315 bx_param_bool_c *bx_real_sim_c::get_param_bool(const char *pname, bx_param_c *base)
316 {
317   bx_param_c *gen = get_param(pname, base);
318   if (gen==NULL) {
319     BX_ERROR(("get_param_bool(%s) could not find a parameter", pname));
320     return NULL;
321   }
322   if (gen->get_type () == BXT_PARAM_BOOL)
323     return (bx_param_bool_c *)gen;
324   BX_ERROR(("get_param_bool(%s) could not find a bool parameter with that name", pname));
325   return NULL;
326 }
327 
get_param_enum(const char * pname,bx_param_c * base)328 bx_param_enum_c *bx_real_sim_c::get_param_enum(const char *pname, bx_param_c *base)
329 {
330   bx_param_c *gen = get_param(pname, base);
331   if (gen==NULL) {
332     BX_ERROR(("get_param_enum(%s) could not find a parameter", pname));
333     return NULL;
334   }
335   if (gen->get_type() == BXT_PARAM_ENUM)
336     return (bx_param_enum_c *)gen;
337   BX_ERROR(("get_param_enum(%s) could not find a enum parameter with that name", pname));
338   return NULL;
339 }
340 
bx_init_siminterface()341 void bx_init_siminterface()
342 {
343   if (SIM == NULL) {
344     siminterface_log = new logfunctions();
345     siminterface_log->put("siminterface", "SIM");
346     SIM = new bx_real_sim_c();
347   }
348   if (root_param == NULL) {
349     root_param = new bx_list_c(NULL,
350       "bochs",
351       "list of top level bochs parameters"
352       );
353   }
354 }
355 
bx_real_sim_c()356 bx_real_sim_c::bx_real_sim_c()
357 {
358   bxevent_callback = NULL;
359   bxevent_callback_data = NULL;
360   ci_callback = NULL;
361   ci_callback_data = NULL;
362   is_sim_thread_func = NULL;
363   bx_debug_gui = 0;
364   bx_log_viewer = 0;
365   wxsel = 0;
366 
367   enabled = 1;
368   init_done = 0;
369   quit_context = NULL;
370   exit_code = 0;
371   param_id = BXP_NEW_PARAM_ID;
372   rt_conf_entries = NULL;
373   addon_options = NULL;
374 }
375 
set_init_done(bool n)376 int bx_real_sim_c::set_init_done(bool n)
377 {
378 #if BX_USE_TEXTCONFIG
379   if (n) {
380     if (bx_gui->has_gui_console()) {
381       if (strcmp(registered_ci_name, "textconfig") != 0) {
382         PLUG_load_plugin(textconfig, PLUGTYPE_CORE);
383       }
384     }
385   }
386 #endif
387   init_done = n;
388   return 0;
389 }
390 
reset_all_param()391 void bx_real_sim_c::reset_all_param()
392 {
393   bx_reset_options();
394 }
395 
get_n_log_modules()396 int bx_real_sim_c::get_n_log_modules()
397 {
398   return io->get_n_logfns();
399 }
400 
get_logfn_name(int mod)401 const char *bx_real_sim_c::get_logfn_name(int mod)
402 {
403   logfunc_t *logfn = io->get_logfn(mod);
404   return logfn->get_name();
405 }
406 
get_logfn_id(const char * name)407 int bx_real_sim_c::get_logfn_id(const char *name)
408 {
409   logfunc_t *logfn;
410   int id = -1;
411 
412   for (int i = 0; i < io->get_n_logfns(); i++) {
413     logfn = io->get_logfn(i);
414     if (!stricmp(name, logfn->get_name())) {
415       id = i;
416       break;
417     }
418   }
419   return id;
420 }
421 
get_prefix(int mod)422 const char *bx_real_sim_c::get_prefix(int mod)
423 {
424   logfunc_t *logfn = io->get_logfn(mod);
425   return logfn->getprefix();
426 }
427 
get_log_action(int mod,int level)428 int bx_real_sim_c::get_log_action(int mod, int level)
429 {
430   logfunc_t *logfn = io->get_logfn(mod);
431   return logfn->getonoff(level);
432 }
433 
set_log_action(int mod,int level,int action)434 void bx_real_sim_c::set_log_action(int mod, int level, int action)
435 {
436   // normal
437   if (mod >= 0) {
438     logfunc_t *logfn = io->get_logfn(mod);
439     logfn->setonoff(level, action);
440     return;
441   }
442   // if called with mod<0 loop over all
443   int nmod = get_n_log_modules();
444   for (mod=0; mod<nmod; mod++)
445     set_log_action(mod, level, action);
446 }
447 
get_action_name(int action)448 const char *bx_real_sim_c::get_action_name(int action)
449 {
450   return io->getaction(action);
451 }
452 
is_action_name(const char * val)453 int bx_real_sim_c::is_action_name(const char *val)
454 {
455   return io->isaction(val);
456 }
457 
get_log_level_name(int level)458 const char *bx_real_sim_c::get_log_level_name(int level)
459 {
460   return io->getlevel(level);
461 }
462 
quit_sim(int code)463 void bx_real_sim_c::quit_sim(int code)
464 {
465   BX_INFO(("quit_sim called with exit code %d", code));
466   exit_code = code;
467   io->exit_log();
468   // use longjmp to quit cleanly, no matter where in the stack we are.
469   if (quit_context != NULL) {
470     longjmp(*quit_context, 1);
471     BX_PANIC(("in bx_real_sim_c::quit_sim, longjmp should never return"));
472   } else {
473     // use exit() to stop the application.
474     if (!code)
475       BX_PANIC(("Quit simulation command"));
476     ::exit(exit_code);
477   }
478 }
479 
get_default_rc(char * path,int len)480 int bx_real_sim_c::get_default_rc(char *path, int len)
481 {
482   char *rc = bx_find_bochsrc();
483   if (rc == NULL) return -1;
484   strncpy(path, rc, len);
485   path[len-1] = 0;
486   return 0;
487 }
488 
read_rc(const char * rc)489 int bx_real_sim_c::read_rc(const char *rc)
490 {
491   return bx_read_configuration(rc);
492 }
493 
494 // return values:
495 //   0: written ok
496 //  -1: failed
497 //  -2: already exists, and overwrite was off
write_rc(const char * rc,int overwrite)498 int bx_real_sim_c::write_rc(const char *rc, int overwrite)
499 {
500   return bx_write_configuration(rc, overwrite);
501 }
502 
get_log_file(char * path,int len)503 int bx_real_sim_c::get_log_file(char *path, int len)
504 {
505   strncpy(path, SIM->get_param_string(BXPN_LOG_FILENAME)->getptr(), len);
506   return 0;
507 }
508 
set_log_file(const char * path)509 int bx_real_sim_c::set_log_file(const char *path)
510 {
511   SIM->get_param_string(BXPN_LOG_FILENAME)->set(path);
512   return 0;
513 }
514 
get_log_prefix(char * prefix,int len)515 int bx_real_sim_c::get_log_prefix(char *prefix, int len)
516 {
517   strncpy(prefix, SIM->get_param_string(BXPN_LOG_PREFIX)->getptr(), len);
518   return 0;
519 }
520 
set_log_prefix(const char * prefix)521 int bx_real_sim_c::set_log_prefix(const char *prefix)
522 {
523   SIM->get_param_string(BXPN_LOG_PREFIX)->set(prefix);
524   return 0;
525 }
526 
get_debugger_log_file(char * path,int len)527 int bx_real_sim_c::get_debugger_log_file(char *path, int len)
528 {
529   strncpy(path, SIM->get_param_string(BXPN_DEBUGGER_LOG_FILENAME)->getptr(), len);
530   return 0;
531 }
532 
set_debugger_log_file(const char * path)533 int bx_real_sim_c::set_debugger_log_file(const char *path)
534 {
535   SIM->get_param_string(BXPN_DEBUGGER_LOG_FILENAME)->set(path);
536   return 0;
537 }
538 
539 const char *floppy_devtype_names[] = { "none", "5.25\" 360K", "5.25\" 1.2M", "3.5\" 720K", "3.5\" 1.44M", "3.5\" 2.88M", NULL };
540 const char *floppy_type_names[] = { "none", "1.2M", "1.44M", "2.88M", "720K", "360K", "160K", "180K", "320K", "auto", NULL };
541 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 };
542 const char *media_status_names[] = { "ejected", "inserted", NULL };
543 const char *bochs_bootdisk_names[] = { "none", "floppy", "disk","cdrom", "network", NULL };
544 
set_notify_callback(bxevent_handler func,void * arg)545 void bx_real_sim_c::set_notify_callback(bxevent_handler func, void *arg)
546 {
547   bxevent_callback = func;
548   bxevent_callback_data = arg;
549 }
550 
get_notify_callback(bxevent_handler * func,void ** arg)551 void bx_real_sim_c::get_notify_callback(bxevent_handler *func, void **arg)
552 {
553   *func = bxevent_callback;
554   *arg = bxevent_callback_data;
555 }
556 
sim_to_ci_event(BxEvent * event)557 BxEvent *bx_real_sim_c::sim_to_ci_event(BxEvent *event)
558 {
559   if (bxevent_callback == NULL) {
560     BX_ERROR(("notify called, but no bxevent_callback function is registered"));
561     return NULL;
562   } else {
563     return (*bxevent_callback)(bxevent_callback_data, event);
564   }
565 }
566 
log_dlg(const char * prefix,int level,const char * msg,int mode)567 int bx_real_sim_c::log_dlg(const char *prefix, int level, const char *msg, int mode)
568 {
569   BxEvent be;
570   be.type = BX_SYNC_EVT_LOG_DLG;
571   be.u.logmsg.prefix = prefix;
572   be.u.logmsg.level = level;
573   be.u.logmsg.msg = msg;
574   be.u.logmsg.mode = mode;
575   // default return value in case something goes wrong.
576   be.retcode = BX_LOG_NOTIFY_FAILED;
577   // calling notify
578   sim_to_ci_event(&be);
579   return be.retcode;
580 }
581 
log_msg(const char * prefix,int level,const char * msg)582 void bx_real_sim_c::log_msg(const char *prefix, int level, const char *msg)
583 {
584   if (SIM->has_log_viewer()) {
585     // send message to the log viewer
586     char *logmsg = new char[strlen(prefix) + strlen(msg) + 4];
587     sprintf(logmsg, "%s %s\n", prefix, msg);
588     BxEvent *event = new BxEvent();
589     event->type = BX_ASYNC_EVT_LOG_MSG;
590     event->u.logmsg.prefix = NULL;
591     event->u.logmsg.level = level;
592     event->u.logmsg.msg = logmsg;
593     sim_to_ci_event(event);
594   }
595 }
596 
597 // Called by simulator whenever it needs the user to choose a new value
598 // for a registered parameter.  Create a synchronous ASK_PARAM event,
599 // send it to the CI, and wait for the response.  The CI will call the
600 // set() method on the parameter if the user changes the value.
ask_param(bx_param_c * param)601 int bx_real_sim_c::ask_param(bx_param_c *param)
602 {
603   BX_ASSERT(param != NULL);
604   // create appropriate event
605   BxEvent event;
606   event.type = BX_SYNC_EVT_ASK_PARAM;
607   event.u.param.param = param;
608   sim_to_ci_event(&event);
609   return event.retcode;
610 }
611 
ask_param(const char * pname)612 int bx_real_sim_c::ask_param(const char *pname)
613 {
614   bx_param_c *paramptr = SIM->get_param(pname);
615   BX_ASSERT(paramptr != NULL);
616   // create appropriate event
617   BxEvent event;
618   event.type = BX_SYNC_EVT_ASK_PARAM;
619   event.u.param.param = paramptr;
620   sim_to_ci_event(&event);
621   return event.retcode;
622 }
623 
ask_filename(const char * filename,int maxlen,const char * prompt,const char * the_default,int flags)624 int bx_real_sim_c::ask_filename(const char *filename, int maxlen, const char *prompt, const char *the_default, int flags)
625 {
626   BxEvent event;
627   bx_param_filename_c param(NULL, "filename", prompt, "", the_default, maxlen);
628   param.set_options(param.get_options() | flags);
629   event.type = BX_SYNC_EVT_ASK_PARAM;
630   event.u.param.param = &param;
631   sim_to_ci_event(&event);
632   if (event.retcode >= 0)
633     memcpy((char *)filename, param.getptr(), maxlen);
634   return event.retcode;
635 }
636 
ask_yes_no(const char * title,const char * prompt,bool the_default)637 int bx_real_sim_c::ask_yes_no(const char *title, const char *prompt, bool the_default)
638 {
639   BxEvent event;
640   char format[512];
641 
642   bx_param_bool_c param(NULL, "yes_no", title, prompt, the_default);
643   sprintf(format, "%s\n\n%s [%%s] ", title, prompt);
644   param.set_ask_format(format);
645   event.type = BX_SYNC_EVT_ASK_PARAM;
646   event.u.param.param = &param;
647   sim_to_ci_event(&event);
648   if (event.retcode >= 0) {
649     return param.get();
650   } else {
651     return event.retcode;
652   }
653 }
654 
message_box(const char * title,const char * message)655 void bx_real_sim_c::message_box(const char *title, const char *message)
656 {
657   BxEvent event;
658 
659   event.type = BX_SYNC_EVT_MSG_BOX;
660   event.u.logmsg.prefix = title;
661   event.u.logmsg.msg = message;
662   sim_to_ci_event(&event);
663 }
664 
periodic()665 void bx_real_sim_c::periodic()
666 {
667   // give the GUI a chance to do periodic things on the bochs thread. in
668   // particular, notice if the thread has been asked to die.
669   BxEvent tick;
670   tick.type = BX_SYNC_EVT_TICK;
671   sim_to_ci_event (&tick);
672   if (tick.retcode < 0) {
673     BX_INFO(("Bochs thread has been asked to quit."));
674 #if !BX_DEBUGGER
675     bx_atexit();
676     quit_sim(0);
677 #else
678     bx_dbg_exit(0);
679 #endif
680   }
681   static int refresh_counter = 0;
682   if (++refresh_counter == 50) {
683     // only ask the CI to refresh every 50 times periodic() is called.
684     // This should obviously be configurable because system speeds and
685     // user preferences vary.
686     refresh_ci();
687     refresh_counter = 0;
688   }
689 }
690 
691 // create a disk image file called filename, size=512 bytes * sectors.
692 // If overwrite is 0 and the file exists, returns -1 without changing it.
693 // Otherwise, opens up the image and starts writing.  Returns -2 if
694 // the image could not be opened, or -3 if there are failures during
695 // write, e.g. disk full.
696 //
697 // wxWidgets: This may be called from the gui thread.
create_disk_image(const char * filename,int sectors,bool overwrite)698 int bx_real_sim_c::create_disk_image(const char *filename, int sectors, bool overwrite)
699 {
700   FILE *fp;
701   if (!overwrite) {
702     // check for existence first
703     fp = fopen(filename, "r");
704     if (fp) {
705       // yes it exists
706       fclose(fp);
707       return -1;
708     }
709   }
710   fp = fopen(filename, "w");
711   if (fp == NULL) {
712 #ifdef HAVE_PERROR
713     char buffer[1024];
714     sprintf(buffer, "while opening '%s' for writing", filename);
715     perror(buffer);
716     // not sure how to get this back into the CI
717 #endif
718     return -2;
719   }
720   int sec = sectors;
721   /*
722    * seek to sec*512-1 and write a single character.
723    * can't just do: fseek(fp, 512*sec-1, SEEK_SET)
724    * because 512*sec may be too large for signed int.
725    */
726   while (sec > 0)
727   {
728     /* temp <-- min(sec, 4194303)
729      * 4194303 is (int)(0x7FFFFFFF/512)
730      */
731     int temp = ((sec < 4194303) ? sec : 4194303);
732     fseek(fp, 512*temp, SEEK_CUR);
733     sec -= temp;
734   }
735 
736   fseek(fp, -1, SEEK_CUR);
737   if (fputc('\0', fp) == EOF)
738   {
739     fclose(fp);
740     return -3;
741   }
742   fclose(fp);
743   return 0;
744 }
745 
refresh_ci()746 void bx_real_sim_c::refresh_ci()
747 {
748   if (SIM->has_debug_gui()) {
749     // It's an async event, so allocate a pointer and send it.
750     // The event will be freed by the recipient.
751     BxEvent *event = new BxEvent();
752     event->type = BX_ASYNC_EVT_REFRESH;
753     sim_to_ci_event(event);
754   }
755 }
756 
get_first_atadevice(Bit32u search_type)757 bx_param_c *bx_real_sim_c::get_first_atadevice(Bit32u search_type)
758 {
759   char pname[80];
760   for (int channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
761     sprintf(pname, "ata.%d.resources.enabled", channel);
762     if (!SIM->get_param_bool(pname)->get())
763       continue;
764     for (int slave=0; slave<2; slave++) {
765       sprintf(pname, "ata.%d.%s.type", channel, (slave==0)?"master":"slave");
766       Bit32u type = SIM->get_param_enum(pname)->get();
767       if (type == search_type) {
768         sprintf(pname, "ata.%d.%s", channel, (slave==0)?"master":"slave");
769         return SIM->get_param(pname);
770       }
771     }
772   }
773   return NULL;
774 }
775 
is_pci_device(const char * name)776 bool bx_real_sim_c::is_pci_device(const char *name)
777 {
778 #if BX_SUPPORT_PCI
779   unsigned i, max_pci_slots = BX_N_PCI_SLOTS;
780   char devname[80];
781   const char *device;
782 
783   if (SIM->get_param_bool(BXPN_PCI_ENABLED)->get()) {
784     if (SIM->get_param_enum(BXPN_PCI_CHIPSET)->get() == BX_PCI_CHIPSET_I440BX) {
785       max_pci_slots = 4;
786     }
787     for (i = 0; i < max_pci_slots; i++) {
788       sprintf(devname, "pci.slot.%d", i+1);
789       device = SIM->get_param_enum(devname)->get_selected();
790       if (!strcmp(name, device)) {
791         return 1;
792       }
793     }
794   }
795 #endif
796   return 0;
797 }
798 
is_agp_device(const char * name)799 bool bx_real_sim_c::is_agp_device(const char *name)
800 {
801 #if BX_SUPPORT_PCI
802   if (get_param_bool(BXPN_PCI_ENABLED)->get() && DEV_agp_present()) {
803     const char *device = SIM->get_param_enum("pci.slot.5")->get_selected();
804     if (!strcmp(name, device)) {
805       return 1;
806     }
807   }
808 #endif
809   return 0;
810 }
811 
812 #if BX_DEBUGGER
813 
814 // this can be safely called from either thread.
debug_break()815 void bx_real_sim_c::debug_break()
816 {
817   bx_debug_break();
818 }
819 
820 // this should only be called from the sim_thread.
debug_interpret_cmd(char * cmd)821 void bx_real_sim_c::debug_interpret_cmd(char *cmd)
822 {
823   if (!is_sim_thread()) {
824     fprintf(stderr, "ERROR: debug_interpret_cmd called but not from sim_thread\n");
825     return;
826   }
827   bx_dbg_interpret_line(cmd);
828 }
829 
debug_get_next_command()830 char *bx_real_sim_c::debug_get_next_command()
831 {
832   BxEvent event;
833   event.type = BX_SYNC_EVT_GET_DBG_COMMAND;
834   BX_DEBUG(("asking for next debug command"));
835   sim_to_ci_event (&event);
836   BX_DEBUG(("received next debug command: '%s'", event.u.debugcmd.command));
837   if (event.retcode >= 0)
838     return event.u.debugcmd.command;
839   return NULL;
840 }
841 
debug_puts(const char * text)842 void bx_real_sim_c::debug_puts(const char *text)
843 {
844   if (SIM->has_debug_gui()) {
845     // send message to the gui debugger
846     BxEvent *event = new BxEvent();
847     event->type = BX_ASYNC_EVT_DBG_MSG;
848     event->u.logmsg.msg = text;
849     sim_to_ci_event(event);
850   } else {
851     // text mode debugger: just write to console
852     fputs(text, stdout);
853   }
854 }
855 #endif
856 
register_configuration_interface(const char * name,config_interface_callback_t callback,void * userdata)857 void bx_real_sim_c::register_configuration_interface(
858   const char* name,
859   config_interface_callback_t callback,
860   void *userdata)
861 {
862   ci_callback = callback;
863   ci_callback_data = userdata;
864   registered_ci_name = name;
865 }
866 
configuration_interface(const char * ignore,ci_command_t command)867 int bx_real_sim_c::configuration_interface(const char *ignore, ci_command_t command)
868 {
869   if (!ci_callback) {
870     BX_PANIC(("no configuration interface was loaded"));
871     return -1;
872   }
873   if (!strcmp(registered_ci_name, "wx"))
874     wxsel = 1;
875   else
876     wxsel = 0;
877   bx_debug_gui = wxsel;
878   // enter configuration mode, just while running the configuration interface
879   set_display_mode(DISP_MODE_CONFIG);
880   int retval = (*ci_callback)(ci_callback_data, command);
881   set_display_mode(DISP_MODE_SIM);
882   return retval;
883 }
884 
begin_simulation(int argc,char * argv[])885 int bx_real_sim_c::begin_simulation(int argc, char *argv[])
886 {
887   return bx_begin_simulation(argc, argv);
888 }
889 
register_runtime_config_handler(void * dev,rt_conf_handler_t handler)890 int bx_real_sim_c::register_runtime_config_handler(void *dev, rt_conf_handler_t handler)
891 {
892   rt_conf_entry_t *rt_conf_entry = new rt_conf_entry_t;
893   rt_conf_entry->id = rt_conf_id;
894   rt_conf_entry->device = dev;
895   rt_conf_entry->handler = handler;
896   rt_conf_entry->next = NULL;
897 
898   if (rt_conf_entries == NULL) {
899     rt_conf_entries = rt_conf_entry;
900   } else {
901     rt_conf_entry_t *temp = rt_conf_entries;
902 
903     while (temp->next) {
904       temp = temp->next;
905     }
906     temp->next = rt_conf_entry;
907   }
908   return rt_conf_id++;
909 }
910 
unregister_runtime_config_handler(int id)911 void bx_real_sim_c::unregister_runtime_config_handler(int id)
912 {
913   rt_conf_entry_t *prev = NULL, *curr = rt_conf_entries;
914 
915   while (curr != NULL) {
916     if (curr->id == id) {
917       if (prev != NULL) {
918         prev->next = curr->next;
919       } else {
920         rt_conf_entries = curr->next;
921       }
922       delete curr;
923       break;
924     } else {
925       prev = curr;
926       curr = curr->next;
927     }
928   }
929 }
930 
update_runtime_options()931 void bx_real_sim_c::update_runtime_options()
932 {
933   rt_conf_entry_t *temp = rt_conf_entries;
934 
935   while (temp != NULL) {
936     temp->handler(temp->device);
937     temp = temp->next;
938   }
939   bx_gui->update_drive_status_buttons();
940   bx_virt_timer.set_realtime_delay();
941 }
942 
is_sim_thread()943 bool bx_real_sim_c::is_sim_thread()
944 {
945   if (is_sim_thread_func == NULL) return 1;
946   return (*is_sim_thread_func)();
947 }
948 
949 // check if the text console exists.  On some platforms, if Bochs is
950 // started from the "Start Menu" or by double clicking on it on a Mac,
951 // there may be nothing attached to stdin/stdout/stderr.  This function
952 // tests if stdin/stdout/stderr are usable and returns 0 if not.
test_for_text_console()953 bool bx_real_sim_c::test_for_text_console()
954 {
955 #if BX_WITH_CARBON
956   // In a Carbon application, you have a text console if you run the app from
957   // the command line, but if you start it from the finder you don't.
958   if(!isatty(STDIN_FILENO)) return 0;
959 #endif
960   // default: yes
961   return 1;
962 }
963 
is_addon_option(const char * keyword)964 bool bx_real_sim_c::is_addon_option(const char *keyword)
965 {
966   addon_option_t *addon_option;
967 
968   for (addon_option = addon_options; addon_option; addon_option = addon_option->next) {
969     if (!strcmp(addon_option->name, keyword)) return 1;
970   }
971   return 0;
972 }
973 
register_addon_option(const char * keyword,addon_option_parser_t parser,addon_option_save_t save_func)974 bool bx_real_sim_c::register_addon_option(const char *keyword, addon_option_parser_t parser,
975                                              addon_option_save_t save_func)
976 {
977   addon_option_t *addon_option = new addon_option_t;
978   addon_option->name = keyword;
979   addon_option->parser = parser;
980   addon_option->savefn = save_func;
981   addon_option->next = NULL;
982 
983   if (addon_options == NULL) {
984     addon_options = addon_option;
985   } else {
986     addon_option_t *temp = addon_options;
987 
988     while (temp->next) {
989       if (!strcmp(temp->name, keyword)) {
990         delete addon_option;
991         return 0;
992       }
993       temp = temp->next;
994     }
995     temp->next = addon_option;
996   }
997   return 1;
998 }
999 
unregister_addon_option(const char * keyword)1000 bool bx_real_sim_c::unregister_addon_option(const char *keyword)
1001 {
1002   addon_option_t *addon_option, *prev = NULL;
1003 
1004   for (addon_option = addon_options; addon_option; addon_option = addon_option->next) {
1005     if (!strcmp(addon_option->name, keyword)) {
1006       if (prev == NULL) {
1007         addon_options = addon_option->next;
1008       } else {
1009         prev->next = addon_option->next;
1010       }
1011       delete addon_option;
1012       return 1;
1013     } else {
1014       prev = addon_option;
1015     }
1016   }
1017   return 0;
1018 }
1019 
parse_addon_option(const char * context,int num_params,char * params[])1020 Bit32s bx_real_sim_c::parse_addon_option(const char *context, int num_params, char *params [])
1021 {
1022   for (addon_option_t *addon_option = addon_options; addon_option; addon_option = addon_option->next) {
1023     if ((!strcmp(addon_option->name, params[0])) &&
1024         (addon_option->parser != NULL)) {
1025       return (*addon_option->parser)(context, num_params, params);
1026     }
1027   }
1028   return -1;
1029 
1030 }
1031 
save_addon_options(FILE * fp)1032 Bit32s bx_real_sim_c::save_addon_options(FILE *fp)
1033 {
1034   for (addon_option_t *addon_option = addon_options; addon_option; addon_option = addon_option->next) {
1035     if (addon_option->savefn != NULL) {
1036       (*addon_option->savefn)(fp);
1037     }
1038   }
1039   return 0;
1040 }
1041 
init_statistics()1042 void bx_real_sim_c::init_statistics()
1043 {
1044   if (get_statistics_root() == NULL) {
1045     new bx_list_c(root_param, "statistics", "statistics");
1046   }
1047 }
1048 
cleanup_statistics()1049 void bx_real_sim_c::cleanup_statistics()
1050 {
1051   bx_list_c *list;
1052 
1053   if ((list = get_statistics_root()) != NULL) {
1054     list->clear();
1055   }
1056 }
1057 
init_save_restore()1058 void bx_real_sim_c::init_save_restore()
1059 {
1060   if (get_bochs_root() == NULL) {
1061     new bx_list_c(root_param, "bochs", "subtree for save/restore");
1062   }
1063 }
1064 
cleanup_save_restore()1065 void bx_real_sim_c::cleanup_save_restore()
1066 {
1067   bx_list_c *list = get_bochs_root();
1068 
1069   if (list != NULL) {
1070     list->clear();
1071   }
1072 }
1073 
save_state(const char * checkpoint_path)1074 bool bx_real_sim_c::save_state(const char *checkpoint_path)
1075 {
1076   char sr_file[BX_PATHNAME_LEN];
1077   char devname[20];
1078   int dev, ndev = SIM->get_n_log_modules();
1079   int type, ntype = SIM->get_max_log_level();
1080 
1081   get_param_string(BXPN_RESTORE_PATH)->set(checkpoint_path);
1082   sprintf(sr_file, "%s/config", checkpoint_path);
1083   if (write_rc(sr_file, 1) < 0)
1084     return 0;
1085   sprintf(sr_file, "%s/logopts", checkpoint_path);
1086   FILE *fp = fopen(sr_file, "w");
1087   if (fp != NULL) {
1088     for (dev=0; dev<ndev; dev++) {
1089       strcpy(devname, get_logfn_name(dev));
1090       if ((strlen(devname) > 0) && (strcmp(devname, "?"))) {
1091         fprintf(fp, "%s: ", devname);
1092         for (type=0; type<ntype; type++) {
1093           if (type > 0) fprintf(fp, ", ");
1094           fprintf(fp, "%s=%s", get_log_level_name(type), get_action_name(get_log_action(dev, type)));
1095         }
1096         fprintf(fp, "\n");
1097       }
1098     }
1099     fclose(fp);
1100   } else {
1101     return 0;
1102   }
1103   bx_list_c *sr_list = get_bochs_root();
1104   ndev = sr_list->get_size();
1105   for (dev=0; dev<ndev; dev++) {
1106     sprintf(sr_file, "%s/%s", checkpoint_path, sr_list->get(dev)->get_name());
1107     fp = fopen(sr_file, "w");
1108     if (fp != NULL) {
1109       save_sr_param(fp, sr_list->get(dev), checkpoint_path, 0);
1110       fclose(fp);
1111     } else {
1112       return 0;
1113     }
1114   }
1115   get_param_string(BXPN_RESTORE_PATH)->set("none");
1116   return 1;
1117 }
1118 
restore_config()1119 bool bx_real_sim_c::restore_config()
1120 {
1121   char config[BX_PATHNAME_LEN];
1122   sprintf(config, "%s/config", get_param_string(BXPN_RESTORE_PATH)->getptr());
1123   BX_INFO(("restoring '%s'", config));
1124   return (read_rc(config) >= 0);
1125 }
1126 
restore_logopts()1127 bool bx_real_sim_c::restore_logopts()
1128 {
1129   char logopts[BX_PATHNAME_LEN];
1130   char line[512], string[512], devname[20];
1131   char *ret, *ptr;
1132   int i, j, p, dev = 0, type = 0, action = 0;
1133   FILE *fp;
1134 
1135   sprintf(logopts, "%s/logopts", get_param_string(BXPN_RESTORE_PATH)->getptr());
1136   BX_INFO(("restoring '%s'", logopts));
1137   fp = fopen(logopts, "r");
1138   if (fp != NULL) {
1139     do {
1140       ret = fgets(line, sizeof(line)-1, fp);
1141       line[sizeof(line) - 1] = '\0';
1142       int len = strlen(line);
1143       if ((len>0) && (line[len-1] < ' '))
1144         line[len-1] = '\0';
1145       i = 0;
1146       if ((ret != NULL) && strlen(line)) {
1147         ptr = strtok(line, ":");
1148         while (ptr) {
1149           p = 0;
1150           while (isspace(ptr[p])) p++;
1151           strcpy(string, ptr+p);
1152           while (isspace(string[strlen(string)-1])) string[strlen(string)-1] = 0;
1153           if (i == 0) {
1154             strcpy(devname, string);
1155             dev = get_logfn_id(devname);
1156           } else if (dev >= 0) {
1157             j = 6;
1158             if (!strncmp(string, "DEBUG=", 6)) {
1159               type = LOGLEV_DEBUG;
1160             } else if (!strncmp(string, "INFO=", 5)) {
1161               type = LOGLEV_INFO;
1162               j = 5;
1163             } else if (!strncmp(string, "ERROR=", 6)) {
1164               type = LOGLEV_ERROR;
1165             } else if (!strncmp(string, "PANIC=", 6)) {
1166               type = LOGLEV_PANIC;
1167             }
1168             action = is_action_name(string+j);
1169             if (action >= ACT_IGNORE) {
1170               set_log_action(dev, type, action);
1171             }
1172           } else {
1173             if (i == 1) {
1174               BX_ERROR(("restore_logopts(): log module '%s' not found", devname));
1175             }
1176           }
1177           i++;
1178           ptr = strtok(NULL, ",");
1179         }
1180       }
1181     } while (!feof(fp));
1182     fclose(fp);
1183   } else {
1184     return 0;
1185   }
1186   return 1;
1187 }
1188 
bx_restore_getline(FILE * fp,char * line,int maxlen)1189 static int bx_restore_getline(FILE *fp, char *line, int maxlen)
1190 {
1191   char *ret = fgets(line, maxlen - 1, fp);
1192   line[maxlen - 1] = '\0';
1193   int len = strlen(line);
1194   if ((len > 0) && (line[len - 1] < ' '))
1195     line[len - 1] = '\0';
1196   return (ret != NULL) ? len : 0;
1197 }
1198 
restore_bochs_param(bx_list_c * root,const char * sr_path,const char * restore_name)1199 bool bx_real_sim_c::restore_bochs_param(bx_list_c *root, const char *sr_path, const char *restore_name)
1200 {
1201   char devstate[BX_PATHNAME_LEN], devdata[BX_PATHNAME_LEN];
1202   char line[512], buf[512];
1203   char pname[81]; // take extra 81st character for /0
1204   char *ptr;
1205   int i;
1206   unsigned n;
1207   bx_param_c *param = NULL;
1208   FILE *fp, *fp2;
1209 
1210   if (root->get_by_name(restore_name) == NULL) {
1211     BX_ERROR(("restore_bochs_param(): unknown parameter to restore"));
1212     return 0;
1213   }
1214 
1215   sprintf(devstate, "%s/%s", sr_path, restore_name);
1216   BX_INFO(("restoring '%s'", devstate));
1217   bx_list_c *base = root;
1218   fp = fopen(devstate, "r");
1219   if (fp != NULL) {
1220     do {
1221       int len = bx_restore_getline(fp, line, BX_PATHNAME_LEN);
1222       i = 0;
1223       if (len > 0) {
1224         ptr = strtok(line, " ");
1225         while (ptr) {
1226           if (i == 0) {
1227             if (!strcmp(ptr, "}")) {
1228               base->restore();
1229               base = (bx_list_c*)base->get_parent();
1230               break;
1231             } else {
1232               param = get_param(ptr, base);
1233               strncpy(pname, ptr, 80);
1234             }
1235           } else if (i == 2) {
1236             if (param == NULL) {
1237               BX_PANIC(("cannot find param '%s'!", pname));
1238             }
1239             else {
1240               if (param->get_type() != BXT_LIST) {
1241                 param->get_param_path(pname, 80);
1242                 BX_DEBUG(("restoring parameter '%s'", pname));
1243               }
1244               switch (param->get_type()) {
1245                 case BXT_PARAM_NUM:
1246                 case BXT_PARAM_BOOL:
1247                 case BXT_PARAM_ENUM:
1248                 case BXT_PARAM_STRING:
1249                 case BXT_PARAM_BYTESTRING:
1250                   param->parse_param(ptr);
1251                   break;
1252                 case BXT_PARAM_DATA:
1253                   {
1254                     bx_shadow_data_c *dparam = (bx_shadow_data_c*)param;
1255                     if (!dparam->is_text_format()) {
1256                       sprintf(devdata, "%s/%s", sr_path, ptr);
1257                       fp2 = fopen(devdata, "rb");
1258                       if (fp2 != NULL) {
1259                         fread(dparam->getptr(), 1, dparam->get_size(), fp2);
1260                         fclose(fp2);
1261                       }
1262                     } else if (!strcmp(ptr, "[")) {
1263                       i = 0;
1264                       do {
1265                         bx_restore_getline(fp, buf, BX_PATHNAME_LEN);
1266                         ptr = strtok(buf, " ");
1267                         while (ptr) {
1268                           if (!strcmp(ptr, "]")) {
1269                             i = 0;
1270                             break;
1271                           } else {
1272                             if (sscanf(ptr, "0x%02x", &n) == 1) {
1273                               dparam->set(i++, (Bit8u)n);
1274                             }
1275                           }
1276                           ptr = strtok(NULL, " ");
1277                         }
1278                       } while (i > 0);
1279                     }
1280                   }
1281                   break;
1282                 case BXT_PARAM_FILEDATA:
1283                   sprintf(devdata, "%s/%s", sr_path, ptr);
1284                   fp2 = fopen(devdata, "rb");
1285                   if (fp2 != NULL) {
1286                     FILE **fpp = ((bx_shadow_filedata_c*)param)->get_fpp();
1287                     // If the temporary backing store file wasn't created, do it now.
1288                     if (*fpp == NULL) {
1289                       *fpp = tmpfile64();
1290                     } else {
1291                       fseeko64(*fpp, 0, SEEK_SET);
1292                     }
1293                     if (*fpp != NULL) {
1294                       char *buffer = new char[4096];
1295                       while (!feof(fp2)) {
1296                         size_t chars = fread(buffer, 1, 4096, fp2);
1297                         fwrite(buffer, 1, chars, *fpp);
1298                       }
1299                       delete [] buffer;
1300                       fflush(*fpp);
1301                     }
1302                     ((bx_shadow_filedata_c*)param)->restore(fp2);
1303                     fclose(fp2);
1304                   }
1305                   break;
1306                 case BXT_LIST:
1307                   base = (bx_list_c*)param;
1308                   break;
1309                 default:
1310                   BX_ERROR(("restore_bochs_param(): unknown parameter type"));
1311               }
1312             }
1313           }
1314           i++;
1315           ptr = strtok(NULL, " ");
1316         }
1317       }
1318     } while (!feof(fp));
1319     fclose(fp);
1320   } else {
1321     BX_ERROR(("restore_bochs_param(): error in file open"));
1322     return 0;
1323   }
1324 
1325   return 1;
1326 }
1327 
restore_hardware()1328 bool bx_real_sim_c::restore_hardware()
1329 {
1330   bx_list_c *sr_list = get_bochs_root();
1331   int ndev = sr_list->get_size();
1332   for (int dev=0; dev<ndev; dev++) {
1333     if (!restore_bochs_param(sr_list, get_param_string(BXPN_RESTORE_PATH)->getptr(), sr_list->get(dev)->get_name()))
1334       return 0;
1335   }
1336   return 1;
1337 }
1338 
save_sr_param(FILE * fp,bx_param_c * node,const char * sr_path,int level)1339 bool bx_real_sim_c::save_sr_param(FILE *fp, bx_param_c *node, const char *sr_path, int level)
1340 {
1341   int i, j;
1342   char pname[BX_PATHNAME_LEN], tmpstr[BX_PATHNAME_LEN+1];
1343   FILE *fp2;
1344 
1345   for (i=0; i<level; i++)
1346     fprintf(fp, "  ");
1347   if (node == NULL) {
1348       BX_ERROR(("NULL pointer"));
1349       return 0;
1350   }
1351   fprintf(fp, "%s = ", node->get_name());
1352   switch (node->get_type()) {
1353     case BXT_PARAM_NUM:
1354     case BXT_PARAM_BOOL:
1355     case BXT_PARAM_ENUM:
1356     case BXT_PARAM_STRING:
1357     case BXT_PARAM_BYTESTRING:
1358       node->dump_param(fp);
1359       fprintf(fp, "\n");
1360       break;
1361     case BXT_PARAM_DATA:
1362       {
1363         bx_shadow_data_c *dparam = (bx_shadow_data_c*)node;
1364         if (!dparam->is_text_format()) {
1365           node->get_param_path(pname, BX_PATHNAME_LEN);
1366           if (!strncmp(pname, "bochs.", 6)) {
1367             strcpy(pname, pname+6);
1368           }
1369           fprintf(fp, "%s\n", pname);
1370           if (sr_path)
1371             sprintf(tmpstr, "%s/%s", sr_path, pname);
1372           else
1373             strcpy(tmpstr, pname);
1374           fp2 = fopen(tmpstr, "wb");
1375           if (fp2 != NULL) {
1376             fwrite(dparam->getptr(), 1, dparam->get_size(), fp2);
1377             fclose(fp2);
1378           }
1379         } else {
1380           fprintf(fp, "[\n");
1381           for (i=0; i < (int)dparam->get_size(); i++) {
1382             if ((i % 16) == 0) {
1383               for (j=0; j<(level+1); j++)
1384                 fprintf(fp, "  ");
1385             } else {
1386               fprintf(fp, ", ");
1387             }
1388             fprintf(fp, "0x%02x", dparam->get(i));
1389             if (i == (int)(dparam->get_size() - 1)) {
1390               fprintf(fp, "\n");
1391             } else if ((i % 16) == 15) {
1392               fprintf(fp, ",\n");
1393             }
1394           }
1395           for (i=0; i<level; i++)
1396             fprintf(fp, "  ");
1397           fprintf(fp, "]\n");
1398         }
1399       }
1400       break;
1401     case BXT_PARAM_FILEDATA:
1402       fprintf(fp, "%s.%s\n", node->get_parent()->get_name(), node->get_name());
1403       if (sr_path)
1404         sprintf(tmpstr, "%s/%s.%s", sr_path, node->get_parent()->get_name(), node->get_name());
1405       else
1406         sprintf(tmpstr, "%s.%s", node->get_parent()->get_name(), node->get_name());
1407       fp2 = fopen(tmpstr, "wb");
1408       if (fp2 != NULL) {
1409         FILE **fpp = ((bx_shadow_filedata_c*)node)->get_fpp();
1410         // If the backing store hasn't been created, just save an empty 0 byte placeholder file.
1411         if (*fpp != NULL) {
1412           char *buffer = new char[4096];
1413           fseeko64(*fpp, 0, SEEK_SET);
1414           while (!feof(*fpp)) {
1415             size_t chars = fread (buffer, 1, 4096, *fpp);
1416             fwrite(buffer, 1, chars, fp2);
1417           }
1418           delete [] buffer;
1419         }
1420         ((bx_shadow_filedata_c*)node)->save(fp2);
1421         fclose(fp2);
1422       }
1423       break;
1424     case BXT_LIST:
1425       {
1426         fprintf(fp, "{\n");
1427         bx_list_c *list = (bx_list_c*)node;
1428         for (i=0; i < list->get_size(); i++) {
1429           save_sr_param(fp, list->get(i), sr_path, level+1);
1430         }
1431         for (i=0; i<level; i++)
1432           fprintf(fp, "  ");
1433         fprintf(fp, "}\n");
1434         break;
1435       }
1436     default:
1437       BX_ERROR(("save_sr_param(): unknown parameter type"));
1438       return 0;
1439   }
1440 
1441   return 1;
1442 }
1443 
opt_plugin_ctrl(const char * plugname,bool load)1444 bool bx_real_sim_c::opt_plugin_ctrl(const char *plugname, bool load)
1445 {
1446   bx_list_c *plugin_ctrl = (bx_list_c*)SIM->get_param(BXPN_PLUGIN_CTRL);
1447   if (!strcmp(plugname, "*")) {
1448     // verify optional plugin configuration and load/unload plugins if necessary
1449     int i = 0;
1450     while (i < plugin_ctrl->get_size()) {
1451       bx_param_bool_c *plugin = (bx_param_bool_c*)plugin_ctrl->get(i);
1452       if (load == (bool)plugin->get()) {
1453         opt_plugin_ctrl(plugin->get_name(), load);
1454       }
1455       i++;
1456     }
1457     return 1;
1458   }
1459   if (plugin_ctrl->get_by_name(plugname) == NULL) {
1460     BX_PANIC(("Plugin '%s' not found", plugname));
1461     return 0;
1462   }
1463   if (load != PLUG_device_present(plugname)) {
1464     if (load) {
1465       if (PLUG_load_opt_plugin(plugname)) {
1466         SIM->get_param_bool(plugname, plugin_ctrl)->set(1);
1467         return 1;
1468       } else {
1469         // plugin load code panics in this case
1470         return 0;
1471       }
1472     } else {
1473       if (PLUG_unload_opt_plugin(plugname)) {
1474         SIM->get_param_bool(plugname, plugin_ctrl)->set(0);
1475         return 1;
1476       } else {
1477         // plugin load code panics in this case
1478         return 0;
1479       }
1480     }
1481   }
1482   return 0;
1483 }
1484 
1485 #if BX_NETWORKING
init_std_nic_options(const char * name,bx_list_c * menu)1486 void bx_real_sim_c::init_std_nic_options(const char *name, bx_list_c *menu)
1487 {
1488   bx_init_std_nic_options(name, menu);
1489 }
1490 #endif
1491 
1492 #if BX_SUPPORT_PCIUSB
init_usb_options(const char * usb_name,const char * pname,int maxports)1493 void bx_real_sim_c::init_usb_options(const char *usb_name, const char *pname, int maxports)
1494 {
1495   bx_init_usb_options(usb_name, pname, maxports);
1496 }
1497 #endif
1498 
1499 
parse_param_from_list(const char * context,const char * param,bx_list_c * base)1500 int bx_real_sim_c::parse_param_from_list(const char *context, const char *param, bx_list_c *base)
1501 {
1502   return bx_parse_param_from_list(context, param, base);
1503 }
1504 
parse_nic_params(const char * context,const char * param,bx_list_c * base)1505 int bx_real_sim_c::parse_nic_params(const char *context, const char *param, bx_list_c *base)
1506 {
1507   return bx_parse_nic_params(context, param, base);
1508 }
1509 
parse_usb_port_params(const char * context,const char * param,int maxports,bx_list_c * base)1510 int bx_real_sim_c::parse_usb_port_params(const char *context, const char *param,
1511                                          int maxports, bx_list_c *base)
1512 {
1513   return bx_parse_usb_port_params(context, param, maxports, base);
1514 }
1515 
split_option_list(const char * msg,const char * rawopt,char ** argv,int max_argv)1516 int bx_real_sim_c::split_option_list(const char *msg, const char *rawopt,
1517                                      char **argv, int max_argv)
1518 {
1519   return bx_split_option_list(msg, rawopt, argv, max_argv);
1520 }
1521 
write_param_list(FILE * fp,bx_list_c * base,const char * optname,bool multiline)1522 int bx_real_sim_c::write_param_list(FILE *fp, bx_list_c *base, const char *optname, bool multiline)
1523 {
1524   return bx_write_param_list(fp, base, optname, multiline);
1525 }
1526 
1527 #if BX_SUPPORT_PCIUSB
write_usb_options(FILE * fp,int maxports,bx_list_c * base)1528 int bx_real_sim_c::write_usb_options(FILE *fp, int maxports, bx_list_c *base)
1529 {
1530   return bx_write_usb_options(fp, maxports, base);
1531 }
1532 #endif
1533 
1534 #if BX_USE_GUI_CONSOLE
bx_printf(const char * fmt,...)1535 int bx_real_sim_c::bx_printf(const char *fmt, ...)
1536 {
1537   va_list ap;
1538   char buf[1025];
1539 
1540   va_start(ap, fmt);
1541   vsnprintf(buf, 1024, fmt, ap);
1542   va_end(ap);
1543   if (get_init_done()) {
1544     if (bx_gui->has_gui_console()) {
1545       return bx_gui->bx_printf(buf);
1546     }
1547   }
1548   return printf("%s", buf);
1549 }
1550 
bx_gets(char * s,int size,FILE * stream)1551 char* bx_real_sim_c::bx_gets(char *s, int size, FILE *stream)
1552 {
1553   if (get_init_done()) {
1554     if (bx_gui->has_gui_console()) {
1555       return bx_gui->bx_gets(s, size);
1556     }
1557   }
1558   return fgets(s, size, stream);
1559 }
1560 #endif
1561