📄 process.hxx
字号:
#ifndef __MACHINE_PROCESS_HXX__#define __MACHINE_PROCESS_HXX__/* * 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 <arch-kerninc/PTE.hxx>#include <eros/Invoke.h>#include <kerninc/Invocation.hxx>/* This file requires #include <kerninc/Process.hxx> *//* This file requires #include <kerninc/Thread.hxx> *//* Machine-specific helper functions for process operations: */extern PTE*proc_BuildMapping(Process* p, ula_t ula, bool forWriting, bool prompt);/* Return 0 if no mapping can be found with the desired access, * otherwise return the kernel *virtual* PAGE address containing the * virtual BYTE address uva. * * Note that successive calls to this, after inlining, should * successfully CSE the page directory part of the computation. */inline PTE*proc_TranslatePage(Process *p, ula_t ula, uint32_t mode, bool forWriting){#ifdef OPTION_SMALL_SPACES if (p->fixRegs.MappingTable == KERNPAGEDIR && p->smallPTE == 0) return 0;#else if (p->fixRegs.MappingTable == KERNPAGEDIR) return 0;#endif assert(p->fixRegs.MappingTable); if (p->fixRegs.MappingTable) { PTE* pde = (PTE*) PTOV(p->fixRegs.MappingTable); uint32_t ndx0 = (ula >> 22) & 0x3ffu; uint32_t ndx1 = (ula >> 12) & 0x3ffu; pde += ndx0; if (PTE_IS(*pde, mode)) { if (forWriting && PTE_ISNOT(*pde, PTE_W)) goto fail; PTE *pte = (PTE*) PTOV( (pde->AsWord() & ~EROS_PAGE_MASK) ); pte += ndx1; if (PTE_IS(*pte, mode)) { if (forWriting && PTE_ISNOT(*pte, PTE_W)) goto fail; return pte; } } }fail: return 0;}boolproc_DoPageFault(Process * p, ula_t la, bool isWrite, bool prompt);#ifndef FAST_IPC_ARG_VALIDATEinline voidProcess::ValidateEntryBlock(){ /* Check valid invocation type field + uppermost part of control field: */ if (fixRegs.invType >= 0x3) goto bogus; if (fixRegs.invKey >= EROS_NODE_SIZE) goto bogus; if (fixRegs.sndKeys & 0xe0e0e0e0u) /* high bits must be clear */ goto bogus; if (fixRegs.invType != IT_Send && fixRegs.rcvKeys & 0xe0e0e0e0u) /* high bits must be clear */ goto bogus; /* Check valid string len: */ if (fixRegs.sndLen > EROS_MESSAGE_LIMIT) goto bogus; return;bogus: SetFault(FC_BadEntryBlock, fixRegs.EIP); Thread::Current()->Yield();}#endifinline voidProcess::SetupEntryBlock(Invocation& inv){#ifndef FAST_IPC_ARG_VALIDATE ValidateEntryBlock();#endif /* Not hazarded because invocation key */ inv.key = &keyReg[fixRegs.invKey]; inv.key->Prepare(); inv.keyType = inv.key->GetType(); inv.invType = fixRegs.invType; inv.entry.code = fixRegs.EAX; inv.entry.w1 = fixRegs.EBX; inv.entry.w2 = fixRegs.ECX; inv.entry.w3 = fixRegs.EDX; uint8_t *sndKeys = (uint8_t *) &fixRegs.sndKeys; /* Not hazarded because invocation key */ inv.entry.key[0] = &keyReg[sndKeys[0]]; inv.entry.key[1] = &keyReg[sndKeys[1]]; inv.entry.key[2] = &keyReg[sndKeys[2]]; inv.entry.key[3] = &keyReg[sndKeys[3]]; /* Figure out the string length: */ uint32_t len = fixRegs.sndLen; inv.entry.len = len;}inline voidProcess::SetupExitBlock(Invocation& inv){ /* NOTE THAT THIS PROCEEDS EVEN IF THE EXIT BLOCK IS INVALID!!! */ /* inv.exit.code may be overwritten by the actual key handler: */ inv.exit.code = RC_OK; inv.exit.w1 = 0; inv.exit.w2 = 0; inv.exit.w3 = 0; inv.exit.len = 0; /* setting this twice cheaper than branch */ inv.exit.pKey[0] = 0; inv.exit.pKey[1] = 0; inv.exit.pKey[2] = 0; inv.exit.pKey[3] = 0; uint8_t *rcvKeys = (uint8_t *) &fixRegs.rcvKeys; if (fixRegs.rcvKeys) { if (fixRegs.rcvKeys & 0xe0e0e0e0) { SetFault(FC_BadExitBlock, 0, false); inv.suppressXfer = true; } else { if (rcvKeys[0]) inv.exit.pKey[0] = &keyReg[rcvKeys[0]]; if (rcvKeys[1]) inv.exit.pKey[1] = &keyReg[rcvKeys[1]]; if (rcvKeys[2]) inv.exit.pKey[2] = &keyReg[rcvKeys[2]]; if (rcvKeys[3]) inv.exit.pKey[3] = &keyReg[rcvKeys[3]]; } } #if 0 assert(inv.exit.key[0].IsPrepared() == false); assert(inv.exit.key[1].IsPrepared() == false); assert(inv.exit.key[2].IsPrepared() == false); assert(inv.exit.key[3].IsPrepared() == false);#endif#if 0 /* We do not zero the keys here any longer. Any exit keys that were used * by the last invocation will have been rezeroed in the post-invocation * cleanup logic in Invocation::Cleanup(), which is careful only to * rezero the keys that were actually touched. That makes a * staggeringly big difference in performance. */ /* Not hazarded because invocation key */ inv.exit.key[0].NH_VoidKey(); inv.exit.key[1].NH_VoidKey(); inv.exit.key[2].NH_VoidKey(); inv.exit.key[3].NH_VoidKey();#endif /* This assumes that we do not remap it into the kernel map. Logic * here is that we switch into the recipient address space as our * last action. */ if (inv.suppressXfer || this == 0) { inv.validLen = 0; return; } inv.validLen = fixRegs.ESI; /* Should this set a fault code? */ if (inv.validLen > EROS_MESSAGE_LIMIT) inv.validLen = EROS_MESSAGE_LIMIT; assert( IsRunnable() );}inline voidProcess::DeliverGateResult(Invocation& inv, bool wantFault){ /* No need to call Prepare() here -- it has already been called in * the invocation path. */ /* There used to be a check of IsRunnable() here. I removed it * because if the recipient had a bad string a fault code was * generated in SetupExitString, and as a consequence the recipient * is no longer runnable. It is guaranteed, however, that such a * short string will not impede progress. */ uint16_t keyData = inv.key->keyData; if (fixRegs.rcvKeys) { if (fixRegs.rcvKeys & 0x1f1f1fu) { if (inv.exit.pKey[0]) inv.exit.pKey[0]->NH_Set(*inv.entry.key[0]); if (inv.exit.pKey[1]) inv.exit.pKey[1]->NH_Set(*inv.entry.key[1]); if (inv.exit.pKey[2]) inv.exit.pKey[2]->NH_Set(*inv.entry.key[2]); } if (inv.exit.pKey[3]) { if (inv.invType == IT_Call) { Thread::CurContext()->BuildResumeKey(*inv.exit.pKey[3]); if (wantFault) inv.exit.pKey[3]->keyData = KsitFault; } else inv.exit.pKey[3]->NH_Set(*inv.entry.key[3]); } } /* copy return code and words */ fixRegs.EAX = inv.entry.code; fixRegs.EBX = inv.entry.w1; fixRegs.ECX = inv.entry.w2; fixRegs.EDX = inv.entry.w3;#ifdef DDB /* Duplicate here so that debugger reporting is accurate. */ inv.exit.code = inv.entry.code; inv.exit.w1 = inv.entry.w1; inv.exit.w2 = inv.entry.w2; inv.exit.w3 = inv.entry.w3;#endif uint32_t rcvBase = fixRegs.EDI; fixRegs.EDI = keyData; /* Data has already been copied out, so don't need to copy here. DO * need to deliver the data length, however: */ fixRegs.ESI = inv.exit.len; /* If the recipient specified an invalid receive area, though, they * are gonna get FC_ParmLack: */ if (inv.validLen < inv.exit.len) SetFault(FC_ParmLack, rcvBase + inv.validLen, false); /* Make sure it isn't later overwritten by the general delivery * mechanism. */ inv.suppressXfer = true;}#ifdef ASM_VALIDATE_STRINGS/* The reason to do this is that until OPTION_PURE_ENTRY_STRINGS is removed there are a whole lot of places where this gets called. The net effect is that ASM_VALIDATE_STRINGS implies OPTION_PURE_ENTRY_STRINGS whether OPTION_PURE_ENTRY_STRINGS is set or not. */inline voidProcess::SetupEntryString(struct Invocation& inv){#ifndef OPTION_SMALL_SPACES const uint32_t bias = 0;#endif uint32_t addr = (uint32_t) fixRegs.sndPtr + bias + KUVA; inv.entry.data = (uint8_t *) addr;}#endif#endif /* __MACHINE_PROCESS_HXX__ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -