summaryrefslogtreecommitdiff
path: root/sys/arch/i386/i386/db_mp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/i386/i386/db_mp.c')
-rw-r--r--sys/arch/i386/i386/db_mp.c203
1 files changed, 86 insertions, 117 deletions
diff --git a/sys/arch/i386/i386/db_mp.c b/sys/arch/i386/i386/db_mp.c
index 0a859f08360..3c1b184a927 100644
--- a/sys/arch/i386/i386/db_mp.c
+++ b/sys/arch/i386/i386/db_mp.c
@@ -1,32 +1,19 @@
-/* $OpenBSD: db_mp.c,v 1.2 2004/06/13 21:49:15 niklas Exp $ */
+/* $OpenBSD: db_mp.c,v 1.3 2004/06/21 22:41:11 andreas Exp $ */
/*
- * Copyright (c) 2003 Andreas Gunnarsson
- * All rights reserved.
+ * Copyright (c) 2003, 2004 Andreas Gunnarsson <andreas@openbsd.org>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
@@ -36,19 +23,24 @@
#include <ddb/db_output.h>
-#define DDB_STATE_NOT_RUNNING 0
-#define DDB_STATE_RUNNING 1
-
struct SIMPLELOCK ddb_mp_slock;
volatile int ddb_state = DDB_STATE_NOT_RUNNING; /* protected by ddb_mp_slock */
volatile cpuid_t ddb_active_cpu; /* protected by ddb_mp_slock */
+extern volatile boolean_t db_switch_cpu;
+extern volatile long db_switch_to_cpu;
+
/*
- * ddb_enter_ddb() is called when ddb is entered to stop the other
- * CPUs. If another cpu is already in ddb we'll wait until it's finished.
+ * All processors wait in db_enter_ddb() (unless explicitly started from
+ * ddb) but only one owns ddb. If the current processor should own ddb,
+ * db_enter_ddb() returns 1. If the current processor should keep
+ * executing as usual (if ddb is exited or the processor is explicitly
+ * started), db_enter_ddb returns 0.
+ * If this is the first CPU entering ddb, db_enter_ddb() will stop all
+ * other CPUs by sending IPIs.
*/
-void
+int
db_enter_ddb()
{
int s, i;
@@ -56,57 +48,72 @@ db_enter_ddb()
s = splhigh();
SIMPLE_LOCK(&ddb_mp_slock);
- while (ddb_state == DDB_STATE_RUNNING
- && ddb_active_cpu != cpu_number()) {
- db_printf("CPU %d waiting to enter ddb\n", cpu_number());
+ /* If we are first in, grab ddb and stop all other CPUs */
+ if (ddb_state == DDB_STATE_NOT_RUNNING) {
+ ddb_active_cpu = cpu_number();
+ ddb_state = DDB_STATE_RUNNING;
+ curcpu()->ci_ddb_paused = CI_DDB_INDDB;
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ for (i = 0; i < I386_MAXPROCS; i++) {
+ if (cpu_info[i] != NULL && i != cpu_number() &&
+ cpu_info[i]->ci_ddb_paused != CI_DDB_STOPPED) {
+ cpu_info[i]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
+ i386_send_ipi(cpu_info[i], I386_IPI_DDB);
+ }
+ }
+ splx(s);
+ return (1);
+ }
+
+ /* Leaving ddb completely. Start all other CPUs and return 0 */
+ if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_EXITING) {
+ for (i = 0; i < I386_MAXPROCS; i++) {
+ if (cpu_info[i] != NULL) {
+ cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING;
+ }
+ }
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
+ return (0);
+ }
+
+ /* We're switching to another CPU. db_ddbproc_cmd() has made sure
+ * it is waiting for ddb, we just have to set ddb_active_cpu. */
+ if (ddb_active_cpu == cpu_number() && db_switch_cpu) {
+ curcpu()->ci_ddb_paused = CI_DDB_SHOULDSTOP;
+ db_switch_cpu = 0;
+ ddb_active_cpu = db_switch_to_cpu;
+ cpu_info[db_switch_to_cpu]->ci_ddb_paused = CI_DDB_ENTERDDB;
+ }
+
+ /* Wait until we should enter ddb or resume */
+ while (ddb_active_cpu != cpu_number() &&
+ curcpu()->ci_ddb_paused != CI_DDB_RUNNING) {
+ if (curcpu()->ci_ddb_paused == CI_DDB_SHOULDSTOP)
+ curcpu()->ci_ddb_paused = CI_DDB_STOPPED;
SIMPLE_UNLOCK(&ddb_mp_slock);
splx(s);
/* Busy wait without locking, we'll confirm with lock later */
- while (ddb_state == DDB_STATE_RUNNING
- && ddb_active_cpu != cpu_number())
+ while (ddb_active_cpu != cpu_number() &&
+ curcpu()->ci_ddb_paused != CI_DDB_RUNNING)
; /* Do nothing */
s = splhigh();
SIMPLE_LOCK(&ddb_mp_slock);
}
- ddb_state = DDB_STATE_RUNNING;
- ddb_active_cpu = cpu_number();
-
- for (i = 0; i < I386_MAXPROCS; i++) {
- if (cpu_info[i] != NULL) {
- if (i == cpu_number())
- cpu_info[i]->ci_ddb_paused = CI_DDB_INDDB;
- else if (cpu_info[i]->ci_ddb_paused
- != CI_DDB_STOPPED) {
- cpu_info[i]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
- db_printf("Sending IPI to cpu %d\n", i);
- i386_send_ipi(cpu_info[i], I386_IPI_DDB);
- }
- }
- }
- db_printf("CPU %d entering ddb\n", cpu_number());
- SIMPLE_UNLOCK(&ddb_mp_slock);
- splx(s);
-}
-
-void
-db_leave_ddb()
-{
- int s, i;
-
- s = splhigh();
- SIMPLE_LOCK(&ddb_mp_slock);
- db_printf("CPU %d leaving ddb\n", cpu_number());
- for (i = 0; i < I386_MAXPROCS; i++) {
- if (cpu_info[i] != NULL) {
- cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING;
- }
+ /* Either enter ddb or exit */
+ if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_RUNNING) {
+ curcpu()->ci_ddb_paused = CI_DDB_INDDB;
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
+ return (1);
+ } else {
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
+ return (0);
}
- ddb_state = DDB_STATE_NOT_RUNNING;
- SIMPLE_UNLOCK(&ddb_mp_slock);
- splx(s);
}
void
@@ -128,60 +135,22 @@ db_stopcpu(int cpu)
{
int s;
- if (cpu != cpu_number() && cpu_info[cpu] != NULL) {
- s = splhigh();
- SIMPLE_LOCK(&ddb_mp_slock);
+ s = splhigh();
+ SIMPLE_LOCK(&ddb_mp_slock);
+ if (cpu != cpu_number() && cpu_info[cpu] != NULL &&
+ cpu_info[cpu]->ci_ddb_paused != CI_DDB_STOPPED) {
cpu_info[cpu]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
- db_printf("Sending IPI to cpu %d\n", cpu);
SIMPLE_UNLOCK(&ddb_mp_slock);
splx(s);
i386_send_ipi(cpu_info[cpu], I386_IPI_DDB);
+ } else {
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
}
}
void
-db_movetocpu(int cpu)
-{
- int s;
-
- s = splhigh();
- SIMPLE_LOCK(&ddb_mp_slock);
- cpu_info[cpu]->ci_ddb_paused = CI_DDB_ENTERDDB;
- db_printf("Sending IPI to cpu %d\n", cpu);
- SIMPLE_UNLOCK(&ddb_mp_slock);
- splx(s);
- /* XXX If other CPU was running and IPI is lost, we lose. */
- i386_send_ipi(cpu_info[cpu], I386_IPI_DDB);
-}
-
-void
i386_ipi_db(struct cpu_info *ci)
{
- int s;
-
- s = splhigh();
- SIMPLE_LOCK(&ddb_mp_slock);
- db_printf("CPU %d received ddb IPI\n", cpu_number());
- while (ci->ci_ddb_paused == CI_DDB_SHOULDSTOP
- || ci->ci_ddb_paused == CI_DDB_STOPPED) {
- if (ci->ci_ddb_paused == CI_DDB_SHOULDSTOP)
- ci->ci_ddb_paused = CI_DDB_STOPPED;
- SIMPLE_UNLOCK(&ddb_mp_slock);
- while (ci->ci_ddb_paused == CI_DDB_STOPPED)
- ; /* Do nothing */
- SIMPLE_LOCK(&ddb_mp_slock);
- }
- if (ci->ci_ddb_paused == CI_DDB_ENTERDDB) {
- ddb_state = DDB_STATE_RUNNING;
- ddb_active_cpu = cpu_number();
- ci->ci_ddb_paused = CI_DDB_INDDB;
- db_printf("CPU %d grabbing ddb\n", cpu_number());
- SIMPLE_UNLOCK(&ddb_mp_slock);
- Debugger();
- SIMPLE_LOCK(&ddb_mp_slock);
- ci->ci_ddb_paused = CI_DDB_RUNNING;
- }
- db_printf("CPU %d leaving ddb IPI handler\n", cpu_number());
- SIMPLE_UNLOCK(&ddb_mp_slock);
- splx(s);
+ Debugger();
}