os-irix6.4.tcl 7.25 KB
#
# Copyright (C) 1996-1998 by the Board of Trustees
#    of Leland Stanford Junior University.
# 
# This file is part of the SimOS distribution. 
# See LICENSE file for terms of the license. 
#

###
### This file is responsible for raising OS level annotations and tracking
### the current process.
###
###

####
#### init this module
####

annotation type osEvent enum {
        startUser   endUser
        startKernel endKernel
        startIdle   endIdle
        startSync   endSync
        switchIn    switchOut
        procstart   procexit   procexec
}

set R4000_KERNEL   1

if [info exists R4000_KERNEL] {
    proc inUserMode {} {
        global sr
        expr !($sr & 0x4) && !($sr &0x2) && (($sr & 0x18) == 0x10)
    }
} else {
    proc inUserMode {} {
        global sr
        expr ($sr & 0x02) != 0
    }
}

## 
## Useful shortcuts
## 
set curprocp       "$private.p_curproc"
set current_pid    "$curprocp->p_pid"
set current_comm   "$curprocp->p_ui.u_comm"
set kthread        "$private.p_curkthread"
set sthread        "$kthread->k_sthread"
set kthread_id     "$kthread.k_id"
set sthread_name   "$kthread->k_sthread->st_name"
set ithread_name   "$kthread->k_ithread->it_name"

##
## Give simos control on kernel panics
## 
annotation set pc kernel::_assfail:START {
    debug
}


#
# Called when switching between processes
#
proc NewProc {pid process ktid} {
    global CPU PROCESS PID
    annotation exec osEvent switchOut
    log "NewProc old ($PID($CPU),$PROCESS($CPU)) new ($pid, $process)\n"
    set PROCESS($CPU) $process
    set PID($CPU)     $pid
    set KTID($CPU)    $ktid
    annotation exec osEvent switchIn
}


##
## process and idle tracking
##

# Determining starting process 
annotation set simos enter {
    if {!$SIMOS(RestoringCpt)} {
        set PROCESS($CPU) "boot"
        set PID($CPU)     boot$CPU
        set KTID($CPU)    boot$CPU
    } elseif {(([hex $pc] >= [symbol read kernel::idle:START])
               && ([hex $pc] <= ([symbol read kernel::idle:END] + 4)))
              || ((![catch {symbol read kernel::vmp_find_work:START}]) && 
                  ([hex $pc] >= [symbol read kernel::vmp_find_work:START])
                  && ([hex $pc] <= ([symbol read kernel::vmp_find_work:END] + 4)))} {
        set PROCESS($CPU) "idle"
        set PID($CPU) idle$CPU
        set KTID($CPU) idle$CPU
    } elseif { [catch {symbol read kernel::$current_comm}] } {
        console "OS: Problem getting process info\n"
        set PROCESS($CPU) "None"
        set PID($CPU)     0
        set KTID($CPU)    0
    } else {
        set PROCESS($CPU) [symbol read kernel::$current_comm]
        set PID($CPU) [symbol read kernel::$current_pid]
        set KTID($CPU) [symbol read kernel::$kthread_id]
    }
    console "OS: $CPU starting in $PROCESS($CPU) - $PID($CPU) - $KTID($CPU)\n"
}

##
## TRACKING THREADS
##

#annotation set pc kernel::resumenewthread:START {
#    console "$CPU SWITCHING FROM $PROCESS($CPU) $PID($CPU) "
#}
#
#annotation set pc kernel::resumeidle:START {
#    console " TO IDLE\n"
#}
#annotation set pc kernel::itresume:START {
#    console " TO ITHREAD\n"
#}
#annotation set pc kernel::stresume:START {
#    console " TO STHREAD\n"
#}
#annotation set pc kernel::presume:START {
#    console " TO USER PROCESS\n"
#}
#
#annotation set pc kernel:fork.c:procdup:START {
#    console "PROCDUP called\n"
#}

annotation set pc kernel:fork.c:procdup:END {
    console "OS: - PROCDUP\n"
    set pid [symbol read kernel::$current_pid]
    set ktid [symbol read kernel::$kthread_id]
    if {$pid != $PID($CPU)} {
        # child process of the fork
        NewProc $pid [symbol read kernel::$current_comm] $ktid
        annotation exec osEvent procstart
    }
}

