📄 memmgr.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. * *---------------------------------------------------------------------- *//* * memmgr.c (memory) * * Memory management (Virtual storage version) */#include "segmgr.h"#include <extension/sys/tkse_ssid.h>#include <extension/sys/svc/ifmemory.h>/* * Minimum size of memory to be reserved for system (number of pages) * In the case of local memory, if the remaining memory is smaller than SysReserve, * return E_NOMEM. In other cases, continue to reserve memory until the remaining size * becomes 0. */LOCAL W SysReserve;/* * Exclusive control lock for memory management * At OS startup, Lock() is called before CreateLock(). * In this case, set initial values to prevent wait sate. * * Memory management may be called during LockPinfo. * Do not execute LockPinfo during LockMEM. */LOCAL FastLock MemLock = { -1, -1 };#define LockMEM() Lock(&MemLock)#define UnlockMEM() Unlock(&MemLock)/* * Page */typedef struct { VB mem[PAGESIZE];} PAGE;typedef UW PN; /* Page numbers (1-) *//* * Page management queue */typedef struct { unsigned int cont:1; /* Two or more consecutive pages: 1 */ unsigned int use:1; /* When the current page is in use: 1 */ unsigned int wall:2; /* Wall flag */ unsigned int next:28; unsigned int atr:4; /* Memory block attribute */ unsigned int prev:28;} PAGEQUE;#define USE 1 /* In use */#define FREE 0 /* Free */#define CONT 1 /* Consecutive (two or more blocks in a row) */#define ONE 0 /* Single */#define TWALL 1U /* Wall on the side of lower address */#define EWALL 2U /* Wall on the side of upper address */static const PAGEQUE _clrPageQue = { ONE, FREE, 0, 0, 0, 0 };#define clrPageQue(q) ( (q) = (_clrPageQue) )#define NumOfPages(q) ( ( (q)->cont != 0 )? ((q)+1)->next: 1 ) /* Number of consecutive pages *//* * Memory block attribute */#define MB_LOCAL 0x1U /* Local memory */#define MB_DELETE 0x2U /* Delete at process termination */#define MB_SHARE 0x4U /* Shared memory *//* * Page management table * Start of pageque is used for freeque. * freeque is sorted in increasing order of number of consecutive free pages. */typedef struct { UW maxpage; /* Total number of pages */ UW freepage; /* Number of free pages */ PAGE *toppage; /* Address of first page */ PAGEQUE pageque[1]; /* Array of management information for all pages */} PAGETBL;#define freeque pageque[0] /* Queue of free pages */#define _PageAdr(pt, pn) ( (VP)((pt)->toppage + ((pn) - 1)) )#define _PageNo(pt, adr) ( (PN)(((PAGE*)(adr) - (pt)->toppage) + 1) )LOCAL PAGETBL *SystemPageTable; /* System memory space management table */Inline VP PageAdr( PAGETBL *pt, PN pn );Inline PN PageNo( PAGETBL *pt, VP adr );Inline void setPageQue( PAGEQUE *q, BOOL u, BOOL c, PN n, PN p, UW a );Inline void initPageQue( PAGETBL *pt, PN pn );Inline void insertPageQue( PAGETBL *pt, PN que, PN ent );Inline void removePageQue( PAGETBL *pt, PN ent );Inline BOOL isEmptyPageQue( PAGETBL *pt, PN que );Inline void setUsePages( PAGETBL *pt, PN pn, W n, UW atr );LOCAL PN searchFreeQue( PAGETBL *pt, W n );LOCAL void appendFreePages( PAGETBL *pt, PN pn, W n );LOCAL void initFreePages( PAGETBL *pt, PN pn, W n );LOCAL VP getPages( PAGETBL *pt, VP *p_grp, W npage, UW atr );LOCAL W relPage1( PAGETBL *pt, PN pn );LOCAL W relPages( PAGETBL *pt, VP laddr, VP *p_grp );LOCAL W initPageTable( VP top, VP end, UW lsid );LOCAL PAGETBL* checkAddr( VP adr );LOCAL ER _tkse_get_mbk( VP *adr_p, INT nblk, UINT atr );LOCAL ER _tkse_rel_mbk( VP adr );LOCAL ER _tkse_mbk_sts( M_STATE *sts );LOCAL ER relMemGrpPiece( PAGETBL *pt, PN pn, UW lsid );LOCAL ER relMemGrp( PAGETBL *pt, VP *p_grp, UW lsid );LOCAL void MemCleanUp( ID resid, W pid );LOCAL WER MemSVCentry( VP para, W fn );#define TSD_AFP_VAL_2 2#define TSD_SUP_VAL_2 2#define TSD_DMT_DIV_1024 1024/* * Interconversion between page number and address */Inline VP PageAdr( PAGETBL *pt, PN pn ){#if USERLEVEL_ADDRESS_MASK /* Processing to be performed when access right is determined based on address. */ VP adr = _PageAdr(pt, pn); if ( (pt->pageque[pn].atr & MB_SHARE) != 0U ) { adr = (VP)((UW)adr & (UW)USERLEVEL_ADDRESS_MASK); } return adr;#else return _PageAdr(pt, pn);#endif}Inline PN PageNo( PAGETBL *pt, VP adr ){#if USERLEVEL_ADDRESS_MASK if ( pt == SystemPageTable ) { adr = (VP)((UW)adr | ~(UW)USERLEVEL_ADDRESS_MASK); }#endif return _PageNo(pt, adr);}/* ------------------------------------------------------------------------ *//* * Set page queue */Inline void setPageQue( PAGEQUE *q, BOOL u, BOOL c, PN n, PN p, UW a ){ q->use = u; q->cont = c; q->next = n; q->prev = p; q->atr = a;}/* * Initialize page queue */Inline void initPageQue( PAGETBL *pt, PN pn ){ pt->pageque[pn].next = pt->pageque[pn].prev = pn;}/* * Insert page queue * Insert ent immediately anterior to que */Inline void insertPageQue( PAGETBL *pt, PN que, PN ent ){ pt->pageque[ent].prev = pt->pageque[que].prev; pt->pageque[ent].next = que; pt->pageque[pt->pageque[que].prev].next = ent; pt->pageque[que].prev = ent;}/* * Separate page queue * Separate ent from queue */Inline void removePageQue( PAGETBL *pt, PN ent ){ if ( pt->pageque[ent].next != ent ) { pt->pageque[pt->pageque[ent].prev].next = pt->pageque[ent].next; pt->pageque[pt->pageque[ent].next].prev = pt->pageque[ent].prev; }}/* * The page queue is empty: TRUE */Inline BOOL isEmptyPageQue( PAGETBL *pt, PN que ){ return ( pt->pageque[que].next == que );}/* * Search for free page queue * Search for a queue whose number of free pages is equal to "n", * or greater but closest to "n". If not found, return 0 (freeque). */LOCAL PN searchFreeQue( PAGETBL *pt, W n ){ PN pn = 0; while ( (pn = pt->pageque[pn].next) > 0U ) { if ( NumOfPages(&pt->pageque[pn]) >= n ) { return pn; } } return 0;}/* * Register free page additionally * As additional free pages, register n consecutive pages starting from page pn. */LOCAL void appendFreePages( PAGETBL *pt, PN pn, W n ){ PN ins; /* Set queue */ pt->pageque[pn].use = FREE; pt->pageque[pn].cont = ( n > 1 )? CONT: ONE; pt->pageque[pn].atr = 0; if ( n > 1 ) { setPageQue(&pt->pageque[pn + 1U], FREE, CONT, (UW)n, 0U, 0U); } if ( n > TSD_AFP_VAL_2 ) { setPageQue(&pt->pageque[pn + (UW)n - 1U], FREE, CONT, (UW)n, 0U, 0U); } /* Find position for addition of free page */ ins = searchFreeQue(pt, n); /* Register free page */ insertPageQue(pt, ins, pn);}/* * Register free page newly * Newly register n consecutive pages starting from page pn. */LOCAL void initFreePages( PAGETBL *pt, PN pn, W n ){ appendFreePages(pt, pn, n); if ( n > 1 ) { pt->pageque[pn ].wall = TWALL; pt->pageque[pn + (UW)n - 1U].wall = EWALL; } else { pt->pageque[pn ].wall = TWALL|EWALL; }}/* * Set page to be used */Inline void setUsePages( PAGETBL *pt, PN pn, W n, UW atr ){ /* Set queue */ pt->pageque[pn].use = USE; pt->pageque[pn].cont = ( n > 1 )? CONT: ONE; pt->pageque[pn].atr = atr; if ( n > 1 ) { setPageQue(&pt->pageque[pn + 1U], USE, CONT, (PN)n, 0U, 0U); } if ( n > TSD_SUP_VAL_2 ) { setPageQue(&pt->pageque[pn + (UW)n - 1U], USE, CONT, (PN)n, 0U, 0U); } initPageQue(pt, pn);}/* * Obtain page */LOCAL VP getPages( PAGETBL *pt, VP *p_grp, W npage, UW atr ){ PN pn; W free; /* Search for free page */ pn = searchFreeQue(pt, npage); if ( pn == 0U ) { return NULL; } free = NumOfPages(&pt->pageque[pn]); /* Temporarily remove all of pn consecutive free pages from the free queue. */ removePageQue(pt, pn); /* Separate the necessary number of pages. */ free -= npage; setUsePages(pt, pn, npage, atr); if ( free > 0 ) { /* Return the remaining pages to free the queue. */ appendFreePages(pt, pn + (UW)npage, free); /* PAGEQUE is not initialized until it is used for the first time. * When PAGEQUE is used anew due to division of an area, * it is necessary to initialize PAGEQUE. Here, initialize * wall only because the others are initialized setUsePages() * and appendFreePages(). */ if ( npage > 1 ) { pt->pageque[pn + (UW)npage - 1U].wall = 0; } if ( free > 1 ) { pt->pageque[pn + (UW)npage ].wall = 0; } } if ( p_grp != NULL ) { /* Register obtained pages in a group. */ if ( *p_grp != NULL ) { insertPageQue(pt, PageNo(pt, *p_grp), pn); } *p_grp = PageAdr(pt, pn); } pt->freepage -= (UW)npage; return PageAdr(pt, pn);}/* * Release a series of consecutive areas. * Return the number of released pages. */LOCAL W relPage1( PAGETBL *pt, PN pn ){ W npage, free; ER err; if ( pt->pageque[pn].use == FREE ) { err = E_PAR; goto err_ret; } /* Separate pages to be released from the group. */ removePageQue(pt, pn); /* Number of pages to be released */ free = npage = NumOfPages(&pt->pageque[pn]); /* Check if there are free pages located posterior to the released pages. */ if (( (pt->pageque[pn + (UW)npage - 1U].wall & EWALL) == 0U ) &&( pt->pageque[pn + (UW)npage].use == FREE )) { /* Temporarily remove free pages located posterior from the free queue. */ removePageQue(pt, pn + (UW)npage); /* Merge free and released pages. */ npage += NumOfPages(&pt->pageque[pn + (UW)npage]); } /* Check if there are free pages located anterior to the released pages. */ if (( (pt->pageque[pn].wall & TWALL) == 0U ) &&( pt->pageque[pn - 1U].use == FREE )) { /* Number of free pages located anterior */ W n = ( pt->pageque[pn - 1U].cont != 0 )? pt->pageque[pn - 1U].next: 1; /* Temporarily remove free pages located anterior from the free queue. */ removePageQue(pt, pn - (UW)n); /* Merge free and released pages. */ pn -= (UW)n; npage += n; } /* Register released pages in free queue. */ appendFreePages(pt, pn, npage); pt->freepage += (UW)free; return free;err_ret: DEBUG_PRINT(("relPage1 err = %d\n", err)); return err;}/* * Release page * Return the total number of released pages */LOCAL W relPages( PAGETBL *pt, VP laddr, VP *p_grp ){ PN pn; VP grp = NULL; ER err; pn = PageNo(pt, laddr); if ( p_grp != NULL ) { grp = ( isEmptyPageQue(pt, pn) != 0 )? NULL: PageAdr(pt, pt->pageque[pn].next); } err = relPage1(pt, pn); if ( err < E_OK ) { goto err_ret; } if ( p_grp != NULL ) { *p_grp = grp; } return err;err_ret: DEBUG_PRINT(("relPages err = %d\n", err)); return err;}/* * Initialize memory management table on a page basis. * Manage areas located between top and end. * top and end must be located on page boundaries. * The management table will be at the top position. * Return the size of management table (number of pages). * * (*) An area between top and end must be the current logical space. */LOCAL W initPageTable( VP top, VP end, UW lsid ){ PAGETBL *pt; UW memsz, maxpage, tblpage; ER err; /* Memory size */ memsz = (UW)end - (UW)top; /* Number of pages except for management table */ maxpage = (memsz - sizeof(PAGETBL)) / ((UW)PAGESIZE + sizeof(PAGEQUE)); /* Size of management table (number of pages) */ tblpage = PageCount(sizeof(PAGETBL) + (sizeof(PAGEQUE) * maxpage)); /* Allocate logical space to management table. */ err = _MakeSpace(top, (W)tblpage, lsid, (UW)PTE_SMEM_NC); if ( err < E_OK ) { goto err_ret; } /* Initialize management table. */ pt = (PAGETBL*)top; pt->maxpage = maxpage; pt->freepage = maxpage; pt->toppage = (PAGE*)top + tblpage; clrPageQue(pt->freeque); initFreePages(pt, 1U, (W)maxpage); return (W)tblpage;err_ret: DEBUG_PRINT(("initPageTbl err = %d\n", err)); return err;}/* ------------------------------------------------------------------------ *//* * Check size of memory to be reserved. * Reserve memory for npage; if the remaining memory becomes smaller than * the minimum size to be reserved for system, return E_NOMEM. */EXPORT ER ChkSysRsvMem( W npage ){ return ( (AvailablePages() - npage) < SysReserve )? E_NOMEM: E_OK;}/* * Address check */LOCAL PAGETBL* checkAddr( VP adr ){ PAGETBL *pt; if ( isLocalSpace(adr) != 0 ) { /* Local memory */ PINFO *pinfo = GetPinfo(TSK_SELF); if ( pinfo == NULL ) { return NULL; } pt = pinfo->lpgtbl; } else { /* System memory */ pt = SystemPageTable;#if USERLEVEL_ADDRESS_MASK adr = (VP)((UW)adr | ~(UW)USERLEVEL_ADDRESS_MASK);#endif } return ( (adr >= (VP)pt->toppage) && (adr < (VP)(pt->toppage + pt->maxpage)) && (((UW)adr & ((UW)PAGESIZE - 1U)) == 0U) )? pt: NULL;}/* * Obtain memory block */LOCAL ER _tkse_get_mbk( VP *adr_p, INT nblk, UINT atr ){#define ATR_MASK (M_SYSTEM|M_RESIDENT|TA_DELEXIT) PAGETBL *pt; PINFO *pinfo = NULL; UW lsid = GetLSID_tid(TSK_SELF); UW mb_atr; VP *memgrp, adr; UW pte; ER err; /* Parameter check */ if (( nblk <= 0 )||( (atr & ~(UW)ATR_MASK) != 0U )) { err = E_PAR; goto err_ret1; } err = ChkSpaceRW(adr_p, sizeof(VP*)); if ( err < E_OK ) { goto err_ret1; } LockMEM(); /* Check if the number of pages is allocatable. */ if ( (atr & M_SYSTEM) == M_SYSTEM ) { if ( nblk > AvailablePages() ) { err = E_NOMEM; goto err_ret2; } } else { err = ChkSysRsvMem(nblk); if ( err < E_OK ) { goto err_ret2; } } /* Memory attribute */ mb_atr = 0; if ( (atr & TA_DELEXIT) != 0U ) { mb_atr |= MB_DELETE; } switch ( atr & M_SYSTEM ) { case 0: mb_atr |= MB_LOCAL; break; case M_COMMON: mb_atr |= MB_SHARE; break; default: /* nothing to do */ break; } if ( (mb_atr & (MB_LOCAL|MB_DELETE)) != 0U ) { pinfo = GetPinfo(TSK_SELF); if ( pinfo == NULL ) { err = E_CTX; goto err_ret2; } } memgrp = ( (mb_atr & MB_LOCAL) != 0U )? &pinfo->lmemgrp: (( (mb_atr & MB_DELETE) != 0U )? &pinfo->smemgrp: NULL); pt = ( (mb_atr & MB_LOCAL) != 0U )? pinfo->lpgtbl: SystemPageTable; /* Obtain memory */ adr = getPages(pt, memgrp, nblk, mb_atr); if ( adr == NULL ) { err = E_NOMEM; goto err_ret2; } /* Generate memory space */ pte = ( (atr & M_SYSTEM) == M_SYSTEM )? PTE_SMEM_NC: PTE_UMEM_NC; err = MakeSpace(adr, nblk, (W)lsid, pte); if ( err < E_OK ) { goto err_ret3; } if ( (atr & M_RESIDENT) != 0U ) { /* Resident */ err = LockSpace(adr, nblk * PAGESIZE); if ( err < E_OK ) { goto err_ret4; } } else { /* Allocate physical memory to all pages so that it will be reflected in the amount of physical memory consumed. */ W i; for ( i = (nblk - 1) * PAGESIZE; i >= 0; i -= PAGESIZE ) { ((UB*)adr)[i] = 0U; } } *adr_p = adr; UnlockMEM(); return E_OK;err_ret4: (void)UnmakeSpace(adr, nblk, (W)lsid);err_ret3: (void)relPages(pt, adr, memgrp);err_ret2: UnlockMEM();err_ret1: DEBUG_PRINT(("_tkse_get_mbk err = %d\n", err)); return ERtoERR(err);}/* * Release memory block */LOCAL ER _tkse_rel_mbk( VP adr ){ PAGETBL *pt; PINFO *pinfo = NULL; UW mb_atr; VP *memgrp; W nblk; ER err; LockMEM(); /* Address check */ pt = checkAddr(adr); if ( pt == NULL ) { err = E_PAR; goto err_ret1; } /* Memory attribute */ mb_atr = pt->pageque[PageNo(pt, adr)].atr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -