📄 kern_key.cxx
字号:
/* * Copyright (C) 1998, 1999, 2001, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <kerninc/kernel.hxx>#include <disk/DiskKey.hxx>#include <kerninc/Check.hxx>#include <kerninc/Process.hxx>#include <kerninc/Thread.hxx>#include <kerninc/Node.hxx>#include <kerninc/ObjectCache.hxx>#include <kerninc/util.h>#include <kerninc/StackTester.hxx>#include <kerninc/ObjectSource.hxx>#include <eros/SysTraceKey.h>#define dbg_prepare 0x1 /* steps in taking snapshot *//* Following should be an OR of some of the above */#define dbg_flags (0)#define DBCOND(x) (dbg_##x & dbg_flags)#define DEBUG(x) if DBCOND(x)#define DEBUG2(x,y) if ((dbg_##x|dbg_##y) & dbg_flags)ObjectHeader *Key::GetObjectPtr() const{ assert( IsPreparedObjectKey() ); if (IsGateKey()) return gk.pContext->procRoot; else return ok.pObj;}OIDKey::GetKeyOid() const{ assert (IsObjectKey()); if ( IsPreparedObjectKey() ) return GetObjectPtr()->ob.oid; return unprep.oid;}uint32_tKey::GetAllocCount() const{ assert (GetType() > LAST_GATE_KEYTYPE); assert (GetType() <= LAST_OBJECT_KEYTYPE); if ( IsPreparedObjectKey() ) return GetObjectPtr()->ob.allocCount; return unprep.count;}Key Key::VoidKey; /* default constructor *//* NOTE: if we are running OB_MOD_CHECK, the key prepare logic does an * incremental recomputation on the check field in the containing object. */voidKey::DoPrepare(){ assert( IsUnprepared() ); assert ( NeedsPrepare() ); KernStats.nKeyPrep++; #ifdef TEST_STACK StackTester st;#endif #if 0 if (ktByte > UNPREPARED(LAST_PREPARED_KEYTYPE)) return;#endif#ifdef MEM_OB_CHECK uint32_t ck = CalcCheck();#endif ObjectHeader *pObj = 0; switch(GetType()) { /* not prepared, so not hazarded! */ case KT_Resume: case KT_Start: { /* Gate keys are linked onto the context structure. First, we * need to validate the key: */ Process * context = 0; Node *pNode = (Node *) ObjectCache::GetObject(unprep.oid, ObType::NtUnprepared, unprep.count, IsType(KT_Resume) ? false : true); if (IsType(KT_Resume) && pNode->callCount != unprep.count) pNode = 0; if (pNode == 0) { DEBUG(prepare) printf("Voiding invalid gate key\n"); assert ( IsHazard() == false ); assert ( IsUnprepared() ); /* key was not prepared, so cannot be hazarded */ KS_RescindKey(); return; } assertex(pNode, ObjectCache::ValidNodePtr(pNode)); pNode->TransLock(); context = pNode->GetDomainContext(); if (! context ) /* malformed domain */ fatal("Preparing gate key to malformed domain\n"); /* Okay, we prepared successfully. */ gk.pContext = context; /* Link into context chain on left or right according to key * type. */ if ( IsType(KT_Resume) ) { gk.prev = context->kr.prev; gk.prev->next = (KeyRing *) this; context->kr.prev = (KeyRing *) this; gk.next = (KeyRing*) &context->kr; } else { gk.next = context->kr.next; gk.next->prev = (KeyRing *) this; context->kr.next = (KeyRing *) this; gk.prev = (KeyRing*) &context->kr; } SetPrepared();#if 0 printf("Prepared key "); Print();#endif #ifdef MEM_OB_CHECK assert(ck == CalcCheck());#endif #ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("In Key::DoPrepare()");#endif#ifdef TEST_STACK st.check();#endif return; } case KT_Page: { pObj = ObjectCache::GetObject(unprep.oid, ObType::PtDataPage, unprep.count, true); if (pObj) assertex(this, ObjectCache::ValidPagePtr(pObj)); break; } case KT_Node: case KT_Segment: case KT_Process:#ifdef KT_Wrapper case KT_Wrapper:#endif pObj = ObjectCache::GetObject(unprep.oid, ObType::NtUnprepared, unprep.count, true); break; default: SetPrepared(); return; } if (pObj == 0) { DEBUG(prepare) dprintf(true, "Voiding invalid key\n"); assert ( IsHazard() == false ); assert ( IsUnprepared() ); NH_RescindKey();#ifdef TEST_STACK st.check();#endif return; } /* It's definitely an object key. Pin the object it names. */ pObj->TransLock(); /* Link as next key after object */ ok.pObj = pObj; ok.next = pObj->kr.next; ok.prev = (KeyRing *) pObj; pObj->kr.next = (KeyRing*) this; ok.next->prev = (KeyRing*) this;#ifdef MEM_OB_CHECK assert(ck == CalcCheck());#endif SetPrepared();#if 0 printf("Prepared key "); Print();#endif#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("End Key::DoPrepare()");#endif#ifdef TEST_STACK st.check();#endif return;}#ifndef NDEBUGvoidKey::Prepare(){ extern bool InvocationCommitted; assert (InvocationCommitted == false); if (IsUnprepared()) DoPrepare(); if ( NeedsPin() ) ok.pObj->TransLock();}#endifboolKey::Prepare(KeyType ty){#ifndef NDEBUG extern bool InvocationCommitted;#endif assert (InvocationCommitted == false); /* printf("Key::Prepare(ty) -- want ty %d\n", ty); */ if (IsType(ty) == false) { Print(); fatal("Key::Prepare(kt) -- wrong keytype 0x%x (wanted 0x%x)\n", GetType(), ty); return false; } if (NeedsPrepare()) DoPrepare(); if (NeedsPin()) ok.pObj->TransLock(); if (IsType(KT_Number) && (ty != KT_Number)) { printf("Key::Prepare(ty) -- number key. Key rescinded?\n"); return false; } return true;}#define CAP_REGMOVE#ifdef CAP_REGMOVE/* save_key(from, to) -- given a key address /from/ that is within a * capability register, copy that key to the key address /to/, which * is a slot in a capability page. * * Note that all functions called by save_key() are prompt and do not * yield. This is important, as we are running on an interrupt stack. */extern "C" { void copy_key(Key *fromKeyReg, Key *toKeyReg); void xchg_key(Key *kr0, Key *kr1);}voidcopy_key(Key *from, Key *to){ if (to == &Thread::CurContext()->keyReg[0]) return; /* Do not bother to deprepare dest key, as it isn't going to disk as * a result of this operation. */ to->NH_Set(*from);}voidxchg_key(Key *cr0, Key *cr1){ Key tmp; tmp.NH_Set(*cr0); if (cr0 != &Thread::CurContext()->keyReg[0]) { cr0->NH_Set(*cr1); } if (cr1 != &Thread::CurContext()->keyReg[0]) { cr1->NH_Set(tmp); } tmp.NH_Unchain();}#endif /* CAP_REGMOVE */voidKey::NH_Unprepare(){#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Top Key::NH_Unprepare()");#endif /* fatal("Unprepare() called\n"); */ assert(IsHazard() == false); if ( IsUnprepared() ) return; if ( IsObjectKey() ) { ObjectHeader *pObj = ok.pObj; if ( IsGateKey() ) {#ifndef NDEBUG extern bool ValidCtxtPtr(const Process *); if (ValidCtxtPtr(gk.pContext) == false) fatal("Key 0x%08x Kt %d, 0x%08x not valid ctxt ptr\n", this, GetType(), gk.pContext);#endif pObj = gk.pContext->procRoot; }#ifndef NDEBUG if ( IsType(KT_Page) ) { if ( ObjectCache::ValidPagePtr(pObj) == false ) fatal("Key 0x%08x Kt %d, 0x%08x not valid page ptr\n", this, GetType(), pObj); } else { if ( ObjectCache::ValidNodePtr((Node *)pObj) == false ) fatal("Key 0x%08x Kt %d, 0x%08x not valid node ptr\n", this, GetType(), pObj); }#endif NH_Unchain(); pObj->SetFlags(OFLG_DISKCAPS); unprep.oid = pObj->ob.oid; if ( IsType(KT_Resume) ) unprep.count = ((Node *) pObj)->callCount; else unprep.count = pObj->ob.allocCount; } SetUnprepared();#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("End Key::NH_Unprepare()");#endif#if 0 printf("Deprepared key "); Print();#endif}voidDiskKey::operator=(const Key& k){ assert ( k.IsValid() ); if ( k.IsPreparedObjectKey() ) { ObjectHeader *pObj = k.ok.pObj; if ( k.IsType(KT_Resume) || k.IsType(KT_Start) ) {#ifndef NDEBUG extern bool ValidCtxtPtr(const Process *); if (ValidCtxtPtr(k.gk.pContext) == false) fatal("Kt %d, 0x%08x not valid ctxt ptr\n", k.GetType(), k.gk.pContext);#endif pObj = k.gk.pContext->procRoot; }#ifndef NDEBUG if ( k.IsType(KT_Page) ) { if ( ObjectCache::ValidPagePtr(pObj) == false ) fatal("Kt %d, 0x%08x not valid page ptr\n", k.GetType(), pObj); } else { if ( ObjectCache::ValidNodePtr((Node *)pObj) == false ) fatal("Kt %d, 0x%08x not valid node ptr\n", k.GetType(), pObj); }#endif keyType = k.keyType; keyFlags = k.keyFlags & ~KFL_HAZARD_BITS; keyData = k.keyData; SetUnprepared(); if ( k.IsType(KT_Resume) ) unprep.count = ((Node *) pObj)->callCount; else unprep.count = pObj->ob.allocCount; unprep.oid = pObj->ob.oid; pObj->SetFlags(OFLG_DISKCAPS); } else { keyType = k.keyType; keyFlags = k.keyFlags & ~KFL_HAZARD_BITS; keyData = k.keyData; SetUnprepared(); nk.value[0] = k.nk.value[0]; nk.value[1] = k.nk.value[1]; nk.value[2] = k.nk.value[2]; }}voidKey::Print() const{ uint32_t * pWKey = (uint32_t *) this; if ( IsPreparedObjectKey() ) { ObjectHeader * pObj = GetObjectPtr(); uint32_t * pOID = (uint32_t *) &pObj->ob.oid; if (IsType(KT_Resume)) {#if 0 printf("rsm 0x%08x 0x%08x 0x%08x 0x%08x (obj=0x%08x)\n", pWKey[0], ((Node *)pObj)->callCount, pOID[0], pOID[1], pObj); #else printf("0x%08x rsm 0x%08x 0x%08x 0x%08x 0x%08x\n", this, pWKey[0], ((Node *)pObj)->callCount, pOID[0], pOID[1]);#endif } else {#if 0 printf("pob 0x%08x 0x%08x 0x%08x 0x%08x (obj=0x%08x)\n", pWKey[0], ok.pObj->allocCount, pOID[0], pOID[1], pObj);#else printf("0x%08x pob 0x%08x 0x%08x 0x%08x 0x%08x\n", this, pWKey[0], ((Node *)pObj)->ob.allocCount, pOID[0], pOID[1]);#endif } } else {#if 0 printf("ukt 0x%08x 0x%08x 0x%08x 0x%08x\n", pWKey[0], pWKey[1], pWKey[2], pWKey[3]);#else printf("0x%08x ukt 0x%08x 0x%08x 0x%08x 0x%08x\n", this, pWKey[0], pWKey[1], pWKey[2], pWKey[3]);#endif }}#ifdef OPTION_OB_MOD_CHECKuint32_tKey::CalcCheck(){ uint32_t ck = 0; assert(this); uint32_t *pWKey = (uint32_t *) this; /* mask out prepared, hazard bits! */ uint32_t saveFirstWord = pWKey[0]; keyFlags &= ~KFL_ALL_FLAG_BITS; ck ^= pWKey[0]; *pWKey = saveFirstWord; if ( IsPreparedObjectKey() ) { if (IsType(KT_Resume)) { /* Inject the checksum for a void key instead so that * zapping them won't change the checksum: */ ck = VoidKey.CalcCheck(); } else if (IsType(KT_Start)) { /* This pointer hack is simply so that I don't have to remember * machine specific layout conventions for long long */ Node *pDomain = gk.pContext->procRoot; ck ^= pDomain->ob.allocCount; uint32_t * pOID = (uint32_t *) &pDomain->ob.oid; ck ^= pOID[0]; ck ^= pOID[1]; } else { /* This pointer hack is simply so that I don't have to remember * machine specific layout conventions for long long */ ck ^= ok.pObj->ob.allocCount; uint32_t * pOID = (uint32_t *) &ok.pObj->ob.oid; ck ^= pOID[0]; ck ^= pOID[1]; } } else { ck ^= pWKey[1]; ck ^= pWKey[2]; ck ^= pWKey[3]; } return ck;}#endif/* New Key -- make it void, since in a couple of cases we do this on * the stack and there is no telling what garbage bits are sitting there. */Key::Key(){ KS_VoidInitKey();}#ifndef NDEBUGboolKey::IsValid() const{ if ( IsMiscKey() ) { if (nk.value[0] || nk.value[1] || nk.value[2]) return false; }#if defined(DBG_WILD_PTR) /* Following is a debugging-only check. */ if (IsObjectKey() && GetKeyOid() > 0x100000000llu) { OID oid = GetKeyOid(); printf("Key 0x%08x has invalid OID 0x%08x%08x\n", this, (uint32_t) (oid>>32), (uint32_t) oid); }#endif if ( IsPreparedObjectKey() ) { extern bool ValidCtxtPtr(const Process *); extern bool ValidCtxtKeyRingPtr(const KeyRing *); #ifndef NDEBUG if ( IsGateKey() ) { Process *ctxt = gk.pContext; if (ValidCtxtPtr(ctxt) == false) return false; } else if ( IsType(KT_Page) ) { ObjectHeader *pObject = ok.pObj; if ( ObjectCache::ValidPagePtr(pObject) == false ) { Print(); printf("Key 0x%08x has invalid pObject 0x%08x\n", this, pObject); return false; } if ( pObject->IsFree() ) { Print(); printf("Prepared key 0x%08x names free pObject 0x%08x\n", this, pObject); return false; } } else { assertex (this, IsObjectKey() ); Node *pNode = (Node *) ok.pObj; if ( ObjectCache::ValidNodePtr(pNode) == false ) { printf("0x%x is not a valid node ptr\n", pNode); return false; } if ( pNode->IsFree() ) { Print(); printf("Prepared key 0x%08x names free pObject 0x%08x\n", this, pNode); return false; } }#endif if ( IsObjectKey() ) { /* KeyRing pointers must either point to key slots or to * object root. */#ifndef NDEBUG KeyRing * krn = ok.next; KeyRing * krp = ok.prev; if ( ! ( ObjectCache::ValidKeyPtr((Key *) krn) || ObjectCache::ValidPagePtr((ObjectHeader*) krn) || ObjectCache::ValidNodePtr((Node *) krn) || ValidCtxtKeyRingPtr(krn) ) ) { printf("key 0x%x nxt key 0x%x bogus\n", this, krn); return false; } if ( ! ( ObjectCache::ValidKeyPtr((Key *) krp) || ObjectCache::ValidPagePtr((ObjectHeader *) krp) || ObjectCache::ValidNodePtr((Node *) krp) || ValidCtxtKeyRingPtr(krp) ) ) { printf("key 0x%x prv key 0x%x bogus\n", this, krp); return false; } /* Prev and next pointers must be linked properly: */ if (krp->next != (KeyRing *) this) { printf("Prepared key 0x%08x bad keyring links to prev\n", this); return false; } if (krn->prev != (KeyRing *) this) { printf("Prepared key 0x%08x bad keyring links to next\n", this); return false; }#endif } } return true;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -