📄 space.c
字号:
la = NextPage(la); /* Next page */ if ( --np <= 0 ) { break; } } if ( pfe->dbn_no == 0 ) { /* When a page table becomes empty, delete the page table itself. */ pde->w = PDE_NONE; /* Release page frames for page tables. */ DiscardPageFrame(pfe); } } if ( error < E_OK ) { goto err_ret; } return E_OK;err_ret: DEBUG_PRINT(("__UnmakeSpace err = %d\n", error)); return error;}EXPORT ER _UnmakeSpace( VP laddr, W npage, UW lsid ){ ER err; LockSEG(); err = __UnmakeSpace(laddr, npage, lsid); UnlockSEG(); return err;}/* * Change logical space attribute * In lsid logical space, change attributes of virtual memory allocated to npage of area * (starting from a page that includes a logical address laddr) into chg_pte. * Change attributes related to specification of access mode and copy-on-write only. * The other attributes of page table are not changed. * If the logical space does not have a process unique space, specify "lsid = 0". */EXPORT ER __ChangeSpace( VP laddr, W npage, UW lsid, UW chg_pte ){const UW CHG_MSK = (PT_Writable|PT_User|PT_CopyOnWrite); VP la = laddr; W np = npage; VP uatb; PDE *pde; PTE *pte; W i; ER err, error = E_OK; /* For a shared space, specify "lsid = 0". */ if ( !isLocalSpace(laddr) ) { lsid = 0; } chg_pte &= CHG_MSK; uatb = GetUATB_lsid(lsid); while ( np > 0 ) { /* Obtain page directory entry */ pde = GetPDE(la, uatb, &err); if ( pde == NULL ) { error = err; } if ( (pde == NULL) || (pde->c.p == 0) ) { /* No page table */ i = (W)(N_PTE - PTBL_NUM(la)); la = (VP)((VB*)la + (PAGESIZE * i)); np -= i; continue; } /* Obtain page table address. */ pte = PFAtoLADR(pde->c.pfa); for ( i = (W)PTBL_NUM(la); i < (W)N_PTE; ++i ) { /* Change attribute of page table. */ pte[i].w = (pte[i].w & ~CHG_MSK) | chg_pte; PurgePageTLB(la, lsid); la = NextPage(la); /* Next page */ if ( --np <= 0 ) { break; } } } if ( error < E_OK ) { goto err_ret; } return E_OK;err_ret: DEBUG_PRINT(("__ChangeSpace err = %d\n", error)); return error;}EXPORT ER _ChangeSpace( VP laddr, W npage, UW lsid, UW chg_pte ){ ER err; LockSEG(); err = __ChangeSpace(laddr, npage, lsid, chg_pte); UnlockSEG(); return err;}/* * Lock logical space * Allocate real memory to len bytes of area (starting from a logical address laddr) * to make the area resident (lock the area). */EXPORT ER __LockSpace( VP laddr, W len ){ T_TSKSPC tskspc; VB *la, *end; PDE *pde; PTE *pte; PFE *pfe; W i, limit_new, limit_exs; BOOL newpg; ER err; if ( len <= 0 ) { err = E_PAR; goto err_ret1; } /* Non-logical spaces are always made resident. */ if ( !isLogicalSpace(laddr) ) { return E_OK; } if ( isLocalSpace(laddr) != 0 ) { tskspc = GetTSKSPC_tid(TSK_SELF); } else { tskspc = GetTSKSPC_lsid(0); } end = (VB*)laddr + len; la = PageAlignL(laddr); /* getting the number of pages to enable to resident * limit_new : the number of new pages to enable to resident * limit_exs : the number of existing pages to enable to resident */ limit_new = LockablePages(&limit_exs); while ( la < end ) { /* Obtain page directory entry */ pde = GetPDE(la, tskspc.uatb, &err); if ( pde == NULL ) { goto err_ret2; } if ( pde->c.p == 0 ) { goto err_adr; /* No page table */ } /* Obtain page table address. */ pte = PFAtoLADR(pde->c.pfa); for ( i = (W)PTBL_NUM(la); i < N_PTE; ++i ) { if ( pte[i].w == (UW)PTE_NONE ) { goto err_adr; /* Invalid PTE */ } newpg = ( (pte[i].c.p == 0) && (pte[i].c.va == 0) ); if ( pte[i].c.p == 0 ) { /* Page in. */ err = PageIn(la, tskspc.lsid); if ( err < E_OK ) { goto err_ret2; } } if ( pte[i].c.cow != 0 ) { /* Perform copy-on-write. */ err = CopyOnWrite(la, tskspc.lsid); if ( err < E_OK ) { goto err_ret2; } } pfe = PFAtoPFE(pte[i].c.pfa); /* Count the number of locking. */ err = LockCount(pfe, la, tskspc.lsid, (+1)); if ( err < E_OK ) { goto err_ret2; } if ( err == 1 ) { /* the case of first residentation */ if ( (!newpg) && (limit_exs > 0) ) { --limit_exs; } else if ( --limit_new < 0 ) { LockCount(pfe, la, tskspc.lsid, TSD_ULS_VAL_M1); err = E_NOMEM; goto err_ret2; } } pte[i].c.va = 0; /* Indicate that page frames are locked. */ /* Set frames locks at locked state. */ LockPageFrame(pfe); la += PAGESIZE; if ( la >= end ) { break; } } } return E_OK;err_adr: err = E_MACV;err_ret2: (void)__UnlockSpace(laddr, la - (VB*)laddr);err_ret1: DEBUG_PRINT(("__LockSpace err = %d\n", err)); return err;}EXPORT ER _LockSpace( VP laddr, W len ){ ER err; LockSEG(); err = __LockSpace(laddr, len); UnlockSEG(); return err;}/* * Unlock logcal space * Make len bytes of area (starting from a logical address laddr) non-resident (unlock the area). */EXPORT ER __UnlockSpace( VP laddr, W len ){ T_TSKSPC tskspc; VB *la, *end; PDE *pde; PTE *pte; PFE *pfe; W i; ER err, error = E_OK; if ( len <= 0 ) { error = E_PAR; goto err_ret; } /* Non-logical spaces are always made resident. */ if ( !isLogicalSpace(laddr) ) { return E_OK; } if ( isLocalSpace(laddr) != 0 ) { tskspc = GetTSKSPC_tid(TSK_SELF); } else { tskspc = GetTSKSPC_lsid(0); } end = (VB*)laddr + len; la = PageAlignL(laddr); while ( la < end ) { /* Obtain page directory entry */ pde = GetPDE(la, tskspc.uatb, &err); if ( (pde == NULL) || (pde->c.p == 0) ) { /* No page table */ error = ( pde == NULL )? err: E_MACV; i = (W)(N_PTE - PTBL_NUM(la)); la += PAGESIZE * i; continue; } /* Obtain page table address. */ pte = PFAtoLADR(pde->c.pfa); for ( i = (W)PTBL_NUM(la); i < (W)N_PTE; ++i ) { if ( (pte[i].c.p != 0) && (pte[i].c.va == 0) ) { pfe = PFAtoPFE(pte[i].c.pfa); /* Count the number of locking. */ err = LockCount(pfe, la, (UW)tskspc.lsid, TSD_ULS_VAL_M1); if ( err < E_OK ) { error = err; } /* When the number of locking becomes 0, unlock page frames. */ if ( err == 0 ) { pte[i].c.va = 1; /* Indicate that page frames are unlocked. */ /* Reset the locked state of page frames. */ UnlockPageFrame(pfe); /* Enable the cache. */ pte[i].w |= (UW)PT_Cachable; PurgePageTLB(la, (UW)tskspc.lsid); } } else { error = E_MACV; } la += PAGESIZE; if ( la >= end ) { break; } } }err_ret:#ifdef DEBUG if ( error < E_OK ) { DEBUG_PRINT(("__UnlockSpace err = %d\n", error)); }#endif return error;}EXPORT ER _UnlockSpace( VP laddr, W len ){ ER err; LockSEG(); err = __UnlockSpace(laddr, len); UnlockSEG(); return err;}/* * Obtain physical address * In a logical space of the task, determine the physical address of logical address * laddr and return it as *paddr. As a return value, return the number of bytes of * consecutive physical memory in len bytes of area starting from laddr. * In the returned bytes of area starting from laddr, the cache is disabled. * The disabled cache is reset by UnlockSpace(). * It is necessary to lock it in advance by LockSpace(). * * (*) Do not execute LockSEG(). * It causes deadlock when called from the disk driver. * (*) Note that page fault may occur when access is made to *paddr. */EXPORT W _CnvPhysicalAddr( VP laddr, W len, VP *paddr ){ VP la; VP uatb; UW lsid; PDE *pde; PTE *pte; W i; UW next_pfa = 0; W plen; UW imask; ER err; /* Non-logical spaces are handled in the same manner as physical addresses. */ if ( !isLogicalSpace(laddr) ) { /* For the time being, do not include P1 area (except for ROM area) where the cache cannot be controlled on a page basis. */ if ( isP1(laddr) && !isROM(laddr) ) { return E_PAR; } *paddr = (VP)toPhysicalAddress(laddr); return len; } /* Obtain uatb of the current space from TTB register. */ uatb = CurrentUATB(); lsid = GetLSID_uatb(uatb); la = laddr; plen = 0; do { /* Obtain page directory entry */ pde = GetPDE(la, uatb, &err); if ( (pde == NULL) || (pde->c.p == 0) ) { return E_MACV; /* No page table */ } /* Obtain page table address. */ pte = PFAtoLADR(pde->c.pfa); for ( i = (W)PTBL_NUM(la); i < (W)N_PTE; ++i ) { if ( pte[i].c.p == 0 ) { break; /* Page is absent. */ } if ( plen == 0 ) { /* First page */ *paddr = (VB*)PFAtoPADR(pte[i].c.pfa) + POFS_NUM(la); plen = PAGESIZE - (W)POFS_NUM(la); next_pfa = pte[i].c.pfa + 1U; } else { if ( pte[i].c.pfa != next_pfa ) { break; /* Non-consecutive */ } plen += PAGESIZE; next_pfa++; } DI(imask); /* In DMA transfer, an update flag is not set for the page table. * Set an update flag based on the assumption that physical * address are used for DMA transfer. * However, this is not the case if writing is disabled. */ if ( pte[i].c.w != 0 ) { pte[i].c.d = 1; } /* Disable the cache. */ ExtFlushCache(la, lsid, pte[i].w); pte[i].w &= ~(UW)PT_Cachable; PurgePageTLB(la, lsid); EI(imask); la = (VB*)laddr + plen; if ( plen >= len ) { break; } } } while ( i == (W)N_PTE ); if ( plen > len ) { plen = len; } return plen;}/* * Check access attribute of logical space * In a logical space of the task, check if it is possible to make access to len bytes * of area (starting from a logical address laddr) from env environment in mode. * If it is possible, return E_OK; if not possible, return E_MACV. * * (*) Do not execute LockSEG(). * It causes deadlock when called from the disk driver. */EXPORT ER _ChkSpace( VP laddr, W len, UW mode, UW env ){ VP la; VP uatb; PDE *pde; PTE *pte; UW chk_u, chk_w; UW imask; W i; W plen = 0; ER err; /* Obtain uatb of the current space from TTB register. */ uatb = CurrentUATB(); /* Attributes necessary for access */ chk_u = ( (env & (UW)MDR_PPL(TSD_LSC_PPL_3)) == (UW)MDR_PPL(TSD_LSC_PPL_3) )? 1U: 0U; chk_w = ( (mode & MA_WRITE) != 0U )? 1U: 0U; /* Check non-logical spaces in a fixed manner. */ if ( !isLogicalSpace(laddr) ) { if ( (chk_u > 0U) && !isP0(laddr) ) { goto ret; } return E_OK; } do { la = (VB*)laddr + plen; /* Disable interruption to prevent deletion of the page table while it is checked. */ DI(imask); /* Obtain page directory entry */ pde = GetPDE(la, uatb, &err); if ( (pde == NULL) || (pde->c.p == 0) ) { /* No page table */ EI(imask); break; } /* Obtain page table address. */ pte = PFAtoLADR(pde->c.pfa); for ( i = (W)PTBL_NUM(la); i < (W)N_PTE; ++i ) { if ( pte[i].w == (UW)PTE_NONE ) { break; /* Invalid PTE */ } /* Check access right. Enable writing for CopyOnWrite. */ if ( pte[i].c.u < chk_u ) { break; } if ( (pte[i].c.w < chk_w) && (pte[i].c.cow == 0) ) { break; } if ( plen == 0 ) { /* First page */ plen = PAGESIZE - (W)POFS_NUM(la); } else { plen += PAGESIZE; } if ( plen >= len ) { break; } } EI(imask); } while ( i == (W)N_PTE );ret:#ifdef DEBUG if ( plen < len ) { DEBUG_PRINT(("_ChkSpace(%#x, %d, %d, %#x) = E_MACV\n", laddr, len, mode, env)); }#endif return ( plen >= len )? E_OK: E_MACV;}/* * Check access attribute of logical space(TC character string) * In a logical space of the task, check if it is possible to make access to an area * (starting from a logical address str to TNULL or to the max-th character) from * env environment in mode. When set at "max = 0", ignore the number (max) of characters. * If it is possible, return the number of characters or the value of max (when "max > 0" * and TNULL is not found before the max-th character); if not possible, return E_MACV. * * (*) It is assumed that str is an even-number address. * (*) Do not execute LockSEG(). * It causes deadlock when called from the disk driver. */EXPORT W _ChkSpaceTstr( TC *str, W max, UW mode, UW env ){ TC *tp = str; VP uatb; PDE *pde; PTE *pte; UW chk_u, chk_w; UW imask; W n;#ifdef DEBUG W _max = max;#endif ER err; /* Obtain uatb of the current space from TTB register. */ uatb = CurrentUATB(); /* Attributes necessary for access */ chk_u = ( (env & (UW)MDR_PPL(TSD_LSC_PPL_3)) == (UW)MDR_PPL(TSD_LSC_PPL_3) )? 1U: 0U; chk_w = ( (mode & MA_WRITE) != 0U )? 1U: 0U; /* Check non-logical spaces in a fixed manner. */ if ( !isLogicalSpace(str) ) { if ( (chk_u > 0U) && !isP0(str) ) { goto err_ret; } while ( *tp != TNULL ) { tp++; if ( --max == 0 ) { break; } } return tp - str; } for ( ;; ) { /* Disable interruption to prevent deletion of the page table while it is checked. */ DI(imask); /* Obtain page directory entry */ pde = GetPDE(tp, uatb, &err); if ( (pde == NULL) || (pde->c.p == 0) ) { break; /* No page table */ } /* Obtain page table address. */ pte = PFAtoLADR(pde->c.pfa); /* Page table entry */ pte += PTBL_NUM(tp); if ( pte->w == (UW)PTE_NONE ) { break; /* Invalid PTE */ } /* Check access right. Enable writing for CopyOnWrite. */ if ( pte->c.u < chk_u ) { break; } if ( (pte->c.w < chk_w) && (pte->c.cow == 0) ) { break; } EI(imask); /* Number of characters within this page */ n = (PAGESIZE - (W)POFS_NUM(tp)) / (W)sizeof(TC); /* TNULL checking (Page-in may occur.) */ while ( --n >= 0 ) { if ( *tp == TNULL ) { return tp - str; } tp++; if ( --max == 0 ) { return tp - str; } } } EI(imask);err_ret: DEBUG_PRINT(("_ChkSpaceTstr(%#x, %d, %d, %#x) = E_MACV\n", str, _max, mode, env)); return E_MACV;}/* * Check access attribute of logical space(B character string) * In a logical space of the task, check if it is possible to make access to an area * (starting from a logical address str to '\0' or to the max-th byte) from * env environment in mode. When set at "max = 0", ignore the number (max) of bytes. * If it is possible, return the number of bytes or the value of max (when "max > 0" * and '\0' is not found before the max-th byte); if not possible, return E_MACV. * * (*) Do not execute LockSEG(). * It causes deadlock when called from the disk driver. */EXPORT W _ChkSpaceBstr( UB *str, W max, UW mode, UW env ){ UB *p = str; VP uatb; PDE *pde; PTE *pte; UW chk_u, chk_w; UW imask; W n;#ifdef DEBUG W _max = max;#endif ER err; /* Obtain uatb of the current space from TTB register. */ uatb = CurrentUATB(); /* Attributes necessary for access */ chk_u = ( (env & (UW)MDR_PPL(TSD_LSC_PPL_3)) == (UW)MDR_PPL(TSD_LSC_PPL_3) )? 1: 0; chk_w = ( (mode & MA_WRITE) != 0U )? 1: 0; /* Check non-logical spaces in a fixed manner. */ if ( !isLogicalSpace(str) ) { if ( (chk_u > 0U) && !isP0(str) ) { goto err_ret; } while ( *p != '\0' ) { p++; if ( --max == 0 ) { break; } } return p - str; } for ( ;; ) { /* Disable interruption to prevent deletion of the page table while it is checked. */ DI(imask); /* Obtain page directory entry */ pde = GetPDE(p, uatb, &err); if ( (pde == NULL) || (pde->c.p == 0) ) { break; /* No page table */ } /* Obtain page table address. */ pte = PFAtoLADR(pde->c.pfa); /* Page table entry */ pte += PTBL_NUM(p); if ( pte->w == (UW)PTE_NONE ) { break; /* Invalid PTE */ } /* Check access right. Enable writing for CopyOnWrite. */ if ( pte->c.u < chk_u ) { break; } if ( (pte->c.w < chk_w) && (pte->c.cow == 0) ) { break; } EI(imask); /* Number of characters within this page */ n = PAGESIZE - (W)POFS_NUM(p); /* '\0' checking (Page-in may occur.) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -