Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: ui_cmds.cc | |
4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
6 | // | |
7 | // The above named program is free software; you can redistribute it and/or | |
8 | // modify it under the terms of the GNU General Public | |
9 | // License version 2 as published by the Free Software Foundation. | |
10 | // | |
11 | // The above named program is distributed in the hope that it will be | |
12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | // | |
16 | // You should have received a copy of the GNU General Public | |
17 | // License along with this work; if not, write to the Free Software | |
18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | // | |
20 | // ========== Copyright Header End ============================================ | |
21 | /* icq | |
22 | SELECT - input multiplexing | |
23 | DONE - done replies to the sync-server | |
24 | */ | |
25 | /* | |
26 | * Copyright (C) 1996, 2001, 2005 Sun Microsystems, Inc. | |
27 | * All rights reserved. | |
28 | */ | |
29 | #pragma ident "%%1.119 07/01/09 %%" | |
30 | ||
31 | // "ui_cmds.cc" | |
32 | // | |
33 | // handles UI input multiplexing (stdin, sync socket, back door, script file) | |
34 | // and command parsing, lookup, and calling of registered function for command | |
35 | // | |
36 | // | |
37 | // public functions: | |
38 | // | |
39 | // preinit_ui lame excuse for poor programming | |
40 | // UI_register_cmd add a command string to the lookup list | |
41 | // UI_invalidate_cmd delete a command string from the lookup list | |
42 | // | |
43 | // init_ui starts up the UI thread | |
44 | // UI_exec_cmd inserts a command into the back-door queue | |
45 | // | |
46 | // | |
47 | // public variables: | |
48 | // -- none !!! -- | |
49 | // | |
50 | // extraneous junk: | |
51 | // | |
52 | // send_diskinfo_to_fakeprom called from scsi_ctrl, fc_ctrl. Yeuch! | |
53 | // | |
54 | ||
55 | ||
56 | /* standard C includes */ | |
57 | #include <stdio.h> | |
58 | #include <thread.h> | |
59 | #include <stdlib.h> | |
60 | #include <string.h> | |
61 | #include <assert.h> | |
62 | #include <stdio.h> | |
63 | #include <unistd.h> | |
64 | #include <ctype.h> | |
65 | ||
66 | /* solaris includes */ | |
67 | #include <signal.h> | |
68 | #include <sys/types.h> | |
69 | #include <sys/exec.h> | |
70 | #include <sys/stat.h> | |
71 | #include <sys/time.h> | |
72 | #include <sys/resource.h> | |
73 | #include <sys/procfs.h> | |
74 | #include <sys/socket.h> | |
75 | #include <netinet/in.h> | |
76 | #include <arpa/inet.h> | |
77 | #include <fcntl.h> | |
78 | #include <netdb.h> | |
79 | #include <stropts.h> | |
80 | ||
81 | #include <dlfcn.h> | |
82 | ||
83 | /* project includes */ | |
84 | #include "mmi.h" | |
85 | // FlexConfig: needs this | |
86 | #include "serial_mod.h" | |
87 | ||
88 | #include "ui.h" | |
89 | #include "types.h" | |
90 | #include "blaze_globals.h" | |
91 | #include "system.h" | |
92 | #include "mem.h" | |
93 | typedef void* TM_OPAQUE_DATA; | |
94 | #include "tracemod.h" | |
95 | #include "ui_utils.h" | |
96 | #include "sim_cmd_struct.h" | |
97 | #include "ui_cmds.h" | |
98 | #include "blaze_globals.h" | |
99 | #include "ui_cmd_struct.h" | |
100 | #include "ui_cmds.h" | |
101 | #include "ui_elfsym.h" | |
102 | #include "blz_runtime.h" | |
103 | #include "macrolib.h" | |
104 | #include "netsim.h" | |
105 | #include "cpu_interface.h" | |
106 | #include "stracer.h" | |
107 | #include "workerthread.h" | |
108 | #include "command_opts.h" | |
109 | #include "spix_sparc.h" | |
110 | ||
111 | #include "readline/readline.h" | |
112 | #include "readline/history.h" | |
113 | ||
114 | extern uint32_t boot_ctrl_id; | |
115 | extern uint32_t boot_target_id; | |
116 | extern uint32_t boot_part_id; | |
117 | extern uint32_t boot_disk_id; | |
118 | ||
119 | char bootpath[256]; | |
120 | ||
121 | // global cpu_id set by pselect command | |
122 | int pselect_cpu_id = 0; | |
123 | ||
124 | extern int eventque_ui_cmds (void*, int argc, char **argv); | |
125 | ||
126 | ||
127 | // ============================================================================ | |
128 | // | |
129 | // public data | |
130 | // | |
131 | ||
132 | volatile bool_t cpu_enabled[MAX_MP]; /* init'd in main.cc */ | |
133 | volatile bool_t cpu_enable_changed; /* init'd in main.cc */ | |
134 | ||
135 | ||
136 | extern int blaze_debug; /* lives in main.cc */ | |
137 | extern int blaze_option; /* lives in main.cc */ | |
138 | ||
139 | ||
140 | ||
141 | ||
142 | // ============================================================================ | |
143 | // | |
144 | // private functions | |
145 | // | |
146 | ||
147 | int exec_cmd (char *s_cmd); | |
148 | ||
149 | static int version_ui_cmd (void*, int argc, char **argv); | |
150 | static int conf_ui_cmd (void*, int argc, char **argv); | |
151 | static int mips_ui_cmd (void*, int argc, char **argv); | |
152 | static int file_ui_cmd (void*, int argc, char **argv); | |
153 | static int write_ui_cmd (void*, int argc, char **argv); | |
154 | static int cs_ui_cmd (void*, int argc, char **argv); | |
155 | static int load_ui_cmd (void*, int argc, char **argv); | |
156 | static int setreg_ui_cmd (void*, int argc, char **argv); | |
157 | static int stop_ui_cmd (void*, int argc, char **argv); | |
158 | static int stepim_ui_cmd (void*, int argc, char **argv); | |
159 | static int stept_ui_cmd (void*, int argc, char **argv); | |
160 | static int sync_ui_cmd (void*, int argc, char **argv); | |
161 | static int resume_ui_cmd (void*, int argc, char **argv); | |
162 | static int on_ui_cmd (void*, int argc, char **argv); | |
163 | static int rdt_ui_cmd (void*, int argc, char **argv); | |
164 | static int diskdelay_ui_cmd (void*, int argc, char **argv); | |
165 | static int perf_ui_cmd (void*, int argc, char **argv); | |
166 | static int help_ui_cmd (void*, int argc, char **argv); | |
167 | static int debug_ui_cmd (void*, int argc, char **argv); | |
168 | static int option_ui_cmd (void*, int argc, char **argv); | |
169 | static int alias_ui_cmd (void*, int argc, char **argv); | |
170 | static int unalias_ui_cmd (void*, int argc, char **argv); | |
171 | static int quit_ui_cmd (void*, int argc, char **argv); | |
172 | static int break_ui_cmd (void*, int argc, char **argv); | |
173 | static int list_breakpoints_ui_cmd (void*, int argc, char **argv); | |
174 | static int dbreak_ui_cmd (void*, int argc, char **argv); | |
175 | static int delete_ui_cmd (void*, int argc, char **argv); | |
176 | static int pty_display (void *, int argc, char **argv); | |
177 | static int penable_ui_cmd (void *, int argc, char **argv); | |
178 | static int pdisable_ui_cmd (void *, int argc, char **argv); | |
179 | static int tlbs_ui_cmd (void *, int argc, char **argv); | |
180 | static int vdebug_ui_cmd (void *, int argc, char **argv); | |
181 | static int loglev_ui_cmd (void*, int argc, char**argv); | |
182 | static int devmap_ui_cmd (void*, int argc, char**argv); | |
183 | static int pselect_ui_cmd (void*, int argc, char**argv); | |
184 | static int translate_ui_cmd(void*, int argc, char **argv); | |
185 | static int get_ui_cmd(void*, int argc, char **argv); | |
186 | static int set_ui_cmd(void*, int argc, char **argv); | |
187 | static int disassemble_ui_cmd(void*, int argc, char **argv); | |
188 | static int run_python_file_ui_cmd(void*, int argc, char **argv); | |
189 | static int echo_ui_cmd(void*, int argc, char **argv); | |
190 | static int run_ui_cmd (void*, int argc, char **argv); | |
191 | static int stepi_ui_cmd (void*, int argc, char **argv); | |
192 | static int stepc_ui_cmd (void*, int argc, char **argv); | |
193 | static int read_asi_ui_cmd (void*, int argc, char **argv); | |
194 | static int write_asi_ui_cmd (void*, int argc, char **argv); | |
195 | ||
196 | ||
197 | ||
198 | static void init_sync (); | |
199 | ||
200 | ||
201 | static Vcpu * get_vcpu_by_name ( char *name ); | |
202 | ||
203 | // ======================= GLOBAL VARIABLES =================================== | |
204 | ||
205 | Ui_cmd ui_cmd_list [] = | |
206 | { | |
207 | {"version","\n", 0, version_ui_cmd, NULL, NULL}, | |
208 | {"run", "run <mode>\n", 0, run_ui_cmd, NULL, NULL}, | |
209 | {"file", "file <script file name>\n", 0, file_ui_cmd, NULL, NULL}, | |
210 | {"run-cmd-file", "run-cmd-file <script file name>\n", 0, file_ui_cmd, NULL, NULL}, | |
211 | {"stop", "just stop SAM\n", 0, stop_ui_cmd, NULL, NULL}, | |
212 | {"conf", "conf <name> <value>\n", 0, conf_ui_cmd, NULL, NULL}, | |
213 | {"mips", "mips \n", 0, mips_ui_cmd, NULL, NULL}, | |
214 | {"write", "write <pa> <file> <va> \n", 0, write_ui_cmd, NULL, NULL}, | |
215 | {"load", "load <mode> <addr> <value>\n", 0, load_ui_cmd, NULL, NULL}, | |
216 | {"setreg", "setreg <regname> <value> \n", 0, setreg_ui_cmd, NULL, NULL}, | |
217 | #ifdef V5_FAKEPROM | |
218 | {"console-send", "console-send <string> \n",FUI_STRING, cs_ui_cmd, NULL, NULL}, | |
219 | #endif | |
220 | {"quit", "quit SAM\n", 0, quit_ui_cmd, NULL, NULL}, | |
221 | {"help", "help <command>", 0, help_ui_cmd, NULL, NULL}, | |
222 | {"debug", "debug [N]", 0, debug_ui_cmd, NULL, NULL}, | |
223 | {"option", "option [N]", 0, option_ui_cmd, NULL, NULL}, | |
224 | {"events", "events", 0, eventque_ui_cmds, NULL, NULL}, | |
225 | {"stepi", "stepi <N>", 0, stepi_ui_cmd, NULL, NULL}, | |
226 | {"stepc", "stepc <N>", 0, stepc_ui_cmd, NULL, NULL}, | |
227 | {"stepim", "stepim <N>", 0, stepim_ui_cmd, NULL, NULL}, | |
228 | {"stept", "stept <usecs>", 0, stept_ui_cmd, NULL, NULL}, | |
229 | {"on", "on STOP <command>", 0, on_ui_cmd, NULL, NULL}, | |
230 | {"rdt", "rdt [<FILE>]", 0, rdt_ui_cmd, NULL, NULL}, | |
231 | {"diskdelay", "diskdelay [ddelay[/wrddelay]] [start_cycle]", 0, diskdelay_ui_cmd, NULL, NULL}, | |
232 | {"perf", "perf # | off", 0, perf_ui_cmd, NULL, NULL}, | |
233 | {"sync", "on|off", 0, sync_ui_cmd, NULL, NULL}, | |
234 | {"resume", "back to prev sync mode", 0, resume_ui_cmd, NULL, NULL}, | |
235 | {"alias", "alias [<old cmd>] [<new cmd>] ",0, alias_ui_cmd, NULL, NULL}, | |
236 | {"unalias", "unalias <alias cmd>" ,0, unalias_ui_cmd, NULL, NULL}, | |
237 | {"penable","penable [-all | <thN>]", 0, penable_ui_cmd, NULL, NULL}, | |
238 | {"pdisable", "pdisable [-all | <thN>]", 0, pdisable_ui_cmd, NULL, NULL}, | |
239 | {"pty", "pty", 0, pty_display, NULL, NULL}, | |
240 | {"break", "set a breakpoint \n", 0, break_ui_cmd, NULL, NULL}, | |
241 | {"list-breakpoints", "list breakpoints \n", 0, list_breakpoints_ui_cmd, NULL, NULL}, | |
242 | {"dbreak", "delete a breakpoint <bp_id>\n", 0, dbreak_ui_cmd, NULL, NULL}, | |
243 | {"delete", "delete breakpoints [all|<bp_id>...]\n", 0, delete_ui_cmd, NULL, NULL}, | |
244 | {"vdebug", "debug tracer on|off\n", 0, vdebug_ui_cmd, NULL, NULL}, | |
245 | {"load_symbols","load symbol table\n", 0, load_sym_ui_cmd, NULL, NULL}, | |
246 | {"unload_symbols","uload symbol table\n", 0, unload_sym_ui_cmd, NULL, NULL}, | |
247 | {"sym", "display symbol table\n", 0, symbols_ui_cmd, NULL, NULL}, | |
248 | {"where", "display call stack\n", 0, where_ui_cmd, NULL, NULL}, | |
249 | {"tlbs", "display tlb entries\n", 0, tlbs_ui_cmd, NULL, NULL}, | |
250 | {"loglev", "loglev [1|2|3]\n", 0, loglev_ui_cmd, NULL, NULL}, | |
251 | {"devmap", "show internal device id map\n", 0, devmap_ui_cmd, NULL, NULL}, | |
252 | {"pselect", "pselect cpu_id\n", 0, pselect_ui_cmd, NULL, NULL}, | |
253 | {"translate", "translate address\n", 0, translate_ui_cmd, NULL, NULL}, | |
254 | {"get", "get memory\n", 0, get_ui_cmd, NULL, NULL}, | |
255 | {"set", "set memory\n", 0, set_ui_cmd, NULL, NULL}, | |
256 | {"disassemble", "disassemble memory\n", 0, disassemble_ui_cmd, NULL, NULL}, | |
257 | {"echo", "echo [(\"string\"|integer|float)]\n", 0, echo_ui_cmd, NULL, NULL}, | |
258 | {"run-python-file", "py execfile\n", 0, run_python_file_ui_cmd, NULL, NULL}, | |
259 | {"read-asi", "read non-translating asi\n", 0, read_asi_ui_cmd, NULL, NULL}, | |
260 | {"write-asi", "write non-translating asi\n",0, write_asi_ui_cmd, NULL, NULL} | |
261 | }; | |
262 | static Ui_cmd * plast = NULL; | |
263 | ||
264 | ||
265 | // ------------ ui-misc globals ------------ | |
266 | // | |
267 | static Ui_misc the_misc = {0}; | |
268 | static Ui_misc *pui_misc = &the_misc; | |
269 | ||
270 | static uint32_t diskdelay, wrdiskdelay ; | |
271 | static uint64_t ddelay_start_cycle = 0; | |
272 | ||
273 | int& CpuSet::max_cpu_ndx = g_vcpu_id_max; | |
274 | ||
275 | ||
276 | // ------------- UI-thread globals ------------- | |
277 | // | |
278 | static volatile int sync_fd = -1; | |
279 | static volatile int sync_on = 0; | |
280 | ||
281 | static thread_t ui_sync_tid; | |
282 | ||
283 | // ============================ end globals =================================== | |
284 | ||
285 | ||
286 | // --------------------------- some forward decls -------------------------- | |
287 | ||
288 | int arbitrary_ui_cmd (char * s); | |
289 | ||
290 | // these are in "main.cc" | |
291 | typedef int (*ui_cmd_fn) (char *); | |
292 | extern void fe_register_ui_action (ui_cmd_fn foo) ; | |
293 | extern char* fe_get_sofile (); | |
294 | extern void* fe_get_sohandle (); | |
295 | ||
296 | ||
297 | extern char *pty_dev_a, *pty_dev_b; | |
298 | extern char *pty_dev_c, *pty_dev_d; | |
299 | ||
300 | // the pointers are set to point to real impl. if the py module is loaded to | |
301 | // add/delete the dynamically created SAM UI commands | |
302 | typedef void (*Py_Intf_fn)(const char *); | |
303 | Py_Intf_fn addPycmd = 0; | |
304 | Py_Intf_fn delPycmd = 0; | |
305 | bool python_UI = false; | |
306 | ||
307 | ||
308 | ||
309 | ||
310 | ||
311 | ///////////////////////////////////////////////// | |
312 | // | |
313 | // | |
314 | // | |
315 | void linkup (Ui_cmd * pc) | |
316 | { | |
317 | int i; | |
318 | if (!plast) { | |
319 | for (i = 0; i < (sizeof(ui_cmd_list) / sizeof(Ui_cmd)) - 1; i++) { | |
320 | ui_cmd_list[i].next = &ui_cmd_list[i+1]; | |
321 | } | |
322 | plast = &ui_cmd_list[i]; | |
323 | } | |
324 | plast->next = pc; | |
325 | plast = pc; | |
326 | } | |
327 | ||
328 | ||
329 | ||
330 | ///////////////////////////////////////////////// | |
331 | void preinit_ui () | |
332 | { | |
333 | int i; | |
334 | if (!plast) { | |
335 | for (i = 0; i < (sizeof(ui_cmd_list) / sizeof(Ui_cmd)) - 1; i++) { | |
336 | ui_cmd_list[i].next = &ui_cmd_list[i+1]; | |
337 | } | |
338 | plast = &ui_cmd_list[i]; | |
339 | } | |
340 | ||
341 | ||
342 | } | |
343 | ||
344 | ||
345 | ||
346 | /////////////////////////////////////////////// | |
347 | // | |
348 | // These functions below register new UI commands | |
349 | // | |
350 | void UI_register_cmd_1 (char * name, char *help, | |
351 | ui_cmd_exe_handler efn, ui_cmd_help_handler hfn) | |
352 | { | |
353 | ||
354 | Ui_cmd *pcmd = (Ui_cmd*) calloc (1, sizeof(Ui_cmd)); | |
355 | if (pcmd == NULL) { | |
356 | ui->error("UI_register can not malloc\n"); | |
357 | return; | |
358 | } | |
359 | pcmd->name = (char*) strdup(name); | |
360 | pcmd->help = (char*) strdup(help); | |
361 | pcmd->cmd_exe_func = efn; | |
362 | pcmd->cmd_help_func = hfn; | |
363 | ||
364 | pcmd->flags = FUI_STRING; /* _1 */ | |
365 | pcmd->alias_argc = 1; | |
366 | ||
367 | linkup (pcmd); | |
368 | ||
369 | if(addPycmd) (*addPycmd)(name); | |
370 | } | |
371 | // | |
372 | // | |
373 | void UI_register_cmd_2 (char * name, char *help, | |
374 | ui_cmd_exe_handler efn, ui_cmd_help_handler hfn) | |
375 | { | |
376 | ||
377 | Ui_cmd *pcmd = (Ui_cmd*) calloc (1, sizeof(Ui_cmd)); | |
378 | if (pcmd == NULL) { | |
379 | ui->error("UI_register can not malloc\n"); | |
380 | return; | |
381 | } | |
382 | pcmd->name = (char*) strdup(name); | |
383 | pcmd->help = (char*) strdup(help); | |
384 | pcmd->cmd_exe_func = efn; | |
385 | pcmd->cmd_help_func = hfn; | |
386 | ||
387 | pcmd->flags = 0; /* _2 */ | |
388 | pcmd->alias_argc = 1; | |
389 | ||
390 | linkup (pcmd); | |
391 | ||
392 | if(addPycmd) (*addPycmd)(name); | |
393 | } | |
394 | // | |
395 | // | |
396 | void UI_register_cmd_3 (char * name, char *help, | |
397 | ui_cmd_exe_handler efn, ui_cmd_help_handler hfn, uint32_t flags) | |
398 | { | |
399 | Ui_cmd *pcmd = (Ui_cmd*) calloc (1, sizeof(Ui_cmd)); | |
400 | if (pcmd == NULL) { | |
401 | ui->error("UI_register can not malloc\n"); | |
402 | return; | |
403 | } | |
404 | pcmd->name = (char*) strdup(name); | |
405 | pcmd->help = (char*) strdup(help); | |
406 | pcmd->cmd_exe_func = efn; | |
407 | pcmd->cmd_help_func = hfn; | |
408 | ||
409 | pcmd->flags = flags; /* _3 */ | |
410 | pcmd->alias_argc = 1; | |
411 | ||
412 | linkup (pcmd); | |
413 | ||
414 | if(addPycmd) (*addPycmd)(name); | |
415 | ||
416 | } | |
417 | ||
418 | /////////////////////////////////////////////// | |
419 | // | |
420 | // this command un-registers a UI command | |
421 | // | |
422 | void UI_invalidate_cmd (char *name) | |
423 | { | |
424 | Ui_cmd *pcmd; | |
425 | bool_t done = FALSE; | |
426 | ||
427 | for (pcmd = &ui_cmd_list[0]; pcmd;pcmd = pcmd->next) { | |
428 | if (strcmp(pcmd->name, name) == NULL) { | |
429 | ||
430 | pcmd->flags |= FUI_INVALID; | |
431 | ||
432 | done = TRUE; | |
433 | } | |
434 | } | |
435 | ||
436 | if (done == FALSE) | |
437 | ui->error("unable to find <%s> command", name); | |
438 | ||
439 | // delete the command with the PY UI if present | |
440 | if(delPycmd) (*delPycmd)(name); | |
441 | } | |
442 | ||
443 | ||
444 | ||
445 | ||
446 | ||
447 | /////////////////////////////////////////////// | |
448 | ||
449 | static const int max_cmd_length = 2048; | |
450 | ||
451 | static int fdgets (char * sss, int fd) | |
452 | { | |
453 | char * s = sss; | |
454 | int n = 0; | |
455 | while (1) { | |
456 | if (read (fd, sss, 1) != 1) | |
457 | return 0; // convention for closed socket | |
458 | ++n; | |
459 | if (*sss == '\n') { | |
460 | *++sss = '\0'; | |
461 | return n; | |
462 | } | |
463 | if (*sss == '\0') | |
464 | return n; | |
465 | ++sss; | |
466 | if (n>= max_cmd_length) { | |
467 | ui->error("UI command too long (limit %d characters)\n", max_cmd_length); | |
468 | *s = 0; | |
469 | return 0; | |
470 | } | |
471 | } | |
472 | } | |
473 | ||
474 | ||
475 | sint64_t perf_ui_interval = 0, // all in "hrtime" units of nanosecs | |
476 | perf_ui_start = 0, | |
477 | next_perf_ui_time = 0, | |
478 | perf_now = 0, | |
479 | perf_tmp = 0, | |
480 | last_perf_globaltick = 0; | |
481 | ||
482 | ||
483 | ||
484 | // ============================ UI SYNC THREAD ================================ | |
485 | // | |
486 | // the purpose of this thread is to enable concurrent input from | |
487 | // sync_fd (is the global-time-sync socket) and to deal with the | |
488 | // perf command | |
489 | ||
490 | extern "C" void * ui_sync_thread (void *arg) | |
491 | { | |
492 | char sss[max_cmd_length]; | |
493 | ||
494 | fd_set read_set; | |
495 | int selrc; | |
496 | struct timeval timeout, *tvp; | |
497 | ||
498 | // Open a fake input so that select below works ok | |
499 | // when there is no sync_fd. | |
500 | int fake_fd = open("/dev/null",O_RDONLY,0); | |
501 | ||
502 | for (;;) { | |
503 | ||
504 | FD_ZERO (&read_set); | |
505 | FD_SET (fake_fd,&read_set); | |
506 | ||
507 | if (sync_fd >= 0) { | |
508 | if (IN_SYNC_STATE(blaze_run_state)) | |
509 | FD_SET (sync_fd, &read_set); | |
510 | } | |
511 | ||
512 | if (perf_ui_interval != 0) { | |
513 | sint64_t tmp = (next_perf_ui_time - gethrtime()); | |
514 | if (tmp > 0) { | |
515 | timeout.tv_sec = tmp / 1000000000; | |
516 | timeout.tv_usec = (tmp - 1000000000 * timeout.tv_sec) / 1000; | |
517 | } else { | |
518 | timeout.tv_sec = timeout.tv_usec = 0; | |
519 | } | |
520 | tvp = &timeout; | |
521 | } else | |
522 | tvp = NULL; | |
523 | ||
524 | selrc = select (FD_SETSIZE, &read_set, 0, 0, tvp); /* SELECT */ | |
525 | ||
526 | if (perf_ui_interval != 0 | |
527 | && (perf_now = gethrtime()) > next_perf_ui_time) { | |
528 | perf_tmp = SYSTEM_get_ticks (); | |
529 | ui->output(" %6.1f %6.3f MIPS \n", | |
530 | (double)(perf_now - perf_ui_start) / 1000000000.0, | |
531 | (double)(perf_tmp - last_perf_globaltick) | |
532 | / (perf_ui_interval / 1000.0)); | |
533 | next_perf_ui_time += perf_ui_interval; | |
534 | last_perf_globaltick = perf_tmp; | |
535 | ||
536 | } | |
537 | ||
538 | if (selrc < 0) { | |
539 | /* @@@ what about EINTR (for keyboard ctrl-C ?) */ | |
540 | ui->perror ("ui select: "); | |
541 | } | |
542 | ||
543 | if (sync_fd >= 0 && FD_ISSET (sync_fd, &read_set)) { /*SYNC*/ | |
544 | sss[0] = '\0'; | |
545 | if (fdgets(sss, sync_fd)) { | |
546 | ||
547 | if (sync_on) { | |
548 | if (strncmp (sss, "stept ", 6) == 0) { | |
549 | UI_exec_cmd (sss); | |
550 | } else { | |
551 | ui->error("###sync cmd \"%s\", ignored.\n", sss); | |
552 | } | |
553 | } else { | |
554 | write (sync_fd, "done\n", 5); /*quick DONE*/ | |
555 | } | |
556 | } else { // the socket closed ... | |
557 | ||
558 | UI_exec_cmd ("sync off\n"); | |
559 | UI_exec_cmd ("sync disconnect\n"); | |
560 | if (IN_SYNC_STATE(blaze_run_state)) { | |
561 | UI_exec_cmd ("stop\n"); | |
562 | } | |
563 | } | |
564 | } | |
565 | } | |
566 | return NULL; | |
567 | } | |
568 | ||
569 | ||
570 | //////////////////////////////////////////////////////// | |
571 | // | |
572 | // read user command input | |
573 | // | |
574 | void ui_readline () | |
575 | { | |
576 | while(1) | |
577 | { | |
578 | char *line, *help; // read line buffer | |
579 | const char* prompt = "sam: "; | |
580 | switch (blaze_run_state) | |
581 | { | |
582 | case e_BLAZE_STOP: prompt = "stop: "; break; | |
583 | case e_BLAZE_STEP: prompt = "step: "; break; | |
584 | case e_BLAZE_RUN: prompt = "run: "; break; | |
585 | case e_BLAZE_GTSTEP: prompt = "gtstep:"; break; | |
586 | case e_BLAZE_GTWAIT: prompt = "gtwait:"; break; | |
587 | default: prompt = "???"; break; | |
588 | } | |
589 | ||
590 | // Read a line from input. An EOF results in a NULL | |
591 | // pointer. We simply exit on EOF. | |
592 | ||
593 | ui->input(prompt); | |
594 | ui->flush(); | |
595 | ||
596 | line = readline(prompt); | |
597 | ||
598 | if (line) | |
599 | { | |
600 | ui->input(line); | |
601 | ui->input("\n"); | |
602 | UI_exec_cmd(line); | |
603 | ||
604 | // Only add non blank lines to the history. | |
605 | ||
606 | for (help = line; *help && isspace(*help); ++help) | |
607 | ; | |
608 | if (*help) | |
609 | add_history(line); | |
610 | ||
611 | free(line); | |
612 | } | |
613 | else | |
614 | break; // eof hit, exit | |
615 | } | |
616 | ||
617 | if (IN_RUN_STATE (blaze_run_state)) | |
618 | UI_exec_cmd("stop\n"); | |
619 | ||
620 | SYSTEM_quit_UI (); | |
621 | } | |
622 | ||
623 | // ============================ UI THREAD INIT ================================ | |
624 | // | |
625 | // | |
626 | void init_ui (char *rc, bool_t notused) | |
627 | { | |
628 | ||
629 | pui_misc->rcfile = (rc) ? (char*) strdup(rc) : NULL; | |
630 | pui_misc->redirect_fd = (-1); | |
631 | ||
632 | ||
633 | init_sync (); // connect to global-time-sync if server specified | |
634 | ||
635 | thr_create (NULL, NULL, ui_sync_thread, (void*)0, THR_BOUND, &ui_sync_tid); | |
636 | } | |
637 | ||
638 | ||
639 | ||
640 | // ================================ EXEC_CMD ================================== | |
641 | // | |
642 | // | |
643 | // | |
644 | // | |
645 | ||
646 | static void clear_invalid_aliases() | |
647 | { | |
648 | for (Ui_cmd* pcmd = &ui_cmd_list[0]; pcmd; pcmd = pcmd->next) | |
649 | if ((pcmd->flags & (FUI_ALIAS|FUI_INVALID)) == | |
650 | (FUI_ALIAS|FUI_INVALID)) | |
651 | pcmd->flags &= ~FUI_INVALID; | |
652 | } | |
653 | ||
654 | int exec_cmd (char *s_cmd) | |
655 | { | |
656 | static char lastCommand [max_cmd_length] = ""; | |
657 | ||
658 | char * ps = NULL, *ps1 = NULL, *ps2 = NULL, **argv = NULL; | |
659 | int argc = 16; | |
660 | bool quoted = false; | |
661 | Ui_cmd *pcmd = NULL; | |
662 | AGAIN: | |
663 | ps = s_cmd; | |
664 | while (isspace(*ps)) { | |
665 | ++ps; | |
666 | } | |
667 | ||
668 | if ((*ps == '\0') || (*ps == '#')) | |
669 | return 0; | |
670 | ||
671 | //check if the cmd is well double-quoted. | |
672 | if (ps1 = strchr(ps, '"')) { | |
673 | int count = 0; | |
674 | bool appear = false; | |
675 | while ( *ps1 != '\0' ) { | |
676 | //only when '"' is not escaped by '\', it will be regarded as a valid double-quoted sign. | |
677 | if (((*ps1 == '"') && ((*(ps1-1) != '\\')) || (ps1 == ps))) { | |
678 | count++; | |
679 | } | |
680 | if (*ps1 == '#') { | |
681 | appear = true; | |
682 | } | |
683 | ps1++; | |
684 | } | |
685 | //when the number of valid double-quoted sign is even, the cmd is well quoted. | |
686 | if ((!(count%2))&&appear) { | |
687 | quoted = true; | |
688 | } | |
689 | } | |
690 | ||
691 | //when the cmd is not well double-quoted, '#' is regarded as a comment. Or, keep the '#' when it is put into a | |
692 | //well double-quoted cmd. | |
693 | if (!quoted) { | |
694 | if (ps2 = strchr(ps, '#')) { | |
695 | *ps2 = '\0'; | |
696 | } | |
697 | } | |
698 | ||
699 | if ( strcmp(ps, "!!") == NULL ) | |
700 | { | |
701 | strcpy(s_cmd, lastCommand); | |
702 | goto AGAIN; | |
703 | } | |
704 | else | |
705 | { | |
706 | strcpy(lastCommand, s_cmd); // save last command | |
707 | } | |
708 | ||
709 | if (*ps == '%') // register read | |
710 | return cpu_read_register_name (ps+1); | |
711 | ||
712 | argv = ui_argv_argc_parse (ps, &argc); | |
713 | if (argv == NULL) { | |
714 | ui->error("cmd format error <%s>", ps); | |
715 | return 1; | |
716 | } | |
717 | ||
718 | bool saw_alias = false; | |
719 | ||
720 | retry: | |
721 | for (pcmd = &ui_cmd_list[0]; pcmd;pcmd = pcmd->next) { | |
722 | ||
723 | if (pcmd->flags & FUI_INVALID) | |
724 | continue; | |
725 | if (strcmp(argv[0], pcmd->name) == NULL) { | |
726 | if (pcmd->flags & FUI_ALIAS) { | |
727 | int new_argc = argc + pcmd->alias_argc - 1; | |
728 | free(argv[0]); | |
729 | argv = (char**) realloc(argv, | |
730 | sizeof(const char*) * new_argc); | |
731 | memmove(argv + pcmd->alias_argc, argv + 1, | |
732 | sizeof(char**) * (argc - 1)); | |
733 | memmove(argv, pcmd->alias_argv, sizeof(char**) * pcmd->alias_argc); | |
734 | for (int ndx = 0; ndx < pcmd->alias_argc; ++ndx) | |
735 | { | |
736 | char *p = argv[ndx]; | |
737 | argv[ndx] = strdup(p); | |
738 | if (argv[ndx] == NULL) { | |
739 | ui->error("cannot strdup <%s>", p); | |
740 | return 1; | |
741 | } | |
742 | } | |
743 | argc = new_argc; | |
744 | pcmd->flags |= FUI_INVALID; | |
745 | saw_alias = true; | |
746 | goto retry; | |
747 | } | |
748 | if (pcmd->flags & FUI_STRING) { | |
749 | char *pw0; | |
750 | char *str = ui_parsew(s_cmd, &pw0); | |
751 | argc = 2; | |
752 | ||
753 | argv[1] = (char*) strdup (str); | |
754 | } | |
755 | if (pcmd->cmd_exe_func) { /*******/ | |
756 | if (saw_alias) | |
757 | clear_invalid_aliases(); | |
758 | int rv = (pcmd->cmd_exe_func (NULL, argc, argv)); /*DO IT*/ | |
759 | ||
760 | ui_argv_free(argc, argv); | |
761 | return rv; | |
762 | } /*******/ | |
763 | } | |
764 | } | |
765 | ||
766 | if (saw_alias) | |
767 | clear_invalid_aliases(); | |
768 | ui_argv_free(argc, argv); | |
769 | ||
770 | ui->error("unknown command <%s>\n", ps); | |
771 | return 1; | |
772 | } | |
773 | ||
774 | ||
775 | //============================================================================== | |
776 | // ====================== locally implemented ui functions ==================== | |
777 | ||
778 | ||
779 | ///////////////////////////////////////////// | |
780 | // | |
781 | // RUN | |
782 | // | |
783 | static int run_ui_cmd (void*, int argc, char **argv) | |
784 | { | |
785 | ||
786 | if (!IN_STOP_STATE (blaze_run_state)) | |
787 | { | |
788 | ui->error("not in stop state, use stop command first\n"); | |
789 | return 1; | |
790 | } | |
791 | if (argc != 1) { | |
792 | ui->output("usage: run\nUse stepi <instruction count> to single step\n"); | |
793 | return 1; | |
794 | } | |
795 | SYSTEM_run_UI (); /* kicks off async running of cpu-sim threads */ | |
796 | return 1; | |
797 | } | |
798 | ||
799 | ||
800 | /////////////////////////////////////////////// | |
801 | // | |
802 | // STOP | |
803 | // | |
804 | static int stop_ui_cmd (void*, int argc, char **argv) | |
805 | { | |
806 | // we intentionally leave sync_on alone for now... | |
807 | // that way "resume" can decide which way to go... | |
808 | ||
809 | SYSTEM_stop_UI (); | |
810 | return 1; | |
811 | } | |
812 | ||
813 | ||
814 | //////////////////////////////////////////// | |
815 | // | |
816 | // STEPI <ninstrs> | |
817 | // | |
818 | // Step for n instructions all cpu's, | |
819 | // optionally show trace for vcpu: cpuid | |
820 | // | |
821 | // stepi [<nsteps>] [-t [<cpuid>]] | |
822 | // | |
823 | static int stepi_ui_cmd (void*, int argc, char **argv) | |
824 | { | |
825 | int64_t ni = 1; | |
826 | ||
827 | if (SYSTEM_in_execution_driven_mode()) { | |
828 | ui->error("cannot do stepi in exec-driven mode\n"); | |
829 | return 1; | |
830 | } | |
831 | ||
832 | if (!IN_STOP_STATE (blaze_run_state)) { | |
833 | ui->error("not in stop state\n"); | |
834 | return 1; | |
835 | } | |
836 | ||
837 | if ((argc > 1) && isdigit(argv[1][0])) | |
838 | { | |
839 | sscanf(argv[1], "%lli", &ni); | |
840 | ni = strtoll(argv[1], NULL, 0); | |
841 | if (ni == 0 ) ni = 1; | |
842 | } | |
843 | ||
844 | for (int i=1; i<argc; i++) | |
845 | { | |
846 | if ((strcmp(argv[i], "-t")==0) || (strcmp(argv[i], "-o")==0)) | |
847 | { | |
848 | ui->error("to enable debug tracer use vdebug command\n"); | |
849 | return 1; | |
850 | } | |
851 | else if(strcmp(argv[i], "?")==0) | |
852 | { | |
853 | ui->output("usage: stepi [<ninstr>]\n"); | |
854 | return 1; | |
855 | } | |
856 | } | |
857 | ||
858 | SYSTEM_stepi_UI (ni); | |
859 | return 0; | |
860 | } | |
861 | ||
862 | ||
863 | static int stepc_ui_cmd(void *, int argc, char **argv) | |
864 | { | |
865 | if (!SYSTEM_in_execution_driven_mode()) { | |
866 | ui->error("stepc only supported in exec-driven mode\n"); | |
867 | return 1; | |
868 | } | |
869 | ||
870 | if (!IN_STOP_STATE(blaze_run_state)) | |
871 | { | |
872 | ui->error("not in stop state, use stop command first\n"); | |
873 | return 1; | |
874 | } | |
875 | int64_t nc=1; | |
876 | int i = 1; | |
877 | while(i<argc) { | |
878 | if (argv[i][0] == '?') { | |
879 | ui->output("usage: stepc [<ncycles>]\n"); | |
880 | return 1; | |
881 | } else { | |
882 | errno = 0; | |
883 | nc = strtoll(argv[i], NULL, 0); | |
884 | if (errno) { | |
885 | ui->error("invalid argument %s\n", argv[i]); | |
886 | return 1; | |
887 | } | |
888 | i++; | |
889 | if (!nc) nc = 1; | |
890 | } | |
891 | } | |
892 | ||
893 | SYSTEM_stepc_UI(nc); | |
894 | return 0; | |
895 | } | |
896 | ||
897 | ||
898 | /////////////////////////////////////////////// | |
899 | // | |
900 | // STEPIM <ninstrs> | |
901 | // | |
902 | int stepim_ui_cmd (void*, int argc, char **argv) | |
903 | { | |
904 | int64_t ni = 1; | |
905 | if (argc > 1) sscanf(argv[1], "%lli", &ni); | |
906 | ||
907 | struct timeval btime, etime; | |
908 | gettimeofday ((struct timeval*)&btime, NULL); | |
909 | ||
910 | stepi_ui_cmd (NULL, argc, argv); | |
911 | ||
912 | gettimeofday ((struct timeval*)&etime, NULL); | |
913 | ||
914 | { | |
915 | uint64_t elapsed_usecs = etime.tv_sec * 1000000 + etime.tv_usec - | |
916 | (btime.tv_sec * 1000000 + btime.tv_usec); | |
917 | uint64_t icount = ni * the_arch.numcpus; | |
918 | ||
919 | double instr_per_sec = (double)(icount) / | |
920 | ((double)elapsed_usecs / 1000000.0); | |
921 | ui->output("ic = %lld, usecs = %lld : %.4f \n", | |
922 | icount, elapsed_usecs, instr_per_sec); | |
923 | } | |
924 | return 0; | |
925 | } | |
926 | ||
927 | ||
928 | ||
929 | /////////////////////////////////////////////////// | |
930 | // | |
931 | // STEPT <usecs> <seqnum> | |
932 | // | |
933 | ||
934 | static volatile int64_t stept_usecs = 1; | |
935 | static volatile int64_t stept_seqnum = -1; /* most recent request */ | |
936 | static volatile int64_t done_seqnum = -1; /* most recent reply */ | |
937 | ||
938 | extern "C" { | |
939 | static void stept_done_callback (void * x) | |
940 | { | |
941 | int res; | |
942 | char buf[max_cmd_length]; | |
943 | ||
944 | if (sync_fd != -1 && sync_on) { | |
945 | if (stept_seqnum != -1) { | |
946 | sprintf (buf, "done %lld\n", stept_seqnum); | |
947 | } else { | |
948 | sprintf (buf, "done\n"); | |
949 | } | |
950 | res = write (sync_fd, buf, strlen(buf)); /*DONE*/ | |
951 | ||
952 | if (res != strlen(buf)) { | |
953 | ui->perror ("sync-done writemsg error:"); | |
954 | } | |
955 | done_seqnum = stept_seqnum; | |
956 | } | |
957 | } | |
958 | }; | |
959 | ||
960 | static int SYNCDEBUG = 0; | |
961 | ||
962 | int stept_ui_cmd (void*, int argc, char **argv) | |
963 | { | |
964 | ||
965 | if (!IN_GTWAIT_STATE(blaze_run_state)) { | |
966 | ui->error("not in sync-mode\n"); | |
967 | return 1; | |
968 | } | |
969 | ||
970 | if (argc > 1) sscanf(argv[1], "%lli", &stept_usecs); | |
971 | if (argc > 2) sscanf(argv[2], "%lli", &stept_seqnum); | |
972 | else stept_seqnum = -1; | |
973 | ||
974 | if (SYNCDEBUG) | |
975 | ui->output("sync[%lld]: for %lld-usecs, now=%lld\n", | |
976 | stept_seqnum, stept_usecs, SYSTEM_get_time()); | |
977 | ||
978 | SYSTEM_stept_UI (stept_usecs, stept_seqnum, stept_done_callback); | |
979 | ||
980 | return 0; | |
981 | } | |
982 | ||
983 | ||
984 | ///////////////////////////////////////////// | |
985 | // | |
986 | // RESUME | |
987 | // | |
988 | static int resume_ui_cmd (void*, int argc, char **argv) | |
989 | { | |
990 | if (!IN_STOP_STATE (blaze_run_state)) | |
991 | { | |
992 | ui->error("not in stop state, use stop command first\n"); | |
993 | return 1; | |
994 | } | |
995 | if (sync_on) { | |
996 | SYSTEM_syncon_UI (); | |
997 | } else { | |
998 | SYSTEM_run_UI (); | |
999 | } | |
1000 | return 0; | |
1001 | } | |
1002 | ||
1003 | ||
1004 | /////////////////////////////////////////////// | |
1005 | // | |
1006 | // QUIT | |
1007 | // | |
1008 | static int quit_ui_cmd (void*, int argc, char **argv) | |
1009 | { | |
1010 | if (IN_RUN_STATE (blaze_run_state)) | |
1011 | stop_ui_cmd (NULL, 0, NULL); | |
1012 | SYSTEM_quit_UI (); | |
1013 | return 0; | |
1014 | } | |
1015 | ||
1016 | ||
1017 | /////////////////////////////////////////////// | |
1018 | // | |
1019 | // LOAD <pa> <filename> <va> // was totally simplified by Tycho | |
1020 | // | |
1021 | ||
1022 | extern void load_elf64 (char *filename, uint64_t base_pa, uint64_t base_va); | |
1023 | ||
1024 | extern void schizo_ext_init (uint64_t , uint64_t); | |
1025 | ||
1026 | static int load_ui_cmd (void*, int argc, char **argv) | |
1027 | { | |
1028 | char *filename; | |
1029 | uint64_t base_pa, addr, size, seg_size; | |
1030 | uint64_t base_va; | |
1031 | int ret, zero_pad = 0, create_lbl = 0; | |
1032 | bool_t load_image = FALSE; | |
1033 | ||
1034 | if (mm1 == NULL) | |
1035 | { | |
1036 | ui->error("RAM object is not ready yet!\n"); | |
1037 | return 1; | |
1038 | } | |
1039 | ||
1040 | if (BLAZE_restore_from_checkpoint()) | |
1041 | { | |
1042 | // don't load the image again, it should be in mem dump already | |
1043 | if (argc>=2) | |
1044 | ui->error("<%s> image should be already in memory \n", argv[2]); | |
1045 | return 1; | |
1046 | } | |
1047 | ||
1048 | if ((argc == 3) && (strcmp(argv[1], "image") == NULL)) | |
1049 | { | |
1050 | load_image = TRUE; | |
1051 | if (mm1->load(argv[2]) !=0 ) | |
1052 | { | |
1053 | ui->error("Error in <%s> memory image\n ", argv[2]); | |
1054 | return 1; | |
1055 | } | |
1056 | else | |
1057 | { | |
1058 | return 1; | |
1059 | } | |
1060 | } | |
1061 | ||
1062 | // Format will be 'load bin file_name start_addr' | |
1063 | if ((argc == 4) && (strcmp(argv[1], "bin") == NULL)) | |
1064 | { | |
1065 | ret = sscanf (argv[3], "%llx", &addr); | |
1066 | if (mm1->load_bin(argv[2], addr) !=0 ) | |
1067 | { | |
1068 | ui->error("Error in <%s> bin image\n ", argv[2]); | |
1069 | return 1; | |
1070 | } | |
1071 | return 1; | |
1072 | } | |
1073 | ||
1074 | if (argc < 4) { | |
1075 | ui->error("check LOAD command format\n"); | |
1076 | return 1; | |
1077 | } | |
1078 | ||
1079 | ret = sscanf (argv[1], "%lli", &base_pa); | |
1080 | if (ret != 1) { | |
1081 | ui->error("check PA arg <%s>\n", argv[1]); | |
1082 | return 1; | |
1083 | } | |
1084 | ||
1085 | ret = sscanf (argv[3], "%lli", &base_va); | |
1086 | if (ret != 1) { | |
1087 | ui->error("check VA arg <%s>\n", argv[3]); | |
1088 | return 1; | |
1089 | } | |
1090 | ||
1091 | filename = (char*)malloc (strlen(argv[2]) + 16); | |
1092 | sscanf (argv[2], "%s", filename); | |
1093 | ||
1094 | load_elf64(filename, base_pa, base_va); | |
1095 | return 1; | |
1096 | ||
1097 | } | |
1098 | ||
1099 | ||
1100 | /////////////////////////////////////////////// | |
1101 | // | |
1102 | // FILE <filename> | |
1103 | // | |
1104 | ||
1105 | static int file_ui_cmd (void*, int argc, char **argv) | |
1106 | { | |
1107 | if (argc != 2) { | |
1108 | ui->error("UI (file): format error"); | |
1109 | return 1; | |
1110 | } | |
1111 | ||
1112 | FILE* fp = fopen(argv[1],"r"); | |
1113 | if (!fp) { | |
1114 | ui->error("Can't open <%s>", argv[1]); | |
1115 | return 1; | |
1116 | } | |
1117 | ||
1118 | char line[max_cmd_length]; | |
1119 | ||
1120 | while (fgets(line,max_cmd_length,fp)) | |
1121 | exec_cmd(line); | |
1122 | ||
1123 | fclose(fp); | |
1124 | ||
1125 | return 0; | |
1126 | } | |
1127 | ||
1128 | ||
1129 | /////////////////////////////////////////////// | |
1130 | // | |
1131 | // CONF <name> <value> | |
1132 | // | |
1133 | // | |
1134 | ||
1135 | extern void complete_cfg (); | |
1136 | extern uint8_t get_platform_index (char *s); | |
1137 | ||
1138 | static void print_new_cpi () | |
1139 | { | |
1140 | if (g_vcpu[0] != NULL) | |
1141 | { | |
1142 | for (int i=0; i<=g_vcpu_id_max; i++) | |
1143 | { | |
1144 | Vcpu *vcpu = get_vcpu(i); | |
1145 | if (!vcpu) | |
1146 | continue; | |
1147 | ||
1148 | vcpu->config.cpi = ((double)(vcpu->config.stickincr)) * (vcpu->config.cpufreq) | |
1149 | / (vcpu->config.loopticks) / (vcpu->config.stickfreq); | |
1150 | ui->output("%s new cpi (=stinc*cpufq/ltick/sysfq) = %6.3f\n", | |
1151 | vcpu->config.name, vcpu->config.cpi); | |
1152 | } | |
1153 | } | |
1154 | } | |
1155 | ||
1156 | ||
1157 | static int conf_ui_cmd (void*, int argc, char **argv) | |
1158 | { | |
1159 | uint8_t idx_to_plist; | |
1160 | char s[max_cmd_length]; | |
1161 | uint64_t pa; | |
1162 | char *default_s = (char*)"sun4u"; | |
1163 | ||
1164 | static bool numcores_initialized = FALSE; | |
1165 | static bool numcpus_initialized = FALSE; | |
1166 | ||
1167 | if (argc == 1) | |
1168 | { | |
1169 | if (the_arch.cmp_mode) { | |
1170 | ui->output("CMP mode: %s\n", the_arch.cmp_mode?"true":"false"); | |
1171 | ui->output("Number of cores: %d\n", the_arch.numcores); | |
1172 | ui->output("CPUs per core: %d\n", the_arch.cpus_per_core); | |
1173 | } | |
1174 | #if defined (CHPLUS_OBP) || defined(CHPLUS) || defined(CHEETAH_OBP) || defined(CHEETAH) | |
1175 | ui->output("mmutype: %s\n", the_arch.mmutype); | |
1176 | ui->output("flags: 0x%x \n", the_arch.arch_flags); | |
1177 | #endif | |
1178 | ui->output("numcpu: %d \n", the_arch.numcpus); | |
1179 | ui->output("ramsize: 0x%llx bytes (%lld MB) \n", | |
1180 | the_arch.ramsize, the_arch.ramsize >> 20); | |
1181 | ui->output("cpu per thread: %d\n", the_arch.cpus_per_thread); | |
1182 | if (the_arch.umips == the_arch.mips && the_arch.kmips == the_arch.mips) | |
1183 | ui->output("mips: %lld\n\n", the_arch.mips); | |
1184 | else | |
1185 | ui->output("umips: %lld\n" | |
1186 | "kmips: %lld\n\n", the_arch.umips, the_arch.kmips); | |
1187 | ui->output("cpufreq: %llu\n", the_arch.cpu_freq); | |
1188 | ui->output("stickfreq: %llu\n", the_arch.stick_freq); | |
1189 | ||
1190 | ui->output("conf numthreads = %d\n", the_arch.numthreads); | |
1191 | ui->output("conf roundrobin = %d\n", the_arch.roundrobin); | |
1192 | } | |
1193 | else if (strcmp (argv[1], "ramsize") == NULL) | |
1194 | { | |
1195 | if (argc == 2) | |
1196 | { | |
1197 | ui->output ("ramsize: 0x%llx bytes (%lld MB) \n", | |
1198 | the_arch.ramsize, the_arch.ramsize >> 20); | |
1199 | return 1; | |
1200 | } | |
1201 | char *mfile_name = NULL; | |
1202 | if (argc > 2) | |
1203 | { | |
1204 | char *p; | |
1205 | uint64_t lval = strtoll (argv[2], &p, 0); | |
1206 | if (*p == 'K') | |
1207 | lval <<= 10; | |
1208 | if (*p == 'M') | |
1209 | lval <<= 20; | |
1210 | the_arch.ramsize = lval; | |
1211 | the_arch.ramsizeS = (char*)strdup(argv[2]); | |
1212 | } | |
1213 | ||
1214 | if ((argc > 3) && !BLAZE_restore_from_checkpoint()) | |
1215 | { | |
1216 | mfile_name = argv[3]; | |
1217 | } | |
1218 | ||
1219 | // mem object is global for entire system | |
1220 | if (mm1) | |
1221 | { | |
1222 | ui->error("RAM object is already created !!"); | |
1223 | return 0; | |
1224 | } | |
1225 | else | |
1226 | { | |
1227 | mm1 = new SMemory (the_arch.ramsize); | |
1228 | } | |
1229 | ||
1230 | if ( !mm1 || !mm1->init(mfile_name) ) | |
1231 | { | |
1232 | ui->error("cannot allocate mem object size of %llx\n",the_arch.ramsize ); | |
1233 | quit_simulation(); | |
1234 | } | |
1235 | ||
1236 | if (!BLAZE_restore_from_checkpoint()) | |
1237 | { | |
1238 | pa = 0x1c; | |
1239 | LO_W(pa) &= ~7; | |
1240 | #ifdef V5_FAKEPROM | |
1241 | memwrite64s_nl(mm1, pa, the_arch.ramsize); | |
1242 | #endif | |
1243 | } | |
1244 | the_arch.arch_flags |= FA_RAMSIZE; | |
1245 | // TO DO: why do we need these flags? | |
1246 | the_arch.arch_flags |= FA_STICKINCR|FA_TLBSIZE|FA_PLATFORM; | |
1247 | ||
1248 | } | |
1249 | #ifdef MEMORY_SEGMENTED | |
1250 | else if (strcmp (argv[1], "memseg") == NULL) | |
1251 | { | |
1252 | assert(argc >= 5 && argc <= 6); | |
1253 | char *mfile_name = NULL; | |
1254 | const char * name = argv[2]; | |
1255 | uint64_t base = strtoll(argv[3],0,0); | |
1256 | uint64_t size; | |
1257 | { | |
1258 | char *p; | |
1259 | char q[128]; | |
1260 | size = strtoll (argv[4], &p, 0); | |
1261 | if (*p == 'K') | |
1262 | size <<= 10; | |
1263 | if (*p == 'M') | |
1264 | size <<= 20; | |
1265 | the_arch.ramsize += size; | |
1266 | the_arch.ramsizeS = strdup(ulltostr(the_arch.ramsize,q)); | |
1267 | } | |
1268 | ||
1269 | if ((argc > 5) && !BLAZE_restore_from_checkpoint()) | |
1270 | { | |
1271 | mfile_name = argv[5]; | |
1272 | } | |
1273 | ||
1274 | if(!mm1) | |
1275 | mm1 = new SMemory (); | |
1276 | if (!mm1->addMem(name,base,size,mfile_name) ) | |
1277 | { | |
1278 | ui->error("memseg: cannot allocate mem object size of %llx\n",size ); | |
1279 | quit_simulation(); | |
1280 | } | |
1281 | if (!BLAZE_restore_from_checkpoint()) | |
1282 | { | |
1283 | pa = 0x1c; | |
1284 | LO_W(pa) &= ~7; | |
1285 | #ifdef V5_FAKEPROM | |
1286 | memwrite64s_nl(mm1, pa, the_arch.ramsize); | |
1287 | #endif | |
1288 | } | |
1289 | the_arch.arch_flags |= FA_RAMSIZE; | |
1290 | // TO DO: why do we need these flags? | |
1291 | the_arch.arch_flags |= FA_STICKINCR|FA_TLBSIZE|FA_PLATFORM; | |
1292 | ||
1293 | } | |
1294 | #endif | |
1295 | else if (strcmp(argv[1], "mips") == 0) | |
1296 | { | |
1297 | if (argc > 2) { | |
1298 | sscanf (argv[2], "%lld", &the_arch.mips); | |
1299 | the_arch.kmips = the_arch.mips; | |
1300 | the_arch.umips = the_arch.mips; | |
1301 | } | |
1302 | else { | |
1303 | if (the_arch.umips == the_arch.kmips) | |
1304 | ui->output("mips: %lld\n\n", the_arch.umips); | |
1305 | else | |
1306 | ui->output("kmips: %lld, umips: %lld\n\n", | |
1307 | the_arch.kmips, the_arch.umips); | |
1308 | } | |
1309 | } | |
1310 | else if (strcmp(argv[1], "kmips") == 0) | |
1311 | { | |
1312 | if (argc > 2) | |
1313 | sscanf (argv[2], "%lld", &the_arch.kmips); | |
1314 | ui->output("conf kmips = %lld\n", the_arch.kmips); | |
1315 | } | |
1316 | else if (strcmp(argv[1], "umips") == 0) | |
1317 | { | |
1318 | if (argc > 2) | |
1319 | sscanf (argv[2], "%lld", &the_arch.umips); | |
1320 | ui->output("conf umips = %lld\n", the_arch.umips); | |
1321 | } | |
1322 | else if (strcmp(argv[1], "cmips") == 0) | |
1323 | { | |
1324 | if (argc > 2) | |
1325 | sscanf (argv[2], "%lld", &the_arch_cmips); | |
1326 | if (argc > 3) | |
1327 | sscanf (argv[3], "%d", &the_arch_ccntx); | |
1328 | if (the_arch_ccntx) | |
1329 | ui->output("conf cmips = %lld for context %d\n", | |
1330 | the_arch_cmips, the_arch_ccntx); | |
1331 | else | |
1332 | ui->output("conf cmips is ineffective when context is zero\n"); | |
1333 | } | |
1334 | ||
1335 | else if (strcmp (argv[1], "cpu_per_thread") == 0) | |
1336 | { | |
1337 | if (argc > 2) { | |
1338 | sscanf (argv[2], "%d", &the_arch.cpus_per_thread); | |
1339 | cpu_enable_changed = true; | |
1340 | if (g_nvcpu) | |
1341 | the_arch.numthreads = g_nvcpu / the_arch.cpus_per_thread; | |
1342 | } | |
1343 | if (g_nvcpu) { | |
1344 | ui->output ("conf cpu_per_thread = %d (numthreads = %d)\n", | |
1345 | the_arch.cpus_per_thread, the_arch.numthreads); | |
1346 | } else | |
1347 | ui->output ("conf cpu_per_thread = %d\n", the_arch.cpus_per_thread); | |
1348 | } | |
1349 | else if (strcmp (argv[1], "numthreads") == 0) | |
1350 | { | |
1351 | if (argc > 2) { | |
1352 | sscanf (argv[2], "%d", &the_arch.numthreads); | |
1353 | cpu_enable_changed = true; | |
1354 | if (g_nvcpu) | |
1355 | the_arch.cpus_per_thread = g_nvcpu / the_arch.numthreads; | |
1356 | } | |
1357 | if (g_nvcpu) { | |
1358 | ui->output ("conf numthreads = %d (cpu_per_thread = %d)\n", | |
1359 | the_arch.numthreads, the_arch.cpus_per_thread); | |
1360 | } else | |
1361 | ui->output ("conf numthreads = %d\n", the_arch.numthreads); | |
1362 | } | |
1363 | ||
1364 | ||
1365 | ||
1366 | ||
1367 | ||
1368 | else if (strcmp (argv[1], "roundrobin") == 0) | |
1369 | { | |
1370 | if (argc > 2) | |
1371 | sscanf (argv[2], "%d", &the_arch.roundrobin); | |
1372 | ui->output ("conf roundrobin = %d\n", the_arch.roundrobin); | |
1373 | } | |
1374 | ||
1375 | ||
1376 | ||
1377 | ||
1378 | ||
1379 | else if (argc == 4) | |
1380 | { | |
1381 | uint32_t id, ret; | |
1382 | double fv; | |
1383 | float ffv; | |
1384 | #if defined (CHPLUS_OBP) || defined(CHPLUS) || defined(CHEETAH_OBP) || defined(CHEETAH) | |
1385 | if (strcmp (argv[1], "loopticks") == NULL) | |
1386 | { | |
1387 | ui->warning("loopticks has been dpecrecated. Use conf mips\n"); | |
1388 | Vcpu *vcpu = get_vcpu_by_name ( argv[3] ); | |
1389 | if (vcpu != NULL) | |
1390 | { | |
1391 | int temp; | |
1392 | sscanf (argv[2], "%i", &temp); | |
1393 | if (temp >= vcpu->config.stickincr) | |
1394 | { | |
1395 | vcpu->config.loopticks = temp; | |
1396 | print_new_cpi (); | |
1397 | } | |
1398 | else | |
1399 | { | |
1400 | ui->error("Ignored: loopticks >= stickincr, limitation\n"); | |
1401 | } | |
1402 | } | |
1403 | else | |
1404 | { | |
1405 | ui->error("Ignored: unknow cpu instance. \n"); | |
1406 | } | |
1407 | } | |
1408 | else if (strcmp (argv[1], "stickincr") == NULL) | |
1409 | { | |
1410 | ui->warning("stickincr has been dpecrecated. Use conf mips\n"); | |
1411 | Vcpu *vcpu = get_vcpu_by_name ( argv[3] ); | |
1412 | if (vcpu != NULL) | |
1413 | { | |
1414 | int temp; | |
1415 | sscanf (argv[2], "%i", &temp ); | |
1416 | vcpu->config.stickincr = temp; | |
1417 | print_new_cpi (); | |
1418 | } | |
1419 | else | |
1420 | { | |
1421 | ui->error("Ignored: unknow cpu instance. \n"); | |
1422 | } | |
1423 | ||
1424 | } | |
1425 | else if (strcmp(argv[1], "cpi") == NULL) | |
1426 | { | |
1427 | // conf cpi N xx.xx | |
1428 | ||
1429 | ui->error("SAM-GTSync doesn't support cpi feature \n"); | |
1430 | if (g_vcpu[0] == NULL) | |
1431 | { | |
1432 | ui->error("conf cpi: move this line to be after cpu is created.\n"); | |
1433 | exit (1); | |
1434 | } | |
1435 | ret = sscanf (argv[2], "%i", &id); | |
1436 | if ( (ret != 1) ) | |
1437 | { | |
1438 | ui->error("wrong cpu id argument <%s>\n", argv[2]); | |
1439 | return 0; | |
1440 | } | |
1441 | Vcpu * vcpu = get_vcpu(id); | |
1442 | if(!vcpu){ | |
1443 | ui->error("wrong cpu id argument <%s>\n", argv[2]); | |
1444 | return 0; | |
1445 | } | |
1446 | ret = sscanf (argv[3], "%f", &ffv); | |
1447 | fv = ffv; | |
1448 | if (ret != 1) | |
1449 | { | |
1450 | ui->error("wrong cpi argument <%s>\n", argv[3]); | |
1451 | return 0; | |
1452 | } | |
1453 | ui->output("cpu%d cpi=%f \n", id, fv); | |
1454 | ||
1455 | vcpu->config.cpi = fv; | |
1456 | the_arch.cpi = TRUE; | |
1457 | ||
1458 | } | |
1459 | else | |
1460 | { | |
1461 | ui->error("Ignored: wrong parameter\n"); | |
1462 | } | |
1463 | #endif | |
1464 | } | |
1465 | else if (argc == 3) | |
1466 | { | |
1467 | // TO DO: why do we need these flags? | |
1468 | the_arch.arch_flags |= FA_STICKINCR|FA_TLBSIZE|FA_PLATFORM; | |
1469 | ||
1470 | ||
1471 | // | |
1472 | // TODO : some of these arguments should be written into thw memory after | |
1473 | // LOAD fakeprom ufsboot | |
1474 | // Not necessarily. All these arguments should be put into 0 page | |
1475 | // so it can be done right in instant way | |
1476 | ||
1477 | if (strcmp (argv[1], "numcores") == NULL) | |
1478 | { | |
1479 | int rv = sscanf(argv[2], "%i", &the_arch.numcores); | |
1480 | if (rv != 1 || !the_arch.numcores) | |
1481 | { | |
1482 | ui->error("conf command: invalid arg %s\n", argv[2]); | |
1483 | exit(1); | |
1484 | } | |
1485 | the_arch.cmp_mode = true; | |
1486 | if (numcpus_initialized) | |
1487 | { | |
1488 | the_arch.cpus_per_core = the_arch.numcpus/the_arch.numcores; | |
1489 | // assume divisible | |
1490 | if (the_arch.numcpus % the_arch.numcores) | |
1491 | { | |
1492 | ui->error("numcpus %d not divisible by numcores %d\n", the_arch.numcpus, the_arch.numcores); | |
1493 | exit(1); | |
1494 | } | |
1495 | } | |
1496 | numcores_initialized = TRUE; | |
1497 | } | |
1498 | else if (strcmp (argv[1], "numcpu") == NULL) | |
1499 | { | |
1500 | sscanf (argv[2], "%i", &the_arch.numcpus); | |
1501 | ||
1502 | pa = 0x14; | |
1503 | LO_W(pa) &= ~3; | |
1504 | #ifdef V5_FAKEPROM | |
1505 | memwrite32u_nl(mm1, pa, the_arch.numcpus); | |
1506 | #endif | |
1507 | ||
1508 | the_arch.arch_flags |= FA_NCPU; | |
1509 | if (numcores_initialized) | |
1510 | { | |
1511 | the_arch.cpus_per_core = the_arch.numcpus/the_arch.numcores; | |
1512 | // assume divisible | |
1513 | if (the_arch.numcpus % the_arch.numcores) | |
1514 | { | |
1515 | ui->error("numcpus %d not divisible by numcores %d\n", the_arch.numcpus, the_arch.numcores); | |
1516 | exit(1); | |
1517 | } | |
1518 | } | |
1519 | numcpus_initialized = TRUE; | |
1520 | ||
1521 | } | |
1522 | else if (strcmp (argv[1], "nwins") == NULL) | |
1523 | { | |
1524 | sscanf (argv[2], "%i", &the_arch.nwins); | |
1525 | the_arch.arch_flags |= FA_NWINS; | |
1526 | } | |
1527 | else if (strcmp (argv[1], "mmutype") == NULL) | |
1528 | { | |
1529 | sscanf (argv[2], "%s", s); | |
1530 | the_arch.mmutype = (char*)strdup(s); | |
1531 | the_arch.arch_flags |= FA_MMUTYPE; | |
1532 | } | |
1533 | else if (strcmp (argv[1], "cputype") == NULL) | |
1534 | { | |
1535 | sscanf (argv[2], "%s", s); | |
1536 | the_arch.mmutype = (char*)strdup(s); | |
1537 | the_arch.arch_flags |= FA_MMUTYPE; | |
1538 | } | |
1539 | else if (strcmp (argv[1], "tlbsize") == NULL) | |
1540 | { | |
1541 | sscanf (argv[2], "%i", &the_arch.tlbsize); | |
1542 | the_arch.arch_flags |= FA_TLBSIZE; | |
1543 | } | |
1544 | #if defined (CHPLUS_OBP) || defined(CHPLUS) || defined(CHEETAH_OBP) || defined(CHEETAH) | |
1545 | else if (strcmp (argv[1], "loopticks") == NULL) | |
1546 | { | |
1547 | ui->warning("loopticks has been dpecrecated in favor of mips\n"); | |
1548 | ||
1549 | int temp; | |
1550 | sscanf (argv[2], "%i", &temp); | |
1551 | ||
1552 | // set loopticks for all vcpu's | |
1553 | if (g_vcpu[0] != NULL) | |
1554 | { | |
1555 | if (temp >= the_arch.stickincr) | |
1556 | { | |
1557 | for (int i=0; i<=g_vcpu_id_max; i++) | |
1558 | { | |
1559 | Vcpu *vcpu = get_vcpu(i); | |
1560 | if (!vcpu) | |
1561 | continue; | |
1562 | vcpu->config.loopticks = temp; | |
1563 | } | |
1564 | ||
1565 | the_arch.loopticks = temp; | |
1566 | the_arch.loopticks_cp = the_arch.loopticks; | |
1567 | ||
1568 | print_new_cpi (); | |
1569 | } else { | |
1570 | ui->error("Ignored: loopticks >= stickincr, limitation\n"); | |
1571 | } | |
1572 | } | |
1573 | } | |
1574 | else if (strcmp (argv[1], "stickincr") == NULL) | |
1575 | { | |
1576 | ui->warning("stickincr has been dpecrecated in favor of mips\n"); | |
1577 | ||
1578 | int temp; | |
1579 | sscanf (argv[2], "%i", &temp); | |
1580 | ||
1581 | // set stickincr for all vcpu's | |
1582 | if (g_vcpu[0] != NULL) | |
1583 | { | |
1584 | for (int i=0; i<=g_vcpu_id_max; i++) | |
1585 | { | |
1586 | Vcpu *vcpu = get_vcpu(i); | |
1587 | if (!vcpu) | |
1588 | continue; | |
1589 | vcpu->config.stickincr = temp; | |
1590 | } | |
1591 | ||
1592 | the_arch.stickincr = temp; | |
1593 | ||
1594 | print_new_cpi (); | |
1595 | } | |
1596 | } | |
1597 | #endif | |
1598 | else if (strcmp (argv[1], "cpufreq") == NULL) | |
1599 | { | |
1600 | if ((the_arch.arch_flags & FA_FREQ) == 0) | |
1601 | { | |
1602 | sscanf (argv[2], "%llu", &the_arch.cpu_freq); | |
1603 | pa = 0x24; | |
1604 | LO_W(pa) &= ~7; | |
1605 | #ifdef V5_FAKEPROM | |
1606 | memwrite64s_nl(mm1, pa, the_arch.cpu_freq); | |
1607 | #endif | |
1608 | the_arch.arch_flags |= FA_FREQ; | |
1609 | print_new_cpi (); | |
1610 | } | |
1611 | else | |
1612 | { | |
1613 | ui->error("cannot change cpufreq \n"); | |
1614 | } | |
1615 | } | |
1616 | else if (strcmp (argv[1], "stickfreq") == NULL) | |
1617 | { | |
1618 | if ((the_arch.arch_flags & FA_SFREQ) == 0) | |
1619 | { | |
1620 | sscanf (argv[2], "%llu", &the_arch.stick_freq); | |
1621 | pa = 0x28; | |
1622 | LO_W(pa) &= ~7; | |
1623 | #ifdef V5_FAKEPROM | |
1624 | memwrite64s_nl(mm1, pa, the_arch.stick_freq); | |
1625 | #endif | |
1626 | the_arch.arch_flags |= FA_SFREQ; | |
1627 | print_new_cpi (); | |
1628 | } | |
1629 | else | |
1630 | { | |
1631 | // allow end user to change the stick freq. The reason | |
1632 | // this may be useful is when we want to reach a particular | |
1633 | // simulation state fast. Higher stick frequency(than what is | |
1634 | // known to Solaris) would result in time moving faster from | |
1635 | // Solaris's perspective, making timeouts faster. Another | |
1636 | // sideeffect would be that CPI would change by a factor | |
1637 | // of sam_stick/solaris_stick. | |
1638 | ui->warning("changing stickfreq \n" | |
1639 | "stick freq in simulated Solaris(prtconf -pv), should be same as in SAM\n" | |
1640 | "cpi observed from Solaris will change to old_cpi*sam_stickfreq/sol_stickfreq\n"); | |
1641 | sscanf (argv[2], "%llu", &the_arch.stick_freq); | |
1642 | for(int i = 0; i <= g_vcpu_id_max; i++) | |
1643 | { | |
1644 | Vcpu *vcpu = get_vcpu(i); | |
1645 | if (!vcpu) | |
1646 | continue; | |
1647 | ||
1648 | vcpu->config.stickfreq = the_arch.stick_freq; | |
1649 | } | |
1650 | } | |
1651 | } | |
1652 | else if (strcmp (argv[1], "skipmp") == NULL) | |
1653 | { | |
1654 | ui->warning("skipmp has been dpecrecated. Value will be ignored \n"); | |
1655 | sscanf (argv[2], "%i", &the_arch.skip_mp); | |
1656 | } | |
1657 | else if (strcmp (argv[1], "blockmp") == NULL) | |
1658 | { | |
1659 | ui->warning("blockmp has been dpecrecated. Value will be ignored \n"); | |
1660 | sscanf (argv[2], "%i", &the_arch.block_mp); | |
1661 | } | |
1662 | #ifdef V5_FAKEPROM | |
1663 | else if (strcmp (argv[1], "platform") == NULL) | |
1664 | { | |
1665 | sscanf (argv[2], "%s", s); | |
1666 | the_arch.platform= (char *) strdup(s); | |
1667 | // convert platform to index to pass down to fakeprom | |
1668 | idx_to_plist = get_platform_index(the_arch.platform); | |
1669 | pa = 0x30; | |
1670 | memwrite8u_nl(mm1, pa, idx_to_plist); | |
1671 | the_arch.arch_flags |= FA_PLATFORM; | |
1672 | } | |
1673 | #endif | |
1674 | ||
1675 | #ifdef V5_FAKEPROM | |
1676 | else if (strcmp (argv[1], "bootpath") == NULL) | |
1677 | { | |
1678 | strcpy (bootpath, argv[2]); | |
1679 | int boot_aid,boot_dev,boot_bus; | |
1680 | char boot_part[3]; | |
1681 | boot_disk_id = 0; //lun of scsi disk. always 0. | |
1682 | // boot_ctrl_id set from parse_arg on sysconf scsi line | |
1683 | // fakeprom doesn;t need it. | |
1684 | // boot path is of this form - /pci@aid,[6|7]00000/scsi@dev/disk@targ,lun:slice | |
1685 | int result = sscanf(argv[2], "/pci@%x,%d/scsi@%d/disk@%x,0:%s", | |
1686 | &boot_aid,&boot_bus, &boot_dev, &boot_target_id, boot_part); | |
1687 | if (result != 5) { | |
1688 | ui->error("unknown parameter <%s> for boot path", argv[2]); | |
1689 | exit(1); | |
1690 | } | |
1691 | boot_bus = (boot_bus == 7000000) ? 1:0; | |
1692 | boot_part_id = boot_part[0] - 'a'; | |
1693 | // the pa used below comes from struct fkparam in fakeprom.h | |
1694 | pa = 0x33; | |
1695 | memwrite8u_nl(mm1, pa, (uint8_t)boot_dev);//pci device number of scsi hba on sysconf line | |
1696 | pa = 0x34; | |
1697 | memwrite8u_nl(mm1, pa, (uint8_t)boot_target_id);//scsi disk target id, specified from scsidisk.init | |
1698 | pa = 0x35; | |
1699 | memwrite8u_nl(mm1, pa, (uint8_t)boot_part_id);//parition id of scsi disk, from scsidisk.init | |
1700 | pa = 0x36; | |
1701 | memwrite8u_nl(mm1, pa, (uint8_t)boot_disk_id);//lun of scsi disk. always 0 for our supported disks, redundant info currently | |
1702 | pa = 0x4a; | |
1703 | memwrite8u_nl(mm1, pa, (uint8_t)boot_aid);//aid of schizo, to which scsi hba connects to | |
1704 | pa = 0x4b; | |
1705 | memwrite8u_nl(mm1, pa, (uint8_t)boot_bus);//busA=0 busB=1. to help fakeprom decide whether boot path prefix is | |
1706 | // pci@<aid>,600000 or pci@<aid>,700000 | |
1707 | } | |
1708 | #endif | |
1709 | else if (strcmp (argv[1], "DC") == NULL) | |
1710 | { | |
1711 | sscanf (argv[2], "%i", &the_arch.numDCs); | |
1712 | ui->output("%d DC on board \n", the_arch.numDCs); | |
1713 | } | |
1714 | else if (strcmp (argv[1], "NIC") == NULL) | |
1715 | { | |
1716 | sscanf (argv[2], "%i", &the_arch.numNICs); | |
1717 | pa = 0x48; | |
1718 | #ifdef V5_FAKEPROM | |
1719 | memwrite8u_nl(mm1, pa, the_arch.numNICs); | |
1720 | #endif | |
1721 | } | |
1722 | else if (strcmp (argv[2], "done") == NULL) | |
1723 | { | |
1724 | if (strcmp (argv[1], "cpu") == NULL) { | |
1725 | ui->error("unknown parameter <%s> ", argv[1]); | |
1726 | return 1; | |
1727 | } | |
1728 | } | |
1729 | else | |
1730 | { | |
1731 | ui->error("unknown parameter <%s> ", argv[1]); | |
1732 | } | |
1733 | ||
1734 | } /*end-if-argc*/ | |
1735 | ||
1736 | if (the_arch.platform == NULL) | |
1737 | // set the_arch.platform to sun4u as default | |
1738 | the_arch.platform = strdup(default_s); | |
1739 | ||
1740 | return 1; | |
1741 | } | |
1742 | ||
1743 | ||
1744 | /* | |
1745 | * instrumentation to see if simulator U/K sync-intervals ratio matches | |
1746 | * the actual U/K instructions ratio. | |
1747 | * also calculates the simulated mips using simulated time (stick-interrupts). | |
1748 | */ | |
1749 | ||
1750 | static int mips_ui_cmd (void*, int argc, char **argv) | |
1751 | { | |
1752 | int ncpus = SYSTEM_get_ncpu(), n = 0; | |
1753 | int64_t instrs, Uinstrs, Kinstrs; | |
1754 | int64_t intervals, Uintervals, Kintervals; | |
1755 | int64_t stIntrpts; | |
1756 | ||
1757 | ui->output("\n"); | |
1758 | ||
1759 | ||
1760 | // total instructions simulated, all cpus | |
1761 | // | |
1762 | Uinstrs = atomic_and_64 (& WorkerThread::u_instrs, 0); | |
1763 | Kinstrs = atomic_and_64 (& WorkerThread::k_instrs, 0); | |
1764 | instrs = Uinstrs + Kinstrs; | |
1765 | if (instrs == 0) | |
1766 | ui->output("instructions: %12d\n", 0); | |
1767 | else | |
1768 | ui->output( | |
1769 | "instructions: %12lld, %12lld-Usr, %12lld-Ker; (%d/%d)\n", | |
1770 | (Uinstrs+Kinstrs)/ncpus, Uinstrs/ncpus, Kinstrs/ncpus, | |
1771 | (int)((Uinstrs*100+50)/instrs), | |
1772 | (int)((Kinstrs*100+50)/instrs)); | |
1773 | ||
1774 | ||
1775 | // total 1-usec time sync intervals, all cpus | |
1776 | // | |
1777 | Uintervals = atomic_and_64 (& WorkerThread::u_intervals, 0); | |
1778 | Kintervals = atomic_and_64 (& WorkerThread::k_intervals, 0); | |
1779 | intervals = Uintervals + Kintervals; | |
1780 | if (intervals == 0) | |
1781 | ui->output("sync-intervals: %12d\n", 0); | |
1782 | else | |
1783 | ui->output( | |
1784 | "sync-intervals: %12lld, %12lld-Usr, %12lld-Ker; (%d/%d)\n", | |
1785 | intervals/ncpus, Uintervals/ncpus, Kintervals/ncpus, | |
1786 | (int)((Uintervals*100+50)/intervals), | |
1787 | (int)((Kintervals*100+50)/intervals)); | |
1788 | ||
1789 | ||
1790 | // average per-cpu mips, in simulated time not wall clock time | |
1791 | // | |
1792 | if (intervals == 0) | |
1793 | ui->output("effective-mips: %12d\n", 0); | |
1794 | else | |
1795 | ui->output("effective-mips: %12lld\n", | |
1796 | instrs / intervals); | |
1797 | ||
1798 | ||
1799 | ui->output("\n"); | |
1800 | return 1; | |
1801 | } | |
1802 | ||
1803 | ||
1804 | // this function is called by: | |
1805 | // fc_mod.cc | |
1806 | // scsi_mod.cc | |
1807 | // | |
1808 | uint8_t send_diskinfo_to_fakeprom() | |
1809 | { | |
1810 | uint64_t pa; | |
1811 | #ifdef V5_FAKEPROM | |
1812 | pa = 0x31; | |
1813 | memwrite8u_nl(mm1, pa, (uint8_t)SYSTEM_get_scsi_disk_enable_flag() | |
1814 | | (uint8_t)SYSTEM_get_fc_disk_enable_flag() <<1); | |
1815 | ||
1816 | pa = 0x32; | |
1817 | memwrite8u_nl(mm1, pa, (uint8_t)SYSTEM_get_scsi_boot_enable_flag() | |
1818 | | (uint8_t)SYSTEM_get_fc_boot_enable_flag() <<1); | |
1819 | ||
1820 | pa = 0x49; | |
1821 | memwrite8u_nl(mm1, pa, (uint8_t)SYSTEM_get_ce_enable_flag()); | |
1822 | #endif | |
1823 | return 0; | |
1824 | } | |
1825 | ||
1826 | ||
1827 | // added for platform support, to pass down to fakeprom | |
1828 | const char *os_platform_lists[] = { // fakeprom must have the same table | |
1829 | "sun4u", // default settting | |
1830 | "FJSV,GPUU", | |
1831 | "NATE,s-Note_737S", | |
1832 | "NATE,s-Note_747S", | |
1833 | "NATE,s-Note_777S", | |
1834 | "sun4u", | |
1835 | "SUNW,Netra-T12", | |
1836 | "SUNW,Netra-T4", | |
1837 | "SUNW,Sun-Blade-100", | |
1838 | "SUNW,Sun-Blade-1000", | |
1839 | "SUNW,Sun-Fire", | |
1840 | "SUNW,Sun-Fire-15000", | |
1841 | "SUNW,Sun-Fire-280R", | |
1842 | "SUNW,Sun-Fire-480R", | |
1843 | "SUNW,Sun-Fire-880", | |
1844 | "SUNW,Ultra-1", | |
1845 | "SUNW,Ultra-1-Engine", | |
1846 | "SUNW,Ultra-2", | |
1847 | "SUNW,Ultra-250", | |
1848 | "SUNW,Ultra-30", | |
1849 | "SUNW,Ultra-4", | |
1850 | "SUNW,Ultra-5_10", | |
1851 | "SUNW,Ultra-60", | |
1852 | "SUNW,Ultra-80", | |
1853 | "SUNW,UltraAX-e", | |
1854 | "SUNW,UltraAX-e2", | |
1855 | "SUNW,UltraAX-i2", | |
1856 | "SUNW,UltraAX-MP", | |
1857 | "SUNW,Ultra-Enterprise", | |
1858 | "SUNW,Ultra-Enterprise-10000", | |
1859 | "SUNW,UltraSPARCengine_CP-20", | |
1860 | "SUNW,UltraSPARCengine_CP-40", | |
1861 | "SUNW,UltraSPARCengine_CP-60", | |
1862 | "SUNW,Sun-Fire-V440", | |
1863 | "nomore", // no found | |
1864 | }; | |
1865 | ||
1866 | uint8_t get_platform_index(char *s) | |
1867 | { | |
1868 | int retval = 0; | |
1869 | while (strcmp (s, os_platform_lists[retval]) != NULL) { | |
1870 | if (strcmp (os_platform_lists[retval], "nomore") == NULL) | |
1871 | return 0; // if not found, set to default "sun4u" | |
1872 | retval++; | |
1873 | } | |
1874 | ||
1875 | return retval; | |
1876 | } | |
1877 | ||
1878 | ||
1879 | /////////////////////////////////////////////// | |
1880 | // | |
1881 | // WRITE <> <> | |
1882 | // | |
1883 | static int write_ui_cmd (void*, int argc, char **argv) | |
1884 | { | |
1885 | uint64_t paddr, value; | |
1886 | int ret; | |
1887 | ||
1888 | if (argc != 4) { | |
1889 | ui->error("Check command format"); | |
1890 | return(0); | |
1891 | } | |
1892 | ||
1893 | ret = sscanf (argv[2], "%lli", &paddr); | |
1894 | if (ret != 1) { | |
1895 | ui->error("wrong address"); | |
1896 | return 0; | |
1897 | } | |
1898 | ret = sscanf (argv[3], "%lli", &value); | |
1899 | if (ret != 1) { | |
1900 | ui->error("wrong value"); | |
1901 | return 0; | |
1902 | } | |
1903 | ||
1904 | if (mm1 == NULL) { | |
1905 | ui->error("RAM object is not ready yet!"); | |
1906 | return 0; | |
1907 | } | |
1908 | ||
1909 | if (strcmp(argv[1], "word") == 0) { | |
1910 | LO_W(paddr) &= ~3; | |
1911 | memwrite32u_nl(mm1, paddr, value); | |
1912 | } else if (strcmp(argv[1], "lword") == 0) { | |
1913 | LO_W(paddr) &= ~7; | |
1914 | memwrite64s_nl(mm1, paddr, value); | |
1915 | } else if (strcmp(argv[1], "hword") == 0) { | |
1916 | LO_W(paddr) &= ~1; | |
1917 | memwrite16u_nl(mm1, paddr, value); | |
1918 | } else if (strcmp(argv[1], "byte") == 0) { | |
1919 | memwrite8u_nl(mm1, paddr, value); | |
1920 | } else { | |
1921 | ui->error("wrong format (size)"); | |
1922 | return 0; | |
1923 | } | |
1924 | return 1; | |
1925 | } | |
1926 | ||
1927 | ||
1928 | /////////////////////////////////////////////// | |
1929 | // | |
1930 | // CONSOLE SEND "string" | |
1931 | // | |
1932 | //typedef void (*serial_send)(void *, char *); | |
1933 | ||
1934 | extern serialInterface * systemConsole; | |
1935 | ||
1936 | #ifdef V5_FAKEPROM | |
1937 | int static cs_ui_cmd (void*, int argc, char **argv) | |
1938 | { | |
1939 | char *str = NULL; | |
1940 | if (argc < 2) { | |
1941 | ui->error("command format error!\n"); | |
1942 | return 0; | |
1943 | } | |
1944 | ||
1945 | if(systemConsole == 0){ | |
1946 | ui->error("system console not yet initialized\n"); | |
1947 | return 0; | |
1948 | } | |
1949 | ||
1950 | str = extract_string(argv[1]); | |
1951 | ||
1952 | systemConsole->chars_send(str,systemConsole->portH); | |
1953 | free(str); | |
1954 | return 1; | |
1955 | } | |
1956 | #endif | |
1957 | ||
1958 | ||
1959 | /////////////////////////////////////////////// | |
1960 | // | |
1961 | // RDT <filename> # redirect stdout | |
1962 | // | |
1963 | // | |
1964 | /*static?*/ int rdt_ui_cmd (void*, int argc, char **argv) | |
1965 | { | |
1966 | ||
1967 | if (argc == 1) { | |
1968 | // redirect back (FILE->stdout) | |
1969 | redirect_back (); | |
1970 | } | |
1971 | else if (argc == 2) { | |
1972 | FILE * fp = fopen (argv[1], "w"); | |
1973 | if (fp == NULL) { | |
1974 | ui->perror (argv[1]); | |
1975 | return 0; | |
1976 | } | |
1977 | if (redirect_stdout (fileno(fp))) { | |
1978 | ui->output("STDOUT redirected to <%s>\n", argv[1]); | |
1979 | } | |
1980 | } | |
1981 | else { | |
1982 | ui->error("wrong RDT command format\n"); | |
1983 | } | |
1984 | return 1; | |
1985 | } | |
1986 | ||
1987 | ||
1988 | /////////////////////////////////////////////// | |
1989 | // | |
1990 | // ON STOP <string> | |
1991 | // | |
1992 | /*static?*/ int on_ui_cmd (void*, int argc, char **argv) | |
1993 | { | |
1994 | if (argc <= 2) { | |
1995 | ui->error("wrong format ON command\n"); | |
1996 | return 0; | |
1997 | } | |
1998 | if (strcmp(argv[1], "stop") == NULL) { | |
1999 | int ii, len = 0; | |
2000 | char * str; | |
2001 | for (ii = 2; ii < argc; ii++) { | |
2002 | len += (int)strlen(argv[ii]); | |
2003 | } | |
2004 | len += argc + 4; // just in case :-) | |
2005 | str = (char*) malloc (len); | |
2006 | strcpy(str, argv[2]); | |
2007 | strcat(str, " "); | |
2008 | for (ii = 3; ii < argc; ii++) { | |
2009 | strcat(str, " "); | |
2010 | strcat (str, argv[ii]); | |
2011 | } | |
2012 | ||
2013 | if (strcmp(argv[2], "discard") == NULL) { | |
2014 | Ui_blcmd *pcmd = pui_misc->stop_list, *next; | |
2015 | for (;pcmd;) { | |
2016 | next = pcmd->next; | |
2017 | free (pcmd->cmd_str); | |
2018 | free ((char*)pcmd); | |
2019 | pui_misc->stop_list = pcmd = next; | |
2020 | } | |
2021 | return 1; | |
2022 | } | |
2023 | ||
2024 | add_to_stop_list (str); | |
2025 | } | |
2026 | return 1; | |
2027 | } | |
2028 | ||
2029 | ||
2030 | /////////////////////////////////////////////// | |
2031 | // | |
2032 | // SETREG <reg> <value> | |
2033 | // | |
2034 | int static setreg_ui_cmd (void*, int argc, char **argv) | |
2035 | { | |
2036 | ||
2037 | uint64_t value; | |
2038 | int ret; | |
2039 | ||
2040 | if (argc < 3) { | |
2041 | ui->error("wrong number of arguments : %d\n", argc); | |
2042 | return 0; | |
2043 | } | |
2044 | ||
2045 | if (g_vcpu[0] == NULL) { | |
2046 | ui->error("Move this line to be after CPU is created ...\n"); | |
2047 | exit (1); | |
2048 | } | |
2049 | ||
2050 | if (argc == 3) { | |
2051 | ret = sscanf (argv[2], "%lli", &value); | |
2052 | if (ret != 1) { | |
2053 | ui->error("wrong VALUE argument <%s>\n", argv[2]); | |
2054 | return 0; | |
2055 | } | |
2056 | ||
2057 | if (strcmp(argv[1], "pc") == NULL) { | |
2058 | ||
2059 | for (uint32_t id = 0; id <= g_vcpu_id_max; id++) { | |
2060 | Vcpu *vcpu = get_vcpu(id); | |
2061 | if (!vcpu) continue; | |
2062 | g_vcpu[id]->set_reg(VCPU_ASR_PC, value); | |
2063 | } | |
2064 | ||
2065 | } | |
2066 | else if (strcmp(argv[1], "npc") == NULL) { | |
2067 | ||
2068 | for (uint32_t id = 0; id <= g_vcpu_id_max; id++) { | |
2069 | Vcpu *vcpu = get_vcpu(id); | |
2070 | if (!vcpu) continue; | |
2071 | g_vcpu[id]->set_reg(VCPU_ASR_NPC, value); | |
2072 | } | |
2073 | } | |
2074 | else { | |
2075 | ui->error("unsupported register <%s>\n", argv[1]); | |
2076 | return 0; | |
2077 | } | |
2078 | } | |
2079 | else if (argc == 4) { | |
2080 | uint32_t id ; | |
2081 | Vcpu * vcpu = 0; | |
2082 | ret = sscanf (argv[1], "%i", &id); | |
2083 | if ( ret != 1 ) { | |
2084 | ui->error("wrong cpu id argument <%s>\n", argv[2]); | |
2085 | return 0; | |
2086 | } | |
2087 | vcpu = get_vcpu(id); | |
2088 | if(!vcpu){ | |
2089 | ui->error("wrong cpu id argument <%s>\n", argv[2]); | |
2090 | return 0; | |
2091 | } | |
2092 | ret = sscanf (argv[3], "%lli", &value); | |
2093 | if (ret != 1) { | |
2094 | ui->error("wrong value argument <%s>\n", argv[3]); | |
2095 | return 0; | |
2096 | } | |
2097 | ||
2098 | if (strcmp(argv[2], "pc") == NULL) { | |
2099 | vcpu->set_reg(VCPU_ASR_PC, value); | |
2100 | } | |
2101 | else if (strcmp(argv[2], "npc") == NULL) { | |
2102 | vcpu->set_reg(VCPU_ASR_NPC, value); | |
2103 | ||
2104 | } | |
2105 | else { | |
2106 | ui->error("unknown reg NAME <%s>\n", argv[2]); | |
2107 | return 0; | |
2108 | } | |
2109 | } | |
2110 | return 1; | |
2111 | } | |
2112 | ||
2113 | ||
2114 | /////////////////////////////////////////////// | |
2115 | // | |
2116 | // ALIAS <newname> <cmd> | |
2117 | // | |
2118 | int static alias_ui_cmd (void*, int argc, char **argv) | |
2119 | { | |
2120 | if (argc == 1) { | |
2121 | ||
2122 | Ui_cmd *pcmd = NULL; | |
2123 | for (pcmd = &ui_cmd_list[0]; pcmd;pcmd = pcmd->next) { | |
2124 | if (pcmd->flags & FUI_ALIAS) { | |
2125 | ui->output("<%s> --> ", pcmd->name); | |
2126 | for (int32_t ndx = 0; ndx < pcmd->alias_argc; ++ndx) | |
2127 | ui->output("%s ", pcmd->alias_argv[ndx]); | |
2128 | ui->output("\n"); | |
2129 | } | |
2130 | } | |
2131 | return 1; | |
2132 | } | |
2133 | else if (argc == 2){ | |
2134 | Ui_cmd *pcmd = NULL; | |
2135 | for (pcmd = &ui_cmd_list[0]; pcmd;pcmd = pcmd->next) { | |
2136 | if (strcmp(argv[1], pcmd->name) == NULL) | |
2137 | break; | |
2138 | } | |
2139 | ||
2140 | if (pcmd == NULL) { | |
2141 | ui->error("command <%s> not found \n", argv[1]); | |
2142 | return 0; | |
2143 | } | |
2144 | ||
2145 | if (!(pcmd->flags & FUI_ALIAS)) { | |
2146 | ui->error("command <%s> is not an alias \n", argv[1]); | |
2147 | return 0; | |
2148 | } | |
2149 | ||
2150 | ui->output("<%s> --> ", pcmd->name); | |
2151 | for (int32_t ndx = 0; ndx < pcmd->alias_argc; ++ndx) | |
2152 | ui->output("%s ", pcmd->alias_argv[ndx]); | |
2153 | ui->output("\n"); | |
2154 | return 1; | |
2155 | } | |
2156 | ||
2157 | // handle "alias new old ..." | |
2158 | ||
2159 | // limit aliases to C-style identifiers i.e. alphanumeric and '_'; | |
2160 | // no leading digits | |
2161 | ||
2162 | char* const alias_name = argv[1]; | |
2163 | for (int ndx = 0; alias_name[ndx] != '\0'; ++ndx) { | |
2164 | if (!isalpha(alias_name[ndx]) && alias_name[ndx] != '_') { | |
2165 | if (ndx == 0 || !isdigit(alias_name[ndx])) { | |
2166 | ui->error("illegal alias name <%s>\n", alias_name); | |
2167 | return 0; | |
2168 | } | |
2169 | } | |
2170 | } | |
2171 | ||
2172 | Ui_cmd *pcmd = NULL; | |
2173 | Ui_cmd *prev_cmd = NULL; | |
2174 | for (pcmd = &ui_cmd_list[0]; | |
2175 | pcmd; | |
2176 | prev_cmd = pcmd, pcmd = pcmd->next) { | |
2177 | if (strcmp(alias_name, pcmd->name) == NULL) { | |
2178 | if ((pcmd->flags & FUI_ALIAS) == 0) | |
2179 | { | |
2180 | ui->error("command <%s> cannot be aliased\n", alias_name); | |
2181 | return 0; | |
2182 | } | |
2183 | free((void*)pcmd->name); | |
2184 | free((void*)pcmd->help); | |
2185 | while (pcmd->alias_argc) | |
2186 | free((void*)pcmd->alias_argv[pcmd->alias_argc--]); | |
2187 | free((void*)pcmd->alias_argv); | |
2188 | prev_cmd->next = pcmd->next; | |
2189 | break; | |
2190 | } | |
2191 | } | |
2192 | ||
2193 | if (pcmd == NULL) | |
2194 | pcmd = (Ui_cmd*) calloc (1, sizeof(Ui_cmd)); | |
2195 | ||
2196 | if (pcmd == NULL) { | |
2197 | ui->error("register: cant malloc\n"); | |
2198 | return 0; | |
2199 | } | |
2200 | pcmd->name = (char*) strdup(alias_name); | |
2201 | char buf[1000]; | |
2202 | sprintf(buf, "alias for %s", pcmd->name); | |
2203 | pcmd->help = (char*) strdup(buf); | |
2204 | pcmd->cmd_exe_func = NULL; | |
2205 | pcmd->cmd_help_func = NULL; | |
2206 | pcmd->flags = FUI_ALIAS; | |
2207 | pcmd->alias_argc = argc - 2; | |
2208 | pcmd->alias_argv = | |
2209 | (const char**)malloc((argc-2) * sizeof(const char*)); | |
2210 | ||
2211 | if (pcmd->alias_argv == NULL) { | |
2212 | ui->error("register: cant malloc\n"); | |
2213 | return 0; | |
2214 | } | |
2215 | ||
2216 | for (int ndx = 0; ndx < argc - 2; ++ndx) | |
2217 | { | |
2218 | pcmd->alias_argv[ndx] = strdup(argv[ndx + 2]); | |
2219 | if (pcmd->alias_argv[ndx] == NULL) { | |
2220 | ui->error("register: cant strdup %x\n", argv[ndx + 2]); | |
2221 | return 0; | |
2222 | } | |
2223 | } | |
2224 | ||
2225 | Ui_cmd* pc = &ui_cmd_list[0]; | |
2226 | for ( ;pc->next; pc = pc->next) | |
2227 | ; | |
2228 | pc->next = pcmd; | |
2229 | ||
2230 | return 1; | |
2231 | } | |
2232 | ||
2233 | ||
2234 | /////////////////////////////////////////////// | |
2235 | // | |
2236 | // UNALIAS <cmd> | |
2237 | // | |
2238 | int static unalias_ui_cmd (void*, int argc, char **argv) | |
2239 | { | |
2240 | if (argc == 2) { | |
2241 | ||
2242 | Ui_cmd *pcmd = NULL; | |
2243 | Ui_cmd *prev_cmd = NULL; | |
2244 | for (pcmd = &ui_cmd_list[0]; | |
2245 | pcmd; | |
2246 | prev_cmd = pcmd, pcmd = pcmd->next) { | |
2247 | if (strcmp(argv[1], pcmd->name) == NULL) { | |
2248 | if ((pcmd->flags & FUI_ALIAS) == 0) | |
2249 | { | |
2250 | ui->error("command <%s> cannot be aliased\n", argv[1]); | |
2251 | return 0; | |
2252 | } | |
2253 | free((void*)pcmd->name); | |
2254 | free((void*)pcmd->help); | |
2255 | while (pcmd->alias_argc) | |
2256 | free((void*)pcmd->alias_argv[pcmd->alias_argc--]); | |
2257 | free((void*)pcmd->alias_argv); | |
2258 | prev_cmd->next = pcmd->next; | |
2259 | free(pcmd); | |
2260 | return 1; | |
2261 | } | |
2262 | } | |
2263 | ||
2264 | ui->error("cannot find alias <%s>\n", | |
2265 | argv[1]); | |
2266 | return 0; | |
2267 | } | |
2268 | ||
2269 | ui->error("usage: unalias <alias cmd>\n"); | |
2270 | return 0; | |
2271 | } | |
2272 | ||
2273 | ||
2274 | /////////////////////////////////////////////// | |
2275 | // | |
2276 | // MIPS [#|off] # compute blaze MIPS | |
2277 | // | |
2278 | // | |
2279 | ||
2280 | static int | |
2281 | perf_ui_cmd (void*, int argc, char**argv) | |
2282 | { | |
2283 | float tmp; | |
2284 | ||
2285 | if ((argc == 2 && strcmp (argv[1], "off") == 0) || argc == 1) { | |
2286 | perf_ui_interval = 0; | |
2287 | return 1; | |
2288 | } | |
2289 | if (argc == 2 && sscanf (argv[1], "%f", &tmp) == 1) { | |
2290 | perf_ui_interval = tmp * 1000000000; /* cvt to nano-secs for hr time*/ | |
2291 | perf_ui_start = gethrtime(); | |
2292 | next_perf_ui_time = perf_ui_start + perf_ui_interval; | |
2293 | last_perf_globaltick = SYSTEM_get_ticks (); | |
2294 | return 1; | |
2295 | } | |
2296 | ||
2297 | ui->error("usage : perf # | off \n"); | |
2298 | return 1; | |
2299 | } | |
2300 | ||
2301 | ||
2302 | /////////////////////////////////////////////// | |
2303 | // | |
2304 | // DEBUG, and OPTION settings | |
2305 | // | |
2306 | ||
2307 | int static debug_ui_cmd (void*, int argc, char **argv) | |
2308 | { | |
2309 | if (argc == 2) { | |
2310 | blaze_debug = strtoul((const char*)argv[1], (char**)NULL, 0); | |
2311 | } | |
2312 | ui->output("blaze_debug = %d \n", blaze_debug); | |
2313 | return 1; | |
2314 | } | |
2315 | ||
2316 | int static option_ui_cmd (void*, int argc, char **argv) | |
2317 | { | |
2318 | if (argc == 2) { | |
2319 | blaze_option = strtoul((const char*)argv[1], (char**)NULL, 0); | |
2320 | } | |
2321 | ui->output("blaze_option = %d \n", blaze_option); | |
2322 | return 1; | |
2323 | } | |
2324 | ||
2325 | ||
2326 | /////////////////////////////////////////////// | |
2327 | // | |
2328 | // VERSION | |
2329 | // | |
2330 | int static version_ui_cmd (void*, int argc, char **argv) | |
2331 | { | |
2332 | ui->output("SAM VERSION %s\n", BLAZEVERSION_STRING); | |
2333 | ui->output("BUILT ON %s, AT %s, IN %s\n", __DATE__,__TIME__,__CWD__); | |
2334 | return 1; | |
2335 | } | |
2336 | ||
2337 | ||
2338 | /////////////////////////////////////////////// | |
2339 | // | |
2340 | // HELP | |
2341 | // | |
2342 | int static help_ui_cmd (void*, int argc, char **argv) | |
2343 | { | |
2344 | ||
2345 | Ui_cmd *pcmd; | |
2346 | if (argc == 1) { | |
2347 | ui->output("SAM now supports UI commands: \n\n"); | |
2348 | for (pcmd = &ui_cmd_list[0]; pcmd; pcmd = pcmd->next) { | |
2349 | if (pcmd->flags & FUI_INVALID) | |
2350 | continue; | |
2351 | ui->output("%s\n", pcmd->name); | |
2352 | } | |
2353 | return 1; | |
2354 | } | |
2355 | ||
2356 | if (strcmp(argv[1], "all") == NULL) { | |
2357 | for (pcmd = &ui_cmd_list[0]; pcmd; pcmd = pcmd->next) { | |
2358 | if (pcmd->flags & FUI_INVALID) | |
2359 | continue; | |
2360 | if (pcmd->help) | |
2361 | ui->output ("%s : %s\n", pcmd->name, pcmd->help); | |
2362 | } | |
2363 | return 1; | |
2364 | } | |
2365 | ||
2366 | for (pcmd = &ui_cmd_list[0]; pcmd; pcmd = pcmd->next) { | |
2367 | if (pcmd->flags & FUI_INVALID) | |
2368 | continue; | |
2369 | if (strcmp(pcmd->name, argv[1]) == NULL) { | |
2370 | if (pcmd->help) { | |
2371 | ui->output("%s\n", pcmd->help); | |
2372 | break; | |
2373 | } | |
2374 | } | |
2375 | } | |
2376 | return 1; | |
2377 | } | |
2378 | ||
2379 | ||
2380 | /////////////////////////////////////////////// | |
2381 | // The interface for UI commands | |
2382 | // | |
2383 | void UI_exec_cmd (char *cmd) | |
2384 | { | |
2385 | SYSTEM_lock_UI(); | |
2386 | ||
2387 | exec_cmd(cmd); | |
2388 | ||
2389 | SYSTEM_unlock_UI(); | |
2390 | } | |
2391 | ||
2392 | ||
2393 | /////////////////////////////////////////////// | |
2394 | ||
2395 | void store_stdout_fd (int fd) | |
2396 | { | |
2397 | pui_misc->redirect_fd = fd; | |
2398 | } | |
2399 | ||
2400 | /////////////////////////////////////////////// | |
2401 | ||
2402 | int get_stdout_fd() | |
2403 | { | |
2404 | return pui_misc->redirect_fd; | |
2405 | } | |
2406 | ||
2407 | /////////////////////////////////////////////// | |
2408 | ||
2409 | void add_to_stop_list (char * cmd_str) | |
2410 | { | |
2411 | Ui_blcmd *pcmd = (Ui_blcmd*) calloc (1, sizeof(Ui_blcmd)); | |
2412 | if (pcmd == NULL) { | |
2413 | ui->error("unable to deffer <%s> command \n", cmd_str); | |
2414 | return; | |
2415 | } | |
2416 | pcmd->cmd_str = cmd_str; | |
2417 | if (pui_misc->stop_list == NULL) { | |
2418 | pui_misc->stop_list = pcmd; | |
2419 | } | |
2420 | else { | |
2421 | Ui_blcmd *prev_cmd = pui_misc->stop_list; | |
2422 | while (prev_cmd->next != NULL) { | |
2423 | prev_cmd = prev_cmd->next; | |
2424 | } | |
2425 | prev_cmd->next = pcmd; | |
2426 | } | |
2427 | } | |
2428 | ||
2429 | ||
2430 | ||
2431 | /////////////////////////////////////////////// | |
2432 | // | |
2433 | // DISKDELAY ... | |
2434 | // | |
2435 | ||
2436 | uint64_t | |
2437 | get_disk_ddelay_start_cycle(void) | |
2438 | { | |
2439 | return ddelay_start_cycle; | |
2440 | } | |
2441 | ||
2442 | int | |
2443 | get_diskdelay(void) | |
2444 | { | |
2445 | return diskdelay; | |
2446 | } | |
2447 | ||
2448 | int | |
2449 | get_wrdiskdelay(void) | |
2450 | { | |
2451 | return wrdiskdelay; | |
2452 | } | |
2453 | static int diskdelay_ui_cmd (void*, int argc, char **argv) | |
2454 | { | |
2455 | if (argc > 1) { | |
2456 | ||
2457 | diskdelay = atoi((const char*)argv[1]); | |
2458 | wrdiskdelay = diskdelay; | |
2459 | ddelay_start_cycle = 0; | |
2460 | ||
2461 | if (strchr(argv[1], '/') != NULL) { | |
2462 | if (sscanf(argv[1], "%d/%d", &diskdelay, &wrdiskdelay) != 2) { | |
2463 | ui->error("diskdelay format error !\n"); | |
2464 | return 1; | |
2465 | } | |
2466 | } | |
2467 | if (argc > 2) { | |
2468 | ddelay_start_cycle = strtoul((const char*)argv[2], (char**)NULL, 0); | |
2469 | } else { | |
2470 | ddelay_start_cycle = SYSTEM_get_ticks (); | |
2471 | } | |
2472 | ui->output("DISK : ddelay = %d, wrddelay = %d, start_cycle = %lld\n", | |
2473 | diskdelay, wrdiskdelay, ddelay_start_cycle); | |
2474 | } | |
2475 | else if (argc == 1) { | |
2476 | ui->output("DISK : ddelay = %d, wrddelay = %d, start_cycle = %lld\n", | |
2477 | diskdelay, wrdiskdelay, ddelay_start_cycle); | |
2478 | } | |
2479 | return 0; | |
2480 | } | |
2481 | ||
2482 | ||
2483 | // ================================== SYNC-UI ================================= | |
2484 | // | |
2485 | // | |
2486 | ||
2487 | // volatile int sync_fd = -1; moved up above to ui-thread, | |
2488 | // volatile int sync_on = 0; ditto, | |
2489 | // along with stept_usecs, stept_seqnum, done_seqnum. | |
2490 | ||
2491 | ||
2492 | typedef volatile struct sync_s { | |
2493 | char *switchname; | |
2494 | } syncT; | |
2495 | static syncT sync_obj = {0}; | |
2496 | static volatile syncT * sync1 = &sync_obj; | |
2497 | ||
2498 | ||
2499 | static int sync_ui_cmd (void*, int argc, char **argv); | |
2500 | static void sync_ui_usage (); | |
2501 | static void sync_connect (syncT * msp, const char * switchname); | |
2502 | static void sync_disconnect (syncT * msp); | |
2503 | ||
2504 | ||
2505 | static void init_sync () | |
2506 | { | |
2507 | syncT * msp = sync1; | |
2508 | ||
2509 | // | |
2510 | // attempt an initial connection if a server name is specified | |
2511 | // | |
2512 | const char * name = SYSTEM_get_hostconfig ("sync.host"); | |
2513 | if (!name) name = SYSTEM_get_hostconfig ("switch.host"); | |
2514 | if (name) { | |
2515 | char buf[1024]; | |
2516 | sprintf (buf, "sync:%s", name); | |
2517 | ||
2518 | sync1->switchname = strdup (buf); | |
2519 | sync_fd = netsim_connect (sync1->switchname); | |
2520 | } | |
2521 | ||
2522 | sync1 = msp; | |
2523 | } | |
2524 | ||
2525 | ||
2526 | /* | |
2527 | * sync UI commands | |
2528 | * | |
2529 | */ | |
2530 | static int sync_ui_cmd (void*, int argc, char * argv[]) | |
2531 | { | |
2532 | syncT * msp = sync1; | |
2533 | ||
2534 | if (argc == 2 && strcmp (argv[1], "on") == 0) { // "sync on" <-- | |
2535 | ||
2536 | if (sync_on) { | |
2537 | ui->error("already in time-sync mode\n"); | |
2538 | } | |
2539 | else if (!IN_STOP_STATE (blaze_run_state)) { | |
2540 | ui->error("not in stop state, use stop command first\n"); | |
2541 | return 1; | |
2542 | } | |
2543 | ||
2544 | if (sync_fd == -1) { | |
2545 | ui->error("time-sync not connected\n"); | |
2546 | } else | |
2547 | write (sync_fd, "conn\n", 5); // Inform Sync-Master !! | |
2548 | ||
2549 | SYSTEM_syncon_UI (); // transition !!! | |
2550 | sync_on = 1; | |
2551 | ||
2552 | return 1; | |
2553 | } | |
2554 | ||
2555 | if (argc == 2 && strcmp (argv[1], "off") == 0) { // "sync off" <- | |
2556 | ||
2557 | ||
2558 | if (!sync_on) | |
2559 | { | |
2560 | ui->error("not in time-sync mode\n"); | |
2561 | // return 1; | |
2562 | } | |
2563 | ||
2564 | if (sync_fd == -1) { | |
2565 | ui->error("time-sync not connected\n"); | |
2566 | } else | |
2567 | write (sync_fd, "disconn\n", 8); // Inform Sync-Master !!! | |
2568 | ||
2569 | SYSTEM_syncoff_UI (); // transition !!! | |
2570 | sync_on = 0; | |
2571 | ||
2572 | return 1; | |
2573 | } | |
2574 | ||
2575 | ||
2576 | ||
2577 | // ------------------ remote connection state ---------------------- | |
2578 | ||
2579 | if (argc == 1 // "" | |
2580 | || (argc == 2 && strcmp (argv[1], "print") == 0)) { // "print" | |
2581 | ||
2582 | if (sync_fd != -1) { | |
2583 | ui->output("\tsync1: %s", msp->switchname); | |
2584 | if (stept_seqnum != -1) { | |
2585 | if (IN_GTSTEP_STATE(blaze_run_state)) | |
2586 | ui->output("\t %s, %lld *\n", | |
2587 | "gtstep", stept_seqnum); | |
2588 | else if (IN_GTWAIT_STATE(blaze_run_state)) | |
2589 | ui->output("\t %s, %lld \n", | |
2590 | "gtwait", done_seqnum); | |
2591 | else | |
2592 | ui->output("\t %s, %lld \n", | |
2593 | (sync_on ? "on" : "off"), done_seqnum); | |
2594 | } else | |
2595 | ui->output("\t %s \n", (sync_on ? "on" : "off")); | |
2596 | } else | |
2597 | ui->output("\tsync1: disconnected\n"); | |
2598 | return 1; | |
2599 | } | |
2600 | if (argc == 2 && strcmp (argv[1], "disconnect") == 0) { // "disconnect" | |
2601 | sync_disconnect (msp); | |
2602 | return 1; | |
2603 | } | |
2604 | if (argc == 2 && strcmp (argv[1], "connect") == 0) { // "connect" | |
2605 | sync_connect (msp, msp->switchname); | |
2606 | return 1; | |
2607 | } | |
2608 | if (argc == 3 && strcmp (argv[1], "connect") == 0) { // "connect host" | |
2609 | sync_connect (msp, argv[2]); | |
2610 | return 1; | |
2611 | } | |
2612 | ||
2613 | // --------------------------- stuff ---------------------------- | |
2614 | ||
2615 | if (argc >= 2 && strcmp (argv[1], "debug") == 0) { // "debug" | |
2616 | if (argc == 2) | |
2617 | ui->output("sync debug level is %d\n", SYNCDEBUG); | |
2618 | else | |
2619 | SYNCDEBUG = atoi (argv[2]); | |
2620 | return 1; | |
2621 | } | |
2622 | ||
2623 | sync_ui_usage (); /* if we haven't already returned... */ | |
2624 | return 1; | |
2625 | } | |
2626 | ||
2627 | ||
2628 | ||
2629 | // see also sync_thread_main for handling of disconnect by other end of socket | |
2630 | // | |
2631 | static void sync_disconnect (syncT * msp) | |
2632 | { | |
2633 | void * thd_status; | |
2634 | ||
2635 | if (sync_fd == -1) { | |
2636 | ui->error("sync already disconnected\n"); | |
2637 | return; | |
2638 | } | |
2639 | close (sync_fd); | |
2640 | sync_fd = -1; /* <--- ui-thread will see this <--- */ | |
2641 | sync_on = 0; | |
2642 | } | |
2643 | ||
2644 | ||
2645 | static void sync_connect (syncT * msp, const char * switchname) | |
2646 | { | |
2647 | int fd; | |
2648 | char buf[1024]; | |
2649 | ||
2650 | if (sync_fd != -1) { | |
2651 | ui->error("sync already connected\n"); | |
2652 | return; | |
2653 | } else if (switchname == NULL) { | |
2654 | ui->error("sync no switchname\n"); | |
2655 | return; | |
2656 | } | |
2657 | ||
2658 | if (SYNCDEBUG) | |
2659 | ui->output("sync reconnecting\n"); | |
2660 | ||
2661 | sprintf(buf,"sync:%s", switchname); | |
2662 | if ((fd = netsim_connect (buf)) >= 0) { | |
2663 | ||
2664 | sync_fd = fd; | |
2665 | sync_on = 0; | |
2666 | msp->switchname = strdup (switchname); | |
2667 | ||
2668 | } else { | |
2669 | ui->error("connection failed\n"); | |
2670 | } | |
2671 | } | |
2672 | ||
2673 | static void sync_ui_usage () | |
2674 | { | |
2675 | ui->output("usage: \n"); | |
2676 | ui->output(" sync on|off\n"); | |
2677 | ui->output(" sync connect [hostname[/portnum]]\n"); | |
2678 | ui->output(" sync disconnect\n"); | |
2679 | ui->output(" sync print|stats|reset|debug\n"); | |
2680 | } | |
2681 | ||
2682 | //////////////////////////////////////////////////////////////// | |
2683 | ||
2684 | class PenableDisableOptions : public CommandOptions | |
2685 | { | |
2686 | public: | |
2687 | ||
2688 | PenableDisableOptions(const std::string& cmd_) | |
2689 | : | |
2690 | cmd(cmd_), | |
2691 | cpu_opt(CpuSet().clear_all(), CpuOption::MULTITUDE) | |
2692 | { | |
2693 | add(cpu_opt); | |
2694 | } | |
2695 | ||
2696 | virtual ~PenableDisableOptions() {} | |
2697 | ||
2698 | std::string get_cmd() const { return cmd; } | |
2699 | ||
2700 | CpuOption cpu_opt; | |
2701 | ||
2702 | int usage() | |
2703 | { | |
2704 | std::string fmt = | |
2705 | "" + cmd + " command usage:\n" | |
2706 | "\t" + cmd + "\n" | |
2707 | "\t" + cmd + " -cpu <cpu set>\n" | |
2708 | "\t" + cmd + " <cpu mask>\n"; | |
2709 | ||
2710 | ui->error(fmt.c_str()); | |
2711 | return 1; | |
2712 | } | |
2713 | ||
2714 | private: | |
2715 | std::string cmd; | |
2716 | }; | |
2717 | ||
2718 | ||
2719 | ||
2720 | static int penable_disable_ui_cmd (void *, int argc, char **argv, | |
2721 | bool new_state, PenableDisableOptions& options) | |
2722 | { | |
2723 | int i; | |
2724 | Vcpu * vcpu = 0; | |
2725 | ||
2726 | if (argc == 1) { | |
2727 | for (i = 0; i < the_arch.numcpus; i++) | |
2728 | { | |
2729 | int sid = get_vcpu(i)->id(); | |
2730 | ui->output("cpuid %d %s\n", sid, cpu_enabled[sid] ? "enabled" : "disabled"); | |
2731 | } | |
2732 | return 1; | |
2733 | } | |
2734 | ||
2735 | CpuSet cpu_set; | |
2736 | std::vector<std::string> pos_args; | |
2737 | bool result = options.parse(argc-1, (const char**)&argv[1], pos_args); | |
2738 | if (result) { | |
2739 | if (options.cpu_opt.is_on()) { | |
2740 | if (!pos_args.empty()) { | |
2741 | options.usage(); | |
2742 | return 0; | |
2743 | } | |
2744 | cpu_set = options.cpu_opt.get_value(); | |
2745 | } | |
2746 | else { | |
2747 | if (pos_args.size() != 1) { | |
2748 | options.usage(); | |
2749 | return 0; | |
2750 | } | |
2751 | uint64_t cpu_mask; | |
2752 | std::string error_msg; | |
2753 | if (!UnsignedOption::parse_number(pos_args[0], cpu_mask, error_msg)) { | |
2754 | std::string fmt = "UI " + options.get_cmd() + ": Bad cpu mask: %s\n"; | |
2755 | ui->error(fmt.c_str(), pos_args[0].c_str()); | |
2756 | return 0; | |
2757 | } | |
2758 | bool out_of_bounds = false; | |
2759 | cpu_set.insert_mask(cpu_mask, &out_of_bounds); | |
2760 | if (out_of_bounds) | |
2761 | ui->warning("cpu mask (%s) out of range\n", | |
2762 | pos_args[0].c_str()); | |
2763 | } | |
2764 | ||
2765 | for (CpuSet::iterator iter = cpu_set.begin(); | |
2766 | iter != cpu_set.end(); | |
2767 | ++iter) { | |
2768 | i = *iter; | |
2769 | ||
2770 | if (get_vcpu(i) != NULL) | |
2771 | cpu_enabled[i] = new_state; | |
2772 | } | |
2773 | cpu_enable_changed = true; | |
2774 | return 1; | |
2775 | } | |
2776 | ||
2777 | std::string fmt = "UI " + options.get_cmd() + ": Syntax error\n\t%s\n"; | |
2778 | ui->error(fmt.c_str(),options.get_error_msg().c_str()); | |
2779 | return 0; | |
2780 | } | |
2781 | ||
2782 | static int penable_ui_cmd (void *, int argc, char **argv) | |
2783 | { | |
2784 | PenableDisableOptions options("penable"); | |
2785 | return penable_disable_ui_cmd(NULL, argc, argv, true, options); | |
2786 | } | |
2787 | ||
2788 | static int pdisable_ui_cmd (void *, int argc, char **argv) | |
2789 | { | |
2790 | PenableDisableOptions options("pdisable"); | |
2791 | return penable_disable_ui_cmd(NULL, argc, argv, false, options); | |
2792 | } | |
2793 | ||
2794 | ||
2795 | ||
2796 | ||
2797 | ////////////////////////////////////////////////////////////// | |
2798 | // | |
2799 | // | |
2800 | // | |
2801 | int static pty_display (void *, int argc, char **argv) | |
2802 | { | |
2803 | ||
2804 | if (pty_dev_a) | |
2805 | ui->output("SAM: Serial port A (pty device) for TIP connection is %s\n", pty_dev_a); | |
2806 | if (pty_dev_b) | |
2807 | ui->output("SAM: Serial port B (pty device) for TIP connection is %s\n", pty_dev_b); | |
2808 | if (pty_dev_c) | |
2809 | ui->output("SAM: Serial port C (pty device) for TIP connection is %s\n", pty_dev_c); | |
2810 | if (pty_dev_d) | |
2811 | ui->output("SAM: Serial port D (pty device) for TIP connection is %s\n", pty_dev_d); | |
2812 | ||
2813 | return (1); | |
2814 | } | |
2815 | ||
2816 | ||
2817 | ////////////////////////////////////////////////////////////// | |
2818 | // | |
2819 | // breakpoints | |
2820 | // | |
2821 | // command : | |
2822 | // | |
2823 | // break [?|cpu=[<cpu_id>|all]] | |
2824 | // [iaddr=<value>|opcode=<value>|data_read_addr=<value>|data_write_addr=<value>] | |
2825 | // [mask=<value>] | |
2826 | // | |
2827 | ||
2828 | int bp_action ( int bp_id, int vcpu_id ) | |
2829 | { | |
2830 | ui->output("cpu %i hit breakpoint %i, stop... \n", vcpu_id, bp_id ); | |
2831 | ||
2832 | // request simulation stop | |
2833 | BLAZE_STOP(blaze_stop_request); | |
2834 | ||
2835 | //sinal stop to remote debug client if any | |
2836 | update_remote_ui(); | |
2837 | return 0; | |
2838 | } | |
2839 | ||
2840 | ||
2841 | class BreakOptions : public CommandOptions | |
2842 | { | |
2843 | public: | |
2844 | ||
2845 | BreakOptions() | |
2846 | : | |
2847 | cpu_opt(CpuSet().insert_all(), CpuOption::MULTITUDE), | |
2848 | trap_opt("trap", 0), | |
2849 | red_opt("red") | |
2850 | { | |
2851 | add(cpu_opt); | |
2852 | add(trap_opt); | |
2853 | add(red_opt); | |
2854 | ||
2855 | // -trap qutiand -red are mutual exclusive | |
2856 | excl_opts.add(trap_opt).add(red_opt); | |
2857 | } | |
2858 | ||
2859 | virtual ~BreakOptions() {} | |
2860 | ||
2861 | CpuOption cpu_opt; | |
2862 | UnsignedOption trap_opt; | |
2863 | Option red_opt; | |
2864 | ||
2865 | static int usage() | |
2866 | { | |
2867 | ui->output("set breakpoint command usage:\n"); | |
2868 | ui->output("\tbreak\n"); | |
2869 | ui->output("\tbreak pc_va\n"); | |
2870 | ui->output("\tbreak pc_va cpu_id\n"); | |
2871 | ui->output("\tbreak -cpu [cpu_id|all] pc_va\n"); | |
2872 | ui->output("\tbreak -cpu [cpu_id|all] -trap trap_type\n"); | |
2873 | ui->output("\tbreak -cpu [cpu_id|all] -red\n"); | |
2874 | return 1; | |
2875 | } | |
2876 | ||
2877 | private: | |
2878 | ||
2879 | ExclusiveOptions excl_opts; | |
2880 | }; | |
2881 | ||
2882 | int break_ui_cmd (void*, int argc, char **argv) | |
2883 | { | |
2884 | if (!IN_STOP_STATE (blaze_run_state)) | |
2885 | { | |
2886 | ui->error("not in stop state, use stop command first\n"); | |
2887 | return 1; | |
2888 | } | |
2889 | ||
2890 | BreakOptions options; | |
2891 | ||
2892 | std::vector<std::string> pos_args; | |
2893 | bool result = options.parse(argc-1, (const char**)&argv[1], pos_args); | |
2894 | if (result) | |
2895 | { | |
2896 | CpuSet cpu_set = options.cpu_opt.get_value(); | |
2897 | ||
2898 | int bp_id; | |
2899 | uint64_t bp_value; | |
2900 | VCPU_BpType bp_type; | |
2901 | uint64_t bp_mask; | |
2902 | ||
2903 | if (argc == 1) | |
2904 | { | |
2905 | // break | |
2906 | // printout all existing breakpoints | |
2907 | for (int i=0; i<=g_vcpu_id_max; i++) | |
2908 | { | |
2909 | if (g_vcpu[i]) | |
2910 | { | |
2911 | g_vcpu[i]->print_breakpoints(ui->get_output_file()); | |
2912 | if (ui->get_log_file()) | |
2913 | g_vcpu[i]->print_breakpoints(ui->get_log_file()); | |
2914 | } | |
2915 | } | |
2916 | return 0; | |
2917 | } | |
2918 | // break on trap | |
2919 | // break -cpu [cpu_id|all] -trap trap_type | |
2920 | if (options.trap_opt.is_on()) | |
2921 | { | |
2922 | if (pos_args.size() == 0) | |
2923 | { | |
2924 | bp_type = VCPU_BP_TRAP; | |
2925 | bp_value = options.trap_opt.get_value(); | |
2926 | } | |
2927 | else | |
2928 | { | |
2929 | ui->error("break on trap does not take any arguments\n"); | |
2930 | return 1; | |
2931 | } | |
2932 | } | |
2933 | // break on red state | |
2934 | // break -cpu [cpu_id|all] -red | |
2935 | else if (options.red_opt.is_on()) | |
2936 | { | |
2937 | if (pos_args.size() == 0) | |
2938 | bp_type = VCPU_BP_RED; | |
2939 | else | |
2940 | { | |
2941 | ui->error("break on red does not take arguments\n"); | |
2942 | return 1; | |
2943 | } | |
2944 | } | |
2945 | else if (options.cpu_opt.is_on()) | |
2946 | { | |
2947 | // break on pc | |
2948 | // break -cpu [cpu_id|all] pc_va | |
2949 | bp_type = VCPU_BP_INSTR_ADDR; | |
2950 | if (pos_args.size() > 0) | |
2951 | { | |
2952 | std::string error_msg; | |
2953 | if (!UnsignedOption::parse_number(pos_args[0], bp_value, error_msg)) | |
2954 | { | |
2955 | error_msg += "pc-value"; | |
2956 | ui->error("%s\n", error_msg.c_str()); | |
2957 | return 1; | |
2958 | } | |
2959 | } | |
2960 | else | |
2961 | { | |
2962 | ui->error("break on PC requires a PC value\n"); | |
2963 | return 1; | |
2964 | } | |
2965 | } | |
2966 | else | |
2967 | { | |
2968 | // break pc_va | |
2969 | // break pc_va [cpu_id] | |
2970 | bp_type = VCPU_BP_INSTR_ADDR; | |
2971 | if (pos_args.size() >= 1) | |
2972 | { | |
2973 | // set on all valid cpus | |
2974 | std::string error_msg; | |
2975 | if (!UnsignedOption::parse_number(pos_args[0], bp_value, error_msg)) | |
2976 | { | |
2977 | error_msg += "pc-value"; | |
2978 | ui->error("%s\n", error_msg.c_str()); | |
2979 | return 1; | |
2980 | } | |
2981 | } | |
2982 | if (pos_args.size() == 2) | |
2983 | { | |
2984 | // set on the specified cpu | |
2985 | uint64_t cpu_id; | |
2986 | std::string error_msg; | |
2987 | if (!UnsignedOption::parse_number(pos_args[1], cpu_id, error_msg)) | |
2988 | { | |
2989 | error_msg += "cpu-id"; | |
2990 | ui->error("%s\n", error_msg.c_str()); | |
2991 | return 1; | |
2992 | } | |
2993 | bool out_of_bounds = false; | |
2994 | cpu_set.clear_all(); | |
2995 | cpu_set.insert(cpu_id, &out_of_bounds); | |
2996 | if (out_of_bounds) | |
2997 | { | |
2998 | ui->error("Cpu number %d is out of range\n", cpu_id); | |
2999 | return 1; | |
3000 | } | |
3001 | } | |
3002 | } | |
3003 | // set breakpoints on all valid cpus | |
3004 | for (CpuSet::iterator iter = cpu_set.begin(); | |
3005 | iter != cpu_set.end(); | |
3006 | ++iter) | |
3007 | { | |
3008 | uint32_t i = *iter; | |
3009 | if (i > g_vcpu_id_max) | |
3010 | { | |
3011 | ui->fatal("internal error: break_ui_cmd: cpu 0x%lx out of range\n",i); | |
3012 | exit(-1); | |
3013 | } | |
3014 | if (g_vcpu[i] && | |
3015 | g_vcpu[i]->set_breakpoint(&bp_id, bp_type, bp_value, | |
3016 | bp_action, bp_mask )== 0) | |
3017 | ui->output("set breakpoint %i, for cpu %i \n", bp_id, g_vcpu[i]->id()); | |
3018 | } | |
3019 | return 0; | |
3020 | } | |
3021 | else | |
3022 | { | |
3023 | ui->error("break command parsing failed: %s\n", | |
3024 | options.get_error_msg().c_str()); | |
3025 | return 1; | |
3026 | } | |
3027 | } | |
3028 | ||
3029 | int break_ui_cmd_OLD (void*, int argc, char **argv) | |
3030 | { | |
3031 | ||
3032 | ||
3033 | int cpu_all = false; | |
3034 | int cpu_id = -1; | |
3035 | Vcpu * vcpu = 0; | |
3036 | ||
3037 | int bp_id; | |
3038 | uint64_t bp_value; | |
3039 | VCPU_BpType bp_type; | |
3040 | uint64_t bp_mask; | |
3041 | ||
3042 | char *name; | |
3043 | char *param; | |
3044 | ||
3045 | if (!IN_STOP_STATE (blaze_run_state)) | |
3046 | { | |
3047 | ui->error("not in stop state, use stop command first\n"); | |
3048 | return 0; | |
3049 | } | |
3050 | ||
3051 | ||
3052 | if ((argc < 2) || (argc > 4)) | |
3053 | return BreakOptions::usage(); | |
3054 | ||
3055 | if (strcmp(argv[1], "?")==0) // print info for all | |
3056 | { | |
3057 | // printout all existing breakpoints | |
3058 | for (int i=0; i<=g_vcpu_id_max; i++) | |
3059 | { | |
3060 | if (g_vcpu[i]) | |
3061 | { | |
3062 | g_vcpu[i]->print_breakpoints(ui->get_output_file()); | |
3063 | if (ui->get_log_file()) | |
3064 | g_vcpu[i]->print_breakpoints(ui->get_log_file()); | |
3065 | } | |
3066 | } | |
3067 | return 1; | |
3068 | } | |
3069 | ||
3070 | // read second argument as cpu=id | |
3071 | name = strtok ( argv[1], " =" ); | |
3072 | param = strtok ( NULL, "\0" ); | |
3073 | ||
3074 | if( !name || !param || (strcmp(name, "cpu") != 0) ) | |
3075 | { | |
3076 | ui->error("missing cpu id \n"); | |
3077 | return BreakOptions::usage(); | |
3078 | } | |
3079 | ||
3080 | if ( strcmp(param, "all") == 0) | |
3081 | { | |
3082 | cpu_all = true; | |
3083 | } | |
3084 | else | |
3085 | { | |
3086 | cpu_id = (int)strtol(param, NULL, 0); | |
3087 | ||
3088 | if ((cpu_id <0) || ( ( vcpu = get_vcpu(cpu_id) ) == 0) ) | |
3089 | { | |
3090 | ui->error("bad cpu id[%d] \n", cpu_id); | |
3091 | return BreakOptions::usage(); | |
3092 | } | |
3093 | } | |
3094 | ||
3095 | if (argc <3) | |
3096 | { | |
3097 | ui->error("incomplete list of breakpoint parameters \n"); | |
3098 | return BreakOptions::usage(); | |
3099 | } | |
3100 | ||
3101 | ||
3102 | // read third argument as <type=value> | |
3103 | name = strtok ( argv[2], " =" ); | |
3104 | param = strtok ( NULL, "\0" ); | |
3105 | ||
3106 | if (!name || !param) | |
3107 | { | |
3108 | ui->error("missing breakpoint type \n"); | |
3109 | return BreakOptions::usage(); | |
3110 | } | |
3111 | ||
3112 | bp_value = strtoull(param, NULL, 0); | |
3113 | ||
3114 | bp_type = VCPU_BP_INSTR_ADDR; | |
3115 | if (strcmp(name, "pc" ) == 0 ) bp_type = VCPU_BP_INSTR_ADDR; | |
3116 | else if (strcmp(name, "opcode") == 0 ) bp_type = VCPU_BP_OPCODE; | |
3117 | else if (strcmp(name, "dread" ) == 0 ) bp_type = VCPU_BP_DATA_READ_ADDR; | |
3118 | else if (strcmp(name, "dwrite") == 0 ) bp_type = VCPU_BP_DATA_WRITE_ADDR; | |
3119 | else | |
3120 | { | |
3121 | ui->error("breakpoint type should be: iaddr | opcode | data_read | data_write \n"); | |
3122 | return BreakOptions::usage(); | |
3123 | } | |
3124 | ||
3125 | bp_mask = ~uint64_t(0); | |
3126 | if (argc == 4) | |
3127 | { | |
3128 | // read bp mask | |
3129 | name = strtok ( argv[3], " =" ); | |
3130 | param = strtok ( NULL, "\0" ); | |
3131 | ||
3132 | if (!name || !param) | |
3133 | { | |
3134 | ui->error("missing breakpoint mask \n"); | |
3135 | return BreakOptions::usage(); | |
3136 | } | |
3137 | ||
3138 | bp_mask = strtoull(param, NULL, 0); | |
3139 | if (bp_mask ==0) | |
3140 | { | |
3141 | ui->error("incorrect breakpoint mask\n"); | |
3142 | return BreakOptions::usage(); | |
3143 | } | |
3144 | } | |
3145 | ||
3146 | // set the breakpoint | |
3147 | ||
3148 | if (cpu_all) | |
3149 | { | |
3150 | for (int i=0; i<=g_vcpu_id_max; i++) | |
3151 | { | |
3152 | if (g_vcpu[i] && | |
3153 | g_vcpu[i]->set_breakpoint(&bp_id, bp_type, bp_value, | |
3154 | bp_action, bp_mask )== 0) | |
3155 | { | |
3156 | ui->output("set breakpoint %i for cpu %i \n", bp_id, g_vcpu[i]->id()); | |
3157 | } | |
3158 | } | |
3159 | return 1; | |
3160 | } | |
3161 | else | |
3162 | { | |
3163 | if ( | |
3164 | vcpu->set_breakpoint(&bp_id, bp_type, bp_value, | |
3165 | bp_action, bp_mask )==0) | |
3166 | { | |
3167 | ui->output("set breakpoint %i for cpu %i \n", bp_id, cpu_id); | |
3168 | } | |
3169 | return 1; | |
3170 | } | |
3171 | ||
3172 | return BreakOptions::usage(); | |
3173 | } | |
3174 | ||
3175 | //////////////////////////////////////////////////// | |
3176 | // | |
3177 | // remove breakpoint | |
3178 | // | |
3179 | // command: dbreak cpu=[<cpu_id>|all] bp_id | |
3180 | // | |
3181 | ||
3182 | static int print_dbreak_usage() | |
3183 | { | |
3184 | ui->output("delete breakpoint command usage:\n dbreak cpu=[<cpu_id>|all]" | |
3185 | " [bp_id=<id>]\n"); | |
3186 | return 0; | |
3187 | } | |
3188 | ||
3189 | ||
3190 | int dbreak_ui_cmd (void*, int argc, char **argv) | |
3191 | { | |
3192 | int cpu_all = false; | |
3193 | int cpu_id = -1; | |
3194 | int bp_id = -1; | |
3195 | Vcpu * vcpu = 0; | |
3196 | ||
3197 | char *name; | |
3198 | char *param; | |
3199 | ||
3200 | ||
3201 | if (!IN_STOP_STATE (blaze_run_state)) | |
3202 | { | |
3203 | ui->error("not in stop state, use stop command first\n"); | |
3204 | return 0; | |
3205 | } | |
3206 | ||
3207 | if ( argc > 3) | |
3208 | return print_dbreak_usage(); | |
3209 | ||
3210 | if (argc == 1) | |
3211 | { | |
3212 | cpu_all = true; | |
3213 | } | |
3214 | ||
3215 | if (argc > 1) | |
3216 | { | |
3217 | // read second argument as cpu=id | |
3218 | name = strtok ( argv[1], " =" ); | |
3219 | param = strtok ( NULL, "\0" ); | |
3220 | ||
3221 | if( !name || !param || (strcmp(name, "cpu") != 0) ) | |
3222 | { | |
3223 | ui->error("break: missing cpu id \n"); | |
3224 | return print_dbreak_usage(); | |
3225 | } | |
3226 | ||
3227 | if ( strcmp(param, "all") == 0) | |
3228 | { | |
3229 | cpu_all = true; | |
3230 | } | |
3231 | else | |
3232 | { | |
3233 | cpu_id = (int)strtol(param, NULL, 0); | |
3234 | ||
3235 | if ((cpu_id <0) || ( ( vcpu = get_vcpu(cpu_id) ) == 0) ) | |
3236 | { | |
3237 | ui->error("bad cpu id[%d] \n", cpu_id); | |
3238 | return print_dbreak_usage(); | |
3239 | } | |
3240 | } | |
3241 | } | |
3242 | if (argc > 2) | |
3243 | { | |
3244 | // read bp id | |
3245 | name = strtok ( argv[2], " =" ); | |
3246 | param = strtok ( NULL, "\0" ); | |
3247 | ||
3248 | if (!name || !param || (strcmp(name, "bp_id") != 0)) | |
3249 | { | |
3250 | ui->error("missing breakpoint id \n"); | |
3251 | return print_dbreak_usage(); | |
3252 | } | |
3253 | ||
3254 | bp_id = strtol(param, NULL, 0); | |
3255 | ||
3256 | } | |
3257 | ||
3258 | // remove breakpoint | |
3259 | if (cpu_all) | |
3260 | { | |
3261 | for (int i=0; i<=g_vcpu_id_max; i++) | |
3262 | { | |
3263 | if (g_vcpu[i] && | |
3264 | g_vcpu[i]->delete_breakpoint(-1)== 0) | |
3265 | { | |
3266 | ui->output("delete breakpoint %i for cpu %i \n", bp_id, g_vcpu[i]->id()); | |
3267 | } | |
3268 | } | |
3269 | return 1; | |
3270 | } | |
3271 | else | |
3272 | { | |
3273 | if ( | |
3274 | vcpu->delete_breakpoint(bp_id)==0) | |
3275 | { | |
3276 | ui->output("delete breakpoint %i for cpu %i \n", bp_id, cpu_id); | |
3277 | } | |
3278 | return 1; | |
3279 | } | |
3280 | ||
3281 | } | |
3282 | ||
3283 | ||
3284 | //////////////////////////////////////////////////// | |
3285 | // | |
3286 | // Delete breakpoint | |
3287 | // | |
3288 | // command: delete [-all] [<bp_id> ... ] | |
3289 | // | |
3290 | ||
3291 | class DeleteOptions : public CommandOptions | |
3292 | { | |
3293 | public: | |
3294 | ||
3295 | DeleteOptions() | |
3296 | : | |
3297 | all_opt("all") | |
3298 | { | |
3299 | add(all_opt); | |
3300 | } | |
3301 | ||
3302 | virtual ~DeleteOptions() {} | |
3303 | ||
3304 | Option all_opt; | |
3305 | ||
3306 | static int usage() | |
3307 | { | |
3308 | ui->output("usage: delete [-all] [<bp_id> ... ]\n"); | |
3309 | return 1; | |
3310 | } | |
3311 | }; | |
3312 | ||
3313 | int delete_ui_cmd (void*, int argc, char **argv) | |
3314 | { | |
3315 | Vcpu * vcpu = 0; | |
3316 | ||
3317 | char *name; | |
3318 | char *param; | |
3319 | ||
3320 | ||
3321 | if (!IN_STOP_STATE (blaze_run_state)) | |
3322 | { | |
3323 | ui->error(" not in stop state, use stop command first\n"); | |
3324 | return 0; | |
3325 | } | |
3326 | ||
3327 | DeleteOptions options; | |
3328 | ||
3329 | std::vector<std::string> pos_args; | |
3330 | bool result = options.parse(argc-1, (const char**)&argv[1], pos_args); | |
3331 | ||
3332 | if (!result) | |
3333 | { | |
3334 | DeleteOptions::usage(); | |
3335 | return 0; | |
3336 | } | |
3337 | ||
3338 | // remove all breakpoints | |
3339 | if (options.all_opt.is_on()) | |
3340 | { | |
3341 | ui->output("deleting all breakpoints\n"); | |
3342 | ||
3343 | for (int i=0; i<=g_vcpu_id_max; i++) | |
3344 | if (g_vcpu[i]) | |
3345 | g_vcpu[i]->delete_breakpoint(-1); | |
3346 | return 1; | |
3347 | } | |
3348 | ||
3349 | for (std::vector<std::string>::iterator iter = pos_args.begin(); | |
3350 | iter != pos_args.end(); | |
3351 | ++iter) | |
3352 | { | |
3353 | uint64_t bp_id; | |
3354 | std::string err_msg; | |
3355 | ||
3356 | if (!UnsignedOption::parse_number(*iter, bp_id, err_msg)) | |
3357 | { | |
3358 | err_msg += "breakpoint id\n"; | |
3359 | ui->error(err_msg.c_str()); | |
3360 | return 0; | |
3361 | } | |
3362 | ||
3363 | int i = 0; | |
3364 | for (i=0; i<=g_vcpu_id_max; i++) | |
3365 | if (g_vcpu[i] && g_vcpu[i]->delete_breakpoint(bp_id) == 0) { | |
3366 | ui->output("deleting breakpoint %d\n", bp_id); | |
3367 | break; | |
3368 | } | |
3369 | ||
3370 | if (i > g_vcpu_id_max) | |
3371 | ui->error("Unknown breakpoint %d\n", bp_id); | |
3372 | } | |
3373 | ||
3374 | return 1; | |
3375 | } | |
3376 | ||
3377 | ||
3378 | ||
3379 | /////////////////////////////////////////////////////// | |
3380 | // | |
3381 | // set debug tracer on/off | |
3382 | // | |
3383 | static int print_vdebug_usage() | |
3384 | { | |
3385 | ui->output("debug tracer usage:\n vdebug [-cpu <cpu_set>][-o <file_name>] on|off\n"); | |
3386 | return 0; | |
3387 | } | |
3388 | static int vdebug_ui_cmd (void*, int argc, char **argv) | |
3389 | { | |
3390 | if (ANY_RUNNING_STATE (blaze_run_state)) | |
3391 | { | |
3392 | ui->error(" not in stop state, use stop command first\n"); | |
3393 | return 0; | |
3394 | } | |
3395 | ||
3396 | // check command options | |
3397 | if ( argc == 1) // show status | |
3398 | { | |
3399 | return tracer_cmd (STRACER_STATUS); | |
3400 | } | |
3401 | if ( argc < 2 ) | |
3402 | return print_vdebug_usage(); | |
3403 | ||
3404 | bool on = false; | |
3405 | char *cmd = "vdebug"; | |
3406 | ||
3407 | CommandOptions option; | |
3408 | CpuOption cpu_option(pselect_cpu_id,CpuOption::MULTITUDE); | |
3409 | StringOption out_option("o"); | |
3410 | option.add(cpu_option); | |
3411 | option.add(out_option); | |
3412 | ||
3413 | std::vector<std::string> args; | |
3414 | if (!option.parse(argc-1,(const char**)&argv[1],args)) | |
3415 | { | |
3416 | fprintf(stderr, "ERROR: %s command parsing failed: %s\n",cmd,option.get_error_msg().c_str()); | |
3417 | return 0; | |
3418 | } | |
3419 | if (args.size() != 1) | |
3420 | { | |
3421 | fprintf(stderr, "ERROR: %s requires 1 positional argument - on|off.\n",cmd); | |
3422 | return 0; | |
3423 | } | |
3424 | else // parse on/off flag | |
3425 | { | |
3426 | if (args[0]=="on") | |
3427 | on = true; | |
3428 | else if (args[0]=="off") | |
3429 | on = false; | |
3430 | else | |
3431 | return print_vdebug_usage(); | |
3432 | } | |
3433 | ||
3434 | bool separate_files = false; | |
3435 | int tprev = -1; | |
3436 | int sid[NCPU_MAX]; // cpu id's that need to be traced | |
3437 | for (int i=0; i<NCPU_MAX; i++) sid[i] = 0; | |
3438 | ||
3439 | // check which vcpus need debug tracing | |
3440 | CpuSet& cpu_set = cpu_option.get_value(); | |
3441 | for (CpuSet::iterator i=cpu_set.begin(); i != cpu_set.end(); ++i) | |
3442 | { | |
3443 | uint32_t cpu_id = *i; | |
3444 | Vcpu* vcpu = g_vcpu[cpu_id]; | |
3445 | if (vcpu == 0) | |
3446 | { | |
3447 | ui->error("cpu[%d] is not available\n", cpu_id); | |
3448 | return print_vdebug_usage(); | |
3449 | } | |
3450 | ||
3451 | if (SYSTEM_get_ncpu() > SYSTEM_get_cpus_per_thread()) | |
3452 | { | |
3453 | // check if specified cpu's belong to the same worker thread | |
3454 | int vid = 0; // get a "sequential id" | |
3455 | for ( ;vid < g_nvcpu; vid++) | |
3456 | if (get_vcpu(vid) == vcpu) | |
3457 | break; | |
3458 | ||
3459 | // check worker thread id | |
3460 | int tid = vid / SYSTEM_get_cpus_per_thread(); | |
3461 | if (tprev < 0 ) tprev = tid; | |
3462 | else if ( tprev != tid ) separate_files = true; | |
3463 | } | |
3464 | // set a flag to enable tracer for this cpu id | |
3465 | sid[cpu_id] = 1; | |
3466 | } | |
3467 | ||
3468 | const char *file_name = out_option.is_on() ? out_option.get_value().c_str() : NULL; | |
3469 | return tracer_cmd ( trace_cmd_t(on), sid, file_name, separate_files ); | |
3470 | } | |
3471 | ||
3472 | ||
3473 | /////////////////////////////////////////////////////// | |
3474 | // | |
3475 | // print all tlb entries | |
3476 | // | |
3477 | static int tlbs_ui_cmd (void*, int argc, char **argv) | |
3478 | { | |
3479 | if (ANY_RUNNING_STATE (blaze_run_state)) | |
3480 | { | |
3481 | ui->error("not in stop state, use stop command first\n"); | |
3482 | return 1; | |
3483 | } | |
3484 | ||
3485 | if (argc < 2 || argc > 3) | |
3486 | { | |
3487 | ui->error("print all valid TTEs, usage: tlbs <cpuid> [<outfile>]\n"); | |
3488 | return 1; | |
3489 | } | |
3490 | ||
3491 | int cpu_id = strtol(argv[1], NULL, 0); | |
3492 | ||
3493 | Vcpu* vcpu = get_vcpu(cpu_id); | |
3494 | if (vcpu == 0) | |
3495 | { | |
3496 | ui->error("SAM: There is no vcpu %i instance \n", cpu_id); | |
3497 | return 1; | |
3498 | } | |
3499 | ||
3500 | if(argc == 3) | |
3501 | { | |
3502 | char * fname = argv[2]; | |
3503 | FILE* stream = fopen (fname, "w"); | |
3504 | ui->output("print tlb entries to %s\n", fname); | |
3505 | vcpu->print_tlbs(stream); | |
3506 | fclose(stream); | |
3507 | } | |
3508 | else | |
3509 | { | |
3510 | vcpu->print_tlbs(ui->get_output_file()); | |
3511 | if (ui->get_log_file()) | |
3512 | vcpu->print_tlbs(ui->get_log_file()); | |
3513 | } | |
3514 | ||
3515 | return 0; | |
3516 | } | |
3517 | ||
3518 | ||
3519 | /////////////////////////////////////////////////////// | |
3520 | // | |
3521 | // set the log level | |
3522 | // | |
3523 | static int | |
3524 | loglev_ui_cmd (void*, int argc, char**argv) | |
3525 | { | |
3526 | int tmp; | |
3527 | ||
3528 | if (argc == 1) { | |
3529 | } | |
3530 | else if (argc == 2 && sscanf (argv[1], "%d", &tmp) == 1 && | |
3531 | tmp >= 1 && tmp <= 3) { | |
3532 | } | |
3533 | else { | |
3534 | ui->error("usage: loglev [1|2|3] \n"); | |
3535 | return 1; | |
3536 | } | |
3537 | ||
3538 | return 0; | |
3539 | } | |
3540 | ||
3541 | ||
3542 | static int | |
3543 | devmap_ui_cmd (void*, int argc, char**argv) | |
3544 | { | |
3545 | int tmp; | |
3546 | ||
3547 | if(argc > 1){ | |
3548 | ui->error("no arguments are allowed\n"); | |
3549 | } | |
3550 | ||
3551 | extern devRegistry * samDevs; | |
3552 | if (ui->get_log_file()) | |
3553 | samDevs->dump(ui->get_log_file()); | |
3554 | ||
3555 | return 1; | |
3556 | } | |
3557 | ||
3558 | ||
3559 | // find a vcpu pointer by cpu instance name | |
3560 | static Vcpu * get_vcpu_by_name ( char *name ) | |
3561 | { | |
3562 | Vcpu *vcpu = NULL; | |
3563 | ||
3564 | for (int i=0; i<g_nvcpu; i++) | |
3565 | { | |
3566 | if ( strcmp ( name, g_vcpu[i]->config.name ) == 0 ) | |
3567 | { | |
3568 | vcpu = g_vcpu[i]; // found a matching name | |
3569 | break; | |
3570 | } | |
3571 | } | |
3572 | ||
3573 | return vcpu; | |
3574 | } | |
3575 | ||
3576 | ||
3577 | /////////////////////////////////////////////////// | |
3578 | // | |
3579 | // run-python-file command | |
3580 | // | |
3581 | ||
3582 | int (*py_source)( int argc, char** argv ); | |
3583 | ||
3584 | static int run_python_file_ui_cmd(void*, int argc, char **argv) | |
3585 | { | |
3586 | if (!IN_STOP_STATE (blaze_run_state)) | |
3587 | { | |
3588 | ui->error("not in stop state, use stop command first\n"); | |
3589 | return 0; | |
3590 | } | |
3591 | if (argc < 2) | |
3592 | { | |
3593 | ui->error("usage: run-python-file <file_name> \n"); | |
3594 | return 0; | |
3595 | } | |
3596 | ||
3597 | // check if py module was loaded already | |
3598 | if (!python_UI) | |
3599 | { | |
3600 | char* sam_py_argv[1]; | |
3601 | exec_cmd("mod load py py.so\n"); | |
3602 | sam_py_argv[0] = "$SAM/pfe/sam.py"; | |
3603 | if (py_source) | |
3604 | (py_source)(1,sam_py_argv); | |
3605 | } | |
3606 | ||
3607 | if (!py_source) | |
3608 | ui->fatal("internal error with python module.\n"); | |
3609 | ||
3610 | return (py_source)(argc - 1,argv + 1); | |
3611 | } | |
3612 | ||
3613 | ||
3614 | ||
3615 | static int print_pselect_usage() | |
3616 | { | |
3617 | ui->output("select cpu command usage:\n"); | |
3618 | ui->output("\tpselect\n"); | |
3619 | ui->output("\tpselect cpu_id\n"); | |
3620 | return 0; | |
3621 | } | |
3622 | ||
3623 | int pselect_ui_cmd (void*, int argc, char **argv) | |
3624 | { | |
3625 | if (!IN_STOP_STATE (blaze_run_state)) | |
3626 | { | |
3627 | ui->error("not in stop state, use stop command first\n"); | |
3628 | return 1; | |
3629 | } | |
3630 | ||
3631 | CommandOptions cmd_options; | |
3632 | ||
3633 | std::vector<std::string> pos_args; | |
3634 | bool result = cmd_options.parse(argc-1, (const char**)&argv[1], pos_args); | |
3635 | if (result) | |
3636 | { | |
3637 | if (argc == 1) | |
3638 | { | |
3639 | // pselect | |
3640 | ui->error("cpu %d is currently selected\n", pselect_cpu_id); | |
3641 | return 0; | |
3642 | } | |
3643 | else | |
3644 | { | |
3645 | // pselect cpu_id | |
3646 | uint64_t cpu_id; | |
3647 | std::string error_msg; | |
3648 | ||
3649 | if (!UnsignedOption::parse_number(pos_args[0], cpu_id, error_msg)) | |
3650 | { | |
3651 | error_msg += "cpu number"; | |
3652 | ui->error("%s\n", error_msg.c_str()); | |
3653 | } | |
3654 | ||
3655 | if (cpu_id <=g_vcpu_id_max && g_vcpu[cpu_id]) | |
3656 | { | |
3657 | pselect_cpu_id = cpu_id; | |
3658 | } | |
3659 | else | |
3660 | { | |
3661 | ui->error("No cpu matching cpu number: %lld\n", cpu_id); | |
3662 | return 1; | |
3663 | } | |
3664 | } | |
3665 | return 0; | |
3666 | } | |
3667 | else | |
3668 | { | |
3669 | ui->error("pselect command parsing failed: %s\n", cmd_options.get_error_msg().c_str()); | |
3670 | return 1; | |
3671 | } | |
3672 | } | |
3673 | ||
3674 | ||
3675 | ////////////////////////////////////////////////////////////////////// | |
3676 | // t r a n s l a t e | |
3677 | ////////////////////////////////////////////////////////////////////// | |
3678 | ||
3679 | class TranslateOptions : public CommandOptions | |
3680 | { | |
3681 | public: | |
3682 | TranslateOptions( int cpu_id ) | |
3683 | : | |
3684 | cpu(cpu_id,CpuOption::MULTITUDE), | |
3685 | addressing(AddressingOptions::VA) | |
3686 | { | |
3687 | add(cpu); | |
3688 | add(addressing); | |
3689 | } | |
3690 | ||
3691 | CpuOption cpu; | |
3692 | AddressingOptions addressing; | |
3693 | ||
3694 | static int usage() | |
3695 | { | |
3696 | // We need to get this from the Options class | |
3697 | // CommandOptions::usage('translate'); | |
3698 | return 1; | |
3699 | } | |
3700 | }; | |
3701 | ||
3702 | int translate_ui_cmd( void*, int argc, char** argv ) | |
3703 | { | |
3704 | static const char* cmd = "translate"; | |
3705 | ||
3706 | if (!IN_STOP_STATE (blaze_run_state)) | |
3707 | { | |
3708 | ui->error("not in stop state, use stop command first\n"); | |
3709 | return 1; | |
3710 | } | |
3711 | ||
3712 | TranslateOptions options(pselect_cpu_id); | |
3713 | std::vector<std::string> args; | |
3714 | ||
3715 | if (!options.parse(argc-1,(const char**)&argv[1],args)) | |
3716 | { | |
3717 | ui->error("%s command parsing failed: %s\n",cmd,options.get_error_msg().c_str()); | |
3718 | return 1; | |
3719 | } | |
3720 | if (args.size() != 1) | |
3721 | { | |
3722 | ui->error("%s requires 1 positional argument; the address to translate.\n",cmd); | |
3723 | return 1; | |
3724 | } | |
3725 | ||
3726 | Vcpu::TranslateMode mode = options.addressing.translate_mode(); | |
3727 | uint64_t ctx = options.addressing.context_id.get_value(); | |
3728 | uint64_t pid = options.addressing.partition_id.get_value(); | |
3729 | uint64_t pa; | |
3730 | uint64_t ea = strtoull(args[0].c_str(), NULL, 0); | |
3731 | CpuSet& cpu_set = options.cpu.get_value(); | |
3732 | ||
3733 | for (CpuSet::iterator i=cpu_set.begin(); i != cpu_set.end(); ++i) | |
3734 | { | |
3735 | uint32_t cpu_id = *i; | |
3736 | ui->output("%d: ",cpu_id); | |
3737 | Vcpu* vcpu = g_vcpu[cpu_id]; | |
3738 | if (vcpu == 0) | |
3739 | ui->output("not available\n"); | |
3740 | else if (vcpu->translate(mode,ea,ctx,pid,&pa) != Vcpu::TRANSLATE_OK) | |
3741 | ui->output("no mapping available\n"); | |
3742 | else | |
3743 | ui->output("pa = 0x%llx\n",pa); | |
3744 | } | |
3745 | ||
3746 | return 0; | |
3747 | } | |
3748 | ||
3749 | ||
3750 | ////////////////////////////////////////////////////////////////////// | |
3751 | // g e t | |
3752 | ////////////////////////////////////////////////////////////////////// | |
3753 | ||
3754 | class GetOptions : public CommandOptions | |
3755 | { | |
3756 | public: | |
3757 | GetOptions( int cpu_id ) | |
3758 | : | |
3759 | cpu(cpu_id), | |
3760 | addressing(AddressingOptions::PA), | |
3761 | count("count",1), | |
3762 | size("size",4) | |
3763 | { | |
3764 | add(cpu); | |
3765 | add(addressing); | |
3766 | add(size); | |
3767 | add(count); | |
3768 | } | |
3769 | ||
3770 | CpuOption cpu; | |
3771 | AddressingOptions addressing; | |
3772 | UnsignedOption size; | |
3773 | UnsignedOption count; | |
3774 | ||
3775 | static int usage() | |
3776 | { | |
3777 | // We need to get this from the Options class | |
3778 | // CommandOptions::usage('get'); | |
3779 | return 1; | |
3780 | } | |
3781 | }; | |
3782 | ||
3783 | int get_ui_cmd( void*, int argc, char** argv ) | |
3784 | { | |
3785 | static const char* cmd = "get"; | |
3786 | ||
3787 | if (!IN_STOP_STATE (blaze_run_state)) | |
3788 | { | |
3789 | ui->error("not in stop state, use stop command first\n"); | |
3790 | return 1; | |
3791 | } | |
3792 | ||
3793 | GetOptions options(pselect_cpu_id); | |
3794 | std::vector<std::string> args; | |
3795 | ||
3796 | if (!options.parse(argc-1,(const char**)&argv[1],args)) | |
3797 | { | |
3798 | ui->error("%s command parsing failed: %s\n",cmd,options.get_error_msg().c_str()); | |
3799 | return 1; | |
3800 | } | |
3801 | ||
3802 | uint32_t size; | |
3803 | uint32_t count; | |
3804 | ||
3805 | switch (args.size()) | |
3806 | { | |
3807 | case 2: | |
3808 | if (options.size.is_on()) | |
3809 | { | |
3810 | ui->error("%s used with confusing arguments: both positional " | |
3811 | "size argument and -size option given: use -size and -count.\n",cmd); | |
3812 | return 1; | |
3813 | } | |
3814 | if (options.count.is_on()) | |
3815 | { | |
3816 | ui->error("%s used with confusing arguments: both positional " | |
3817 | "size argument and -count option given: use -size and -count.\n",cmd); | |
3818 | return 1; | |
3819 | } | |
3820 | ui->warning("%s use -size and -count options as [size] positional " | |
3821 | "argument is deprecated.\n",cmd); | |
3822 | size = strtoull(args[1].c_str(),NULL,0); | |
3823 | count = (size > 8) ? ((size + 7) / 8) : 1; | |
3824 | break; | |
3825 | case 1: | |
3826 | size = options.size.get_value(); | |
3827 | count = options.count.get_value(); | |
3828 | break; | |
3829 | case 0: | |
3830 | default: | |
3831 | ui->error("%s requires address positional argument.\n",cmd); | |
3832 | return 1; | |
3833 | } | |
3834 | ||
3835 | if ((size == 0) || ((size != 1) && (size != 2) && (size != 4) && (size != 8))) | |
3836 | { | |
3837 | if (options.size.is_on() || (size < 8)) | |
3838 | { | |
3839 | ui->error("%s requires size to be 1, 2, 4, or 8.\n",cmd); | |
3840 | return 1; | |
3841 | } | |
3842 | else | |
3843 | { | |
3844 | if (size & 7) | |
3845 | ui->warning("%s rounded size up to nearest multiple of 8.\n",cmd); | |
3846 | size = 8; | |
3847 | } | |
3848 | } | |
3849 | ||
3850 | Vcpu::TranslateMode mode = options.addressing.translate_mode(); | |
3851 | uint64_t ctx = options.addressing.context_id.get_value(); | |
3852 | uint64_t pid = options.addressing.partition_id.get_value(); | |
3853 | uint64_t pa; | |
3854 | uint64_t ea = strtoull(args[0].c_str(),NULL,0); | |
3855 | uint32_t cpu_id = *options.cpu.get_value().find(0); | |
3856 | ||
3857 | Vcpu* vcpu = g_vcpu[cpu_id]; | |
3858 | if (vcpu == 0) | |
3859 | ui->error("cpu %d not available\n",cpu_id); | |
3860 | else if (vcpu->translate(mode,ea,ctx,pid,&pa) != Vcpu::TRANSLATE_OK) | |
3861 | ui->warning("cpu %d has no mapping available for 0x%llx\n",cpu_id,ea); | |
3862 | else | |
3863 | { | |
3864 | uint8_t data8; | |
3865 | uint16_t data16; | |
3866 | uint32_t data32; | |
3867 | uint64_t data64; | |
3868 | ||
3869 | uint_t n; | |
3870 | ||
3871 | for (n = 0; count--; ++n, ea += size, pa += size) | |
3872 | { | |
3873 | if (((ea & 0x1fff) == 0) // At the begin of every 8KByte page | |
3874 | && vcpu->translate(mode,ea,ctx,pid,&pa) != Vcpu::TRANSLATE_OK) | |
3875 | { | |
3876 | ui->warning("cpu %d has no mapping available for 0x%llx\n",cpu_id,ea); | |
3877 | break; | |
3878 | } | |
3879 | ||
3880 | if ((n % (32 / size)) == 0) | |
3881 | ui->output("0x%016llx: ",pa); | |
3882 | ||
3883 | switch (size) | |
3884 | { | |
3885 | case 1: | |
3886 | mmi_memread(pa,(uint8_t*)&data8,1); | |
3887 | ui->output("0x%02llx ",data8); | |
3888 | break; | |
3889 | case 2: | |
3890 | mmi_memread(pa,(uint8_t*)&data16,2); | |
3891 | ui->output("0x%04llx ",data16); | |
3892 | break; | |
3893 | case 4: | |
3894 | mmi_memread(pa,(uint8_t*)&data32,4); | |
3895 | ui->output("0x%08llx ",data32); | |
3896 | break; | |
3897 | case 8: | |
3898 | mmi_memread(pa,(uint8_t*)&data64,8); | |
3899 | ui->output("0x%016llx ",data64); | |
3900 | break; | |
3901 | } | |
3902 | ||
3903 | if (((n + 1) % (32 / size)) == 0) | |
3904 | ui->output("\n"); | |
3905 | } | |
3906 | ||
3907 | if (n % (32 / size)) | |
3908 | ui->output("\n"); | |
3909 | } | |
3910 | ||
3911 | return 0; | |
3912 | } | |
3913 | ||
3914 | ////////////////////////////////////////////////////////////////////// | |
3915 | // s e t | |
3916 | ////////////////////////////////////////////////////////////////////// | |
3917 | ||
3918 | class SetOptions : public CommandOptions | |
3919 | { | |
3920 | public: | |
3921 | SetOptions( int cpu_id ) | |
3922 | : | |
3923 | cpu(cpu_id), | |
3924 | addressing(AddressingOptions::PA), | |
3925 | size("size",4), | |
3926 | count("count",1) | |
3927 | { | |
3928 | add(cpu); | |
3929 | add(addressing); | |
3930 | add(size); | |
3931 | add(count); | |
3932 | } | |
3933 | ||
3934 | CpuOption cpu; | |
3935 | AddressingOptions addressing; | |
3936 | UnsignedOption size; | |
3937 | UnsignedOption count; | |
3938 | ||
3939 | static int usage() | |
3940 | { | |
3941 | // We need to get this from the Options class | |
3942 | // CommandOptions::usage('set'); | |
3943 | return 1; | |
3944 | } | |
3945 | }; | |
3946 | ||
3947 | int set_ui_cmd( void*, int argc, char** argv ) | |
3948 | { | |
3949 | static const char* cmd = "set"; | |
3950 | ||
3951 | if (!IN_STOP_STATE (blaze_run_state)) | |
3952 | { | |
3953 | ui->error("not in stop state, use stop command first\n"); | |
3954 | return 1; | |
3955 | } | |
3956 | ||
3957 | SetOptions options(pselect_cpu_id); | |
3958 | std::vector<std::string> args; | |
3959 | ||
3960 | if (!options.parse(argc-1,(const char**)&argv[1],args)) | |
3961 | { | |
3962 | ui->error("%s command parsing failed: %s\n",cmd,options.get_error_msg().c_str()); | |
3963 | return 1; | |
3964 | } | |
3965 | ||
3966 | uint32_t size; | |
3967 | uint32_t count; | |
3968 | ||
3969 | switch (args.size()) | |
3970 | { | |
3971 | case 3: | |
3972 | if (options.size.is_on()) | |
3973 | { | |
3974 | ui->error("%s used with confusing arguments: both positional " | |
3975 | "size argument and -size option given: use -size and -count.\n",cmd); | |
3976 | return 1; | |
3977 | } | |
3978 | if (options.count.is_on()) | |
3979 | { | |
3980 | ui->error("%s used with confusing arguments: both positional " | |
3981 | "size argument and -count option given: use -size and -count.\n",cmd); | |
3982 | return 1; | |
3983 | } | |
3984 | ui->warning("%s use -size and -count options as [size] positional " | |
3985 | "argument is deprecated.\n",cmd); | |
3986 | size = strtoull(args[2].c_str(),NULL,0); | |
3987 | count = (size > 8) ? ((size + 7) / 8) : 1; | |
3988 | break; | |
3989 | case 2: | |
3990 | size = options.size.get_value(); | |
3991 | count = options.count.get_value(); | |
3992 | break; | |
3993 | case 0: | |
3994 | default: | |
3995 | ui->error("%s requires address [size] positional arguments.\n",cmd); | |
3996 | return 1; | |
3997 | } | |
3998 | ||
3999 | if ((size == 0) || ((size != 1) && (size != 2) && (size != 4) && (size != 8))) | |
4000 | { | |
4001 | if (options.size.is_on() || (size < 8)) | |
4002 | { | |
4003 | ui->error("%s requires size to be 1, 2, 4, or 8.\n",cmd); | |
4004 | return 1; | |
4005 | } | |
4006 | else | |
4007 | { | |
4008 | if (size & 7) | |
4009 | ui->warning("%s rounded size up to nearest multiple of 8.\n",cmd); | |
4010 | size = 8; | |
4011 | } | |
4012 | } | |
4013 | ||
4014 | Vcpu::TranslateMode mode = options.addressing.translate_mode(); | |
4015 | uint64_t ctx = options.addressing.context_id.get_value(); | |
4016 | uint64_t pid = options.addressing.partition_id.get_value(); | |
4017 | uint64_t pa; | |
4018 | uint64_t ea = strtoull(args[0].c_str(),NULL,0); | |
4019 | uint32_t cpu_id = *options.cpu.get_value().find(0); | |
4020 | ||
4021 | Vcpu* vcpu = g_vcpu[cpu_id]; | |
4022 | if (vcpu == 0) | |
4023 | ui->error("cpu %d not available\n",cpu_id); | |
4024 | else if (vcpu->translate(mode,ea,ctx,pid,&pa) != Vcpu::TRANSLATE_OK) | |
4025 | ui->output("cpu %d has no mapping available for 0x%llx\n",cpu_id,ea); | |
4026 | else | |
4027 | { | |
4028 | uint64_t data64 = strtoull(args[1].c_str(),NULL,0); | |
4029 | uint32_t data32 = data64; | |
4030 | uint16_t data16 = data64; | |
4031 | uint8_t data8 = data64; | |
4032 | ||
4033 | for (uint_t n = 0; count--; ++n, ea += size, pa += size) | |
4034 | { | |
4035 | if (((ea & 0x1fff) == 0) // At the begin of every 8KByte page | |
4036 | && vcpu->translate(mode,ea,ctx,pid,&pa) != Vcpu::TRANSLATE_OK) | |
4037 | { | |
4038 | ui->output("cpu %d has no mapping available for 0x%llx\n",cpu_id,ea); | |
4039 | break; | |
4040 | } | |
4041 | switch (size) | |
4042 | { | |
4043 | case 1: mmi_memwrite(pa,(uint8_t*)&data8, 1); break; | |
4044 | case 2: mmi_memwrite(pa,(uint8_t*)&data16,2); break; | |
4045 | case 4: mmi_memwrite(pa,(uint8_t*)&data32,4); break; | |
4046 | case 8: mmi_memwrite(pa,(uint8_t*)&data64,8); break; | |
4047 | } | |
4048 | } | |
4049 | } | |
4050 | ||
4051 | return 0; | |
4052 | } | |
4053 | ||
4054 | ////////////////////////////////////////////////////////////////////// | |
4055 | // d i s a s s e m b l e | |
4056 | ////////////////////////////////////////////////////////////////////// | |
4057 | ||
4058 | class DisassembleOptions : public CommandOptions | |
4059 | { | |
4060 | public: | |
4061 | DisassembleOptions( int cpu_id ) | |
4062 | : | |
4063 | cpu(cpu_id), | |
4064 | addressing(AddressingOptions::VA), | |
4065 | count("count",1) | |
4066 | { | |
4067 | add(cpu); | |
4068 | add(addressing); | |
4069 | add(count); | |
4070 | } | |
4071 | ||
4072 | CpuOption cpu; | |
4073 | AddressingOptions addressing; | |
4074 | UnsignedOption count; | |
4075 | ||
4076 | static int usage() | |
4077 | { | |
4078 | // We need to get this from the Options class | |
4079 | // CommandOptions::usage('disassemble'); | |
4080 | return 1; | |
4081 | } | |
4082 | }; | |
4083 | ||
4084 | int disassemble_ui_cmd( void*, int argc, char** argv ) | |
4085 | { | |
4086 | static const char* cmd = "disassemble"; | |
4087 | ||
4088 | if (!IN_STOP_STATE (blaze_run_state)) | |
4089 | { | |
4090 | ui->error("not in stop state, use stop command first\n"); | |
4091 | return 1; | |
4092 | } | |
4093 | ||
4094 | DisassembleOptions options(pselect_cpu_id); | |
4095 | std::vector<std::string> args; | |
4096 | ||
4097 | if (!options.parse(argc-1,(const char**)&argv[1],args)) | |
4098 | { | |
4099 | ui->error("%s command parsing failed: %s\n",cmd,options.get_error_msg().c_str()); | |
4100 | return 1; | |
4101 | } | |
4102 | ||
4103 | uint64_t ea; | |
4104 | uint32_t cpu_id = *options.cpu.get_value().begin(); | |
4105 | uint32_t count; | |
4106 | Vcpu* vcpu = g_vcpu[cpu_id]; | |
4107 | ||
4108 | if (vcpu == 0) | |
4109 | { | |
4110 | ui->error("cpu %d not available\n",cpu_id); | |
4111 | return 0; | |
4112 | } | |
4113 | ||
4114 | switch (args.size()) | |
4115 | { | |
4116 | case 2: | |
4117 | if (options.count.is_on()) | |
4118 | { | |
4119 | ui->error("%s used with confusing arguments: both positional " | |
4120 | "count argument and -count option given: use -count.\n",cmd); | |
4121 | return 1; | |
4122 | } | |
4123 | ui->warning("%s use -count option as [count] positional " | |
4124 | "argument is deprecated.\n",cmd); | |
4125 | ea = strtoull(args[0].c_str(),NULL,0); | |
4126 | count = strtoull(args[1].c_str(),NULL,0); | |
4127 | break; | |
4128 | ||
4129 | case 1: | |
4130 | ea = strtoull(args[0].c_str(),NULL,0); | |
4131 | count = options.count.get_value(); | |
4132 | break; | |
4133 | ||
4134 | case 0: | |
4135 | #if TO_BE_IMPLEMENTED | |
4136 | vcpu->get_reg(VCPU_ASR_PC,&ea); | |
4137 | count = options.count.get_value(); | |
4138 | break; | |
4139 | #endif | |
4140 | default: | |
4141 | ui->error("%s requires address positional arguments.\n",cmd); | |
4142 | return 1; | |
4143 | } | |
4144 | ||
4145 | Vcpu::TranslateMode mode = options.addressing.translate_mode(); | |
4146 | uint64_t ctx = options.addressing.context_id.get_value(); | |
4147 | uint64_t pid = options.addressing.partition_id.get_value(); | |
4148 | uint64_t pa; | |
4149 | ||
4150 | if (ea & 3) | |
4151 | { | |
4152 | ui->warning("%s likes the address argument to be 4 byte aligned\n",cmd); | |
4153 | ea &= ~3ull; | |
4154 | } | |
4155 | ||
4156 | if (vcpu->translate(mode,ea,ctx,pid,&pa) != Vcpu::TRANSLATE_OK) | |
4157 | ui->error("cpu %d has no mapping available for 0x%llx\n",cpu_id,ea); | |
4158 | else | |
4159 | { | |
4160 | for (; count--; ea += 4, pa += 4) | |
4161 | { | |
4162 | if (((ea & 0x1fff) == 0) // At the begin of every 8KByte page | |
4163 | && vcpu->translate(mode,ea,ctx,pid,&pa) != Vcpu::TRANSLATE_OK) | |
4164 | { | |
4165 | ui->output("cpu %d has no mapping available for 0x%llx\n",cpu_id,ea); | |
4166 | break; | |
4167 | } | |
4168 | ||
4169 | char inst[256]; | |
4170 | uint32_t data; | |
4171 | mmi_memread(pa,(uint8_t*)&data,4); | |
4172 | ||
4173 | spix_sparc_dis(inst,256,spix_sparc_iop(SPIX_SPARC_V9,&data),&data,ea); | |
4174 | ui->output("%d: %llx %llx [%08x] %s\n",cpu_id,ea,pa,data,inst); | |
4175 | } | |
4176 | } | |
4177 | ||
4178 | return 0; | |
4179 | } | |
4180 | ||
4181 | ////////////////////////////////////////////////////////////////////// | |
4182 | // r e a d - a s i | |
4183 | ////////////////////////////////////////////////////////////////////// | |
4184 | ||
4185 | class ReadAsiOptions : public CommandOptions | |
4186 | { | |
4187 | public: | |
4188 | ReadAsiOptions( int cpu_id ) | |
4189 | : | |
4190 | cpu(cpu_id) | |
4191 | { | |
4192 | add(cpu); | |
4193 | } | |
4194 | ||
4195 | CpuOption cpu; | |
4196 | ||
4197 | static int usage() | |
4198 | { | |
4199 | // We need to get this from the Options class | |
4200 | // CommandOptions::usage('disassemble'); | |
4201 | return 1; | |
4202 | } | |
4203 | }; | |
4204 | ||
4205 | int read_asi_ui_cmd( void*, int argc, char** argv ) | |
4206 | { | |
4207 | static const char* cmd = "read-asi"; | |
4208 | ||
4209 | if (!IN_STOP_STATE (blaze_run_state)) | |
4210 | { | |
4211 | ui->error("not in stop state, use stop command first\n"); | |
4212 | return 1; | |
4213 | } | |
4214 | ||
4215 | ReadAsiOptions options(pselect_cpu_id); | |
4216 | std::vector<std::string> args; | |
4217 | ||
4218 | if (!options.parse(argc-1,(const char**)&argv[1],args)) | |
4219 | { | |
4220 | ui->error("%s command parsing failed: %s\n",cmd,options.get_error_msg().c_str()); | |
4221 | return 1; | |
4222 | } | |
4223 | ||
4224 | if (args.size() != 2) | |
4225 | { | |
4226 | ui->error("%s requires <asi> <address> positional arguments.\n",cmd); | |
4227 | return 1; | |
4228 | } | |
4229 | ||
4230 | uint64_t asi = strtoull(args[0].c_str(),NULL,0); | |
4231 | int64_t va = strtoll(args[1].c_str(),NULL,0); // va is signed | |
4232 | uint32_t cpu_id = *options.cpu.get_value().begin(); | |
4233 | ||
4234 | if (asi > 0xff) | |
4235 | { | |
4236 | ui->error("valid non-translating asi values range from 0 to 0xff\n",cmd); | |
4237 | return 1; | |
4238 | } | |
4239 | ||
4240 | if (va & 7) | |
4241 | { | |
4242 | ui->warning("%s requires the address argument to be 8 byte aligned\n",cmd); | |
4243 | va &= ~7ull; | |
4244 | } | |
4245 | ||
4246 | Vcpu* vcpu = g_vcpu[cpu_id]; | |
4247 | if (vcpu == 0) | |
4248 | { | |
4249 | ui->error("cpu %d not available\n",cpu_id); | |
4250 | return 1; | |
4251 | } | |
4252 | ||
4253 | uint64_t data; | |
4254 | int fail = vcpu->get_asi(asi,va,data); | |
4255 | ||
4256 | if (fail) | |
4257 | { | |
4258 | ui->error("0x%02llx:0x%llx is not a valid non-translating asi:va pair\n",asi,va); | |
4259 | return 1; | |
4260 | } | |
4261 | ||
4262 | ui->output("0x%02llx:0x%llx = 0x%llx\n",asi,va,data); | |
4263 | ||
4264 | return 0; | |
4265 | } | |
4266 | ||
4267 | ||
4268 | ////////////////////////////////////////////////////////////////////// | |
4269 | // w r i t e - a s i | |
4270 | ////////////////////////////////////////////////////////////////////// | |
4271 | ||
4272 | class WriteAsiOptions : public CommandOptions | |
4273 | { | |
4274 | public: | |
4275 | WriteAsiOptions( int cpu_id ) | |
4276 | : | |
4277 | cpu(cpu_id) | |
4278 | { | |
4279 | add(cpu); | |
4280 | } | |
4281 | ||
4282 | CpuOption cpu; | |
4283 | ||
4284 | static int usage() | |
4285 | { | |
4286 | // We need to get this from the Options class | |
4287 | // CommandOptions::usage('disassemble'); | |
4288 | return 1; | |
4289 | } | |
4290 | }; | |
4291 | ||
4292 | int write_asi_ui_cmd( void*, int argc, char** argv ) | |
4293 | { | |
4294 | static const char* cmd = "write-asi"; | |
4295 | ||
4296 | if (!IN_STOP_STATE (blaze_run_state)) | |
4297 | { | |
4298 | ui->error("not in stop state, use stop command first\n"); | |
4299 | return 1; | |
4300 | } | |
4301 | ||
4302 | WriteAsiOptions options(pselect_cpu_id); | |
4303 | std::vector<std::string> args; | |
4304 | ||
4305 | if (!options.parse(argc-1,(const char**)&argv[1],args)) | |
4306 | { | |
4307 | ui->error("%s command parsing failed: %s\n",cmd,options.get_error_msg().c_str()); | |
4308 | return 1; | |
4309 | } | |
4310 | ||
4311 | if (args.size() != 3) | |
4312 | { | |
4313 | ui->error("%s requires <asi> <address> <value> positional arguments.\n",cmd); | |
4314 | return 1; | |
4315 | } | |
4316 | ||
4317 | uint64_t asi = strtoull(args[0].c_str(),NULL,0); | |
4318 | int64_t va = strtoll(args[1].c_str(),NULL,0); // va is signed | |
4319 | uint64_t data = strtoull(args[2].c_str(),NULL,0); | |
4320 | uint32_t cpu_id = *options.cpu.get_value().begin(); | |
4321 | ||
4322 | if (asi > 0xff) | |
4323 | { | |
4324 | ui->error("valid non-translating asi values range from 0 to 0xff\n",cmd); | |
4325 | return 1; | |
4326 | } | |
4327 | ||
4328 | if (va & 7) | |
4329 | { | |
4330 | ui->warning("%s requires the address argument to be 8 byte aligned\n",cmd); | |
4331 | va &= ~7ull; | |
4332 | } | |
4333 | ||
4334 | Vcpu* vcpu = g_vcpu[cpu_id]; | |
4335 | if (vcpu == 0) | |
4336 | { | |
4337 | ui->error("cpu %d not available\n",cpu_id); | |
4338 | return 1; | |
4339 | } | |
4340 | ||
4341 | int fail = vcpu->set_asi(asi,va,data); | |
4342 | ||
4343 | if (fail) | |
4344 | { | |
4345 | ui->error("0x%02llx:0x%llx is not a valid non-translating asi:va pair\n",asi,va); | |
4346 | return 1; | |
4347 | } | |
4348 | ||
4349 | return 0; | |
4350 | } | |
4351 | ||
4352 | /////////////////////////////////////////////// | |
4353 | // | |
4354 | // ECHO | |
4355 | // | |
4356 | int static echo_ui_cmd (void*, int argc, char **argv) | |
4357 | { | |
4358 | for (int i = 1; i < argc; ++i) | |
4359 | { | |
4360 | const char* arg = argv[i]; | |
4361 | if (arg[0] == '"') | |
4362 | { | |
4363 | int len = strlen(arg); | |
4364 | if (len > 2 && arg[len-1] == '"') | |
4365 | { | |
4366 | ui->output("%.*s ", len-2, &arg[1]); | |
4367 | continue; | |
4368 | } | |
4369 | } | |
4370 | ui->output("%s ", arg); | |
4371 | } | |
4372 | ui->output("\n"); | |
4373 | return 0; | |
4374 | } | |
4375 | ||
4376 | /////////////////////////////////////////////// | |
4377 | // | |
4378 | // LIST-BREAKPOINTS | |
4379 | // | |
4380 | int static list_breakpoints_ui_cmd (void*, int argc, char **argv) | |
4381 | { | |
4382 | // printout all existing breakpoints | |
4383 | for (int i=0; i<=g_vcpu_id_max; i++) | |
4384 | { | |
4385 | if (g_vcpu[i]) | |
4386 | { | |
4387 | g_vcpu[i]->print_breakpoints(ui->get_output_file()); | |
4388 | if (ui->get_log_file()) | |
4389 | g_vcpu[i]->print_breakpoints(ui->get_log_file()); | |
4390 | } | |
4391 | } | |
4392 | return 0; | |
4393 | } | |
4394 | ||
4395 |