📄 invoke.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 + -