📄 usercontext.cxx
字号:
if (dbg_wild_ptr) if (Check::Contexts("before unload") == false) halt('a');#endif if (curThread) { SyncThread(); curThread->ZapContext(); }#if defined(DBG_WILD_PTR) if (dbg_wild_ptr) if (Check::Contexts("after syncthread") == false) halt('b');#endif fixRegs.MappingTable = 0; saveArea = 0; curThread = 0;#ifdef EROS_HAVE_FPU if ( (hazards & hz::FloatRegs) == 0) FlushFloatRegs();#endif if ((hazards & hz::KeyRegs) == 0) FlushKeyRegs(); if ((hazards & hz::DomRoot) == 0) FlushFixRegs(); if ( (*procRoot)[ProcAddrSpace].IsHazard() ) { Depend_InvalidateKey(&(*procRoot)[ProcAddrSpace]); (*procRoot)[ProcAddrSpace].UnHazard(); hazards |= hz::AddrSpace; } procRoot->context = 0; procRoot->obType = ObType::NtUnprepared; assert(procRoot); kr.UnprepareAll(); hazards = 0; procRoot = 0; saveArea = 0; stallQ.WakeAll();}/* If the process has an invalid address space slot, it would probably * be more efficient to simply invoke the keeper right here rather * than start up a thread we know will fault. There are three reasons * not to do so: * * 1. It might get fixed before it runs. * 2. It is more modular to let the pagefault handler do it, since * that handler needs to deal with this situation already. * 3. This code is goddamn well hairy enough as it is. * * To load the mapping table pointer, we walk down the address space * segment looking for a node spanning 2^32 bits (blss=7). We then * examine it's products looking for a suitable mapping table. * * If we do not find one, we can't just build one on the spot, because * we must fabricate suitable depend entries for the new mapping * table. *//* This is somewhat misnamed, as loading the address space on the x86 * doesn't really load the address space at all -- it locates and * loads the page directory, which need not contain any valid entries. * Further faults will be handled in the page fault path. * * In loading the page directory, the LoadAddressSpace logic does not * need to construct any dependency table entries for the BLSS::bit32 * node. That node is a producer, and if it is taken out of core or * its keys are deprepared we can (and must) walk the producer chain * in any case. * * The address space segment slot may contain a segment key to a * segment whose span is larger than the span of the hardware address * space. For example, the segment might span 2^40 bits while the * hardware address space is only 2^32 bits. In interpreting such a * segment, we take the view that the address space of the process * starts at offset 0 in the larger segment, and is only as big as the * hardware will support. * * In the event that the address space segment is oversized in this * way, however, LoadAddressSpace() must create depend entries for all * nodes whose BLSS is > BLSS::bit32. We commit a slight bit of * silliness in doing this, which in practice works out okay. A page * directory holds 1024 entries. For nodes whose BLSS is > * BLSS::bit32, we know that the only key acting in a memory context * is the key in slot 0. We therefore claim (lying through our teeth) * that these nodes span a range of 16 * 1024 == 16k entries in the * page directory. We check for out of range invalidation in the * invalidate logic, so we never get caught by this. Also, the * invalidate logic knows the difference between page directories and * page tables, and never zaps the kernel entries. * */voidProcess::LoadAddressSpace(bool prompt){ assert (hazards & hz::AddrSpace); /* It's possible that we will end up invalidating exactly the * entries we are after! */ if ( proc_DoPageFault(this, fixRegs.EIP, false, prompt) ) { hazards &= ~hz::AddrSpace; }}/* Fault code is tricky. It is conceivable that the process does not * posess a number key in the fault code slot. In that event we set * the fault code to FC_MalformedProcess. Unless the process node * posesses a number key in the fault code slot, the fault code will * not be written back to the process root. Note that it is not * possible for a process with faultCode = FC_MalformedProcess to * achieve any other fault code without first resolving that one, so * it is okay to fail to write FC_MalformedProcess back to the process * root. * * Note the runstate is not loaded here. If the process root is * malformed it's runstate is intrinsically undefined. Such a process * cannot execute instructions. It's malformedness is discovered in * one of two ways: * * 1. It was running and somehow became malformed, in which case it * invokes it's keeper on it's own behalf. * 2. It was invoked by a third party, who is made to invoke its * keeper on its behalf. * * If the process root later becomes well formed we will be able to * load its run state at that time. */#if 0voidProcess::LoadFaultCode(){ assert (procRoot); if ( procRoot->slot[ProcTrapCode].IsType(KT_Number) ) { DomRegLayout* pDomRegs = (DomRegLayout*) & ((*procRoot)[0]); faultCode = pDomRegs->faultCode; faultInfo = pDomRegs->faultInfo; } else { faultCode = FC_MalformedProcess; faultInfo = 0; } hazards &= ~State::DomFaultCode;}#endif/* The DoPrepare() logic has changed, now that we have merged the * process prep logic into it... */voidProcess::DoPrepare(){ assert(procRoot); assert (isUserContext); procRoot->TransLock(); if (keysNode) keysNode->TransLock(); hazards &= ~hz::Malformed; /* until proven otherwise */ bool check_disjoint = (hazards & (hz::DomRoot | hz::FloatRegs | hz::KeyRegs)); #if 0 printf("Enter Process::DoPrepare()\n");#endif /* The order in which these are tested is important, because * sometimes satisfying one condition imposes another (e.g. floating * point bit set in the eflags register) */ if (hazards & hz::DomRoot) LoadFixRegs(); if (faultCode == FC_MalformedProcess) { assert (processFlags & PF_Faulted); return; } #ifdef EROS_HAVE_FPU if (hazards & hz::FloatRegs) LoadFloatRegs(); if (hazards & hz::NumericsUnit) LoadFPU();#endif if (hazards & hz::KeyRegs) LoadKeyRegs(); if (check_disjoint) { if ( procRoot == keysNode ) { SetMalformed(); } } if (faultCode == FC_MalformedProcess) { assert (processFlags & PF_Faulted); return; } if (hazards & hz::Schedule) { /* FIX: someday deal with schedule keys! */ Key& schedKey = (*procRoot)[ProcSched]; assert(schedKey.IsHazard() == false); schedKey.SetWrHazard(); cpuReserve = &CpuReserve::GetReserve(schedKey); hazards &= ~hz::Schedule; }#if 0 /* This is wrong. The original idea was that by prefaulting the EIP * address we could avoid an unnecessary kernel reentry. * Unfortunately, the prepare logic needs to be callable in order to * load the 32 bit register set from InvokeProcessKeeper. If no * valid address space exists for the process, then trying to build the * address space here causes a segment fault. If the relevant * segment has no keeper, this in turn yields in order to cause the * process keeper (if any) to be invoked. In that particular * sequence of events, however, an infinite loop is created... * * Rather than try to automatically build the address space here, we * go ahead with a zero mapping table and take the extra instruction * fault. */ if (fixRegs.MappingTable == 0) { hazards |= hz::AddrSpace; } if (hazards & hz::AddrSpace) LoadAddressSpace(false);#endif if (hazards & hz::SingleStep) { fixRegs.EFLAGS |= MASK_EFLAGS_Trap; hazards &= ~hz::SingleStep; } ValidateRegValues(); /* Change: It is now okay for the context to carry a fault code * and prepare correctly. */ saveArea = &fixRegs; stallQ.WakeAll();}voidProcess::InvokeProcessKeeper(){ Registers regs;#if 0 dprintf(false, "Fetching register values for InvokeProcessKeeper()\n");#endif GetRegs32(regs); /* Override the current domain state, as this is about to change in the course of the invocation. */ regs.domState = RS_Waiting;#if 0 dprintf(false, " ExNo: 0x%08x, Error: 0x%08x Info: 0x%08x FVA 0x%08x\n", fixRegs.ExceptNo, fixRegs.Error, faultInfo, fixRegs.ExceptAddr);#endif /* Must be unprepared in case we throw()! */ Key processKey; processKey.InitType(KT_Process); processKey.unprep.oid = procRoot->ob.oid; processKey.unprep.count = procRoot->ob.allocCount; /* Guarantee that prepared resume key will be in dirty object -- see * comment in kern_Invoke.cxx: */ assert (procRoot->IsDirty()); InvokeMyKeeper(OC_PROCFAULT, 0, 0, 0, &procRoot->slot[ProcKeeper], &processKey, (uint8_t *) ®s, sizeof(regs));}voidProcess::FlushProcessSlot(uint32_t whichKey){ assert(procRoot); switch (whichKey) { case ProcGenKeys: assert ((hazards & hz::KeyRegs) == 0); FlushKeyRegs(); break; case ProcAddrSpace: Depend_InvalidateKey(&(*procRoot)[whichKey]); (*procRoot)[whichKey].UnHazard(); hazards |= hz::AddrSpace; assert(fixRegs.MappingTable == 0); saveArea = 0; break; default:#ifdef EROS_HAVE_FPU if ( (hazards & hz::FloatRegs) == 0 ) FlushFloatRegs();#endif assert ((hazards & hz::DomRoot) == 0); FlushFixRegs(); break; } saveArea = 0;}#ifdef OPTION_DDBvoidProcess::WriteBackKeySlot(uint32_t k){ /* Write back a single key in support of DDB getting the display correct */ assert ((hazards & hz::KeyRegs) == 0); assert (keysNode->IsDirty()); keysNode->slot[k].UnHazard(); keysNode->slot[k].NH_Set(keyReg[k]); keysNode->slot[k].SetRwHazard();}#endif#if 0voidProcess::SetFault(uint32_t code, uint32_t info, bool needRevalidate){ faultCode = code; faultInfo = info; /* For FC_MalformedProcess, should use SetMalformed() instead!! */ assert(faultCode != FC_MalformedProcess); #if 1 if (faultCode) processFlags |= PF_Faulted; else processFlags &= ~PF_Faulted;#endif #if 0 printf("Fault code set to %d info=0x%x\n", code, info);#endif#if 0 /* It is now sufficient to set the PF_Faulted flag, which has the * effect of rendering the process non-runnable without totally * zapping the entire universe. */ if (needRevalidate) NeedRevalidate();#endif#if 0 Debugger();#endif}#endif/* On entry. inv.rcv.code == RC_OK */boolProcess::GetRegs32(struct Registers& regs){ assert (IsRunnable()); /* Following is x86 specific. On architectures with more annex * nodes this would need to check those too: */ if (hazards & hz::DomRoot) { return false; } regs.arch = ARCH_I386; regs.len = sizeof(regs); regs.pc = fixRegs.EIP; regs.sp = fixRegs.ESP; regs.faultCode = faultCode; regs.faultInfo = faultInfo; regs.domState = runState; regs.domFlags = processFlags; regs.EDI = fixRegs.EDI; regs.ESI = fixRegs.ESI; regs.EBP = fixRegs.EBP; regs.EBX = fixRegs.EBX; regs.EDX = fixRegs.EDX; regs.ECX = fixRegs.ECX; regs.EAX = fixRegs.EAX; regs.EFLAGS = fixRegs.EFLAGS; regs.CS = fixRegs.CS; regs.SS = fixRegs.SS; regs.ES = fixRegs.ES; regs.DS = fixRegs.DS; regs.FS = fixRegs.FS; regs.GS = fixRegs.GS; return true;}/* On entry. inv.rcv.code == RC_OK */boolProcess::SetRegs32(Registers& regs){#if 0 dprintf(true, "ctxt=0x%08x: Call to SetRegs32\n", this);#endif assert (IsRunnable()); if (hazards & hz::DomRoot) { dprintf(true, "ctxt=0x%08x: No root regs\n", this); return false; } /* Done with len, architecture */ fixRegs.EIP = regs.pc;#if 0 nextPC = regs.pc;#endif fixRegs.ESP = regs.sp; faultCode = regs.faultCode; faultInfo = regs.faultInfo; runState = regs.domState; processFlags = regs.domFlags; fixRegs.EDI = regs.EDI; fixRegs.ESI = regs.ESI; fixRegs.EBP = regs.EBP; fixRegs.EBX = regs.EBX; fixRegs.EDX = regs.EDX; fixRegs.ECX = regs.ECX; fixRegs.EAX = regs.EAX; fixRegs.EFLAGS = regs.EFLAGS; fixRegs.CS = regs.CS; fixRegs.SS = regs.SS; fixRegs.ES = regs.ES; fixRegs.DS = regs.DS; fixRegs.FS = regs.FS; fixRegs.GS = regs.GS;#if 0 dprintf(true, "SetRegs(): ctxt=0x%08x: EFLAGS now 0x%08x\n", this, fixRegs.EFLAGS);#endif NeedRevalidate(); return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -