1 /* $OpenBSD: db_mp.c,v 1.14 2023/01/30 10:49:05 jsg 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/param.h>
20 #include <sys/systm.h>
21 #include <sys/types.h>
22 #include <sys/mutex.h>
23
24 #include <machine/db_machdep.h>
25
26 struct db_mutex ddb_mp_mutex = DB_MUTEX_INITIALIZER;
27
28 volatile int ddb_state = DDB_STATE_NOT_RUNNING; /* protected by ddb_mp_mutex */
29 volatile cpuid_t ddb_active_cpu; /* protected by ddb_mp_mutex */
30
31 extern volatile int db_switch_cpu;
32 extern volatile long db_switch_to_cpu;
33
34 /*
35 * All processors wait in db_enter_ddb() (unless explicitly started from
36 * ddb) but only one owns ddb. If the current processor should own ddb,
37 * db_enter_ddb() returns 1. If the current processor should keep
38 * executing as usual (if ddb is exited or the processor is explicitly
39 * started), db_enter_ddb returns 0.
40 * If this is the first CPU entering ddb, db_enter_ddb() will stop all
41 * other CPUs by sending IPIs.
42 */
43 int
db_enter_ddb(void)44 db_enter_ddb(void)
45 {
46 int i;
47
48 db_mtx_enter(&ddb_mp_mutex);
49
50 /* If we are first in, grab ddb and stop all other CPUs */
51 if (ddb_state == DDB_STATE_NOT_RUNNING) {
52 ddb_active_cpu = cpu_number();
53 ddb_state = DDB_STATE_RUNNING;
54 curcpu()->ci_ddb_paused = CI_DDB_INDDB;
55 db_mtx_leave(&ddb_mp_mutex);
56 for (i = 0; i < MAXCPUS; i++) {
57 if (cpu_info[i] != NULL && i != cpu_number() &&
58 cpu_info[i]->ci_ddb_paused != CI_DDB_STOPPED) {
59 cpu_info[i]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
60 i386_send_ipi(cpu_info[i], I386_IPI_DDB);
61 }
62 }
63 return (1);
64 }
65
66 /* Leaving ddb completely. Start all other CPUs and return 0 */
67 if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_EXITING) {
68 for (i = 0; i < MAXCPUS; i++) {
69 if (cpu_info[i] != NULL) {
70 cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING;
71 }
72 }
73 db_mtx_leave(&ddb_mp_mutex);
74 return (0);
75 }
76
77 /* We're switching to another CPU. db_ddbproc_cmd() has made sure
78 * it is waiting for ddb, we just have to set ddb_active_cpu. */
79 if (ddb_active_cpu == cpu_number() && db_switch_cpu) {
80 curcpu()->ci_ddb_paused = CI_DDB_SHOULDSTOP;
81 db_switch_cpu = 0;
82 ddb_active_cpu = db_switch_to_cpu;
83 cpu_info[db_switch_to_cpu]->ci_ddb_paused = CI_DDB_ENTERDDB;
84 }
85
86 /* Wait until we should enter ddb or resume */
87 while (ddb_active_cpu != cpu_number() &&
88 curcpu()->ci_ddb_paused != CI_DDB_RUNNING) {
89 if (curcpu()->ci_ddb_paused == CI_DDB_SHOULDSTOP)
90 curcpu()->ci_ddb_paused = CI_DDB_STOPPED;
91 db_mtx_leave(&ddb_mp_mutex);
92
93 /* Busy wait without locking, we'll confirm with lock later */
94 while (ddb_active_cpu != cpu_number() &&
95 curcpu()->ci_ddb_paused != CI_DDB_RUNNING)
96 ; /* Do nothing */
97
98 db_mtx_enter(&ddb_mp_mutex);
99 }
100
101 /* Either enter ddb or exit */
102 if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_RUNNING) {
103 curcpu()->ci_ddb_paused = CI_DDB_INDDB;
104 db_mtx_leave(&ddb_mp_mutex);
105 return (1);
106 } else {
107 db_mtx_leave(&ddb_mp_mutex);
108 return (0);
109 }
110 }
111
112 void
db_startcpu(int cpu)113 db_startcpu(int cpu)
114 {
115 if (cpu != cpu_number() && cpu_info[cpu] != NULL) {
116 db_mtx_enter(&ddb_mp_mutex);
117 cpu_info[cpu]->ci_ddb_paused = CI_DDB_RUNNING;
118 db_mtx_leave(&ddb_mp_mutex);
119 }
120 }
121
122 void
db_stopcpu(int cpu)123 db_stopcpu(int cpu)
124 {
125 db_mtx_enter(&ddb_mp_mutex);
126 if (cpu != cpu_number() && cpu_info[cpu] != NULL &&
127 cpu_info[cpu]->ci_ddb_paused != CI_DDB_STOPPED) {
128 cpu_info[cpu]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
129 db_mtx_leave(&ddb_mp_mutex);
130 i386_send_ipi(cpu_info[cpu], I386_IPI_DDB);
131 } else {
132 db_mtx_leave(&ddb_mp_mutex);
133 }
134 }
135
136 void
i386_ipi_db(struct cpu_info * ci)137 i386_ipi_db(struct cpu_info *ci)
138 {
139 db_enter();
140 }
141