translate_virtual-irix5.3.tcl 5.27 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. 
#


##
## return a physical address or 0 if failure
##
## assumes kernel has been defined
##

set SIMOS_VERSION_3 FALSE

set mainStart [symbol read kernel::main:START]
console "mainStart = [symbol read kernel::main:START]\n"

if {($mainStart  & 0xffffffff) > 0x80000000} {

    set SIMOS_VERSION_3 TRUE
}

if {$SIMOS_VERSION_3} {
    set UPAGENUM      0xffffd
    set PDAPAGENUM    0xffffa

    set private "(*((struct pda_s*)0xffffa000))"
    set u "(*(struct user*)0xffffd000)"
    
    set K0BASE        0x80000000
    set K2BASE        0xC0000000
    
} else {

    console "\n\n\nYou are running SimOS version 2 --- Upgrade NOW!!\n\n"
    console "Please talk to Scott or Steve, you are in big trouble!\n"
    console "To run, edit your translate_virtual.tcl to take out these lines\n\n\n"
    exit
}

if {[catch {symbol read kernel::get_r4k_config}]} {
    console "TCL: R3000 kernel, please run r4k kernel\n"
    set PTE_VPNMASK    0xFFFFF000
    set PTE_VPNSHIFT   0
    set PTE_VBITMASK   0x00000004
    set PR_SADDR       0x00000040
    set SHRD_SENTINEL  0x00001000
} else {
    set R4000_KERNEL   1
    set PTE_VPNMASK    0xFFFFFE00
    set PTE_VPNSHIFT   3
    set PTE_VBITMASK   0x00000001
    set PR_SADDR       0x00000040
    set SHRD_SENTINEL  0x00000200
}

if [info exists RUNNING_HIVE] {
    set upg_isa_structure 0
    set mod_by_cell 1
} elseif [info exists IRIX_52] {
    set upg_isa_structure 0
    set mod_by_cell 0
} else {
    set upg_isa_structure 1
    set mod_by_cell 0
}

proc TclTranslateVirtual {cpunum vaddr} {
    global UPAGENUM PDAPAGENUM K0BASE K2BASE REGISTER SHRD_SENTINEL PR_SADDR
    global cpusPerCell upg_isa_structure mod_by_cell
    global PTE_VPNMASK PTE_VPNSHIFT PTE_VBITMASK MCPU
    
    #console "Translating virtual: cpunum=$cpunum vaddr=$vaddr\n"

    if {$mod_by_cell} {
        set pdaindx [expr $cpunum % $cpusPerCell]
    } else {
        set pdaindx $MCPU($cpunum)
    }
    if ![symbol read kernel::pdaindr<$pdaindx>.pda] {
        # during boot
        return 0
    }

    set vpn [expr ($vaddr >> 12) & 0x000FFFFF]
    set pgoff [expr $vaddr & 0x00000FFF]

    if {$vpn == $UPAGENUM} {
        if {$upg_isa_structure} {
            set upte [symbol read kernel::pdaindr<$pdaindx>.pda->p_upglo.pgi]
        } else {
            set upte [symbol read kernel::pdaindr<$pdaindx>.pda->p_upglo]
        }

        return [expr (($upte & $PTE_VPNMASK)<<$PTE_VPNSHIFT) | $pgoff]
    }
    
    if {$vpn == $PDAPAGENUM} {
        set pdap [symbol read kernel::pdaindr<$pdaindx>.pda]
        assert {!($pdap & 0x00000FFF)}
        return  [expr ($pdap - $K0BASE) | $pgoff]
    }

    set firstK2Page [expr $K2BASE >> 12]

    if {$vpn >= $firstK2Page} {
        # kernel virtual address
        set lastK2Page [expr $firstK2Page + [symbol read kernel::v.v_syssegsz]]
        
        if {$vpn < $lastK2Page} {
            set kpte [symbol read kernel::kptbl<[expr $vpn - $firstK2Page]>.pgi]
            return [expr (($kpte & $PTE_VPNMASK)<<$PTE_VPNSHIFT) | $pgoff]
        }

        return 0
    }

    if {$vpn < ($K0BASE >> 12)} {
        # user virtual address
        if {$upg_isa_structure} {
            set upte [symbol read kernel::pdaindr<$pdaindx>.pda->p_upglo.pgi]
        } else {
            set upte [symbol read kernel::pdaindr<$pdaindx>.pda->p_upglo]
        }
        set uarea [expr (($upte & $PTE_VPNMASK)<<$PTE_VPNSHIFT) + $K0BASE]

        set procp [symbol read kernel:user.h:((user_t*)$uarea)->u_procp]
        set pmap [symbol read kernel:proc.h:((proc_t*)$procp)->p_pmap]
    
        if {!$pmap} {
            # should get here only if idle, in which case why are
            # we translating a user virtual address?  Anyway, ignore
            # it and go one.  The following warning used to be an
            # assertion but seems to happen occasionally when the
            # debugger is operating, and we don't want to fail in that
            # case.
            if {[symbol read kernel::pdaindr<$pdaindx>.pda->p_curproc]} {
                console "TclTranslateVirtual: pda says a proc is active but pmap is null\n"
            }
            return 0
        }

        set pte [pmapProbe $pmap $vaddr]
        
        if {!$pte || ($pte == $SHRD_SENTINEL)} {
            if {[symbol read kernel:proc.h:((proc_t*)$procp)->p_shmask] & $PR_SADDR} {
                set pmap [symbol read kernel:proc.h:((proc_t*)$procp)->p_shaddr->s_pmap]
                set pte [pmapProbe $pmap $vaddr]
            }
        }

        if {$pte} {
            assert {$pte != $SHRD_SENTINEL}
            return [expr (($pte & $PTE_VPNMASK)<<$PTE_VPNSHIFT)  | $pgoff]
        }
    }
    return 0
}


proc pmapProbe {pmap vaddr} {
    global PTE_VBITMASK

    set segment [expr ($vaddr >> 22) & 0x03FF]
    set segptr [symbol read kernel:pmap.c:((pseg_t*)$pmap)->pseg_segptr<$segment>]
    
    if {!$segptr} {
        # console "no seg pointer\n"
        return 0
    }
    
    set segoff [expr ($vaddr >> 12) & 0x03FF]
    set pte [symbol read kernel:pmap.c:((int*)$segptr)<$segoff>]

    if {!($pte & $PTE_VBITMASK)} {
        # console "TclTranslateVirtual: pte not valid = [hex $pte]\n"
        return 0
    }

    return $pte
}