|
|
GNU Mach 1.5
/*
* Mach Operating System
* Copyright (c) 1993,1992 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or [email protected]
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
#if MACH_KDB
#if NCPUS > 1
#include <mach/boolean.h>
#include <mach/machine.h>
#include <kern/cpu_number.h>
#include <kern/lock.h>
#include <machine/db_machdep.h>
#include <ddb/db_command.h>
#include <ddb/db_run.h>
#include <ddb/db_mp.h>
/*
* Routines to interlock access to the kernel debugger on
* multiprocessors.
*/
decl_simple_lock_data(,db_lock) /* lock to enter debugger */
volatile int db_cpu = -1; /* CPU currently in debugger */
/* -1 if none */
int db_active[NCPUS] = { 0 }; /* count recursive entries
into debugger */
int db_slave[NCPUS] = { 0 }; /* nonzero if cpu interrupted
by another cpu in debugger */
boolean_t db_enter_debug = FALSE;
/*
* Called when entering kernel debugger.
* Takes db lock. If we were called remotely (slave state) we just
* wait for db_cpu to be equal to cpu_number(). Otherwise enter debugger
* if not active on another cpu
*/
boolean_t
db_enter(void)
{
int mycpu = cpu_number();
/*
* Count recursive entries to debugger.
*/
db_active[mycpu]++;
/*
* Wait for other CPUS to leave debugger.
*/
lock_db();
if (db_enter_debug)
db_printf(
"db_enter: cpu %d[%d], master %d, db_cpu %d, run mode %d\n",
mycpu, db_slave[mycpu], master_cpu, db_cpu, db_run_mode);
/*
* If no CPU in debugger, and I am not being stopped,
* enter the debugger.
*/
if (db_cpu == -1 && !db_slave[mycpu]) {
remote_db(); /* stop other cpus */
db_cpu = mycpu;
return TRUE;
}
/*
* If I am already in the debugger (recursive entry
* or returning from single step), enter debugger.
*/
else if (db_cpu == mycpu)
return TRUE;
/*
* Otherwise, cannot enter debugger.
*/
else
return FALSE;
}
/*
* Leave debugger.
*/
void
db_leave(void)
{
int mycpu = cpu_number();
/*
* If continuing, give up debugger
*/
if (db_run_mode == STEP_CONTINUE)
db_cpu = -1;
/*
* If I am a slave, drop my slave count.
*/
if (db_slave[mycpu])
db_slave[mycpu]--;
if (db_enter_debug)
db_printf("db_leave: cpu %d[%d], db_cpu %d, run_mode %d\n",
mycpu, db_slave[mycpu], db_cpu, db_run_mode);
/*
* Unlock debugger.
*/
unlock_db();
/*
* Drop recursive entry count.
*/
db_active[mycpu]--;
}
/*
* invoke kernel debugger on slave processors
*/
void
remote_db(void) {
int my_cpu = cpu_number();
int i;
for (i = 0; i < NCPUS; i++) {
if (i != my_cpu &&
machine_slot[i].is_cpu &&
machine_slot[i].running)
{
cpu_interrupt_to_db(i);
}
}
}
/*
* Save and restore DB global registers.
*
* DB_SAVE_CTXT must be at the start of a block, and
* DB_RESTORE_CTXT must be in the same block.
*/
#ifdef __STDC__
#define DB_SAVE(type, name) extern type name; type name##_save = name
#define DB_RESTORE(name) name = name##_save
#else /* __STDC__ */
#define DB_SAVE(type, name) extern type name; type name/**/_save = name
#define DB_RESTORE(name) name = name/**/_save
#endif /* __STDC__ */
#define DB_SAVE_CTXT() \
DB_SAVE(int, db_run_mode); \
DB_SAVE(boolean_t, db_sstep_print); \
DB_SAVE(int, db_loop_count); \
DB_SAVE(int, db_call_depth); \
DB_SAVE(int, db_inst_count); \
DB_SAVE(int, db_last_inst_count); \
DB_SAVE(int, db_load_count); \
DB_SAVE(int, db_store_count); \
DB_SAVE(boolean_t, db_cmd_loop_done); \
DB_SAVE(jmp_buf_t *, db_recover); \
DB_SAVE(db_addr_t, db_dot); \
DB_SAVE(db_addr_t, db_last_addr); \
DB_SAVE(db_addr_t, db_prev); \
DB_SAVE(db_addr_t, db_next); \
SAVE_DDB_REGS
#define DB_RESTORE_CTXT() \
DB_RESTORE(db_run_mode); \
DB_RESTORE(db_sstep_print); \
DB_RESTORE(db_loop_count); \
DB_RESTORE(db_call_depth); \
DB_RESTORE(db_inst_count); \
DB_RESTORE(db_last_inst_count); \
DB_RESTORE(db_load_count); \
DB_RESTORE(db_store_count); \
DB_RESTORE(db_cmd_loop_done); \
DB_RESTORE(db_recover); \
DB_RESTORE(db_dot); \
DB_RESTORE(db_last_addr); \
DB_RESTORE(db_prev); \
DB_RESTORE(db_next); \
RESTORE_DDB_REGS
/*
* switch to another cpu
*/
void
db_on(int cpu)
{
/*
* Save ddb global variables
*/
DB_SAVE_CTXT();
/*
* Don`t do if bad CPU number.
* CPU must also be spinning in db_entry.
*/
if (cpu < 0 || cpu >= NCPUS || !db_active[cpu])
return;
/*
* Give debugger to that CPU
*/
db_cpu = cpu;
unlock_db();
/*
* Wait for it to come back again
*/
lock_db();
/*
* Restore ddb globals
*/
DB_RESTORE_CTXT();
if (db_cpu == -1) /* someone continued */
db_continue_cmd(0, 0, 0, "");
}
/*
* Called by interprocessor interrupt when one CPU is
* in kernel debugger and wants to stop other CPUs
*/
void
remote_db_enter(void)
{
db_slave[cpu_number()]++;
kdb_kintr();
}
/*
* Acquire kernel debugger.
* Conditional code for forwarding characters from slave to console
* if console on master only.
*/
/*
* As long as db_cpu is not -1 or cpu_number(), we know that debugger
* is active on another cpu.
*/
void
lock_db(void)
{
int my_cpu = cpu_number();
for (;;) {
#if CONSOLE_ON_MASTER
if (my_cpu == master_cpu) {
db_console();
}
#endif /* CONSOLE_ON_MASTER */
if (db_cpu != -1 && db_cpu != my_cpu)
continue;
#if CONSOLE_ON_MASTER
if (my_cpu == master_cpu) {
if (!simple_lock_try(&db_lock))
continue;
}
else {
simple_lock(&db_lock);
}
#else /* CONSOLE_ON_MASTER */
simple_lock(&db_lock);
#endif /* CONSOLE_ON_MASTER */
if (db_cpu == -1 || db_cpu == my_cpu)
break;
simple_unlock(&db_lock);
}
}
void
unlock_db(void)
{
simple_unlock(&db_lock);
}
#if CONSOLE_ON_MASTER
void
db_console(void)
{
if (i_bit(CBUS_PUT_CHAR, my_word)) {
volatile u_char c = cbus_ochar;
i_bit_clear(CBUS_PUT_CHAR, my_word);
cnputc(c);
} else if (i_bit(CBUS_GET_CHAR, my_word)) {
if (cbus_wait_char)
cbus_ichar = cngetc();
else
cbus_ichar = cnmaygetc();
i_bit_clear(CBUS_GET_CHAR, my_word);
#ifndef notdef
} else if (!cnmaygetc()) {
#else /* notdef */
} else if (com_is_char() && !com_getc(TRUE)) {
#endif /* notdef */
simple_unlock(&db_lock);
db_cpu = my_cpu;
}
}
#endif /* CONSOLE_ON_MASTER */
#endif /* NCPUS > 1 */
#endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.