📄 usercontext.cxx
字号:
/* * 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 <kerninc/kernel.hxx>#include <kerninc/Node.hxx>#include <arch-kerninc/KernTune.hxx>#include <kerninc/Depend.hxx>#include <kerninc/Thread.hxx>#include <kerninc/CpuReserve.hxx>#include <kerninc/util.h>#include <kerninc/ObjectCache.hxx>#include <kerninc/Machine.hxx>#include <kerninc/IRQ.hxx>#include <kerninc/Invocation.hxx>#include <kerninc/Check.hxx>#include <eros/Key.h>#include <kerninc/Process.hxx>#include <arch-kerninc/Process.hxx>#include <arch-kerninc/PTE.hxx>#include "TSS.hxx"#include <eros/Invoke.h>#include <eros/ProcessState.h>#include <eros/SegKeeperInfo.h>#include <eros/Registers.h>#include <eros/i486/Registers.h>#include <kerninc/PhysMem.hxx>#include <eros/ProcessKey.h>#include <eros/SysTraceKey.h>#include <kerninc/Invocation.hxx>#if 0#include <machine/RegLayout.hxx>#endif#include <disk/DiskLSS.hxx>#include "gen.REGMOVE.hxx"/* #define MSGDEBUG * #define RESUMEDEBUG * #define XLATEDEBUG */Process *Process::ContextCache;#ifdef EROS_HAVE_FPUProcess *Process::fpuOwner;#endif#ifdef OPTION_SMALL_SPACESPTE *Process::smallSpaces = 0;#endifboolProcess::HasDevicePriveleges(){ bool hasPrivs = false; assert((hazards & hz::DomRoot) == 0); assert((hazards & hz::KeyRegs) == 0); if (procRoot->slot[ProcIoSpace].IsType(KT_DevicePrivs)) hasPrivs = true; return hasPrivs;}voidProcess::AllocUserContexts(){ Process::ContextCache = new (0) Process[KTUNE_NCONTEXT]; assert (KTUNE_NCONTEXT < 1000); for (int i = 0; i < KTUNE_NCONTEXT; i++) { int ndx = i; Process::ContextCache[i].name[0] = 'u'; Process::ContextCache[i].name[1] = 's'; Process::ContextCache[i].name[2] = 'e'; Process::ContextCache[i].name[3] = 'r'; Process::ContextCache[i].name[4] = '0' + (ndx / 100); ndx %= 100; Process::ContextCache[i].name[5] = '0' + (ndx / 10); ndx %= 10; Process::ContextCache[i].name[6] = '0' + (ndx % 10); Process::ContextCache[i].name[7] = 0; } printf("Allocated User Contexts: 0x%x at 0x%08x\n", sizeof(Process[KTUNE_NCONTEXT]), Process::ContextCache);}/* FIX: It is unfortunate that some of these checks require !NDEBUG. * Should they? */boolCheck::Contexts(const char *){ bool result = true; IRQ::DISABLE(); /* It is possible for this to get called from interrupt handlers * before the context cache has been allocated. */ if (Process::ContextCache) { for (int i = 0; i < KTUNE_NCONTEXT; i++) { Process *p = &Process::ContextCache[i]; #ifndef NDEBUG if (p->kr.IsValid(p) == false) { result = false; break; }#endif #ifndef NDEBUG for (unsigned k = 0; k < EROS_PROCESS_KEYREGS; k++) { if (p->keyReg[0].IsValid() == false) { result = false; break; } }#endif if (p->procRoot && p->procRoot->IsFree()) { dprintf(true, "Context 0x%08x has free process root 0x%08x\n", p, p->procRoot); result = false; } if (p->keysNode && p->keysNode->IsFree()) { dprintf(true, "Context 0x%08x has free keys node 0x%08x\n", p, p->keysNode); result = false; } if (result == false) break; } } IRQ::ENABLE(); return result;}#ifndef NDEBUGboolValidCtxtPtr(const Process *ctxt){ if ( ((uint32_t) ctxt < (uint32_t) Process::ContextCache ) || ((uint32_t) ctxt >= (uint32_t) &Process::ContextCache[KTUNE_NCONTEXT]) ) return false; uint32_t offset = ((uint32_t) ctxt) - ((uint32_t) Process::ContextCache); offset %= sizeof(Process); if (offset == 0) return true; return false;}boolProcess::ValidKeyReg(const Key *pKey){ if ( ((uint32_t) pKey < (uint32_t) Process::ContextCache ) || ((uint32_t) pKey >= (uint32_t) &Process::ContextCache[KTUNE_NCONTEXT]) ) return false; /* Find the containing context: */ uint32_t ctxt = ((uint32_t) pKey) - ((uint32_t) Process::ContextCache); ctxt /= sizeof(Process); Process *p = &Process::ContextCache[ctxt]; if ( ((uint32_t) pKey < (uint32_t) &p->keyReg[0] ) || ((uint32_t) pKey >= (uint32_t) &p->keyReg[EROS_PROCESS_KEYREGS]) ) return false; uint32_t offset = ((uint32_t) pKey) - ((uint32_t) &p->keyReg[0]); offset %= sizeof(Key); if (offset == 0) return true; return false;}#endif#ifndef NDEBUGboolValidCtxtKeyRingPtr(const KeyRing* kr){ for (uint32_t c = 0; c < KTUNE_NCONTEXT; c++) { Process *ctxt = &Process::ContextCache[c]; if (kr == &ctxt->kr) return true; } return false;}#endifvoidProcess::FlushAll(){ for (uint32_t c = 0; c < KTUNE_NCONTEXT; c++) { Process *ctxt = &Process::ContextCache[c]; /* Unload the context structure, as we are going to COW the process * root anyway. */ ctxt->Unload(); }}extern "C" { void resume_from_kernel_interrupt(fixregs_t *); void resume_process(Process *); void resume_v86_process(Process *);};voidProcess::DumpFixRegs(){ if (saveArea == 0) printf("Note: context is NOT runnable\n"); ::DumpFixRegs(&fixRegs);}#ifdef EROS_HAVE_FPUvoidProcess::DumpFloatRegs(){ printf("fctrl: 0x%04x fstatus: 0x%04x ftag: 0x%04x fopcode 0x%04x\n", fpuRegs.f_ctrl, fpuRegs.f_status, fpuRegs.f_tag, fpuRegs.f_opcode); printf("fcs: 0x%04x fip: 0x%08x fds: 0x%04x fdp: 0x%08x\n", fpuRegs.f_cs, fpuRegs.f_ip, fpuRegs.f_ds, fpuRegs.f_dp);}#endif voidDumpFixRegs(const fixregs_t * fx){#if 0 uint32_t cip; __asm__("movl 4(%%ebp),%0" : "=g" (cip) : /* no inputs */);#endif#if 0 if ( sa_IsProcess(fx) ) printf("Process Savearea 0x%08x (cip 0x%08x)\n", fx, cip); else printf("Kernel Savearea 0x%08x (cip 0x%08x)\n", fx, cip);#else if ( sa_IsProcess(fx) ) printf("Process Savearea 0x%08x\n", fx); else printf("Kernel Savearea 0x%08x\n", fx);#endif printf( "Units = 0x%08x ASID = 0x%08x EFLAGS = 0x%08x\n" "EAX = 0x%08x EBX = 0x%08x ECX = 0x%08x\n" "EDX = 0x%08x EDI = 0x%08x ESI = 0x%08x\n" "EBP = 0x%08x CS = 0x%08x EIP = 0x%08x\n" "ExNo = 0x%08x ExAdr = 0x%08x Error = 0x%08x\n", fx->ReloadUnits, fx->MappingTable, fx->EFLAGS, fx->EAX, fx->EBX, fx->ECX, fx->EDX, fx->EDI, fx->ESI, fx->EBP, fx->CS, fx->EIP, fx->ExceptNo, fx->ExceptAddr, fx->Error); if ( sa_IsProcess(fx) ) { /* user save area: */ const fixregs_t* sa = fx; printf( "invTy = %d invKey = 0x%x sndPtr = 0x%08x sndLen= %5d sndKeys=0x%08x rcvKeys=0x%08x\n", sa->invType, sa->invKey, sa->sndPtr, sa->sndLen, sa->sndKeys, sa->rcvKeys); printf( "SS = 0x%08x ESP = 0x%08x\n" "DS = 0x%04x ES = 0x%04x FS = 0x%04x" " GS = 0x%04x\n", sa->SS, sa->ESP, sa->DS, sa->ES, sa->FS, sa->GS); } else { uint16_t ss; uint16_t ds; uint16_t es; uint16_t fs; uint16_t gs; __asm__ __volatile__ ("mov %%ss, %0" : "=r" (ss) : /* no input */); __asm__ __volatile__ ("mov %%ds, %0" : "=r" (ds) : /* no input */); __asm__ __volatile__ ("mov %%es, %0" : "=r" (es) : /* no input */); __asm__ __volatile__ ("mov %%fs, %0" : "=r" (fs) : /* no input */); __asm__ __volatile__ ("mov %%gs, %0" : "=r" (gs) : /* no input */); printf( "SS = 0x%08x ESP = 0x%08x\n" "DS = 0x%04x ES = 0x%04x FS = 0x%04x GS = 0x%04x\n", ss, ((uint32_t) fx) + 60, ds, es, fs, gs); }}/* NEW POLICY FOR USER CONTEXT MANAGEMENT: * * A context goes through several stages before being allowed to * run: * * HAZARD ACTION * * DomRoot Load the process root registers. * * Annex0 Reprepare the process general registers annex and load * it's registers * * KeyRegs Reprepare the process key registers annex and load * it's registers * * Validate Verify that all register values are suitable. * * AddrSpace Reload the master address space pointer. * * FloatUnit Floating point unit needs to be loaded. * * Note that the Annex0 hazard implies that the associated capability * in the process root is NOT validated. If any of 'DomRoot' 'Annex0' * or 'KeyRegs' cannot be cleared the process is malformed. * * Since it has been getting me in trouble, I am no longer trying to * micro-optimize slot reload. *//* Simple round-robin policy for now: */voidProcess::Load(Node* procRoot){ assert(procRoot); static uint32_t nextClobber = 0; Process* pContext = 0; #if 0 printf("Begin Process::Load\n");#endif do { pContext = &Process::ContextCache[nextClobber++]; if (nextClobber >= KTUNE_NCONTEXT) nextClobber = 0; if (pContext == Thread::Current()->context) { pContext = 0; continue; } if (inv.IsActive() && pContext == inv.invokee) { pContext = 0; continue; } #if 0 if (pContext->pinCount) pContext = 0;#endif if (pContext->curThread && pContext->curThread->state == Thread::Running) pContext = 0; } while (pContext == 0); Process& cc = (*pContext); /* wipe out current contents, if any */#if 0 printf(" Unload old context\n");#endif cc.Unload();#if 0 printf(" unloaded\n");#endif assert(procRoot->obType == ObType::NtProcessRoot); cc.procRoot = procRoot; cc.saveArea = 0; /* make sure not runnable! */ cc.faultCode = FC_NoFault; cc.faultInfo = 0; cc.processFlags = 0; /* FIX: what to do about runState? */#ifdef OPTION_SMALL_SPACES uint32_t ndx = &cc - Process::ContextCache; cc.limit = SMALL_SPACE_PAGES * EROS_PAGE_SIZE; cc.bias = UMSGTOP + (ndx * SMALL_SPACE_PAGES * EROS_PAGE_SIZE); cc.smallPTE = &smallSpaces[SMALL_SPACE_PAGES * ndx];#if 0 dprintf(true, "Loading small space process 0x%X bias 0x%x " "limit 0x%x\n", procRoot->oid, cc.bias, cc.limit);#endif for (uint32_t pg = 0; pg < SMALL_SPACE_PAGES; pg++) cc.smallPTE[pg].Invalidate();#endif cc.fixRegs.MappingTable = KERNPAGEDIR; cc.hazards = hz::DomRoot | hz::KeyRegs | hz::Schedule | hz::AddrSpace;#ifdef EROS_HAVE_FPU /* Must be hazarded by float regs so that we can correctly re-issue * floating point exceptions on restart: */ cc.hazards |= hz::FloatRegs;#endif cc.curThread = 0; procRoot->context = &cc; procRoot->obType = ObType::NtProcessRoot;#if 0 printf("End Process::Load\n");#endif}/* ValidateRegValues() -- runs last to validate that the loaded context * will not violate protection rules if it is run. This routine must * be careful not to overwrite an existing fault condition. To avoid * this, it must only alter the fault code value if there isn't * already a fault code. Basically, think of this as meaning that bad * register values are the lowest priority fault that will be reported * to the user. */void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -