Annotation of XNU/osfmk/i386/hardclock.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.