annotation set pc kernel::exece:END {
    annotation exec osEvent switchOut
    set PROCESS($CPU) [symbol read kernel::$current_comm]
    console "OS: $CPU exece of $PROCESS($CPU) $PID($CPU)\n"
    annotation exec osEvent procexec
    annotation exec osEvent switchIn
}

# I think all user restores comes through here...
annotation set pc kernel::resume:END {
    annotation exec osEvent switchOut
    set pid [symbol read kernel::$current_pid] 
    set name [symbol read kernel::$current_comm]
    set ktid [symbol read kernel::$kthread_id] 
#    console "OS: $CPU Scheduling $name - PID $pid - KTID $ktid\n"
    NewProc $pid $name $ktid
    annotation exec osEvent switchIn
}



annotation set pc kernel::pexitswtch:START {
    annotation exec osEvent procexit
#    console "OS: EXIT $CYCLES\n"
    NewProc runq$CPU "runq" runq$CPU
}




# Service and Interrupt threads tracking

# The type is determined by null pointers for 
annotation set pc kernel::resumethread:END {
    annotation exec osEvent switchOut
    set st [symbol read kernel::$sthread] 
    if {$st == 0} {
        set type ITHREAD
        set name [symbol read kernel::$ithread_name]
    } else {
        set type STHREAD
        set name [symbol read kernel::$sthread_name]
    }
    set id [symbol read kernel::$kthread_id]
#    console "$CPU Scheduling $type - $name $id\n"
    NewProc $id $name $id
    annotation exec osEvent switchIn
}

annotation set pc kernel::restartithread:END {
    annotation exec osEvent switchOut
    set type ITHREAD
    set id [symbol read kernel::$kthread_id]
    set name [symbol read kernel::$ithread_name]
#    console "$CPU Scheduling (restart) $type $name $id\n"
    NewProc $id $name $id
    annotation exec osEvent switchIn
}

annotation set pc kernel::sthread_create:START {
#    console "$CPU Scheduling CREATING STHREAD \n"
}

annotation set pc kernel::ithread_create:START {
#    console "$CPU Scheduling CREATING ITHREAD \n"
}

##
## IDLE MODE
## 

# This is a bit ugly. IRIX 6.4 implements a quick route to get
# back to the idle loop after handling interrupts, and to get the
# modes stuff hooked up, I need to know where resumeidle was being
# called from. I added a symbol to the kernel for this purpose.  
# - Steve 

set fastIdleRet [expr [symbol read kernel::resumeIdleJump:START] - 8]
set iJump 0

annotation set pc $fastIdleRet {
    global iJump
    set iJump 1
}

annotation set pc kernel::resumeidle:START {
    global iJump 

    if {$iJump == 1} {
        annotation exec osEvent endKernel
        set iJump 0
    } else {
        NewProc idle$CPU "idle" idle$CPU
        annotation exec osEvent startIdle
    }
#    console "$CPU Scheduling Idle\n"
}

annotation set pc kernel::resumeidle:END {
    annotation exec osEvent endIdle
}




##
## 
##

if {$detailLevel >= 2} {
    ## kernel - user transitions
    set MAX_CPUS 256

    for {set i 0} {$i < $MAX_CPUS} {incr i} {
        set utlb($i) 0
    }
    
    annotation set utlb {
        set utlb($CPU) 1
        if {!($epc & $K0BASE)} {
            annotation exec osEvent endUser
        }
        annotation exec osEvent startKernel
    }
    
    annotation set exc {
        if {!$utlb($CPU)} {
            if {!($epc & $K0BASE)} {
                annotation exec osEvent endUser
            }
            annotation exec osEvent startKernel
        }
        set utlb($CPU) 0
    }
        
    annotation set inst rfe {
        set utlb($CPU) 0
        annotation exec osEvent endKernel
        if [inUserMode] {
            annotation exec osEvent startUser
        }
            
    }




    ##
    ## synchronization stuff
    ##

     # IRIX 6.4 changed locks to mutex_spinlock  - fix this
     if { 0 } {
     }
}