📄 memmgr.c
字号:
/* *---------------------------------------------------------------------- * T-Kernel * * Copyright (C) 2004 by Ken Sakamura. All rights reserved. * T-Kernel is distributed under the T-License. *---------------------------------------------------------------------- * * Version: 1.01.00 * Released by T-Engine Forum(http://www.t-engine.org) at 2004/6/28. * *---------------------------------------------------------------------- *//* * memmgr.c (T-Kernel/SM) * No MMU version: memory management */#include "sysmgr.h"#include "cache_info.h"#include <sys/imalloc.h>/* * Page */typedef struct { VB mem[2*1024];} PAGE;#define PAGESZ ( sizeof(PAGE) )typedef UINT PN; /* Page number (1 - maxpage) *//* * Number of pages */EXPORT UW smPageCount( UW byte ){ return (byte + (PAGESZ-1)) / PAGESZ;}/* * Page management queue */typedef struct { BOOL cont:1; /* 1 if multiple pages in succession */ BOOL use:1; /* 1 if page in use */ PN next:30; UINT atr:2; /* Memory block attributes */ PN prev:30;} PAGEQUE;#define USE TRUE /* In use */#define FREE FALSE /* Free */#define CONT TRUE /* Continuation (multiple blocks in succession) */#define ONE FALSE /* Independent */LOCAL PAGEQUE _clrPageQue = { ONE, FREE, 0, 0, 0 };#define clrPageQue(q) ( (q) = _clrPageQue )/* Number of successive pages */#define NumOfPages(q) ( ( (q)->cont )? ((q)+1)->next: 1 )/* * Memory block attributes */#define MB_NOCACHE 1 /* Cache off *//* * Page management table * Top of pageque is used for freeque. * freeque is sorted in order from the smallest number of * successive free pages. */typedef struct { INT maxpage; /* Total number of pages */ INT freepage; /* Number of free pages */ PAGEQUE *pageque; /* Array of management information for all pages */ PAGE *top_page; /* Top page address */} PAGETBL;#define freeque pageque[0] /* Free page queue */#define _PageAdr(pn, pt) ( (VP)((pt)->top_page + ((pn) - 1)) )#define _PageNo(adr, pt) ( (PN)(((PAGE*)(adr) - (pt)->top_page) + 1) )/* ------------------------------------------------------------------------ *//* * Memory management table */LOCAL PAGETBL SysMemTbl; /* System memory management table */#if USE_NOCACHE_MEMTBLLOCAL PAGETBL NoCacheMemTbl; /* Non-cache area memory management table */#endif/* * Memory management exclusion control lock * During OS startup, Lock() is called before CreateLock(). * The initialization value is set to prevent it switching to wait mode.*/LOCAL FastLock MemLock = { -1, -1 };#define LockMEM() Lock(&MemLock)#define UnlockMEM() Unlock(&MemLock)/* ------------------------------------------------------------------------ */Inline VP PageAdr( PN pn, PAGETBL *pt ){ VP adr = _PageAdr(pn, pt); if ( (pt->pageque[pn].atr & MB_NOCACHE) != 0 ) { adr = NoCachingAddr(adr); } return adr;}Inline PN PageNo( VP adr, PAGETBL *pt ){ adr = CachingAddr(adr); return _PageNo(adr, pt);}/* * Address check * Returns TRUE if address is OK. */LOCAL BOOL chkadr( VP adr, PAGETBL *pt ){ adr = CachingAddr(adr); if ( adr >= (VP)pt->top_page && adr < (VP)(pt->top_page + pt->maxpage) ) { if ( ((UINT)adr % PAGESZ) == 0 ) return TRUE; } return FALSE;}/* * Set page queue value */Inline PAGEQUE setPageQue( BOOL u, BOOL c, PN n, PN p, UINT a ){ PAGEQUE q; q.use = u; q.cont = c; q.next = n; q.prev = p; q.atr = a; return q;}/* * Page queue initialization */Inline void initPageQue( PN pn, PAGETBL *pt ){ pt->pageque[pn].next = pt->pageque[pn].prev = pn;}/* * Insert page queue * Inserts ent directly prior to que. */Inline void insertPageQue( PN que, PN ent, PAGETBL *pt ){ PAGEQUE *qp = &pt->pageque[que]; PAGEQUE *ep = &pt->pageque[ent]; ep->prev = qp->prev; ep->next = que; pt->pageque[qp->prev].next = ent; qp->prev = ent;}/* * Isolate page queue * Removes ent from queue. */LOCAL void removePageQue( PN ent, PAGETBL *pt ){ PAGEQUE *ep = &pt->pageque[ent]; if ( ep->next != ent ) { pt->pageque[ep->prev].next = ep->next; pt->pageque[ep->next].prev = ep->prev; }}/* * TRUE if page queue is free */Inline BOOL isEmptyPageQue( PN que, PAGETBL *pt ){ return ( pt->pageque[que].next == que );}/* * Free page queue search * Searches for a queue with n free pages (or the closest * number of free pages greater than n). * If such a queue cannot be found, returns 0 (i.e., freeque). */LOCAL PN searchFreeQue( INT n, PAGETBL *pt ){ PAGEQUE *pageque = pt->pageque; PN pn = 0; while ( (pn = pageque[pn].next) > 0 ) { if ( NumOfPages(&pageque[pn]) >= n ) return pn; } return 0;}/* * Append free page * Registers as free pages n consecutive pages starting * from the pn page. */LOCAL void appendFreePages( PN pn, INT n, PAGETBL *pt ){ PN ins; PAGEQUE *pq = &pt->pageque[pn]; /* Queue setting */ pq->use = FREE; pq->cont = ( n > 1 )? CONT: ONE; pq->atr = 0; if ( n > 1 ) pq[1] = setPageQue(FREE, CONT, n, 0, 0); if ( n > 2 ) pq[n-1] = setPageQue(FREE, CONT, n, 0, 0); /* Search for position where free pages added */ ins = searchFreeQue(n, pt); /* Register free pages */ insertPageQue(ins, pn, pt);}/* * Set queue for using page */Inline void setUsePages( PN pn, INT n, UINT atr, PAGETBL *pt ){ PAGEQUE *pq = &pt->pageque[pn]; /* Queue setting */ pq->use = USE; pq->cont = ( n > 1 )? CONT: ONE; pq->atr = atr; if ( n > 1 ) pq[1] = setPageQue(USE, CONT, n, 0, 0); if ( n > 2 ) pq[n-1] = setPageQue(USE, CONT, n, 0, 0); initPageQue(pn, pt);}/* * Allocate page */LOCAL VP getPage( INT nblk, UINT atr, PAGETBL *pt ){ PN pn; INT free; /* Free page search */ pn = searchFreeQue(nblk, pt); if ( pn == 0 ) return NULL; free = NumOfPages(&pt->pageque[pn]); /* Remove from the free queue all consecutive free pages starting from the pn page */ removePageQue(pn, pt); /* Extract required pages only */ setUsePages(pn, nblk, atr, pt); free -= nblk; if ( free > 0 ) { /* Return remaining pages to the free queue */ appendFreePages(pn + nblk, free, pt); } pt->freepage -= nblk; return PageAdr(pn, pt);}/* * Page release * Returns the total number of pages released */LOCAL INT relPage( VP adr, PAGETBL *pt ){ PN pn; PAGEQUE *pq; INT nblk, free; pn = PageNo(adr, pt); pq = &pt->pageque[pn]; if ( pq->use == FREE ) return E_PAR; /* Number of pages to be released */ free = nblk = NumOfPages(pq); /* Are the pages next to the released pages free? */ if ( pn + nblk <= pt->maxpage && (pq+nblk)->use == FREE ) { /* Remove free pages next to the free queue */ removePageQue(pn+nblk, pt); /* Merge free pages with released pages */ nblk += NumOfPages(pq+nblk); } /* Are there free pages previous to the released pages? */ if ( pn > 1 && (pq-1)->use == FREE ) { /* Number of free previous pages */ INT n = ( (pq-1)->cont )? (pq-1)->next: 1; /* Remove free pages previous to the free queue */ removePageQue(pn-n, pt); /* Merge free pages and released pages */ pn -= n; nblk += n; /* Although essentially unnecessary, set to FREE in case of erroneous calls trying to release the same address more than once. */ pq->use = FREE; } /* Register release page in free queue */ appendFreePages(pn, nblk, pt); pt->freepage += free; return free;}/* * Memory management table initialization */LOCAL ER initPageTbl( VP top, VP end, PAGETBL *pt ){ INT memsz, npage; /* Align top with 8 byte unit alignment */ top = (VP)(((UINT)top + 7) & ~7); memsz = (UINT)end - (UINT)top; /* Allocate page management table */ pt->pageque = (PAGEQUE*)top; /* Determine provisional number of pages */ npage = (memsz - sizeof(PAGEQUE)) / (PAGESZ + sizeof(PAGEQUE)); /* Adjust to match address in page size units and determine top page address */ pt->top_page = (PAGE*)(((UINT)(pt->pageque + npage + 1) + (PAGESZ-1)) / PAGESZ * PAGESZ); /* Recalculate number of pages */ npage = ((UINT)end - (UINT)pt->top_page) / PAGESZ; pt->maxpage = npage; pt->freepage = npage; /* Page management table initialization */ clrPageQue(pt->freeque); appendFreePages(1, npage, pt); return E_OK;}/* ------------------------------------------------------------------------ *//* * Allocate system memory * attr = TA_RNGn | TA_NORESIDENT | TA_NOCACHE */EXPORT VP GetSysMemBlk( INT nblk, UINT attr){ PAGETBL *pt; VP adr; UINT mb_atr; /* Memory management table */#if USE_NOCACHE_MEMTBL pt = ( (attr & TA_NOCACHE) != 0 )? &NoCacheMemTbl: &SysMemTbl;#else pt = &SysMemTbl;#endif /* Memory block attributes */ mb_atr = 0; if ( (attr & TA_NOCACHE) != 0 ) mb_atr |= MB_NOCACHE; /* Get memory block */ LockMEM(); adr = getPage(nblk, mb_atr, pt); UnlockMEM();#ifdef DEBUG if ( adr == NULL ) BMS_DEBUG_PRINT(("GetSysMemBlk E_NOMEM\n"));#endif return adr;}/* * System memory release */EXPORT ER RelSysMemBlk( VP addr ){ PAGETBL *pt; INT free; ER err; pt = ( chkadr(addr, &SysMemTbl) )? &SysMemTbl:#if USE_NOCACHE_MEMTBL ( chkadr(addr, &NoCacheMemTbl) )? &NoCacheMemTbl:#endif NULL; if ( pt == NULL ) { err = E_PAR; goto err_ret; } LockMEM(); free = relPage(addr, pt); UnlockMEM(); if ( free < E_OK ) { err = free; goto err_ret; } /* Invalidate released memory cache */ FlushCache(addr, free * PAGESZ); return E_OK;err_ret: BMS_DEBUG_PRINT(("RelSysMemBlk err = %d\n", err)); return err;}/* * Acquire system memory information */EXPORT ER RefSysMemInfo( T_RSMB *pk_rsmb ){ LockMEM(); pk_rsmb->blksz = PAGESZ; pk_rsmb->total = SysMemTbl.maxpage; pk_rsmb->free = SysMemTbl.freepage; UnlockMEM(); return E_OK;}/* ------------------------------------------------------------------------ *//* * Memory management initialization sequence * Initialization prior to T-Kernel/OS startup */EXPORT ER init_memmgr( void ){/* Low-level memory management information */IMPORT VP lowmem_top, lowmem_limit; VP memend; ER err; /* Acquire system configuration definition information */ err = _tk_get_cfn("RealMemEnd", (INT*)&memend, 1); if ( err < 1 || (UINT)memend > (UINT)lowmem_limit ) memend = lowmem_limit; /* System memory management table initialization */ err = initPageTbl(lowmem_top, memend, &SysMemTbl); if ( err < E_OK ) goto err_ret; lowmem_top = memend; /* Update memory free space */#if USE_NOCACHE_MEMTBL /* Non-cache area memory management table initialization */ err = initPageTbl(NoCacheMemoryTop, NoCacheMemoryEnd, &NoCacheMemTbl); if ( err < E_OK ) goto err_ret;#endif return E_OK;err_ret: BMS_DEBUG_PRINT(("init_memmgr err = %d\n", err)); return err;}/* * Memory management start sequence * Initialization directly after T-Kernel/OS startup */EXPORT ER start_memmgr( void ){ ER err; /* Generate exclusion control lock */ err = CreateLock(&MemLock, "Mem"); if ( err < E_OK ) goto err_ret; return E_OK;err_ret: BMS_DEBUG_PRINT(("start_memmgr err = %d\n", err)); return err;}/* * Memory management start sequence */EXPORT ER finish_memmgr( void ){ return E_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -