⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pk_nodekey.cxx

📁 C++ 编写的EROS RTOS
💻 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 <kerninc/Key.hxx>#include <kerninc/Invocation.hxx>#include <kerninc/Node.hxx>#include <kerninc/Thread.hxx>#include <kerninc/Process.hxx>#include <kerninc/SegWalk.hxx>#include <eros/Invoke.h>#include <eros/StdKeyType.h>#include <eros/NodeKey.h>#include <eros/NumberKey.h>#include <eros/memory.h>/* See pk_ProcessKey.cxx */extern voidMaybeRepairCpuReserveLinkages(Node *theNode, CpuReserve* oldReserve,			      const Key &newKey);/* #define NODEKEYDEBUG *//* Node key implements node keys, RO node keys, and sense keys. * N.B. that the node we point to may NOT be prepared as a node! *//* DANGER -- there is a potential gotcha in the node key * implementation.  Suppose that the node key happens to name the * caller's domain root. The operations (swap, zero, WriteNumbers) * either alter the register values of the domain or cause the domain * to become malformed.  The swap operation may, in addition, cause * the key registers node to be changed, which has the effect of * altering the return key slots. *  * KeyKOS made this all transparent. It would be nice to make all of * this transparent, but if you are holding a node key in the first * place then you have sufficient authority to obtain a domain key to * yourself, by which any alteration that would leave your domain * running can be accomplished.  If you don't want your domain * running, be a sport and return to the null key. *  * Given this, I just made dorking the returnee generate a suitable * return code. *  */voidDesensitize(Key *k){  if (k == 0)    return;    switch (k->GetType()) {  case KT_Node:  case KT_Segment:#ifdef KT_Wrapper  case KT_Wrapper:#endif    k->SetReadOnly();    k->SetNoCall();    k->SetWeak();    break;  case KT_Page:    k->SetReadOnly();    break;  case KT_Number:    break;  case KT_Discrim:  case KT_Returner:    break;  default:    /* Safe because only called on invocation block keys: */    assert( k->IsHazard() == false );    k->NH_VoidKey();    break;  }}voidNodeKey(Invocation& inv){  bool isSense = inv.key->IsWeak();  bool isFetch = inv.key->IsReadOnly();    Node *theNode = (Node *) inv.key->GetObjectPtr();  if (inv.invokee && theNode == inv.invokee->procRoot      && OC_Node_Swap == inv.entry.code)    dprintf(true, "Modifying invokee domain root\n");  if (inv.invokee && theNode == inv.invokee->keysNode      && OC_Node_Swap == inv.entry.code)    dprintf(true, "Modifying invokee keys node\n");  switch (inv.entry.code) {  case OC_KeyType:    {      COMMIT_POINT();      inv.exit.code = RC_OK;      inv.exit.w1 = AKT_Node;      inv.exit.w2 = inv.key->keyData;      return;    }  case OC_Node_Copy:    {      uint32_t slot = inv.entry.w1;      COMMIT_POINT();      if (slot >= EROS_NODE_SIZE) {	inv.exit.code = RC_RequestError;	return;      }      /* All of these complete ok. */      inv.exit.code = RC_OK;            if ( (*theNode)[slot].IsRdHazard() )	theNode->ClearHazard(slot);      /* Does not copy hazard bits, but preserves preparation: */      inv.SetExitKey(0, theNode->slot[slot]);#ifdef NODEKEYDEBUG      dprintf(true, "Copied key to exit slot %d\n", slot);#endif            if (isSense)	Desensitize(inv.exit.pKey[0]);            Thread::Current()->Prepare();            return;    }        case OC_Node_Swap:    {      if (theNode == Thread::CurContext()->keysNode)	dprintf(true, "Swap involving sender keys\n");      if (isFetch) {	COMMIT_POINT();	inv.exit.code = RC_NoAccess;	return;      }	      uint32_t slot = inv.entry.w1;      if (slot >= EROS_NODE_SIZE) {	COMMIT_POINT();	inv.exit.code = RC_RequestError;	return;      }	      /* All of these complete ok. */      inv.exit.code = RC_OK;            theNode->MakeObjectDirty();            COMMIT_POINT();			/* advance the PC! */            /* Following will not cause dirty node because we forced it       * dirty above the commit point.       */      theNode->ClearHazard(slot);      /* Tread carefully, because we need to rearrange the CPU       * reserve linkages.       */      CpuReserve *oldReserve = 0;      if ( slot == ProcSched && theNode->slot[slot].IsType(KT_Sched) )	oldReserve = &CpuReserve::GetReserve(theNode->slot[slot]);	      {	Key k;			/* temporary in case send and receive */				/* slots are the same. */	k.IKS_Set(theNode->slot[slot]);		(*theNode)[slot].NH_Set(*inv.entry.key[0]);	inv.SetExitKey(0, k);	/* Unchain, but do not unprepare -- the objects do not have	 * on-disk keys. 	 */	k.NH_Unchain();      }      if (oldReserve)	MaybeRepairCpuReserveLinkages(theNode, oldReserve,				      theNode->slot[slot]);#ifdef NODEKEYDEBUG      dprintf(true, "Swapped key to slot %d\n", slot);#endif      Thread::Current()->Prepare();      inv.nextPC = ((Process *) Thread::CurContext())->GetPC();      return;    }        case OC_Node_Extended_Copy:  case OC_Node_Extended_Swap:    {      SegWalk wi;      bool result;      wi.faultCode = FC_NoFault;      wi.traverseCount = 0;      wi.segObj = 0;      wi.vaddr = inv.entry.w1;      wi.frameBits = EROS_NODE_LGSIZE;      wi.writeAccess = (inv.entry.code == OC_Node_Extended_Swap) ? true : false;      wi.invokeKeeperOK = true;	/* seg keeper can be invoked */      wi.invokeProcessKeeperOK = false;	/* but not process keeper */      wi.wantLeafNode = true;      segwalk_init(wi, inv.key);      /* Begin the traversal... */      result = proc_WalkSeg(Thread::CurContext(), wi, EROS_PAGE_BLSS,			    0, 0, false);      /* If this is a write operation, we need to mark the node dirty. */      if (wi.writeAccess)	theNode->MakeObjectDirty();            COMMIT_POINT();      if ( result == false ) {	fatal("Node tree traversal fails without keeper.!\n");	inv.exit.code = RC_NoAccess;	inv.exit.w1 = wi.faultCode;	inv.exit.w2 = wi.vaddr;	return;      }      assert(wi.segObj);      assert(wi.segObj->obType <= ObType::NtLAST_NODE_TYPE);      uint32_t slot = inv.entry.w1 & EROS_NODE_SLOT_MASK;      Node *theNode = (Node *) wi.segObj;      COMMIT_POINT();      if (inv.entry.code == OC_Node_Extended_Swap) {	assert(wi.canWrite);	CpuReserve *oldReserve = 0;	if ( slot == ProcSched && theNode->slot[slot].IsType(KT_Sched) )	  oldReserve = &CpuReserve::GetReserve(theNode->slot[slot]);	Key k;			/* temporary in case send and receive */				/* slots are the same. */	k.IKS_Set(theNode->slot[slot]);		(*theNode)[slot].NH_Set(*inv.entry.key[0]);	inv.SetExitKey(0, k);	/* Unchain, but do not unprepare -- the objects do not have	 * on-disk keys. 	 */	k.NH_Unchain();	if (oldReserve)	  MaybeRepairCpuReserveLinkages(theNode, oldReserve,					theNode->slot[slot]);	/* There is no need to check this for sense key status, as the	 * segment walker would have generated an exception if the	 * tree was not writable, and any writable tree is also	 * readable in full power form. */      }      else {	inv.SetExitKey(0, theNode->slot[slot]);	if (wi.canFullFetch == false)	  Desensitize(inv.exit.pKey[0]);      }      inv.exit.code = RC_OK;      return;    }  case OC_Node_MakeNodeKey:  case OC_Node_MakeSegmentKey:#ifdef KT_Wrapper  case OC_Node_MakeWrapperKey:#endif    {      COMMIT_POINT();      uint32_t w = inv.entry.w1;      if ( (w > EROS_KEYDATA_MAX) ) {	inv.exit.code = RC_RequestError;	dprintf(true, "Value 0x%08x is out of range\n", w);	return;      }      w |= (inv.key->keyData & SEGMODE_ATTRIBUTE_MASK);	      inv.exit.code = RC_OK;            inv.SetExitKey(0, *inv.key);      if (inv.exit.pKey[0]) {	inv.exit.pKey[0]->keyData = w;	switch(inv.entry.code) {	case OC_Node_MakeNodeKey:	  break;	case OC_Node_MakeSegmentKey:	  inv.exit.pKey[0]->SetType(KT_Segment);	  break;#ifdef KT_Wrapper	case OC_Node_MakeWrapperKey:	  inv.exit.pKey[0]->SetType(KT_Wrapper);	  break;#endif	}      }	      return;    }      case OC_Node_CompareKey:    {      inv.entry.key[0]->Prepare();      COMMIT_POINT();      inv.exit.code = RC_OK;      inv.exit.w1 = 0;		/* until proven otherwise */      switch (inv.entry.key[0]->GetType()) {      case KT_Node:#ifdef KT_Wrapper      case KT_Wrapper:#endif      case KT_Segment:	/* It's possible - check further below */	break;      default:	return;      }      if (inv.entry.key[0]->GetKeyOid() != inv.key->GetKeyOid())	return;      if (inv.entry.key[0]->GetAllocCount() !=	  inv.key->GetAllocCount()) 	return;	      inv.exit.w1 = 1;      return;    }  case OC_Node_Clear:    {      if (isFetch) {	inv.exit.code = RC_NoAccess;	return;      }      theNode->MakeObjectDirty();      /* If we zero it, we're going to nail all of it's dependencies       * anyway:       */            COMMIT_POINT();      theNode->ClearThisNode();            Thread::Current()->Prepare();            return;    }  case OC_Node_KeyDataField:    {      COMMIT_POINT();      inv.exit.code = RC_OK;      inv.exit.w1 = inv.key->keyData;      return;    }  case OC_Node_WriteNumber:    {      if (isFetch) {	COMMIT_POINT();	inv.exit.code = RC_NoAccess;	return;      }      uint32_t slot = inv.entry.w1;      if (slot >= EROS_NODE_SIZE || inv.entry.len != sizeof(nk_value)) {	COMMIT_POINT();	inv.exit.code = RC_RequestError;	return;      }#ifndef OPTION_PURE_ENTRY_STRINGS      Thread::CurContext()->SetupEntryString(inv);#endif      /* If we overwrite it, we're going to nail all of it's       * dependencies anyway:       */            inv.exit.code = RC_OK;      CpuReserve *oldReserve = 0;            if (slot == ProcSched && theNode->slot[slot].IsType(KT_Sched) )	oldReserve = &CpuReserve::GetReserve(theNode->slot[slot]);      theNode->MakeObjectDirty();      COMMIT_POINT();	      nk_value nkv;      inv.CopyIn(inv.entry.len, &nkv);      theNode->ClearHazard(slot);      assert( (*theNode)[slot].IsUnprepared() );      (*theNode)[slot].KS_SetNumberKey(nkv.value[2],				       nkv.value[1],				       nkv.value[0]);            if (oldReserve) {          Key voidKey;		/* default constructor == void */                                /* any type other than KT_Sched will do */          MaybeRepairCpuReserveLinkages(theNode, oldReserve, voidKey);      }            Thread::Current()->Prepare();      inv.nextPC = ((Process *) Thread::CurContext())->GetPC();      return;    }  case OC_Node_Clone:    {      /* copy content of node key in arg0 to current node */      if (isFetch) {	inv.exit.code = RC_NoAccess;	return;      }      /* Mark the object dirty. */      theNode->MakeObjectDirty();      inv.entry.key[0]->Prepare();      assert(inv.key->IsPrepared());      COMMIT_POINT();      if (inv.entry.key[0]->GetType() != KT_Node) {	inv.exit.code = RC_RequestError;	return;      }      bool isWeak = inv.entry.key[0]->IsWeak();		           Node *fromNode = (Node *) inv.entry.key[0]->GetObjectPtr();      for (unsigned slot = 0; slot < EROS_NODE_SIZE; slot++) {	theNode->ClearHazard(slot);	if (fromNode->slot[slot].IsRdHazard())	  fromNode->ClearHazard(slot);      }      /* The following will do the right thing if the two nodes are       * identical, because the NH_Set code checks for this case.       */      for (unsigned slot = 0; slot < EROS_NODE_SIZE; slot++) {	/* hazards cleared above */	theNode->slot[slot].NH_Set( (*fromNode)[slot] );	if (isWeak)	  Desensitize(&theNode->slot[slot]);      }						          return;    }#if 0  /* Removed because keeping the reserves straight is a pain in the ass. */  case OC_Node_WriteNumbers:    {      if (isFetch) {	inv.exit.code = RC_NoAccess;	return;      }      inv.exit.code = RC_RequestError;      struct inMsg {	Word start;	Word end;	Word numBuf[EROS_NODE_SIZEx][3];	/* number key data fields */      } req;      /* If we overwrite it, we're going to nail all of it's       * dependencies anyway:       */            theNode->Unprepare(true);      theNode->MakeObjectDirty();#ifndef OPTION_PURE_ENTRY_STRINGS      Thread::CurContext()->SetupEntryString(inv);#endif      COMMIT_POINT();      bzero(&req, sizeof(req));      inv.CopyIn(sizeof(req), &req);      if (req.start >= EROS_NODE_SIZEx ||	  req.end >= EROS_NODE_SIZEx ||	  req.start > req.end)	return;      for (uint32_t k = req.start; k < req.end; k++) {	(*theNode)[k].KS_SetNumberKey(req.numBuf[(k-req.start)][2],                                      req.numBuf[(k-req.start)][1],                                      req.numBuf[(k-req.start)][0] );      }      return;    }#endif  default:    COMMIT_POINT();    inv.exit.code = RC_UnknownRequest;    return;  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -