⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pagefault.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
📖 第 1 页 / 共 2 页
字号:
 * should not have authority. *  * A case can be made, however, that a kept red segment should be * permitted to contain a NON-kept red segment that specifies a * background segment.  The main reason to desire this is to allow * (e.g.) VCSK to operate on a background segment that contains a * window. *  * For the moment, we do not support this, and I am inclined to * believe that it is unwise to do so until I see a case in which it * is useful. *  * Local windows are not yet supported by the SegWalk code, but none * of this is an issue for local windows, */inline uint64_tBLSS_MASK64(uint32_t blss, uint32_t frameBits){  uint32_t bits_to_shift =    (blss - EROS_PAGE_BLSS) * EROS_NODE_LGSIZE + frameBits;   uint64_t mask = (1ull << bits_to_shift);  mask -= 1ull;    return mask;}/* #define WALK_LOUD */#define FAST_TRAVERSALboolproc_DoPageFault(Process * p, ula_t la, bool isWrite, bool prompt){  const int walk_root_blss = 4 + EROS_PAGE_BLSS;  const int walk_top_blss = 2 + EROS_PAGE_BLSS;  #ifdef DBG_WILD_PTR  if (dbg_wild_ptr)    Check::Consistency("Top of DoPageFault()");#endif  DoPageFault_CallCounter++;    DEBUG(pgflt) {    printf("DoPageFault: ctxt=0x%08x EIP 0x%08x la=0x%08x, isWrite=%c prompt=%c\n",		   p,		   p->fixRegs.EIP,		   la,		   isWrite ? 't' : 'f',		   prompt ? 't' : 'f');  }  #ifdef OPTION_SMALL_SPACES  uva_t va = la - p->bias;#else  uva_t va = la;#endif    /* If LA is simply out of range, then forget the whole thing: */  if ( la >= KVA ) {    dprintf(true, "Domain accessed kernel or small space la\n");    p->SetFault(FC_InvalidAddr, va, false);    return false;  }#ifdef OPTION_SMALL_SPACES  if (p->smallPTE)    return proc_DoSmallPageFault(p, la, isWrite, prompt);#endif			      /* If LA is simply out of range, then forget the whole thing: */  if ( la >= UMSGTOP ) {    dprintf(true, "Large domain accessed small space la\n");    p->SetFault(FC_InvalidAddr, va, false);    return false;  }  /* If we discover on the way to load the process that it's mapping   * table register was voided, we substituted KERNPAGEDIR.  Notice   * that here:   */  if ( p->fixRegs.MappingTable == KERNPAGEDIR )    p->fixRegs.MappingTable = PTE_ZAPPED;  /* Set up a WalkInfo structure and start building the necessary   * mapping table, PDE, and PTE entries.   */  SegWalk wi;  wi.faultCode = FC_NoFault;  wi.traverseCount = 0;  wi.segObj = 0;  wi.vaddr = va;  wi.frameBits = EROS_PAGE_ADDR_BITS;  wi.writeAccess = isWrite;  wi.invokeKeeperOK = !prompt;  wi.invokeProcessKeeperOK = !prompt;  wi.wantLeafNode = false;  segwalk_init(wi, p->GetSegRoot());  /* See if there is already a page table. If not, go find/build one. */  PTE *pTable = (PTE *) (PTOV(p->fixRegs.MappingTable) & ~EROS_PAGE_MASK);#ifdef WALK_LOUD  dprintf(false, "pTable is 0x%x\n", pTable);#endif    if (pTable == 0)    goto need_pgdir;    {    ObjectHeader *pTableHdr = ObjectCache::PhysPageToObHdr(PtoKPA(pTable));    if (isWrite && !pTableHdr->rwProduct) {      dprintf(true, "DoPageFault(): isWrite && !pTableHdr->rwProduct hdr 0x%x\n", pTableHdr);      goto access_fault;    }    wi.canCall = pTableHdr->caProduct;    #ifdef FAST_TRAVERSAL    /* We have a page directory conveying suitable access rights from       the top.  See if the PDE has the necessary permissions: */    {      uint32_t pdeNdx = (la >> 22) & 0x3ffu;      PTE& thePDE = pTable[pdeNdx];      if ( PTE_IS(thePDE, PTE_V|PTE_USER) ) {	/* We could short-circuit the walk in this case by remembering	 * the status of /wi.canWrite/ in a spare bit in the PTE, but	 * at the moment we do not do so because in most cases the	 * write restriction appears lower down in the segment tree.	 */	if ( PTE_IS(thePDE, PTE_W) || !isWrite ) {	  /* We have a valid PDE with the necessary permissions! */	  pTable = (PTE *) thePDE.PageFrame();	  pTableHdr = ObjectCache::PhysPageToObHdr(PtoKPA(pTable));	  	  wi.offset = wi.vaddr & ((1u << 22) - 1u);	  wi.segBlss = pTableHdr->producerBlss;	  wi.segObj = pTableHdr->producer;	  wi.redSeg = pTableHdr->mp.redSeg;	  if (wi.redSeg) {	    wi.redSpanBlss = pTableHdr->mp.redSpanBlss;	    wi.redSegOffset =	      ((uint64_t) wi.vaddr) & BLSS_MASK64(wi.redSpanBlss, wi.frameBits);	  }#ifdef KT_Wrapper	  wi.segObjIsWrapper = pTableHdr->mp.wrapperProducer;#else	  wi.segObjIsRed = pTableHdr->mp.redProducer;#endif	  wi.canWrite = pTableHdr->rwProduct ? true : false;	  wi.canCall &= pTableHdr->caProduct;#if 0	  if (wi.redSeg && wi.offset != wi.redSegOffset) {      dprintf(false, "pdr proc_WalkSeg: wi.producer 0x%x, wi.prodBlss %d wi.isRed %d\n"		      "wi.vaddr 0x%x wi.offset 0x%X flt %d  wa %d segKey 0x%x\n"		      "canCall %d canWrite %d\n"		      "redSeg 0x%x redOffset 0x%X\n",		      wi.segObj, wi.segBlss, wi.segObjIsRed,		      wi.vaddr, wi.offset, wi.segFault, wi.writeAccess,		      0x0,		      wi.canCall, wi.canWrite,		      wi.redSeg, wi.redSegOffset);	    dprintf(true, "Found pg dir. Offset 0x%X RedSegOffset 0x%X spanBlss %d\n",			    wi.offset, wi.redSegOffset, wi.redSpanBlss);	  }#endif	  	  /* NOTE: This is doing the wrong thing when the red segment	   * needs to be grown upwards, because the segBlss in that	   * case is less than the *potential* span of the red	   * segment.	   */#ifdef WALK_LOUD	  dprintf(false, "have_good_pde\n");#endif	  goto have_good_pde;	}      }    }#endif /* FAST_TRAVERSAL */        wi.offset = wi.vaddr;    wi.segBlss = pTableHdr->producerBlss;    wi.segObj = pTableHdr->producer;    wi.redSeg = pTableHdr->mp.redSeg;    if (wi.redSeg) {      wi.redSpanBlss = pTableHdr->mp.redSpanBlss;      wi.redSegOffset =	((uint64_t) wi.vaddr) & BLSS_MASK64(wi.redSpanBlss, wi.frameBits);    }#ifdef KT_Wrapper    wi.segObjIsWrapper = pTableHdr->mp.wrapperProducer;#else    wi.segObjIsRed = pTableHdr->mp.redProducer;#endif    wi.canWrite = pTableHdr->rwProduct ? true : false;#ifdef WALK_LOUD    dprintf(false, "have_pgdir\n");#endif    goto have_pgdir;  }   need_pgdir:  /* No page directory was found, so we need to construct a page   * directory. */    p->fixRegs.MappingTable = PTE_IN_PROGRESS;    /* Begin the traversal... */  if ( !proc_WalkSeg(p, wi, walk_root_blss,		     (PTE *)&p->fixRegs.MappingTable, 0, false) ) {     p->SetFault(wi.faultCode, va, false);    return false;  }  /* If the wrong depend entry was reclaimed, we may have just lost   * the mapping table entry. If we are still good to go, : */  if (p->fixRegs.MappingTable == PTE_ZAPPED)    Thread::Current()->Yield();  /* Since the address space pointer register lacks permission bits,   * we cannot be here due to lack of permissions at this   * level. Therefore, if we are processing this path at all the   * mapping table must have been invalid, in which case it should now   * be PTE_IN_PROGRESS. */  assert (p->fixRegs.MappingTable == PTE_IN_PROGRESS);  /* We can now reset the value to the zap guard. */  p->fixRegs.MappingTable = PTE_ZAPPED;    assert (pTable == 0);  if (pTable == 0) {    /* See if a mapping table has already been built for this address     * space.  If so, just use it.  Using wi.segBlss is okay here     * because the mapping table pointer will be zapped if anything     * above this point gets changes, whereupon the gunk the the page     * directory will no longer matter.     */    ObjectHeader *pTableHdr =      wi.segObj->FindProduct(wi, EROS_NODE_LGSIZE /* ndx */,			     wi.canWrite, wi.canCall);        if (pTableHdr == 0)      pTableHdr = proc_MakeNewPageDirectory(wi);    pTable = (PTE *) ObjectCache::ObHdrToPage(pTableHdr);    p->fixRegs.MappingTable = VTOP(pTable);  } have_pgdir:  #ifndef NDEBUG  {    ObjectHeader *pTableHdr = ObjectCache::PhysPageToObHdr(PtoKPA(pTable));    assert(wi.segBlss == pTableHdr->producerBlss);    assert(wi.segObj == pTableHdr->producer);    assert(wi.redSeg == pTableHdr->mp.redSeg);    assert(wi.canWrite == (pTableHdr->rwProduct ? true : false));  }#endif  {    /* Start building the PDE entry: */    uint32_t pdeNdx = (la >> 22) & 0x3ffu;    PTE& thePDE = pTable[pdeNdx];    if (PTE_ISNOT(thePDE, PTE_V))      thePDE.w_value = PTE_IN_PROGRESS;    /* Translate the top 8 (10) bits of the address: */    if ( !proc_WalkSeg(p, wi, walk_top_blss, &thePDE, 0, true) )      return false;    if (thePDE.w_value == PTE_ZAPPED)      Thread::Current()->Yield();    if (thePDE.w_value == PTE_IN_PROGRESS)      thePDE.w_value = PTE_ZAPPED;        /* If we get this far, we need the page table to proceed further.     * See if we need to build a new page table:     */    if (PTE_IS(thePDE, PTE_V)) {      pTable = (PTE *) PTOV(thePDE.PageFrame());      if (wi.canWrite && !PTE_IS(thePDE, PTE_W)) {	/* We could only have taken this fault because writing was not	 * enabled at the directory level, which means that we need to	 * flush the PDE from the hardware TLB.	 */	thePDE.Invalidate();      }    }    else {      uint32_t productNdx = 0;      /* Level 0 product need never be a read-only product.  We use       * the write permission bit at the PDE level.       */            ObjectHeader *pTableHdr =	wi.segObj->FindProduct(wi, productNdx, true, true);      if (pTableHdr == 0)	pTableHdr = proc_MakeNewPageTable(wi, productNdx);      assert(wi.segBlss == pTableHdr->producerBlss);      assert(wi.segObj == pTableHdr->producer);      assert(wi.redSeg == pTableHdr->mp.redSeg);      /* On x86, the page table is always RW product, and we rely on	 the write permission bit at the PDE level: */      assert(pTableHdr->rwProduct == true);      pTable = (PTE *) ObjectCache::ObHdrToPage(pTableHdr);    }    /* The level 0 page table is still contentless - there is no     * need to build depend table entries covering it's contents.     * We simply need to fill in the page directory entry:     */    PTE_SET(thePDE, (VTOP((kva_t)pTable) & PTE_FRAMEBITS));    PTE_SET(thePDE, PTE_ACC|PTE_USER|PTE_V);        /* Using /canWrite/ instead of /isWrite/ reduces the number of     * cases in which we need to rebuild the PDE without altering the     * actual permissions, and does not require us to dirty a page.     * This is legal only because on this architecture the node tree     * and the page tables are congruent at this level.     */    if (wi.canWrite)      PTE_SET(thePDE, PTE_W);  }#ifdef FAST_TRAVERSAL have_good_pde:#endif    {    uint32_t pteNdx = (la >> 12) & 0x3ffu;    PTE& thePTE = pTable[pteNdx];    if (PTE_ISNOT(thePTE, PTE_V))      thePTE.w_value = PTE_IN_PROGRESS;        /* Translate the remaining bits of the address: */    if ( !proc_WalkSeg(p, wi, EROS_PAGE_BLSS, &thePTE, 0, true) )      return false;    /* Depend entry triggered -- retry the fault */    if (thePTE.w_value == PTE_ZAPPED)      Thread::Current()->Yield();    if (thePTE.w_value == PTE_IN_PROGRESS)      thePTE.w_value = PTE_ZAPPED;            assert(wi.segObj);    assert(wi.segObj->obType == ObType::PtDataPage ||	   wi.segObj->obType == ObType::PtDevicePage);        kpa_t pageAddr = 0;    if (isWrite)      wi.segObj->MakeObjectDirty();    pageAddr = VTOP(ObjectCache::ObHdrToPage(wi.segObj));    if (pageAddr == 0)      dprintf(true, "wi.segObj 0x%08x at addr 0x%08x!! (wi=0x%08x)\n",		      wi.segObj, pageAddr, &wi);    assert ((pageAddr & EROS_PAGE_MASK) == 0);    assert (pageAddr < PtoKPA(start) || pageAddr >= PtoKPA(end));	      if (isWrite && PTE_IS(thePTE, PTE_V)) {      /* We are doing this because the old PTE had insufficient       * permission, so we must zap the TLB.       */      thePTE.Invalidate();    }      PTE_SET(thePTE, (pageAddr & PTE_FRAMEBITS) );    PTE_SET(thePTE, DATA_PAGE_FLAGS);    if (isWrite)      PTE_SET(thePTE, PTE_W);#ifdef WRITE_THROUGH    if (CpuType >= 5)      PTE_SET(thePTE, PTE_W);#endif  }      if (PteZapped)    Machine::FlushTLB();    #ifdef DBG_WILD_PTR  if (dbg_wild_ptr)    Check::Consistency("End of DoPageFault()");#endif  return true; access_fault:  wi.faultCode = FC_Access;  goto fault_exit; fault_exit:#ifdef WALK_LOUD    dprintf(true, "flt proc_WalkSeg: wi.producer 0x%x, wi.prodBlss %d wi.isRed %d\n"		    "wi.vaddr 0x%x wi.offset 0x%X flt %d  wa %d\n"		    "canCall %d canWrite %d\n",		    wi.segObj, wi.segBlss, wi.segObjIsRed,		    wi.vaddr, wi.offset, wi.segFault, wi.writeAccess,		    wi.canCall, wi.canWrite);#endif  if (wi.invokeKeeperOK)    return p->InvokeSegmentKeeper(wi);  return false;}static ObjectHeader*proc_MakeNewPageDirectory(SegWalk& wi){  ObjectHeader *pTable = ObjectCache::GrabPageFrame();  assert (pTable->kr.IsValid(pTable));  pTable->obType = ObType::PtMappingPage;  pTable->producerNdx = EROS_NODE_LGSIZE;  pTable->producerBlss = wi.segBlss;  pTable->mp.redSeg = wi.redSeg;#ifdef KT_Wrapper  pTable->mp.wrapperProducer = wi.segObjIsWrapper;#else  pTable->mp.redProducer = wi.segObjIsRed;#endif  pTable->mp.redSpanBlss = wi.redSpanBlss;  pTable->rwProduct = wi.canWrite ? 1 : 0;  pTable->caProduct = wi.canCall ? 1 : 0;  pTable->SetDirtyFlag();  kva_t tableAddr = ObjectCache::ObHdrToPage(pTable);  bzero((void *) tableAddr, EROS_PAGE_SIZE);  {    uint32_t *kpgdir = (uint32_t *) PTOV(KERNPAGEDIR);    uint32_t *upgdir = (uint32_t *) tableAddr;        for (uint32_t i = (UMSGTOP >> 22); i < NPTE_PER_PAGE; i++)      upgdir[i] = kpgdir[i];  }      wi.segObj->AddProduct(pTable);  return pTable;}static ObjectHeader*proc_MakeNewPageTable(SegWalk& wi, uint32_t ndx){  /* Need to make a new mapping table: */  ObjectHeader *pTable = ObjectCache::GrabPageFrame();  assert (pTable->kr.IsValid(pTable));  pTable->obType = ObType::PtMappingPage;  pTable->producerNdx = ndx;  pTable->producerBlss = wi.segBlss;    pTable->mp.redSeg = wi.redSeg;#ifdef KT_Wrapper  pTable->mp.wrapperProducer = wi.segObjIsWrapper;#else  pTable->mp.redProducer = wi.segObjIsRed;#endif  pTable->mp.redSpanBlss = wi.redSpanBlss;  pTable->rwProduct = 1;  pTable->caProduct = 1;	/* we use spare bit in PTE */  pTable->SetDirtyFlag();  kva_t tableAddr = ObjectCache::ObHdrToPage(pTable);  bzero((void *)tableAddr, EROS_PAGE_SIZE);#if 0  printf("0x%08x->MkPgTbl(blss=%d,ndx=%d,rw=%c,ca=%c,"		 "producerTy=%d) => 0x%08x\n",		 wi.segObj,		 wi.segBlss, ndx, 'y', 'y', wi.segObj->obType,		 pTable);#endif  wi.segObj->AddProduct(pTable);  return pTable;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -