📄 space.c
字号:
/* *---------------------------------------------------------------------- * T-Kernel / Standard Extension * * Copyright (C) 2006 by Ken Sakamura. All rights reserved. * T-Kernel / Standard Extension is distributed * under the T-License for T-Kernel / Standard Extension. *---------------------------------------------------------------------- * * Version: 1.00.00 * Released by T-Engine Forum(http://www.t-engine.org) at 2006/8/11. * *---------------------------------------------------------------------- *//* * space.c (memory) * * Segment management (SH7727 Virtual storage version) * Logical space control * * (*) It is necessary to use some functions prior to T-Kernel/OS startup. * As for shared space, it must be able to do so without T-Kernel/OS * system call. * (Exercise care in processing related to Imalloc) */#include "segmgr.h"#include "prcinfo.h"#define TSD_PPT_VAL_0XFFFE01FF 0xfffe01ffU#define TSD_PPT_VAL_0XFFFE0100 0xfffe0100U#define TSD_PPT_MSK_0XFFFE0000 0xfffe0000U#define TSD_UDT_VAL_0XFFFE0000 0xfffe0000U#define TSD_UDT_MSK_0XFFFE0000 0xfffe0000U#define TSD_UT2_VAL_0XFFFE0000 0xfffe0000U#define TSD_UT2_MSK_0XFFFE0000 0xfffe0000U#define TSD_UDT_VAL_0XFFFE00FF 0xfffe00ffU#define TSD_UT2_VAL_0XFFFE00FF 0xfffe00ffU#define TSD_ULS_VAL_M1 (-1)#define TSD_LSC_PPL_3 3#define TSD_MCM_RTN_M1 (-1)#define TSD_PPT_VAL_4 4#define TSD_UDT_VAL_4 4#define TSD_UT2_VAL_4 4Inline VP CurrentUATB( void );LOCAL UW GetLSID_uatb( VP uatb );LOCAL void UpdateTLB2( VP laddr, UW lsid, UW pte );LOCAL PDE* GetPDE( VP laddr, VP uatb, ER *p_err );LOCAL W MonitorCheckMemory( VP laddr );/* * Page directory position (logical address) * A unique space page directory is a table of unique spaces for the maximum number of * processes + 1. At the start is a unique space for "lsid = 0" used in tasks that do * not have unique spaces. */EXPORT PDE *SATB; /* Shared space */EXPORT PDE *UATB; /* Unique space */EXPORT UW MaxLSID; /* Maximum number of unique spaces *//* * Obtain LSID */EXPORT UW GetLSID_pinfo( PINFO *pinfo ){#if USE_PROCESS_MANAGER return (UW)((((UB*)pinfo - (UB*)TopPI) / PINFO_sz) + 1);#endif return 0;}EXPORT UW GetLSID_tid( ID taskid ){ return (UW)(GetTSKSPC_tid(taskid).lsid);}LOCAL UW GetLSID_uatb( VP uatb ){ return (UW)(( (PDE*)uatb - UATB ) / NUM_PDIR_ENTRIES);}/* * Obtain UATB */EXPORT VP GetUATB_lsid( UW lsid ){ if ( lsid >= MaxLSID ) { DEBUG_PRINT(("GetUATB_lsid illegal lsid = %d\n", lsid)); lsid = 0; /* Invalid LSID */ } return UATB + (lsid * (UW)NUM_PDIR_ENTRIES);}EXPORT VP GetUATB_tid( ID taskid ){ return GetTSKSPC_tid(taskid).uatb;}/* * Obtain PINFO */EXPORT PINFO* GetPINFO_lsid( UW lsid ){#if USE_PROCESS_MANAGER if ( lsid <= 0U ) { return NULL; } if ( lsid >= MaxLSID ) { DEBUG_PRINT(("GetPINFO_lsid illegal lsid = %d\n", lsid)); return NULL; /* Invalid LSID */ } return (PINFO*)((UB*)TopPI + ((lsid - 1U) * (UW)PINFO_sz));#endif return NULL;}/* * Obtain T_TSKSPC */EXPORT T_TSKSPC GetTSKSPC_pinfo( PINFO *pinfo ){ T_TSKSPC tskspc; tskspc.lsid = (W)GetLSID_pinfo(pinfo); tskspc.uatb = GetUATB_lsid((UW)tskspc.lsid); return tskspc;}EXPORT T_TSKSPC GetTSKSPC_lsid( UW lsid ){ T_TSKSPC tskspc; tskspc.lsid = (W)(( lsid >= MaxLSID )? 0U: lsid); tskspc.uatb = GetUATB_lsid(lsid); return tskspc;}EXPORT T_TSKSPC GetTSKSPC_tid( ID taskid ){ T_TSKSPC tskspc; ER err; err = tk_get_tsp(taskid, &tskspc); if ( err < E_OK ) { DEBUG_PRINT(("GetTSKSPC_tid err = %d\n", err)); tskspc.lsid = 0; tskspc.uatb = UATB; } return tskspc;}/* * Switch logical spaces */EXPORT ER ChangeLogicalSpace( T_TSKSPC *curspc, T_TSKSPC chgspc ){ ER err; if ( curspc != NULL ) { err = tk_get_tsp(TSK_SELF, curspc); if ( err < E_OK ) { goto err_ret; } } err = tk_set_tsp(TSK_SELF, &chgspc); if ( err < E_OK ) { goto err_ret; } return E_OK;err_ret: DEBUG_PRINT(("ChangeLogicalSpace err = %d\n", err)); return err;}/* * Obtain UATB for current space */Inline VP CurrentUATB( void ){ UW uatb; uatb = *(_UW*)TTB; if ( uatb == 0U ) { uatb = (UW)UATB; } return (VP)uatb;}/* ------------------------------------------------------------------------ *//* * Purge TLB that contains specified logical address. */EXPORT void PurgePageTLB( VP laddr, UW lsid ){ register UW vpn asm("r1"); register UW tg asm("r2"); register UW msk asm("r3"); register UW ent asm("r5"); register UW i asm("r6"); vpn = TLB_VPN(laddr, lsid); msk = ( isLocalSpace(laddr) != 0 )? TSD_PPT_VAL_0XFFFE01FF: TSD_PPT_VAL_0XFFFE0100; tg = (((UW)laddr & TSD_PPT_MSK_0XFFFE0000) | lsid | (UW)TLB_V) & msk; DISEXC("r7") for ( i = 0U; i < TSD_PPT_VAL_4; ++i ) { ent = TLB_ADR(vpn, i); if ( (ent & msk) != tg ) { continue; } /* Cancel TLB entry */ TLB_ADR(vpn, i) = ent & ~(UW)TLB_V; break; } ENAEXC}/* * Update TLB * If there is not an entry whose logical address matches the current TLB, do not update TLB. */EXPORT void UpdateTLB( VP laddr, UW lsid, UW pte ){ register UW vpn asm("r1"); register UW tg asm("r2"); register UW msk asm("r3"); register UW ent asm("r4"); register UW i asm("r5"); register UW tlb asm("r6"); tlb = (pte & (UW)TLB_MASK) | (UW)(isLocalSpace(laddr) != 0 ? TLB_PageSize4K: (UW)TLB_PageSize4K|(UW)TLB_Share); vpn = TLB_VPN(laddr, lsid); msk = ( isLocalSpace(laddr) != 0 )? TSD_UDT_VAL_0XFFFE00FF: TSD_UDT_VAL_0XFFFE0000; tg = (((UW)laddr & TSD_UDT_MSK_0XFFFE0000) | lsid) & msk; DISEXC("r7") for ( i = 0U; i < TSD_UDT_VAL_4; ++i ) { ent = TLB_ADR(vpn, i); if ( (ent & msk) != tg ) { continue; } /* TLB loading */ TLB_DAT(vpn, i) = tlb; break; } ENAEXC}/* * Update TLB * If there is not an entry whose logical address matches the current TLB, set a new one. */LOCAL void UpdateTLB2( VP laddr, UW lsid, UW pte ){ register UW vpn asm("r1"); register UW tg asm("r2"); register UW msk asm("r3"); register UW ent asm("r4"); register UW i asm("r5"); register UW way asm("r8"); register UW tlb asm("r6"); tlb = (pte & (UW)TLB_MASK) | (isLocalSpace(laddr) != 0 ? TLB_PageSize4K: (UW)TLB_PageSize4K|(UW)TLB_Share); vpn = TLB_VPN(laddr, lsid); msk = ( isLocalSpace(laddr) != 0 )? TSD_UT2_VAL_0XFFFE00FF: TSD_UT2_VAL_0XFFFE0000; tg = (((UW)laddr & TSD_UT2_MSK_0XFFFE0000) | lsid) & msk; DISEXC("r7") way = 0; for ( i = 0U; i < TSD_UT2_VAL_4; ++i ) { ent = TLB_ADR(vpn, i); if ( (ent & msk) == tg ) { way = i; break; } if ( (ent & (UW)TLB_V) == 0U ) { way = i; } } /* TLB loading */ TLB_ADR(vpn, way) = tg; TLB_DAT(vpn, way) = tlb; ENAEXC}/* ------------------------------------------------------------------------ *//* * Obtain page directory entry */LOCAL PDE* GetPDE( VP laddr, VP uatb, ER *p_err ){ PDE *pde; if ( isLocalSpace(laddr) != 0 ) { /* Unique space */ if ( uatb == 0 ) { /* No unique space */ *p_err = E_PAR; goto err_ret; } pde = (PDE*)uatb + PDIR_NUM(laddr); } else { /* Shared space */ pde = SATB + PDIR_NUM(laddr); } return pde;err_ret: DEBUG_PRINT(("GetPDE err = %d\n", *p_err)); return NULL;}/* ------------------------------------------------------------------------ *//* * Page table access function *//* * Initialize page table access handle * "lsid = 0" indicates the current space. */EXPORT void InitPTH( PTH *pth, VP laddr, UW lsid ){ if ( lsid == 0U ) { /* When "lsid is 0", the function is also called from the page fault handler. * Therefore, TSK_SELF cannot be used to obtain the current space. * Obtain uatb for the current space from TTB register. */ pth->uatb = CurrentUATB(); pth->lsid = GetLSID_uatb(pth->uatb); } else { pth->uatb = GetUATB_lsid(lsid); pth->lsid = lsid; } pth->laddr = PageAlignL(laddr); pth->pde = NULL;}/* * Termination processing of page table access handle * When set at "purge = TRUE", purge all TLB. * When set at "purge = FALSE", do not purge TLB. */EXPORT void EndPTH( PTH *pth, BOOL purge ){ if ( purge != 0 ) { PurgeAllTLB(); }}/* * Move to the next page table entry. * Immediately after InitPTH(), move to the first page specified by InitPTH(). * Cannot move across a boundary between shared and unique spaces (operation is not guaranteed). */EXPORT ER NextPTE( PTH *pth ){ PDE *pde = pth->pde; ER err; if ( pde != NULL ) { /* Second and subsequent times: move to the next page */ pth->laddr = NextPage(pth->laddr); if ( ++(pth->i) >= (W)N_PTE ) { pde = NULL; } } if ( pde == NULL ) { /* Obtain page directory entry */ pde = GetPDE(pth->laddr, pth->uatb, &err); if ( pde == NULL ) { goto err_ret; } /* If there is no page table, return error. */ if ( pde->c.p == 0 ) { err = E_MACV; goto err_ret; } /* Position of page table entry */ pth->pde = pde; pth->pte = PFAtoLADR(pde->c.pfa); pth->i = (W)PTBL_NUM(pth->laddr); } return E_OK;err_ret: DEBUG_PRINT(("NextPTE err = %d\n", err)); return err;}/* * Fetch from the current page table */EXPORT UW GetPTE( PTH *pth ){ return (UW)pth->pte[pth->i].w;}/* * Set to the current page table * When set at "purge = TRUE", purge TLB of intended pages. * When set at "purge = FALSE", do not purge TLB. */EXPORT void SetPTE( PTH *pth, UW pte, BOOL purge ){ pth->pte[pth->i].w = pte; if ( purge != 0 ) { PurgePageTLB(pth->laddr, pth->lsid); }}/* * Change the current page table. * pte = pte & pte_m | pte_v * * When set at "purge = TRUE", purge TLB of intended pages. * When set at "purge = FALSE", do not purge TLB. * * Return a page table setting value before change. */EXPORT UW ChgPTE( PTH *pth, UW pte_v, UW pte_m, BOOL purge ){ PTE old_pte, new_pte; UW imask; DI(imask); old_pte.w = pth->pte[pth->i].w; new_pte.w = (old_pte.w & pte_m) | pte_v; pth->pte[pth->i].w = new_pte.w; EI(imask); if ( purge != 0 ) { PurgePageTLB(pth->laddr, pth->lsid); } return old_pte.w;}/* * Load page table into TLB * The current logical space must match pth->lsid. * Called in interrupt-disabled state and used for TLB exception handler only. */EXPORT void LoadTLB( PTH *pth, UW mmucr ){ (void)_LoadTLB(pth->laddr, pth->lsid, pth->pte[pth->i].w, mmucr);}/* ------------------------------------------------------------------------ *//* * Refer to page table */EXPORT UW GET_PTE( VP laddr, UW lsid ){ PDE *pde; PTE *pte; ER err; /* Obtain page directory */ pde = GetPDE(laddr, GetUATB_lsid(lsid), &err); if ( pde == NULL ) { goto err_ret; } /* If there is no page table, return error. */ if ( pde->c.p == 0 ) { err = E_MACV; goto err_ret; } pte = PFAtoLADR(pde->c.pfa); return (UW)pte[PTBL_NUM(laddr)].w;err_ret: DEBUG_PRINT(("GET_PTE err = %d\n", err)); return PTE_NONE;}/* * Change page table * pte = pte & pte_m | pte_v * * When set at "purge = TRUE", purge TLB of intended pages. * When set at "purge = FALSE", do not purge TLB. * * Return a page table setting value before change. */EXPORT UW CHG_PTE( VP laddr, UW lsid, UW pte_v, UW pte_m, BOOL purge ){ PDE *pde; PTE *pte; PTE old_pte, new_pte; UW imask; ER err; /* Obtain page directory */ pde = GetPDE(laddr, GetUATB_lsid(lsid), &err); if ( pde == NULL ) { goto err_ret; } /* If there is no page table, return error. */ if ( pde->c.p == 0 ) { err = E_MACV; goto err_ret; } pte = PFAtoLADR(pde->c.pfa); pte += PTBL_NUM(laddr); DI(imask); old_pte.w = pte->w; new_pte.w = (old_pte.w & pte_m) | pte_v; pte->w = new_pte.w; EI(imask); if ( purge != 0 ) { PurgePageTLB(laddr, lsid); } return old_pte.w;err_ret: DEBUG_PRINT(("CHG_PTE laddr = %#x lsid = %d err = %d\n", laddr, lsid, err)); return PTE_NONE;}/* ------------------------------------------------------------------------ *//* * Generate logical space * In lsid logical space, allocate virtual memory with set_pte attribute to npage of * area (starting from a page that includes a logical address laddr). If the logical * set_pte is a value (PTE) specified for a page table. */EXPORT ER __MakeSpace( VP laddr, W npage, UW lsid, UW set_pte ){ VP la = laddr; W np = npage; PTE set; VP uatb; PDE *pde; PTE *pte; PFE *pfe; W i; ER err; /* For a shared space, specify "lsid = 0". */ if ( !isLocalSpace(laddr) ) { lsid = 0; } set.w = set_pte; uatb = GetUATB_lsid(lsid); while ( np > 0 ) { /* Obtain page directory entry */ pde = GetPDE(la, uatb, &err); if ( pde == NULL ) { goto err_ret; } /* If there is no page table, obtain a new one. */ if ( pde->c.p == 0 ) { /* Obtain page table */ pfe = GetPFM(PFS_lock, FALSE); if ( pfe == NULL ) { err = E_NOMEM; goto err_ret; } pte = PFEtoLADR(pfe); /* Initialize page table */ memset_w(pte, PTE_NONE, (size_t)N_PTE); /* Set page directory */ pde->w = (UW)PDE_NORM | (UW)toPhysicalAddress(pte); } else { /* Obtain page table address and page number */ pte = PFAtoLADR(pde->c.pfa); pfe = LADRtoPFE(pte); } /* Set page table */ for ( i = (W)PTBL_NUM(la); i < (W)N_PTE; ++i ) { if ( pte[i].w != (UW)PTE_NONE ) { /* This page is already used. */ err = E_MACV; goto err_ret; } pte[i] = set; PurgePageTLB(la, lsid); pfe->dbn_no++; /* Number of valid pages */ la = NextPage(la); /* Next page */ if ( --np <= 0 ) { break; } } } return E_OK;err_ret: (void)__UnmakeSpace(laddr, npage - np, lsid); DEBUG_PRINT(("__MakeSpace err = %d\n", err)); return err;}EXPORT ER _MakeSpace( VP laddr, W npage, UW lsid, UW set_pte ){ ER err; if ( (set_pte & (UW)(PT_Present|PT_Valid)) != 0U ) { err = E_PAR; goto err_ret; } LockSEG(); err = __MakeSpace(laddr, npage, lsid, set_pte); UnlockSEG(); return err;err_ret: DEBUG_PRINT(("_MakeSpace err = %d\n", err)); return err;}/* * Delete logical space * In lsid logical space, delete virtual memory allocated to npage of area * (starting from a page that includes a logical address laddr). If the logical * space does not have a process unique space, specify "lsid = 0". * Locked pages are unlocked. */EXPORT ER __UnmakeSpace( VP laddr, W npage, UW lsid ){ VP la = laddr; W np = npage; VP uatb; PDE *pde; PTE *pte; PFE *pfe; PINFO *pinfo; W i; ER err, error = E_OK; /* For a shared space, specify "lsid = 0". */ if ( !isLocalSpace(laddr) ) { lsid = 0; } /* When performed on a unique space, obtain PINFO on the process. */ pinfo = GetPINFO_lsid(lsid); 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 and page number */ pte = PFAtoLADR(pde->c.pfa); pfe = LADRtoPFE(pte); for ( i = (W)PTBL_NUM(la); i < (W)N_PTE; ++i ) { PTE old; old = pte[i]; if ( old.w != (UW)PTE_NONE ) { /* Set invalid PTE */ pte[i].w = (UW)PTE_NONE; PurgePageTLB(la, lsid); /* Discontinue relations with PTE. */ err = UnlinkPage(old, pinfo); if ( err < E_OK ) { error = err; } pfe->dbn_no--; /* Number of valid pages */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -