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 = ¶m;
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 = ¶m;
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