translate_virtual-irix6.x.tcl 6.72 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. 
#


##
## assumes kernel has been defined
##


set mainStart [symbol read kernel::main:START]

if {$mainStart < 0xa800000000000000} {
   console "This doesn't look like a irix64 kernel!!\n"
   exit
}

set PNUM_SHIFT    14
set PNUM_MASK     0x3fff
set SEG_MASK      0x3FFFFFFF

if ![info exists irix_moose] {
    set irix_moose 0
}

if {$irix_moose} {
    set U_ADDR      0x400002ffffff8000
    set PDA_ADDR    0x400002ffffffc000

    set K0BASE        0x4000000000000000
    set K2BASE        0x4000020000000000
    set KS0BASE        0x4000000000000000
    set KS2BASE        0x4000020000000000

    set MOOSE_PDA_PAGE   0xffffffffffffc000
} else {
    set U_ADDR      0xffffffffffff8000
    set PDA_ADDR    0xffffffffffffc000

    set K0BASE        0xa800000000000000
    set K2BASE        0xc000000000000000
}

set UPAGENUM      [expr $U_ADDR >> $PNUM_SHIFT]
set PDAPAGENUM    [expr $PDA_ADDR >> $PNUM_SHIFT]
set private       "(*(struct pda_s*)$PDA_ADDR)"
set u             "(*(struct user*)$U_ADDR)"

set PTE_VPNMASK   0xFFFFFE00
set PTE_VPNSHIFT  3
set PTE_VBITMASK  0x00000001
set PR_SADDR      0x00000040
set SHRD_SENTINEL 0x00000200

set upg_isa_structure 1
set mod_by_cell 0

if {$irix_moose} {
proc TclTranslateVirtual {cpunum vaddr} {
    global MOOSE_PDA_PAGE PAGE_SHIFT KS0BASE KS2BASE K2BASE OS VCPU
    global OFFSET_MASK
    
    #console "Translating virtual: cpunum=$cpunum vaddr=$vaddr\n"

    if {($vaddr >= $KS0BASE) && ($vaddr < $KS2BASE)} {
        # ks0seg addr
        return [TranslatePhysical $cpunum [expr $vaddr - $KS0BASE]]
    }

    console "Translating virtual: cpunum=$cpunum vaddr=$vaddr\n"
    debug
}

set SEG_SHIFT 19
set PTE_SHIFT 12
set PTE_MASK 0x7f
set PTE_VALID    0x2
set PTE_PFNSHIFT 6
set MOOSE_PAGE_SHIFT 12
set MOOSE_PAGE_MASK 0xfff
proc TranslatePhysical {cpunum paddr} {
    global SEG_SHIFT PTE_MASK PTE_SHIFT PTE_VALID PTE_PFNSHIFT MOOSE_PAGE_SHIFT MOOSE_PAGE_MASK MEMORY
    
    #console "Translating physical: cpunum=$cpunum paddr=[hex $paddr]\n"
    
    set pmap  [symbol read monitor::PDAs<$cpunum>->vcpu_pmap]

    set segnum [expr $paddr >> $SEG_SHIFT]
    set indx [expr ($paddr >> $PTE_SHIFT) & $PTE_MASK]
    set segment [symbol read monitor::((long**)$pmap)<$segnum>]
    set pte [symbol read "monitor::((struct PageMapEntry*)$segment)<$indx>.pte"]
    
    if {$pte & $PTE_VALID} {
        set pgoff [expr $paddr & $MOOSE_PAGE_MASK]
        return [expr (($pte >> $PTE_PFNSHIFT) << $MOOSE_PAGE_SHIFT) | $pgoff]
    } else {
        console "TP failed: pmap=$pmap segment=$segment pte=[hex $pte]\n"
        console "TP failed: segnum=[hex $segnum] indx=[hex $indx]\n"
        debug
    }
}
 
} else {

set SEG_SHIFT 19
set PTE_SHIFT 12
set PTE_MASK 0x7f
set PTE_VALID    0x2
set PTE_PFNSHIFT 6
set PAGE_SHIFT 12
set PAGE_MASK 0xfff

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 PNUM_SHIFT PNUM_MASK SEG_MASK
    
    console "Translating 64-bit virtual - beware: CPU=$cpunum vaddr=$vaddr\n"
    set pdaindx $MCPU($cpunum)

    if ![symbol read kernel::pdaindr<$pdaindx>.pda] {
        console "TV.TCL: pdaindr read of $pdaindx failed \n"
        # during boot
        return 0
    }

    set vpn [expr ($vaddr >> $PNUM_SHIFT) & $SEG_MASK]
    set pgoff [expr $vaddr & $PNUM_MASK]

    console "vpn $vpn, off: $pgoff\n"

    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 & $PNUM_MASK)}
        return  [expr ($pdap - $K0BASE) | $pgoff]
    }

    set firstK2Page [expr $K2BASE >> $PNUM_SHIFT]

    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 >> $PNUM_SHIFT)} {
        # user virtual address
        console "TV.TCL: user virtual address\n"
        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

    console "pmapProbe $pmap $vaddr, pc=$pc, ra=$ra\n"
    debug

    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
}

}