5 #include "jdb_handler_queue.h"
6 #include "per_cpu_data.h"
12 class Jdb_entry_frame;
14 class Jdb : public Jdb_core
17 static Per_cpu<Jdb_entry_frame*> entry_frame;
18 static unsigned current_cpu;
19 static Per_cpu<void (*)(unsigned, void *)> remote_func;
20 static Per_cpu<void *> remote_func_data;
21 static Per_cpu<bool> remote_func_running;
23 static int FIASCO_FASTCALL enter_jdb(Jdb_entry_frame *e, unsigned cpu);
24 static void cursor_end_of_screen();
25 static void cursor_home();
26 static void printf_statline(const char *prompt, const char *help,
27 const char *format, ...)
28 __attribute__((format(printf, 3, 4)));
29 static void save_disable_irqs(unsigned cpu);
30 static void restore_irqs(unsigned cpu);
33 Jdb(); // default constructors are undefined
36 static char hide_statline;
39 static Per_cpu<char[81]> error_buffer;
40 static bool was_input_error;
42 static Thread *current_active;
44 static const char *toplevel_cmds;
45 static const char *non_interactive_cmds;
47 // state for traps in JDB itself
48 static Per_cpu<bool> running;
49 static bool in_service;
50 static bool leave_barrier;
51 static unsigned long cpus_in_debugger;
52 static bool never_break;
53 static bool jdb_active;
55 static void enter_trap_handler(unsigned cpu);
56 static void leave_trap_handler(unsigned cpu);
57 static bool handle_conditional_breakpoint(unsigned cpu);
58 static void handle_nested_trap(Jdb_entry_frame *e);
59 static bool handle_user_request(unsigned cpu);
60 static bool handle_debug_traps(unsigned cpu);
61 static bool test_checksums();
64 static Jdb_handler_queue jdb_enter;
65 static Jdb_handler_queue jdb_leave;
67 // esc sequences for highligthing
68 static char esc_iret[];
70 static char esc_emph[];
71 static char esc_emph2[];
72 static char esc_mark[];
73 static char esc_line[];
74 static char esc_symbol[];
78 //---------------------------------------------------------------------------
86 #include "delayloop.h"
89 #include "jdb_entry_frame.h"
90 #include "jdb_screen.h"
91 #include "kernel_console.h"
92 #include "processor.h"
93 #include "push_console.h"
94 #include "static_init.h"
97 KIP_KERNEL_FEATURE("jdb");
99 Jdb_handler_queue Jdb::jdb_enter;
100 Jdb_handler_queue Jdb::jdb_leave;
102 DEFINE_PER_CPU Per_cpu<char[81]> Jdb::error_buffer;
103 char Jdb::next_cmd; // next global command to execute
106 char Jdb::hide_statline; // show status line on enter_kdebugger
107 DEFINE_PER_CPU Per_cpu<Jdb_entry_frame*> Jdb::entry_frame;
108 unsigned Jdb::current_cpu; // current CPU JDB is running on
109 Thread *Jdb::current_active; // current running thread
110 bool Jdb::was_input_error; // error in command sequence
112 DEFINE_PER_CPU Per_cpu<void (*)(unsigned, void *)> Jdb::remote_func;
113 DEFINE_PER_CPU Per_cpu<void *> Jdb::remote_func_data;
114 DEFINE_PER_CPU Per_cpu<bool> Jdb::remote_func_running;
116 // holds all commands executable in top level (regardless of current mode)
117 const char *Jdb::toplevel_cmds = "j_";
119 // a short command must be included in this list to be enabled for non-
120 // interactive execution
121 const char *Jdb::non_interactive_cmds = "bEIJLMNOPSU^Z";
123 DEFINE_PER_CPU Per_cpu<bool> Jdb::running; // JDB is already running
124 bool Jdb::never_break; // never enter JDB
125 bool Jdb::jdb_active;
126 bool Jdb::in_service;
127 bool Jdb::leave_barrier;
128 unsigned long Jdb::cpus_in_debugger;
133 Jdb::cpu_in_jdb(unsigned cpu)
134 { return Cpu::online(cpu) && running.cpu(cpu); }
138 template< typename Func >
140 Jdb::foreach_cpu(Func const &f)
142 for (unsigned i = 0; i < Config::Max_num_cpus; ++i)
144 if (!Cpu::online(i) || !running.cpu(i))
151 template< typename Func >
153 Jdb::foreach_cpu(Func const &f, bool positive)
156 for (unsigned i = 0; i < Config::Max_num_cpus; ++i)
158 if (!Cpu::online(i) || !running.cpu(i))
174 Jdb::set_next_cmd(char cmd)
187 /** Command aborted. If we are interpreting a debug command like
188 * enter_kdebugger("*#...") this is an error
194 cursor(Jdb_screen::height(), 6);
197 was_input_error = true;
201 // go to bottom of screen and print some text in the form "jdb: ..."
202 // if no text follows after the prompt, prefix the current thread number
205 Jdb::printf_statline(const char *prompt, const char *help,
206 const char *format, ...)
208 cursor(Jdb_screen::height(), 1);
209 unsigned w = Jdb_screen::width();
215 w -= strlen(prompt) + 2;
220 w -= Jdb::prompt_len();
223 // work around for ealier gccs complaining about "empty format strings"
224 if (format && (format[0] != '_' || format[1] != '\0'))
228 va_start(list, format);
229 vsnprintf(s, sizeof(s), format, list);
231 s[sizeof(s) - 1] = 0;
235 if (help && print_len(help) < w)
236 printf("%*.*s", w, w, help);
242 bool Jdb::is_toplevel_cmd(char c)
245 Jdb_core::Cmd cmd = Jdb_core::has_cmd(cm);
247 if (cmd.cmd || (0 != strchr(toplevel_cmds, c)))
259 Jdb::execute_command(const char *s, int first_char = -1)
261 Jdb_core::Cmd cmd = Jdb_core::has_cmd(s);
264 return Jdb_core::exec_cmd(cmd, 0, first_char) == 2 ? 1 : 0;
273 static Push_console c;
277 // Interprete str as non interactive commands for Jdb. We allow mostly
278 // non-interactive commands here (e.g. we don't allow d, t, l, u commands)
281 Jdb::execute_command_ni(Space *task, char const *str, int len = 1000)
284 for (; len && peek(str, task, tmp) && tmp; ++str, --len)
285 if ((unsigned char)tmp != 0xff)
286 push_cons()->push(tmp);
288 if ((unsigned char)tmp != 0xff)
289 push_cons()->push('_'); // terminating return
292 // prevent output of sequences
293 Kconsole::console()->change_state(0, 0, ~Console::OUTENABLED, 0);
299 was_input_error = true;
300 if (0 != strchr(non_interactive_cmds, c))
302 char _cmd[] = {(char)c, 0};
303 Jdb_core::Cmd cmd = Jdb_core::has_cmd(_cmd);
307 if (Jdb_core::exec_cmd (cmd, 0) != 3)
308 was_input_error = false;
312 if (c == KEY_RETURN || c == ' ' || was_input_error)
314 push_cons()->flush();
315 // re-enable all consoles but GZIP
316 Kconsole::console()->change_state(0, Console::GZIP,
317 ~0U, Console::OUTENABLED);
318 return c == KEY_RETURN || c == ' ';
325 Jdb::input_short_mode(Jdb::Cmd *cmd, char const **args, int &cmd_key)
333 if ((c = get_next_cmd()))
338 while (c < ' ' && c != KEY_RETURN);
343 printf("\033[K%c", c); // clreol + print key
345 char cmd_buffer[2] = { (char)c, 0 };
347 *cmd = Jdb_core::has_cmd(cmd_buffer);
351 return false; // do not leave the debugger
353 else if (!handle_special_cmds(c))
354 return true; // special command triggered a JDB leave
355 else if (c == KEY_RETURN)
357 hide_statline = false;
373 char *buffer() { return _b; }
374 int len() const { return _l; }
375 void flush() { _l = 0; _b[0] = 0; }
381 if (l >= 0 && (unsigned)l < _l)
388 void append(int c) { if (_l + 1 < sizeof(_b)) { _b[_l++] = c; _b[_l] = 0; } }
389 void append(char const *str, int len)
391 if (_l + len >= sizeof(_b))
392 len = sizeof(_b) - _l - 1;
394 memcpy(_b + _l, str, len);
399 void overlay(char const *str, unsigned len)
401 if (len + 1 > sizeof(_b))
402 len = sizeof(_b) - 1;
410 memcpy(_b + _l, str, len);
419 Jdb::input_long_mode(Jdb::Cmd *cmd, char const **args)
421 static Cmd_buffer buf;
445 bool multi_match = false;
446 *cmd = Jdb_core::complete_cmd(buf.buffer(), multi_match);
447 if (cmd->cmd && multi_match)
450 unsigned prefix_len = Jdb_core::print_alternatives(buf.buffer());
452 buf.overlay(cmd->cmd->cmd, prefix_len);
453 putnstr(buf.buffer(), buf.len());
457 putstr(cmd->cmd->cmd + buf.len());
459 buf.overlay(cmd->cmd->cmd, strlen(cmd->cmd->cmd));
470 hide_statline = false;
478 printf("\033[K%c", c);
482 *cmd = Jdb_core::has_cmd(buf.buffer());
485 unsigned cmd_len = strlen(cmd->cmd->cmd);
486 *args = buf.buffer() + cmd_len;
487 while (**args == ' ')
489 return false; // do not leave the debugger
493 printf("unknown command: '%s'\n", buf.buffer());
502 Jdb::execute_command()
505 Jdb_core::Cmd cmd(0,0);
510 leave = input_short_mode(&cmd, &args, cmd_key);
512 leave = input_long_mode(&cmd, &args);
519 int ret = Jdb_core::exec_cmd( cmd, args );
522 hide_statline = false;
534 Jdb::open_debug_console(unsigned cpu)
537 save_disable_irqs(cpu);
541 if (!stop_all_cpus(cpu))
542 return false; // CPUs other than 0 never become interacitve
544 if (!Jdb_screen::direct_enabled())
545 Kconsole::console()->
546 change_state(Console::DIRECT, 0, ~Console::OUTENABLED, 0);
554 Jdb::close_debug_console(unsigned cpu)
560 running.cpu(cpu) = 0;
561 // eat up input from console
562 while (Kconsole::console()->getchar(false)!=-1)
565 Kconsole::console()->
566 change_state(Console::DIRECT, 0, ~0UL, Console::OUTENABLED);
569 leave_wait_for_others();
579 Jdb::remote_work(unsigned cpu, void (*func)(unsigned, void *), void *data,
589 if (!Jdb::remote_func_running.cpu(cpu))
594 Jdb::remote_func_running.cpu(cpu) = 1;
595 Jdb::remote_func_data.cpu(cpu) = data;
597 set_monitored_address(&Jdb::remote_func.cpu(cpu), func);
603 if (!Jdb::remote_func_running.cpu(cpu))
614 int res = Kconsole::console()->getchar();
615 check_for_cpus(false);
620 void Jdb::cursor_home()
626 void Jdb::cursor_end_of_screen()
628 putstr("\033[127;1H");
631 //-------- pretty print functions ------------------------------
634 Jdb::write_ll_ns(Signed64 ns, char *buf, int maxlen, bool sign)
636 Unsigned64 uns = (ns < 0) ? -ns : ns;
638 if (uns >= 3600000000000000ULL)
640 snprintf(buf, maxlen, ">999 h ");
646 *buf++ = (ns < 0) ? '-' : (ns == 0) ? ' ' : '+';
650 if (uns >= 60000000000000ULL)
653 Mword _h = uns / 3600000000000ULL;
654 Mword _m = (uns % 3600000000000ULL) / 60000000000ULL;
655 snprintf(buf, maxlen, "%3lu:%02lu h ", _h, _m);
659 if (uns >= 1000000000000ULL)
662 Mword _m = uns / 60000000000ULL;
663 Mword _s = (uns % 60000000000ULL) / 1000ULL;
664 snprintf(buf, maxlen, "%3lu:%02lu M ", _m, _s);
668 if (uns >= 1000000000ULL)
671 Mword _s = uns / 1000000000ULL;
672 Mword _ms = (uns % 1000000000ULL) / 1000000ULL;
673 snprintf(buf, maxlen, "%3lu.%03lu s ", _s, _ms);
680 Mword _ms = uns / 1000000UL;
681 Mword _us = (uns % 1000000UL) / 1000UL;
682 snprintf(buf, maxlen, "%3lu.%03lu ms", _ms, _us);
688 snprintf(buf, maxlen, " 0 ");
692 Console* gzip = Kconsole::console()->find_console(Console::GZIP);
693 Mword _us = uns / 1000UL;
694 Mword _ns = uns % 1000UL;
695 snprintf(buf, maxlen, "%3lu.%03lu %c ", _us, _ns,
696 gzip && gzip->state() & Console::OUTENABLED
698 : Config::char_micro);
703 Jdb::write_ll_hex(Signed64 x, char *buf, int maxlen, bool sign)
706 Unsigned64 xu = (x < 0) ? -x : x;
709 snprintf(buf, maxlen, "%s%03lx" L4_PTR_FMT,
710 (x < 0) ? "-" : (x == 0) ? " " : "+",
711 (Mword)((xu >> 32) & 0xfff), (Mword)xu);
713 snprintf(buf, maxlen, "%04lx" L4_PTR_FMT,
714 (Mword)((xu >> 32) & 0xffff), (Mword)xu);
719 Jdb::write_ll_dec(Signed64 x, char *buf, int maxlen, bool sign)
721 Unsigned64 xu = (x < 0) ? -x : x;
723 // display no more than 11 digits
724 if (xu >= 100000000000ULL)
726 snprintf(buf, maxlen, "%12s", ">= 10^11");
731 snprintf(buf, maxlen, "%+12lld", x);
733 snprintf(buf, maxlen, "%12llu", xu);
738 Jdb::get_current_active()
740 return current_active;
745 Jdb::get_entry_frame(unsigned cpu)
747 return entry_frame.cpu(cpu);
750 /// handling of standard cursor keys (Up/Down/PgUp/PgDn)
753 Jdb::std_cursor_key(int c, Mword cols, Mword lines, Mword max_absy, Mword *absy,
754 Mword *addy, Mword *addx, bool *redraw)
758 case KEY_CURSOR_LEFT:
779 case KEY_CURSOR_RIGHT:
783 if (*addx < cols - 1)
785 else if (*addy < lines - 1)
790 else if (*absy < max_absy)
810 case KEY_CURSOR_DOWN:
814 else if (*absy < max_absy)
820 case KEY_CURSOR_HOME:
836 if (*absy < max_absy)
864 if (*absy+lines-1 < max_absy)
871 if (*absy < max_absy)
876 else if (*addy < lines-1)
891 Jdb::get_task(unsigned cpu)
893 if (!get_thread(cpu))
896 return get_thread(cpu)->space();
901 // memory access wrappers
905 template< typename T >
907 Jdb::peek(T const *addr, Space *task, T &value)
909 // use an Mword here instead of T as some implementations of peek_task use
910 // an Mword in their operation which is potentially bigger than T
911 // XXX: should be fixed
913 bool ret = peek_task((Address)addr, task, &tmp, sizeof(T)) == 0;
919 template< typename T >
921 Jdb::poke(T *addr, Space *task, T const &value)
922 { return poke_task((Address)addr, task, &value, sizeof(T)) == 0; }
925 class Jdb_base_cmds : public Jdb_module
928 Jdb_base_cmds() FIASCO_INIT;
931 static Jdb_base_cmds jdb_base_cmds INIT_PRIORITY(JDB_MODULE_INIT_PRIO);
934 Jdb_module::Action_code
935 Jdb_base_cmds::action (int cmd, void *&, char const *&, int &)
940 Jdb_core::short_mode = !Jdb_core::short_mode;
941 printf("\ntoggle mode: now in %s command mode (use %s) to switch back\n",
942 Jdb_core::short_mode ? "short" : "long",
943 Jdb_core::short_mode ? "*" : "mode");
949 Jdb_base_cmds::num_cmds() const
955 Jdb_module::Cmd const *
956 Jdb_base_cmds::cmds() const
959 { { 0, "*", "mode", "", "*|mode\tswitch long and short command mode",
966 Jdb_base_cmds::Jdb_base_cmds()
967 : Jdb_module("GENERAL")
971 //---------------------------------------------------------------------------
974 PRIVATE inline static void Jdb::rcv_uart_enable() {}
976 //---------------------------------------------------------------------------
977 IMPLEMENTATION [!ux]:
979 #include "kernel_uart.h"
981 PRIVATE inline static
983 Jdb::rcv_uart_enable()
985 if (Config::serial_esc == Config::SERIAL_ESC_IRQ)
986 Kernel_uart::enable_rcv_irq();
989 //---------------------------------------------------------------------------
995 char Jdb::esc_iret[] = "\033[36;1m";
996 char Jdb::esc_bt[] = "\033[31m";
997 char Jdb::esc_emph[] = "\033[33;1m";
998 char Jdb::esc_emph2[] = "\033[32;1m";
999 char Jdb::esc_mark[] = "\033[35;1m";
1000 char Jdb::esc_line[] = "\033[37m";
1001 char Jdb::esc_symbol[] = "\033[33;1m";
1008 Jdb::enter_jdb(Jdb_entry_frame *e, unsigned cpu)
1012 if (!remote_work_ipi_process(cpu))
1018 enter_trap_handler(cpu);
1020 if (handle_conditional_breakpoint(cpu))
1022 // don't enter debugger, only logged breakpoint
1023 leave_trap_handler(cpu);
1027 if (!running.cpu(cpu))
1028 entry_frame.cpu(cpu) = e;
1030 volatile bool really_break = true;
1032 static jmp_buf recover_buf;
1033 static Jdb_entry_frame nested_trap_frame;
1035 if (running.cpu(cpu))
1037 nested_trap_frame = *e;
1039 // Since we entered the kernel debugger a second time,
1040 // Thread::nested_trap_recover
1041 // has a value of 2 now. We don't leave this function so correct the
1043 Thread::nested_trap_recover.cpu(cpu)--;
1045 longjmp(recover_buf, 1);
1048 // all following exceptions are handled by jdb itself
1049 running.cpu(cpu) = true;
1051 if (!open_debug_console(cpu))
1052 { // not on the master CPU just wait
1053 close_debug_console(cpu);
1054 leave_trap_handler(cpu);
1058 Jdb::current_cpu = cpu;
1059 // check for int $3 user debugging interface
1060 if (foreach_cpu(&handle_user_request, true))
1062 close_debug_console(cpu);
1063 leave_trap_handler(cpu);
1067 hide_statline = false;
1069 // clear error message
1070 *error_buffer.cpu(cpu) = '\0';
1072 really_break = foreach_cpu(&handle_debug_traps, false);
1074 while (setjmp(recover_buf))
1076 // handle traps which occured while we are in Jdb
1077 Kconsole::console()->end_exclusive(Console::GZIP);
1078 handle_nested_trap(&nested_trap_frame);
1081 if (!never_break && really_break)
1083 // determine current task/thread from stack pointer
1086 LOG_MSG(current_active, "=== enter jdb ===");
1090 screen_scroll(1, Jdb_screen::height());
1093 cursor(Jdb_screen::height(), 1);
1094 printf("\n%s%s %.*s\033[m \n",
1098 : " WARNING: Fiasco kernel checksum differs -- "
1099 "read-only data has changed!\n",
1100 Jdb_screen::width()-11,
1102 for (unsigned i = 0; i < Config::Max_num_cpus; ++i)
1106 printf(" CPU%2u [" L4_PTR_FMT "]: %s\n", i,
1107 entry_frame.cpu(i)->ip(), error_buffer.cpu(i));
1109 printf(" CPU%2u: is not in JDB (not responding)\n", i);
1111 hide_statline = true;
1114 printf_statline(0, 0, "_");
1116 } while (execute_command());
1118 // reset scrolling region of serial terminal
1119 screen_scroll(1,127);
1122 blink_cursor(Jdb_screen::height(), 1);
1124 // goto end of screen
1125 Jdb::cursor(127, 1);
1128 // reenable interrupts
1129 close_debug_console(cpu);
1133 leave_trap_handler(cpu);
1138 //--------------------------------------------------------------------------
1139 IMPLEMENTATION [!mp]:
1143 Jdb::stop_all_cpus(unsigned /*current_cpu*/)
1149 Jdb::leave_wait_for_others()
1154 Jdb::check_for_cpus(bool)
1157 PRIVATE static inline
1159 Jdb::remote_work_ipi_process(unsigned)
1163 //---------------------------------------------------------------------------
1166 #include "spin_lock.h"
1171 static Spin_lock<> _remote_call_lock;
1172 static void (*_remote_work_ipi_func)(unsigned, void *);
1173 static void *_remote_work_ipi_func_data;
1174 static unsigned long _remote_work_ipi_done;
1177 //--------------------------------------------------------------------------
1178 IMPLEMENTATION [mp]:
1180 void (*Jdb::_remote_work_ipi_func)(unsigned, void *);
1181 void *Jdb::_remote_work_ipi_func_data;
1182 unsigned long Jdb::_remote_work_ipi_done;
1183 Spin_lock<> Jdb::_remote_call_lock;
1187 Jdb::check_for_cpus(bool try_nmi)
1189 enum { Max_wait_cnt = 1000 };
1190 for (unsigned c = 1; c < Config::Max_num_cpus; ++c)
1192 if (Cpu::online(c) && !running.cpu(c))
1193 Ipi::send(Ipi::Debug, 0, c);
1197 unsigned long wait_cnt = 0;
1200 bool all_there = true;
1201 cpus_in_debugger = 0;
1203 for (unsigned c = 1; c < Config::Max_num_cpus; ++c)
1207 if (!running.cpu(c))
1218 if (++wait_cnt == Max_wait_cnt)
1227 bool do_retry = false;
1228 for (unsigned c = 1; c < Config::Max_num_cpus; ++c)
1232 if (!running.cpu(c))
1234 printf("JDB: CPU %d: is not responding ... %s\n",c,
1235 try_nmi ? "trying NMI" : "");
1249 // All CPUs entered JDB, so go on and become interactive
1255 Jdb::stop_all_cpus(unsigned current_cpu)
1257 enum { Max_wait_cnt = 1000 };
1258 // JDB allways runs on CPU 0, if any other CPU enters the debugger
1259 // CPU 0 is notified to do enter the debugger too
1260 if (current_cpu == 0)
1262 // I'm CPU 0 stop all other CPUs and wait for them to enter the JDB
1265 check_for_cpus(true);
1266 // All CPUs entered JDB, so go on and become interactive
1271 // Huh, not CPU 0, so notify CPU 0 to enter JDB too
1272 // The notification is ignored if CPU 0 is already within JDB
1274 Ipi::send(Ipi::Debug, current_cpu, 0);
1276 unsigned long wait_count = Max_wait_cnt;
1277 while (!running.cpu(0) && wait_count)
1285 if (wait_count == 0)
1288 // Wait for messages from CPU 0
1289 while ((volatile bool)jdb_active)
1292 void (**func)(unsigned, void *) = &remote_func.cpu(current_cpu);
1293 void (*f)(unsigned, void *);
1295 if ((f = monitor_address(current_cpu, func)))
1297 // Execute functions from queued from another CPU
1299 f(current_cpu, remote_func_data.cpu(current_cpu));
1301 remote_func_running.cpu(current_cpu) = 0;
1307 // This CPU defacto left JDB
1308 running.cpu(current_cpu) = 0;
1310 // Signal CPU 0, that we are ready to leve the debugger
1311 // This is the second door of the airlock
1312 atomic_mp_add(&cpus_in_debugger, -1UL);
1314 // Wait for CPU 0 to leave us out
1315 while ((volatile bool)leave_barrier)
1321 // CPU 0 signaled us to leave JDB
1329 Jdb::leave_wait_for_others()
1336 bool all_there = true;
1337 for (unsigned c = 0; c < Config::Max_num_cpus; ++c)
1339 if (Cpu::online(c) && running.cpu(c))
1342 set_monitored_address(&Jdb::remote_func.cpu(c),
1343 (void (*)(unsigned, void *))0);
1344 // printf("JDB: wait for CPU[%2u] to leave\n", c);
1359 while ((volatile unsigned long)cpus_in_debugger)
1369 // The remote_work_ipi* functions are for the IPI round-trip benchmark (only)
1372 Jdb::remote_work_ipi_process(unsigned cpu)
1374 if (_remote_work_ipi_func)
1376 _remote_work_ipi_func(cpu, _remote_work_ipi_func_data);
1378 _remote_work_ipi_done = 1;
1386 Jdb::remote_work_ipi(unsigned this_cpu, unsigned to_cpu,
1387 void (*f)(unsigned, void *), void *data, bool wait = true)
1389 if (to_cpu == this_cpu)
1395 if (!Cpu::online(to_cpu))
1398 auto guard = lock_guard(_remote_call_lock);
1400 _remote_work_ipi_func = f;
1401 _remote_work_ipi_func_data = data;
1402 _remote_work_ipi_done = 0;
1404 Ipi::send(Ipi::Debug, this_cpu, to_cpu);
1407 while (!*(volatile unsigned long *)&_remote_work_ipi_done)
1410 _remote_work_ipi_func = 0;