|
|
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.