📄 process.hxx
字号:
#ifndef __PROCESS_HXX__#define __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. *//* This is the revised (improved?) process structure, with reduced * architecture-dependent complexity. Note that we are moving towards * C-style architecture-dependent helper functions, so this is not a * class. *//* CHANGES TO THIS FILE ****MUST**** BE MADE IN THE * ARCHITECTURE-SPECIFIC LAYOUT FILES TOO!!! When the kernel is * converted to C we will be switching to using the LAYOUT file as the * ``official'' source. */#include <eros/ProcessState.h>#include <eros/ProcStats.h>#include <eros/machine/SaveArea.h>#ifdef EROS_HAVE_FPU#include <eros/machine/floatregs.h>#endif#ifdef EROS_HAVE_ARCH_REGS#include <eros/machine/archregs.h>#endif/* This file requires #include <kerninc/kernel.hxx> */#include <kerninc/Node.hxx>#include <kerninc/ThreadPile.hxx>struct Thread;struct SegWalk;/* Every running thread has an associated process structure. The * process structure for user threads has a lot more state. Process * structures for kernel threads are dedicated to the thread. Process * structures for user threads are caches of domain state. A process * is in use if it has a non-zero procRoot pointer. * * Every process has an associated save area pointer. * * Processes are reallocated in round-robin order, which may well prove * to be a dumb thing to do. Kernel processes are not reallocated. */struct Process { /* Pieces of the currently loaded domain: */ union { KeyRing kr; Node *procRoot; }; ThreadPile stallQ; /* procs waiting for this to be available */ bool isUserContext; /* hazards are reasons you cannot run. They generally devolve to * being malformed or needing some functional unit loaded before you * can make progress. */ uint32_t hazards; /* MACHINE DEPENDENT */ struct hz { enum { Malformed = 0x01u, DomRoot = 0x02u, KeyRegs = 0x04u, FloatRegs = 0x08u, Schedule = 0x10u, AddrSpace = 0x20u,#ifdef EROS_HAVE_FPU NumericsUnit = 0x40u, /* need to load FPU */#endif SingleStep = 0x80u, /* requested single step status */ }; }; bool IsWellFormed() {#ifndef NDEBUG if (faultCode == FC_MalformedProcess) { assert (processFlags & PF_Faulted); assert (saveArea == 0); }#endif if (hazards & (hz::DomRoot|hz::KeyRegs|hz::FloatRegs|hz::Malformed)) { assert (saveArea == 0); return false; } return true; } /* END MACHINE DEPENDENT */ /* SaveArea is nonzero exactly when the context has a valid save * image -- i.e. it is fully cached and the resulting context image * is RUNNABLE (i.e. doesn't violate processor privilege constraints). */ struct fixregs_t *saveArea; struct CpuReserve *cpuReserve; /* Processor we last ran on, to recover FP regs * Processor *lastProcessor; */ /* At most one thread in a given context at a time, which will be * pointed to by the context: */ Thread *curThread; Key* GetSegRoot() { return & ((*procRoot)[ProcAddrSpace]); } fixregs_t fixRegs; /* This should immediately follow fixRegs: */ Key keyReg[EROS_PROCESS_KEYREGS]; uint32_t faultCode; uint32_t faultInfo; uint8_t runState; uint8_t processFlags; #ifdef OPTION_SMALL_SPACES uva_t limit; ula_t bias; struct PTE *smallPTE; static struct PTE *smallSpaces; void SwitchToLargeSpace() { smallPTE = 0; bias = 0; limit = UMSGTOP; fixRegs.MappingTable = KERNPAGEDIR; }#endif #ifdef EROS_HAVE_FPU /* FPU support: */ floatregs_t fpuRegs; static Process* fpuOwner; /* FIX: This is not SMP-feasible. */ void SaveFPU(); void LoadFPU(); void DumpFloatRegs();#endif #ifdef EROS_HAVE_ARCH_REGS archregs_t archRegs;#endif Node *keysNode; char arch[4]; /* Useful to have a name for diagnostic purposes. */ char name[8]; ProcStat stats; Key XaddressSpace; Key XioSpace; Key XcpuReserveKey; Key XworkingSet; Key Xkeeper; Key XsymbolTable;#ifndef NDEBUG static bool ValidKeyReg(const Key *pKey);#endif static bool IsKeyReg(const Key *pKey) { /* This isn't quite right, as it will return TRUE for any random * pointer in to the process area, but that's good enough for all * the places that we use it. */ if ( ((uint32_t) pKey >= (uint32_t) ContextCache) && ((uint32_t) pKey < (uint32_t) &ContextCache[KTUNE_NCONTEXT]) ) { return true; } return false; } /* Returns true if the context has been successfully cached. A * context can be successfully cached without being runnable. If * possible, sets the saveArea pointer to a valid save area. The * saveArea pointer cannot be set if (e.g.) it's privileged * registers have improper values. */ void DoPrepare(); /* Fast-path inline version. See comment above on DoPrepare(). * MUST NOT yield if IsRunnable() would return true. */ void Prepare() { /* Anything that invalidates the context will zap the saveArea * pointer, so this is a quick test, which is useful for fast * reload. */ if (saveArea) return; DoPrepare(); } void NeedRevalidate() { saveArea = 0; } /* USED ONLY BY INTERRUPT HANDLERS: */ void SetSaveArea(fixregs_t *sa) { saveArea = sa; } fixregs_t *UnsafeSaveArea() { return saveArea; } bool IsRunnable() { return saveArea ? true : false; } bool IsNotRunnable() { return (saveArea == 0) ? true : false; } void Unthread() { assert (isUserContext); curThread = 0; } void SetThread(Thread *thread) { assert(curThread == 0 || curThread == thread); curThread = thread; } void Resume() NORETURN; bool IsUser() { return isUserContext; } bool IsKernel() { return !isUserContext; } const char* Name() { return name; } /* Called by checkpoint logic */ static void FlushAll(); static void AllocUserContexts(); /* machine dependent! */ void DumpFixRegs(); /* needRevalidate means that the fault is due to a structural * problem in the process, and cannot be cleared without * revalidating the context cache. Another way to think about this * is that any fault for which /needRevalidate/ is true is a fault * that cannot be cleared on the fast path. */ void SetFault(uint32_t code, uint32_t info, bool needRevalidate) { faultCode = code; faultInfo = info; assert(faultCode != FC_MalformedProcess); if (faultCode) processFlags |= PF_Faulted; else processFlags &= ~PF_Faulted; if (needRevalidate) NeedRevalidate();#ifdef OPTION_DDB if (processFlags & PF_DDBTRAP) dprintf(true, "Process 0x%08x has trap code set\n", this);#endif } void SetMalformed() { SetFault(FC_MalformedProcess, 0, true); hazards |= hz::Malformed; } /* Generic keeper invoker: */ void InvokeMyKeeper(uint32_t oc, uint32_t warg1, uint32_t warg2, uint32_t warg3, Key *keeperKey, Key* keyArg2, uint8_t *data, uint32_t len); bool InvokeSegmentKeeper(/*uint32_t code, */ SegWalk&); void InvokeProcessKeeper(); /****************************************************** * Begin new code in support of new invocation logic ******************************************************/ void BuildResumeKey(Key& resumeKey); void DoGeneralKeyInvocation(); void DoKeyInvocation(); /* Following is only needed if assembly code is not used to validate the entry block. */#ifndef FAST_IPC_ARG_VALIDATE inline void ValidateEntryBlock(); /* may throw */#endif#ifdef ASM_VALIDATE_STRINGS inline#endif void SetupEntryString(struct Invocation& inv); void SetupExitString(struct Invocation& inv, uint32_t bound); inline void SetupEntryBlock(struct Invocation& inv); inline void SetupExitBlock(struct Invocation& inv); void DeliverResult(struct Invocation& inv); inline void DeliverGateResult(Invocation& inv, bool wantFault); /****************************************************** * End new code in support of new invocation logic ******************************************************/ /****************************************************** * Code in support of emulated instructions: ******************************************************/ void DoEmulatedInstr(const struct EmulatedInstr& instr); /****************************************************** * End new code in support of emulated instructions ******************************************************/ void LoadFixRegs();#ifdef EROS_HAVE_FPU void LoadFloatRegs();#endif void LoadKeyRegs(); void FlushFixRegs();#ifdef EROS_HAVE_FPU void FlushFloatRegs();#endif void FlushKeyRegs(); /* Following are machine generated because I got tired of making mistakes: */ void DoLoadFixRegs(); void DoFlushFixRegs(); void DoLoadFloatRegs(); void DoFlushFloatRegs(); void LoadAddressSpace(bool prompt); void ValidateRegValues(); /* returns false if faulted */ bool HasDevicePriveleges(); void FlushProcessSlot(uint32_t whichKey);#ifdef OPTION_DDB void WriteBackKeySlot(uint32_t whichKey);#endif void SyncThread(); void Unload(); bool GetRegs32(struct Registers&); bool SetRegs32(struct Registers&); void SetPC(uint32_t oc) { fixRegs.EIP = oc; } /* Called before AdjustInvocationPC() to capture the address of the * next instruction to run if the invocation is successful. */ inline uint32_t CalcPostInvocationPC() { return fixRegs.EIP; } /* Called in the IPC path to reset the PC to point to the invocation * trap instruction... */ inline void AdjustInvocationPC() { fixRegs.EIP -= 2; } inline uint32_t GetPC() { return fixRegs.EIP; } void SetInstrSingleStep() { hazards |= hz::SingleStep; saveArea = 0; } #ifdef EROS_HAVE_FPU void ForceNumericsLoad() { hazards |= hz::NumericsUnit; saveArea = 0; }#endif #ifdef OPTION_SMALL_SPACES static void WriteDisableSmallSpaces();#endif Process(); static Process *ContextCache; static void Load(Node* procRoot);#if 0 /* Note protected constructor!! */ Context(bool isUser) { isUserContext = isUser; cpuReserve = 0; faultCode = FC_NoFault; faultInfo = 0; saveArea = 0; hazards = 0u; /* deriver should change this! */ }#endif};/* Walk a segment as described in WI until one of the following * occurs: * * You find a subsegment whose blss is <= STOPBLSS (walk * succeeded, return true) * You conclude that the desired type of access as described in * ISWRITE cannot be satisfied in this segment (walk failed, * return false) * * At each stage in the walk, add dependency entries between the * traversed slots and the page table entries named by the passed * PTEs. * * If 'prompt' is true, WalkSeg returns as described above. If * prompt is false, WalkSeg invokes the prevailing keeper on error. * * This routine is designed to be re-entered and cache it's * intervening state in the SegWalk structure so that the walk * does not need to be repeated. */ extern boolproc_WalkSeg(Process * p,SegWalk& wi, uint32_t stopBlss, PTE* pPTE0, PTE* pPTE1, bool canMerge);/* This may now be vestigial.... */struct KernProcess : public Process {#ifdef DBG_WILD_PTR uint32_t *stackTop; uint32_t *stackBottom;#endif#if 0 /* Following are for kernel threads: */ KernProcess(const char *myName, Thread& theThread);#endif KernProcess(const char * name, Thread& theThread, void (*pc)(), uint32_t *StackBottom, uint32_t *StackTop); void InitStack();#if 0 void SetStack(uint32_t */*stkBottom*/, uint32_t */*stkTop*/) { stackBottom = stkBottom; stackTop = stkTop; }#endif} ;#endif /* __PROCESS_HXX__ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -