1 /* $OpenBSD: db_mp.c,v 1.4 2004/07/20 20:18:53 art Exp $ */
2
3 /*
4 * Copyright (c) 2003, 2004 Andreas Gunnarsson <andreas@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/types.h>
20 #include <sys/simplelock.h>
21
22 #include <machine/db_machdep.h>
23 #include <sys/mutex.h>
24
25 #include <ddb/db_output.h>
26
27 struct mutex ddb_mp_mutex = MUTEX_INITIALIZER(IPL_HIGH);
28
29 volatile int ddb_state = DDB_STATE_NOT_RUNNING; /* protected by ddb_mp_mutex */
30 volatile cpuid_t ddb_active_cpu; /* protected by ddb_mp_mutex */
31
32 extern volatile boolean_t db_switch_cpu;
33 extern volatile long db_switch_to_cpu;
34
35 /*
36 * All processors wait in db_enter_ddb() (unless explicitly started from
37 * ddb) but only one owns ddb. If the current processor should own ddb,
38 * db_enter_ddb() returns 1. If the current processor should keep
39 * executing as usual (if ddb is exited or the processor is explicitly
40 * started), db_enter_ddb returns 0.
41 * If this is the first CPU entering ddb, db_enter_ddb() will stop all
42 * other CPUs by sending IPIs.
43 */
44 int
45 db_enter_ddb()
46 {
47 int i;
48
49 mtx_enter(&ddb_mp_mutex);
50
51 /* If we are first in, grab ddb and stop all other CPUs */
52 if (ddb_state == DDB_STATE_NOT_RUNNING) {
53 ddb_active_cpu = cpu_number();
54 ddb_state = DDB_STATE_RUNNING;
55 curcpu()->ci_ddb_paused = CI_DDB_INDDB;
56 mtx_leave(&ddb_mp_mutex);
57 for (i = 0; i < I386_MAXPROCS; i++) {
58 if (cpu_info[i] != NULL && i != cpu_number() &&
59 cpu_info[i]->ci_ddb_paused != CI_DDB_STOPPED) {
60 cpu_info[i]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
61 i386_send_ipi(cpu_info[i], I386_IPI_DDB);
62 }
63 }
64 return (1);
65 }
66
67 /* Leaving ddb completely. Start all other CPUs and return 0 */
68 if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_EXITING) {
69 for (i = 0; i < I386_MAXPROCS; i++) {
70 if (cpu_info[i] != NULL) {
71 cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING;
72 }
73 }
74 mtx_leave(&ddb_mp_mutex);
75 return (0);
76 }
77
78 /* We're switching to another CPU. db_ddbproc_cmd() has made sure
79 * it is waiting for ddb, we just have to set ddb_active_cpu. */
80 if (ddb_active_cpu == cpu_number() && db_switch_cpu) {
81 curcpu()->ci_ddb_paused = CI_DDB_SHOULDSTOP;
82 db_switch_cpu = 0;
83 ddb_active_cpu = db_switch_to_cpu;
84 cpu_info[db_switch_to_cpu]->ci_ddb_paused = CI_DDB_ENTERDDB;
85 }
86
87 /* Wait until we should enter ddb or resume */
88 while (ddb_active_cpu != cpu_number() &&
89 curcpu()->ci_ddb_paused != CI_DDB_RUNNING) {
90 if (curcpu()->ci_ddb_paused == CI_DDB_SHOULDSTOP)
91 curcpu()->ci_ddb_paused = CI_DDB_STOPPED;
92 mtx_leave(&ddb_mp_mutex);
93
94 /* Busy wait without locking, we'll confirm with lock later */
95 while (ddb_active_cpu != cpu_number() &&
96 curcpu()->ci_ddb_paused != CI_DDB_RUNNING)
97 ; /* Do nothing */
98
99 mtx_enter(&ddb_mp_mutex);
100 }
101
102 /* Either enter ddb or exit */
103 if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_RUNNING) {
104 curcpu()->ci_ddb_paused = CI_DDB_INDDB;
105 mtx_leave(&ddb_mp_mutex);
106 return (1);
107 } else {
108 mtx_leave(&ddb_mp_mutex);
109 return (0);
110 }
111 }
112
113 void
114 db_startcpu(int cpu)
115 {
116 if (cpu != cpu_number() && cpu_info[cpu] != NULL) {
117 mtx_enter(&ddb_mp_mutex);
118 cpu_info[cpu]->ci_ddb_paused = CI_DDB_RUNNING;
119 mtx_leave(&ddb_mp_mutex);
120 }
121 }
122
123 void
124 db_stopcpu(int cpu)
125 {
126 mtx_enter(&ddb_mp_mutex);
127 if (cpu != cpu_number() && cpu_info[cpu] != NULL &&
128 cpu_info[cpu]->ci_ddb_paused != CI_DDB_STOPPED) {
129 cpu_info[cpu]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
130 mtx_leave(&ddb_mp_mutex);
131 i386_send_ipi(cpu_info[cpu], I386_IPI_DDB);
132 } else {
133 mtx_leave(&ddb_mp_mutex);
134 }
135 }
136
137 void
138 i386_ipi_db(struct cpu_info *ci)
139 {
140 Debugger();
141 }