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

📄 invoke.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
字号:
/* * Copyright (C) 1998, 1999, 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/Thread.hxx>#include <kerninc/util.h>#include <kerninc/Invocation.hxx>#include <kerninc/Machine.hxx>#include <kerninc/util.h>#include <kerninc/IRQ.hxx>#include <arch-kerninc/PTE.hxx>#include <eros/Invoke.h>/* C-coded Fast-path invocation logic for gate jump.  This version * only works if we get all the way through without *any* need to * yield, and it bails out if it discovers that we are going to call a * kernel key that might put us to sleep.  Most notably, it defers * building the Invocation structure as long as possible. */#if 0extern void SlowInvoke(SaveArea*);voidInvoke(SaveArea* sa){#ifdef FAST_INVOKE  ArchContext* sndContext = (ArchContext*) Thread::CurContext();  ArchContext *rcvContext;  Node *recipDomRoot;  SaveArea *rcvArea;  Msg *rcvMsg;  Thread *oldThread = Thread::Current();  uint8_t *sndString = 0;  uint8_t *rcvString = 0;    Key *sndKeyRegs = &(*sndContext->generalKeys)[0];  Key *rcvKeyRegs;  register Msg* sndMsg = (Msg*) sa;  uint32_t invSlot = sndMsg->invokedKey;  printf("invTy %d sndContext: 0x%08x  sndArea: 0x%08x, sa: 0x%08x\n",		 sndMsg->invocationType, sndContext, sndMsg, sa);  Key& invKey = sndKeyRegs[invSlot];  if (invSlot == 0)      goto slowpath;  printf(".");    if (sndMsg->invocationType > IT_Fork || invSlot > 15)    goto slowpath;        /* If not prepared gate key, go to slow path... */  if (invKey.kt.prepared == 0)    goto slowpath;  printf(".");    if (invKey.kt.keyType > LAST_GATE_KEYTYPE)    goto slowpath;    printf(" pOt = 0x%08x ", invKey.ok.pOT);    if (invKey.ok.pOT->allocStatus.removed == 1)    goto slowpath;  printf(".");    invKey.Prepare();  printf(".");    if (invKey.kt.keyType > LAST_GATE_KEYTYPE)    goto slowpath;    if (invKey.kt.keyType == KT_Resume && invKey.subType == KstRestart)    goto slowpath;  printf(".");  recipDomRoot = (Node *) invKey.ok.pOT->pObject;  printf(" recipDomRoot=0x%08x ", recipDomRoot);  if (recipDomRoot->obType != ObType::NtDomainRoot)    goto slowpath;  printf(".");  rcvContext = (ArchContext*) recipDomRoot->context;    printf(".");  /* If recipient domain is uncached, forget it: */  if (rcvContext == 0)    goto slowpath;  if ( invKey.kt.keyType == KT_Resume ) {    if (rcvContext->runState != RS_Waiting)      goto slowpath;  }  else if (rcvContext->runState != RS_Available)    goto slowpath;    rcvArea = rcvContext->UnsafeSaveArea();    printf(".\n");  if (oldThread != Thread::Current())    halt();    /* If recipient context is not fully prepared, forget it: */  if (rcvArea == 0)    goto slowpath;  /* If recipient has invalid address space map, forget it: */  if (rcvArea->MappingTable == 0 || rcvArea->MappingTable == KERNPAGEDIR)    goto slowpath;  rcvMsg = (Msg*) rcvArea;    rcvKeyRegs = &(*rcvContext->generalKeys)[0];  /* Okay.  Both sides look to be able to proceed.  See what it   * looks like.   */  if (sndMsg->sndSpec != Msg::StrString || rcvMsg->rcvSpec != Msg::StrString)    goto slowpath;    if (sndMsg->sndLen != 0) {    /* Check address space for valid mapping by probing first, last     * byte in the range.  If it isn't readable, we will take an     * access violation fault (page fault).  The page fault handler     * recognizes this code address as a special case, patches %eax     * to non-zero, and resumes at 'sender_probe_end:'     */    bool bad;    uint32_t limit = sndMsg->sndLen - 1;        __asm__ __volatile__("\txorl %0,%0\n"			 ".globl send_string_probe\n"			 ".globl send_string_probe_end\n"			 "send_string_probe:\n"			 "\tcmpb $0,(%1)\n"			 "\taddl %2,%1\n"			 "\tcmpb $0,(%1)\n"			 "\tsubl %2,%1\n"			 "send_string_probe_end:\n"			 : "=eax" (bad) /* outputs */			 : "ebx" (sndMsg->sndPtr), "ecx" (limit)			 );    if (bad)      goto slowpath;    else      sndString = (uint8_t *) sndMsg->sndPtr;  }  if (oldThread != Thread::Current())    halt();    if (rcvMsg->rcvLen != 0) {    uint32_t limit = rcvMsg->rcvLen - 1;    /* We know that we have a valid first-level mapping table for     * this process.  Extract the PDE corresponding to the first     * send address:     */    uint32_t pdendx = rcvMsg->rcvData;    pdendx >>= 22;    uint32_t ptendx = rcvMsg->rcvData;    ptendx >>= 12;    ptendx %= 1024;    PTE* pde = ( (PTE*) PTOV(rcvArea->MappingTable) ) + pdendx ;    PTE *pte;			/* declare here so goto won't break below */    /* Protect the kernel, which owns the upper third of the     * address space.     */    if (pdendx >= 767)      goto slowpath;          if ( !(pde->UserPage && pde->Present && pde->Writable))      goto slowpath;    pte = ( (PTE*) PTOV(pde->PageFrame()) ) + ptendx ;	    if ( !(pte->UserPage && pte->Present && pte->Writable))      goto slowpath;    PTE::kern_rcvbuf[0] = *pte;          /* Now check and see if the damn thing crosses a page boundary: */    uint32_t start = rcvMsg->rcvData;    uint32_t end = start + limit;    if ( ((start ^ end) & ~EROS_PAGE_MASK) != 0) {      /* Two cases: simple and hard. */      if (ptendx < 1023) {	pte++;      }      else {	pde++;	if ( !(pde->UserPage && pde->Present && pde->Writable))	  goto slowpath;	pte = ( (PTE*) PTOV(pde->PageFrame()) ) ;	if ( !(pte->UserPage && pte->Present && pte->Writable))	  goto slowpath;	PTE::kern_rcvbuf[1] = *pte;      }    }    /* Someday we should fix up the accessed and modified bits here. */    rcvString = (uint8_t *) ((sndMsg->sndPtr & EROS_PAGE_MASK) | KVA_RCVBUF);  }  if (oldThread != Thread::Current())    halt();    if (sndMsg->invocationType == IT_Fork) {    Thread *newThread = new Thread(Thread::Current()->priority, rcvContext);    if (newThread == 0)      goto slowpath;        newThread->Wakeup();    printf("IT_Fork invocation?? \n");    halt();  }#if 0  goto slowpath;#endif    /* It is no longer possible to fault, so go ahead and update the   * receive length pointer:   */  if (rcvMsg->rcvLen > sndMsg->sndLen)    rcvMsg->rcvLen = sndMsg->sndLen;  /* Before we blow the cache locality of the key arguments, copy   * those if they need it:   */  {    uint32_t sndKeys = sndMsg->sndKeys;    uint32_t rcvKeys = rcvMsg->rcvKeys;    if (sndKeys && rcvKeys) {      /* Copy key arg 0: */      if (rcvKeys & 0xf)	rcvKeyRegs[rcvKeys & 0xf].UnsafeSet(sndKeyRegs[sndKeys & 0xf]);      rcvKeys >>= 4;      sndKeys >>= 4;      /* Copy key arg 1: */      if (rcvKeys & 0xf)	rcvKeyRegs[rcvKeys & 0xf].UnsafeSet(sndKeyRegs[sndKeys & 0xf]);      rcvKeys >>= 4;      sndKeys >>= 4;      /* Copy key arg 2: */      if (rcvKeys & 0xf)	rcvKeyRegs[rcvKeys & 0xf].UnsafeSet(sndKeyRegs[sndKeys & 0xf]);      rcvKeys >>= 4;      sndKeys >>= 4;      if (rcvKeys & 0xf) {	if (sndMsg->invocationType == IT_Call) {	  Key& resumeSlot = rcvKeyRegs[rcvKeys & 0xf];	  resumeSlot.ktByte = PREPARED_KT(KT_Resume); /* zap hazards too. */	  resumeSlot.kt.prepared = 1;	  resumeSlot.subType = KstResume;	  resumeSlot.keyData = 0;	  resumeSlot.ok.SetDiskOid(sndContext->procRoot->oid);	  resumeSlot.ok.pOT = sndContext->procRoot->GetObTableEntry();	  resumeSlot.ok.SetCount(sndContext->procRoot->callCount);#if 0	  /* BUG -- but leave it because it exposes another! */	  rcvKeyRegs[rcvKeys & 0xf].UnsafeSet(sndKeyRegs[sndKeys & 0xf]);#endif	}	else {	  rcvKeyRegs[rcvKeys & 0xf].UnsafeSet(sndKeyRegs[sndKeys & 0xf]);	}      }    }  }  if (oldThread != Thread::Current())    halt();    printf("Copying from uva=0x%08x to kva=0x%08x len=0x%08x\n",		 sndString, rcvString, rcvMsg->rcvLen);    /* Copy the string, blowing away the data cache in all likelihood: */  if (rcvMsg->rcvLen) {    Machine::FlushTLB(KVTOL(KVA_RCVBUF));    Machine::FlushTLB(KVTOL(KVA_RCVBUF + 4096));    bcopy(sndString, rcvString, rcvMsg->rcvLen);  }  if (oldThread != Thread::Current())    halt();    rcvContext->runState = RS_Running;  switch (sndMsg->invocationType) {  case IT_Reply:    sndContext->runState = RS_Available;    printf("Migrate to ctxt=0x%08x\n", rcvContext);    Thread::Current()->MigrateTo(rcvContext);    break;  case IT_Call:    sndContext->runState = RS_Waiting;    printf("Migrate to ctxt=0x%08x\n", rcvContext);    Thread::Current()->MigrateTo(rcvContext);    break;    /* Sender state is unchanged */  case IT_Fork:    sndContext->runState = RS_Running;    printf("IT_Fork invocation?? \n");    halt();    /* Don't migrate -- already done! */    break;  }    printf("rcvContext: 0x%08x  rcvArea: 0x%08x\n",		 rcvContext, rcvArea);  if (oldThread != Thread::Current())    halt();    /* If resume key, bump count: */  if (invKey.kt.keyType == KT_Resume)    rcvContext->procRoot->callCount++;    printf("Thread::Current() is: 0x%08x context: 0x%08x\n",		 Thread::Current(), Thread::CurContext());  if (rcvContext != Thread::CurContext())    halt();  #if 0  printf("Made it!\n");  halt();#endif    return;slowpath:#endif  SlowInvoke(sa);}#endif

⌨️ 快捷键说明

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