xref: /openbsd-src/sys/arch/i386/i386/db_mp.c (revision f4e7063748a2ac72b2bab4389c0a7efc72d82189)
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