|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52:
53: /*
54: * Clock interrupt.
55: */
56: #include <cpus.h>
57: #include <time_stamp.h>
58: #include <mach_kdb.h>
59: #include <kern/cpu_number.h>
60: #include <kern/cpu_data.h>
61: #include <kern/kern_types.h>
62: #include <platforms.h>
63: #include <mp_v1_1.h>
64: #include <mach_kprof.h>
65: #include <mach_mp_debug.h>
66: #include <mach/std_types.h>
67:
68: #include <mach/clock_types.h>
69: #include <mach/boolean.h>
70: #include <i386/thread.h>
71: #include <i386/eflags.h>
72: #include <kern/assert.h>
73: #include <kern/misc_protos.h>
74: #include <i386/misc_protos.h>
75: #include <kern/time_out.h>
76:
77: #include <i386/ipl.h>
78:
79: #include <i386/hardclock_entries.h>
80: #include <i386/rtclock_entries.h>
81:
82: #if MACH_MP_DEBUG
83: #include <i386/mach_param.h> /* for HZ */
84: #endif /* MACH_MP_DEBUG */
85:
86: extern char return_to_iret[];
87:
88: #if TIME_STAMP && NCPUS > 1
89: extern unsigned time_stamp;
90: unsigned old_time_stamp, time_stamp_cum, nstamps;
91:
92: /*
93: * If H/W provides a counter, record number of ticks and cumulated
94: * time stamps to know timestamps rate.
95: * This should go away when ALARMCLOCKS installed
96: */
97: #define time_stamp_stat() \
98: if (my_cpu == 0) \
99: if (!old_time_stamp) { \
100: old_time_stamp = time_stamp; \
101: nstamps = 0; \
102: } else { \
103: nstamps++; \
104: time_stamp_cum = (time_stamp - old_time_stamp); \
105: }
106: #else /* TIME_STAMP && AT386 && NCPUS > 1 */
107: #define time_stamp_stat()
108: #endif /* TIME_STAMP && AT386 && NCPUS > 1 */
109:
110: #if MACH_KPROF
111: int masked_pc[NCPUS];
112: int missed_clock[NCPUS];
113: int detect_lost_tick = 0;
114: #endif /* MACH_KPROF */
115:
116: #if MACH_MP_DEBUG
117: int masked_state_cnt[NCPUS];
118: int masked_state_max = 10*HZ;
119: #endif /* MACH_MP_DEBUG */
120:
121: /*
122: * In the interest of a fast clock interrupt service path,
123: * this routine should be folded into assembly language with
124: * a direct interrupt vector on the i386. The "pit" interrupt
125: * should always call the rtclock_intr() routine on the master
126: * processor. The return value of the rtclock_intr() routine
127: * indicates whether HZ rate clock processing should be
128: * performed. (On the Sequent, all slave processors will
129: * run at HZ rate). For now, we'll leave this routine in C
130: * (with TIME_STAMP, MACH_MP_DEBUG and MACH_KPROF code this
131: * routine is way too large for assembler anyway).
132: */
133:
134: #ifdef PARANOID_KDB
135: int paranoid_debugger = TRUE;
136: int paranoid_count = 1000;
137: int paranoid_current = 0;
138: int paranoid_cpu = 0;
139: #endif /* PARANOID_KDB */
140:
141: void
142: hardclock(struct i386_interrupt_state *regs) /* saved registers */
143: {
144: int mycpu;
145: register unsigned pc;
146: register boolean_t usermode;
147:
148: mp_disable_preemption();
149: mycpu = cpu_number();
150:
151: #ifdef PARANOID_KDB
152: if (paranoid_cpu == mycpu &&
153: paranoid_current++ >= paranoid_count) {
154: paranoid_current = 0;
155: if (paranoid_debugger)
156: Debugger("hardclock");
157: }
158: #endif /* PARANOID_KDB */
159:
160: #if 0
161: #if MACH_MP_DEBUG
162: /*
163: * Increments counter of clock ticks handled under a masked state.
164: * Debugger() is called if masked state is kept during 1 sec.
165: * The counter is reset by splx() when ipl mask is set back to SPL0,
166: * and by spl0().
167: */
168: if (SPL_CMP_GT((old_ipl & 0xFF), SPL0)) {
169: if (masked_state_cnt[mycpu]++ >= masked_state_max) {
170: int max_save = masked_state_max;
171:
172: masked_state_cnt[mycpu] = 0;
173: masked_state_max = 0x7fffffff;
174:
175: if (ret_addr == return_to_iret) {
176: usermode = (regs->efl & EFL_VM) ||
177: ((regs->cs & 0x03) != 0);
178: pc = (unsigned)regs->eip;
179: } else {
180: usermode = FALSE;
181: pc = (unsigned)
182: ((struct i386_interrupt_state *)&old_ipl)->eip;
183: }
184: printf("looping at high IPL, usermode=%d pc=0x%x\n",
185: usermode, pc);
186: Debugger("");
187:
188: masked_state_cnt[mycpu] = 0;
189: masked_state_max = max_save;
190: }
191: } else
192: masked_state_cnt[mycpu] = 0;
193: #endif /* MACH_MP_DEBUG */
194: #endif
195:
196: #if MACH_KPROF
197: /*
198: * If we were masked against the clock skip call
199: * to rtclock_intr(). When MACH_KPROF is set, the
200: * clock frequency of the master-cpu is confined
201: * to the HZ rate.
202: */
203: if (SPL_CMP_LT(old_ipl & 0xFF, SPL7))
204: #endif /* MACH_KPROF */
205: /*
206: * The master processor executes the rtclock_intr() routine
207: * on every clock tick. The rtclock_intr() routine returns
208: * a zero value on a HZ tick boundary.
209: */
210: if (mycpu == master_cpu) {
211: if (rtclock_intr() != 0) {
212: mp_enable_preemption();
213: return;
214: }
215: }
216:
217: /*
218: * The following code is executed at HZ rate by all processors
219: * in the system. This implies that the clock rate on slave
220: * processors must be HZ rate.
221: */
222:
223: time_stamp_stat();
224:
225: #if 0
226: if (ret_addr == return_to_iret) {
227: /*
228: * A kernel-loaded task executing within itself will look like
229: * "kernel mode", here. This is correct with syscalls
230: * implemented using migrating threads, because it means that
231: * the time spent in the server by a client thread will be
232: * treated as "system" time for the client thread (and nothing
233: * for the server). This conforms to the CPU reporting for an
234: * integrated kernel.
235: */
236: #endif
237: usermode = (regs->efl & EFL_VM) || ((regs->cs & 0x03) != 0);
238: pc = (unsigned)regs->eip;
239: #if 0
240: } else {
241: usermode = FALSE;
242: pc = (unsigned)((struct i386_interrupt_state *)&old_ipl)->eip;
243: }
244: #endif
245:
246: #if MACH_KPROF
247: /*
248: * If we were masked against the clock, just memorize pc
249: * and the fact that the clock interrupt is delayed
250: */
251: if (SPL_CMP_GE((old_ipl & 0xFF), SPL7)) {
252: assert(!usermode);
253: if (missed_clock[mycpu]++ && detect_lost_tick > 1)
254: Debugger("Mach_KPROF");
255: masked_pc[mycpu] = pc;
256: } else
257: #endif /* MACH_KPROF */
258:
259: hertz_tick(usermode, pc);
260:
261: #if NCPUS >1
262: /*
263: * Instead of having the master processor interrupt
264: * all active processors, each processor in turn interrupts
265: * the next active one. This avoids all slave processors
266: * accessing the same R/W data simultaneously.
267: */
268: slave_clock();
269: #endif /* NCPUS >1 && AT386 */
270:
271: mp_enable_preemption();
272: }
273:
274: #if MACH_KPROF
275: void
276: delayed_clock(void)
277: {
278: int i;
279: int my_cpu;
280:
281: mp_disable_preemption();
282: my_cpu = cpu_number();
283:
284: if (missed_clock[my_cpu] > 1 && detect_lost_tick)
285: printf("hardclock: missed %d clock interrupt(s) at %x\n",
286: missed_clock[my_cpu]-1, masked_pc[my_cpu]);
287: if (my_cpu == master_cpu) {
288: i = rtclock_intr();
289: assert(i == 0);
290: }
291: hertz_tick(0, masked_pc[my_cpu]);
292: missed_clock[my_cpu] = 0;
293:
294: mp_enable_preemption();
295: }
296: #endif /* MACH_KPROF */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.