📄 kern_segment.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 <eros/SysTraceKey.h>#include <kerninc/Process.hxx>#include <kerninc/SegWalk.hxx>#include <kerninc/SysTimer.hxx>#include <kerninc/Depend.hxx>#include <kerninc/Thread.hxx>#include <kerninc/Invocation.hxx>/* Extracted as macro for clarity of code below, which is already too * complicated. */#define ADD_DEPEND(pKey) \ assert ((wi.frameBits != EROS_PAGE_ADDR_BITS) || pPTE0); \ if (pPTE0) \ Depend_AddKey(pKey, pPTE0, canMerge); \ if (pPTE1) \ Depend_AddKey(pKey, pPTE1, canMerge);/* proc_WalkSeg() is a performance-critical path. The segment walk logic is complex, and it occurs in the middle of page faulting activity, which for obvious reasons is performance-critical. The walker is also entered in stages to allow successive traversals. This is mainly to keep the code machine-independent; a machine-dependent specialization of this routine could avoid a couple of procedure calls. The /pPTE0/ and /pPTE1/ arguments and the /canMerge/ argument should unquestionably be merged into the SegWalkInfo structure. The depth of the walk is bounded by MAX_SEG_DEPTH to detect possible loops in the segment tree. Because the routine is multiply entered the actual depth limit can be two or three times the nominal limit. The architecture guarantees a minimum traversal depth, but does not promise any particular maximum. The traversal process must maintain the following variables: /pSegKey/ pointer to the node slot containing the key that names the segment we are now considering. /segBlss/ size of the segment represented by pSegKey. /pKeptSeg/ pointer to the NODE that was the last red segment we went through. Arguably, we should track two of these: one for keepers and one for background segment logic. At the present time we do not do so. /traverseCount/ the number of traversals we have done on this path. At the moment this is not properly tracked if we use the short-circuited fast walk. /canWrite/ whether the path traversed already conveyed write permission. /canCall/ whether the path traversed already allowed keeper invocation. /faultCode/ the fault code, if any, associated with this traversal. In addition, the following members of the WalkInfo structure are actually arguments passed from above. They are stored in the WalkInfo structure because they do not change across the several calls: /writeAccess/ whether the translation is for writing /prompt/ whether we are willing to take a keeper fault to get a translation. I have temporarily removed the support for capability pages to get one thing right at a time.*/#define BLSS_SHIFT(lss, frameBits) \ (((lss) - EROS_PAGE_BLSS - 1) * EROS_NODE_LGSIZE + frameBits)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;}#ifdef OPTION_DDBextern bool ddb_segwalk_debug;#endifvoidsegwalk_init(SegWalk &wi, Key *pSegKey){ wi.pSegKey = pSegKey; wi.segBlss = EROS_ADDRESS_BLSS + 1; /* until proven otherwise */ wi.offset = wi.vaddr; wi.redSeg = 0; wi.redSegOffset = 0; wi.redSpanBlss = 0;#ifdef KT_Wrapper wi.segObjIsWrapper = false;#else wi.segObjIsRed = false;#endif wi.canCall = true; /* until proven otherwise */ wi.canWrite = true; /* until proven otherwise */ wi.canFullFetch = true; /* until proven otherwise */}boolproc_WalkSeg(Process * p, SegWalk& wi, uint32_t stopBlss, PTE* pPTE0, PTE* pPTE1, bool canMerge){#ifdef OPTION_DDB# ifdef KT_Wrapper#define WALK_DBG_MSG(prefix) \ if (ddb_segwalk_debug) dprintf(true, prefix \ " proc_WalkSeg: wi.producer 0x%x, wi.segBlss %d wi.isWrap %d\n" \ "wi.vaddr 0x%x wi.offset 0x%X flt %d wa %d segKey 0x%x\n" \ "canCall %d canWrite %d stopBlss %d\n" \ "redSeg 0x%x redSpanBlss %d redOffset 0x%X\n", \ wi.segObj, wi.segBlss, wi.segObjIsWrapper, \ wi.vaddr, wi.offset, wi.faultCode, wi.writeAccess, wi.pSegKey, \ wi.canCall, wi.canWrite, stopBlss, \ wi.redSeg, wi.redSpanBlss, wi.redSegOffset);# else#define WALK_DBG_MSG(prefix) \ if (ddb_segwalk_debug) dprintf(true, prefix \ " proc_WalkSeg: wi.producer 0x%x, wi.segBlss %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 stopBlss %d\n" \ "redSeg 0x%x redSpanBlss %d redOffset 0x%X\n", \ wi.segObj, wi.segBlss, wi.segObjIsRed, \ wi.vaddr, wi.offset, wi.faultCode, wi.writeAccess, wi.pSegKey, \ wi.canCall, wi.canWrite, stopBlss, \ wi.redSeg, wi.redSpanBlss, wi.redSegOffset);# endif#else#define WALK_DBG_MSG(prefix)#endif const uint32_t MAX_SEG_DEPTH = 20; KernStats.nWalkSeg++; Key *pFormatKey = 0; if (wi.segObj == 0) goto process_key; for(;;) { /* If it's the leaf object and we wanted a node, it better be seg * key type. Conversely, if we *didn't* want a node, it better NOT * be seg key type. All non-page, non-node cases should already * have been filtered out in the key processing loop below as * malformed segments. */ if (wi.segBlss == EROS_PAGE_BLSS && wi.wantLeafNode != wi.pSegKey->IsSegKeyType()) goto seg_malformed; if (wi.segBlss <= stopBlss) { WALK_DBG_MSG("ret") return true; } KernStats.nWalkLoop++; /********************************* * * BEGIN Traversal step logic: * *********************************/ { WALK_DBG_MSG("wlk")#ifndef NDEBUG if (wi.segObj->obType == ObType::NtUnprepared) fatal("Some node unprepare did not work at kern_Segment.cxx:%d\n", __LINE__);#endif Node* segNode = (Node *) wi.segObj; assertex ( segNode, segNode->obType == ObType::NtSegment ); uint32_t initialSlots = EROS_NODE_SLOT_MASK;#ifdef KT_Wrapper if (wi.segObjIsWrapper) { assertex (&wi, segNode->obType == ObType::NtSegment); pFormatKey = &segNode->slot[WrapperFormat]; ADD_DEPEND(pFormatKey); initialSlots = 0; }#else if (wi.segObjIsRed) {#ifdef KT_Wrapper assert (wi.segObjIsWrapper == false);#endif pFormatKey = &segNode->slot[RedSegFormat]; /* We know that the format key is valid. It was checked in * the key-related checking above, either during the current * pass or when building information about the parent page * table. If the format key has since been modified, then * the parent page table entry will have been modified, and * we will not have gotten here without rechecking it. */ ADD_DEPEND(pFormatKey); initialSlots = REDSEG_GET_INITIAL_SLOTS(pFormatKey->nk); }#endif wi.traverseCount++; uint32_t shiftAmt = BLSS_SHIFT(wi.segBlss, wi.frameBits); uint32_t ndx = wi.offset >> shiftAmt; if (ndx > initialSlots) goto invalid_addr; wi.offset &= BLSS_MASK64(wi.segBlss - 1, wi.frameBits); wi.pSegKey = &segNode->slot[ndx]; } /****************************** * * END Traversal step logic: * ******************************/ if (wi.traverseCount >= MAX_SEG_DEPTH) goto bad_seg_depth; process_key: /******************************** * * BEGIN key processing logic: * ********************************/ {#ifdef WALK_DBG if (wi.segObj == 0) WALK_DBG_MSG("key")#endif wi.pSegKey->Prepare(); uint8_t keyType = wi.pSegKey->GetType(); /* Process everything but the per-object processing first: */ switch(keyType) { case KT_Void: goto invalid_addr; case KT_TimePage: { wi.canWrite = false; wi.canCall = false; wi.segBlss = EROS_PAGE_BLSS; wi.segObj = SysTimer::TimePageHdr;#ifdef KT_Wrapper wi.segObjIsWrapper = false;#else wi.segObjIsRed = false;#endif if (wi.writeAccess) goto access_fault; ADD_DEPEND(wi.pSegKey);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -