gonzui


Format: Advanced Search

tkernel_2/kernel/extension/memory/nommu/memmgr.cbare sourcepermlink (0.03 seconds)

Search this content:

    1: /*
    2:  *----------------------------------------------------------------------
    3:  *    T-Kernel 2.0 Software Package
    4:  *
    5:  *    Copyright 2011 by Ken Sakamura.
    6:  *    This software is distributed under the latest version of T-License 2.x.
    7:  *----------------------------------------------------------------------
    8:  *
    9:  *    Released by T-Engine Forum(http://www.t-engine.org/) at 2011/05/17.
   10:  *    Modified by T-Engine Forum at 2012/10/24.
   11:  *    Modified by T-Engine Forum at 2013/03/07.
   12:  *    Modified by TRON Forum(http://www.tron.org/) at 2015/06/01.
   13:  *
   14:  *----------------------------------------------------------------------
   15:  */
   16: 
   17: /*
   18:  *      memmgr.c (T-Kernel/SM)
   19:  *      No MMU version: memory management
   20:  */
   21: 
   22: #include "sysmgr.h"
   23: #include "cache_info.h"
   24: #include <sys/rominfo.h>
   25: #include <sys/imalloc.h>
   26: 
   27: /*
   28:  * Page
   29:  */
   30: typedef struct {
   31:         VB     mem[2*1024];
   32: } PAGE;
   33: #define PAGESZ          ( sizeof(PAGE) )
   34: 
   35: typedef UINT    PN;        /* Page number (1 - maxpage) */
   36: 
   37: /*
   38:  * Number of pages
   39:  */
   40: EXPORT UW smPageCount( UW byte )
   41: {
   42:         return (byte + (PAGESZ-1)) / PAGESZ;
   43: }
   44: 
   45: /*
   46:  * Page management queue
   47:  */
   48: typedef struct {
   49:         BOOL   cont:1;           /* 1 if multiple pages in succession */
   50:         BOOL   use:1;            /* 1 if page in use */
   51:         PN     next:30;
   52:         UINT   atr:2;            /* Memory block attributes */
   53:         PN     prev:30;
   54: } PAGEQUE;
   55: 
   56: #define USE     TRUE        /* In use */
   57: #define FREE    FALSE      /* Free */
   58: #define CONT    TRUE       /* Continuation (multiple blocks in succession) */
   59: #define ONE     FALSE       /* Independent */
   60: 
   61: CONST LOCAL PAGEQUE     _clrPageQue = { ONE, FREE, 0, 0, 0 };
   62: 
   63: #define clrPageQue(q)   ( (q) = _clrPageQue )
   64: 
   65: /* Number of successive pages */
   66: #define NumOfPages(q)   ( ( (q)->cont )? ((q)+1)->next: 1 )
   67: 
   68: /*
   69:  * Memory block attributes
   70:  */
   71: #define MB_NOCACHE      1    /* Cache off */
   72: 
   73: /*
   74:  * Page management table
   75:  *      Top of pageque is used for freeque.
   76:  *      freeque is sorted in order from the smallest number of
   77:  *      successive free pages.
   78:  */
   79: typedef struct {
   80:         INT    maxpage;   /* Total number of pages */
   81:         INT    freepage;  /* Number of free pages */
   82:         PAGEQUE        *pageque;      /* Array of management information for
   83:                                    all pages */
   84:         PAGE   *top_page;        /* Top page address */
   85: } PAGETBL;
   86: 
   87: #define freeque                 pageque[0]    /* Free page queue */
   88: 
   89: #define _PageAdr(pn, pt)        ( (void*)((pt)->top_page + ((pn) - 1)) )
   90: #define _PageNo(adr, pt)        ( (PN)(((PAGE*)(adr) - (pt)->top_page) + 1) )
   91: 
   92: /* ------------------------------------------------------------------------ */
   93: 
   94: /*
   95:  * Memory management table
   96:  */
   97: LOCAL PAGETBL   SysMemTbl;        /* System memory management table */
   98: #if USE_NOCACHE_MEMTBL
   99: LOCAL PAGETBL   NoCacheMemTbl;    /* Non-cache area memory management table */
  100: #endif
  101: 
  102: /*
  103:  * Memory management exclusion control lock
  104:  *      During OS startup, Lock() is called before CreateLock().
  105:  *      The initialization value is set to prevent it switching to wait mode.
  106: */
  107: LOCAL FastLock  MemLock = { -1, -1 };
  108: #define LockMEM()       Lock(&MemLock)
  109: #define UnlockMEM()     Unlock(&MemLock)
  110: 
  111: /* Set Object Name in .exinf for DEBUG */
  112: #define OBJNAME_MMLOCK  "Mem"            /* Multi-lock for Memory Manager */
  113: 
  114: /* ------------------------------------------------------------------------ */
  115: 
  116: Inline void* PageAdr( PN pn, PAGETBL *pt )
  117: {
  118:         void* adr = _PageAdr(pn, pt);
  119: 
  120:         if ( (pt->pageque[pn].atr & MB_NOCACHE) != 0 ) {
  121:                 adr = NoCachingAddr(adr);
  122:         }
  123:         return adr;
  124: }
  125: Inline PN PageNo( CONST void *adr, PAGETBL *pt )
  126: {
  127:         adr = CachingAddr(adr);
  128:         return _PageNo(adr, pt);
  129: }
  130: 
  131: /*
  132:  * Address check
  133:  *      Returns TRUE if address is OK.
  134:  */
  135: LOCAL BOOL chkadr( CONST void *adr, PAGETBL *pt )
  136: {
  137:         adr = CachingAddr(adr);
  138:         if ( adr >= (void*)pt->top_page && adr < (void*)(pt->top_page + pt->maxpage) ) {
  139:                 if ( ((UINT)adr % PAGESZ) == 0 ) {
  140:                         return TRUE;
  141:                 }
  142:         }
  143:         return FALSE;
  144: }
  145: 
  146: /*
  147:  * Set page queue value
  148:  */
  149: Inline PAGEQUE setPageQue( BOOL u, BOOL c, PN n, PN p, UINT a )
  150: {
  151:         PAGEQUE        q;
  152:         q.use  = u;
  153:         q.cont = c;
  154:         q.next = n;
  155:         q.prev = p;
  156:         q.atr  = a;
  157:         return q;
  158: }
  159: 
  160: /*
  161:  * Page queue initialization
  162:  */
  163: Inline void initPageQue( PN pn, PAGETBL *pt )
  164: {
  165:         pt->pageque[pn].next = pt->pageque[pn].prev = pn;
  166: }
  167: 
  168: /*
  169:  * Insert page queue
  170:  *      Inserts ent directly prior to que.
  171:  */
  172: Inline void insertPageQue( PN que, PN ent, PAGETBL *pt )
  173: {
  174:         PAGEQUE        *qp = &pt->pageque[que];
  175:         PAGEQUE *ep = &pt->pageque[ent];
  176: 
  177:         ep->prev = qp->prev;
  178:         ep->next = que;
  179:         pt->pageque[qp->prev].next = ent;
  180:         qp->prev = ent;
  181: }
  182: 
  183: /*
  184:  * Isolate page queue
  185:  *      Removes ent from queue.
  186:  */
  187: LOCAL void removePageQue( PN ent, PAGETBL *pt )
  188: {
  189:         PAGEQUE        *ep = &pt->pageque[ent];
  190: 
  191:         if ( ep->next != ent ) {
  192:                 pt->pageque[ep->prev].next = ep->next;
  193:                 pt->pageque[ep->next].prev = ep->prev;
  194:         }
  195: }
  196: 
  197: /*
  198:  * TRUE if page queue is free
  199:  */
  200: Inline BOOL isEmptyPageQue( PN que, PAGETBL *pt )
  201: {
  202:         return ( pt->pageque[que].next == que );
  203: }
  204: 
  205: /*
  206:  * Free page queue search
  207:  *      Searches for a queue with n free pages (or the closest
  208:  *      number of free pages greater than n).
  209:  *      If such a queue cannot be found, returns 0 (i.e., freeque).
  210:  */
  211: LOCAL PN searchFreeQue( INT n, PAGETBL *pt )
  212: {
  213:         PAGEQUE        *pageque = pt->pageque;
  214:         PN     pn = 0;
  215: 
  216:         while ( (pn = pageque[pn].next) > 0 ) {
  217:                 if ( NumOfPages(&pageque[pn]) >= n ) {
  218:                         return pn;
  219:                 }
  220:         }
  221:         return 0;
  222: }
  223: 
  224: /*
  225:  * Append free page
  226:  *      Registers as free pages n consecutive pages starting
  227:  *      from the pn page.
  228:  */
  229: LOCAL void appendFreePages( PN pn, INT n, PAGETBL *pt )
  230: {
  231:         PN     ins;
  232:         PAGEQUE        *pq = &pt->pageque[pn];
  233: 
  234:         /* Queue setting */
  235:         pq->use  = FREE;
  236:         pq->cont = ( n > 1 )? CONT: ONE;
  237:         pq->atr  = 0;
  238:         if ( n > 1 ) {
  239:                 pq[1]   = setPageQue(FREE, CONT, n, 0, 0);
  240:         }
  241:         if ( n > 2 ) {
  242:                 pq[n-1] = setPageQue(FREE, CONT, n, 0, 0);
  243:         }
  244: 
  245:         /* Search for position where free pages added */
  246:         ins = searchFreeQue(n, pt);
  247: 
  248:         /* Register free pages */
  249:         insertPageQue(ins, pn, pt);
  250: }
  251: 
  252: /*
  253:  * Set queue for using page
  254:  */
  255: Inline void setUsePages( PN pn, INT n, UINT atr, PAGETBL *pt )
  256: {
  257:         PAGEQUE        *pq = &pt->pageque[pn];
  258: 
  259:         /* Queue setting */
  260:         pq->use  = USE;
  261:         pq->cont = ( n > 1 )? CONT: ONE;
  262:         pq->atr  = atr;
  263:         if ( n > 1 ) {
  264:                 pq[1]   = setPageQue(USE, CONT, n, 0, 0);
  265:         }
  266:         if ( n > 2 ) {
  267:                 pq[n-1] = setPageQue(USE, CONT, n, 0, 0);
  268:         }
  269: 
  270:         initPageQue(pn, pt);
  271: }
  272: 
  273: /*
  274:  * Allocate page
  275:  */
  276: LOCAL void* getPage( INT nblk, UINT atr, PAGETBL *pt )
  277: {
  278:         PN     pn;
  279:         INT    free;
  280: 
  281:         /* Free page search */
  282:         pn = searchFreeQue(nblk, pt);
  283:         if ( pn == 0 ) {
  284:                 return NULL;
  285:         }
  286:         free = NumOfPages(&pt->pageque[pn]);
  287: 
  288:         /* Remove from the free queue all consecutive free pages
  289:            starting from the pn page */
  290:         removePageQue(pn, pt);
  291: 
  292:         /* Extract required pages only */
  293:         setUsePages(pn, nblk, atr, pt);
  294:         free -= nblk;
  295: 
  296:         if ( free > 0 ) {
  297:                 /* Return remaining pages to the free queue */
  298:                 appendFreePages(pn + (UINT)nblk, free, pt);
  299:         }
  300: 
  301:         pt->freepage -= nblk;
  302: 
  303:         return PageAdr(pn, pt);
  304: }
  305: 
  306: /*
  307:  * Page release
  308:  *      Returns the total number of pages released
  309:  */
  310: LOCAL INT relPage( CONST void *adr, PAGETBL *pt )
  311: {
  312:         PN     pn;
  313:         PAGEQUE        *pq;
  314:         INT    nblk, free;
  315: 
  316:         pn = PageNo(adr, pt);
  317:         pq = &pt->pageque[pn];
  318: 
  319:         if ( pq->use == FREE ) {
  320:                 return E_PAR;
  321:         }
  322: 
  323:         /* Number of pages to be released */
  324:         free = nblk = NumOfPages(pq);
  325: 
  326:         /* Are the pages next to the released pages free? */
  327:         if ( pn + (UINT)nblk <= pt->maxpage && (pq+(UINT)nblk)->use == FREE ) {
  328: 
  329:                 /* Remove free pages next to the free queue */
  330:                 removePageQue(pn+(PN)nblk, pt);
  331: 
  332:                 /* Merge free pages with released pages */
  333:                 nblk += NumOfPages(pq+nblk);
  334:         }
  335: 
  336:         /* Are there free pages previous to the released pages? */
  337:         if ( pn > 1 && (pq-1)->use == FREE ) {
  338: 
  339:                 /* Number of free previous pages  */
  340:                 INT n = ( (pq-1)->cont )? (pq-1)->next: 1;
  341: 
  342:                 /* Remove free pages previous to the free queue */
  343:                 removePageQue(pn-(PN)n, pt);
  344: 
  345:                 /* Merge free pages and released pages */
  346:                 pn -= (UINT)n;
  347:                 nblk += n;
  348: 
  349:                 /* Although essentially unnecessary, set to FREE in
  350:                    case of erroneous calls trying to release the
  351:                    same address more than once. */
  352:                 pq->use = FREE;
  353:         }
  354: 
  355:         /* Register release page in free queue */
  356:         appendFreePages(pn, nblk, pt);
  357: 
  358:         pt->freepage += free;
  359: 
  360:         return free;
  361: }
  362: 
  363: /*
  364:  * Memory management table initialization
  365:  */
  366: LOCAL ER initPageTbl( void *top, void *end, PAGETBL *pt )
  367: {
  368:         INT    memsz, npage;
  369: 
  370:         /* Align top with 8 byte unit alignment */
  371:         top = (void*)(((UINT)top + 7) & ~0x00000007U);
  372:         memsz = (INT)((UINT)end - (UINT)top);
  373: 
  374:         /* Allocate page management table */
  375:         pt->pageque = (PAGEQUE*)top;
  376: 
  377:         /* Determine provisional number of pages */
  378:         npage = (INT)(((UINT)memsz - sizeof(PAGEQUE)) / (PAGESZ + sizeof(PAGEQUE)));
  379: 
  380:         /* Adjust to match address in page size units
  381:         and determine top page address */
  382:         pt->top_page = (PAGE*)(((UINT)(pt->pageque + npage + 1)
  383:                                         + (PAGESZ-1)) / PAGESZ * PAGESZ);
  384: 
  385:         /* Recalculate number of pages */
  386:         npage = (INT)(((UINT)end - (UINT)pt->top_page) / (UINT)PAGESZ);
  387:         pt->maxpage  = npage;
  388:         pt->freepage = npage;
  389: 
  390:         /* Page management table initialization */
  391:         clrPageQue(pt->freeque);
  392:         appendFreePages(1, npage, pt);
  393: 
  394:         return E_OK;
  395: }
  396: 
  397: /* ------------------------------------------------------------------------ */
  398: 
  399: /*
  400:  * Allocate system memory
  401:  *      attr = TA_RNGn | TA_NORESIDENT | TA_NOCACHE
  402:  */
  403: EXPORT void* GetSysMemBlk( INT nblk, UINT attr )
  404: {
  405:         PAGETBL        *pt;
  406:         void   *adr;
  407:         UINT   mb_atr;
  408: 
  409:         /* Memory management table */
  410: #if USE_NOCACHE_MEMTBL
  411:         pt = ( (attr & TA_NOCACHE) != 0 )? &NoCacheMemTbl: &SysMemTbl;
  412: #else
  413:         pt = &SysMemTbl;
  414: #endif
  415: 
  416:         /* Memory block attributes */
  417:         mb_atr = 0;
  418:         if ( (attr & TA_NOCACHE) != 0 ) {
  419:                 mb_atr |= MB_NOCACHE;
  420:         }
  421: 
  422:         /* Get memory block */
  423:         LockMEM();
  424:         adr = getPage(nblk, mb_atr, pt);
  425:         UnlockMEM();
  426: 
  427: #ifdef DEBUG
  428:         if ( adr == NULL ) {
  429:                 TM_DEBUG_PRINT(("GetSysMemBlk E_NOMEM\n"));
  430:         }
  431: #endif
  432:         return adr;
  433: }
  434: 
  435: /*
  436:  * System memory release
  437:  */
  438: EXPORT ER RelSysMemBlk( CONST void *addr )
  439: {
  440:         PAGETBL        *pt;
  441:         INT    free;
  442:         ER     ercd;
  443: 
  444:         pt = ( chkadr(addr, &SysMemTbl) )?     &SysMemTbl:
  445: #if USE_NOCACHE_MEMTBL
  446:              ( chkadr(addr, &NoCacheMemTbl) )? &NoCacheMemTbl:
  447: #endif
  448:                                                 NULL;
  449:         if ( pt == NULL ) {
  450:                 ercd = E_PAR;
  451:                 goto err_ret;
  452:         }
  453: 
  454:         LockMEM();
  455:         free = relPage(addr, pt);
  456:         UnlockMEM();
  457:         if ( free < E_OK ) {
  458:                 ercd = free;
  459:                 goto err_ret;
  460:         }
  461: 
  462:         /* Invalidate released memory cache */
  463:         FlushCache(addr, free * (W)PAGESZ);
  464: 
  465:         return E_OK;
  466: 
  467: err_ret:
  468:         TM_DEBUG_PRINT(("RelSysMemBlk ercd = %d\n", ercd));
  469:         return ercd;
  470: }
  471: 
  472: /*
  473:  * Acquire system memory information
  474:  */
  475: EXPORT ER RefSysMemInfo( T_RSMB *pk_rsmb )
  476: {
  477:         LockMEM();
  478:         pk_rsmb->blksz = PAGESZ;
  479:         pk_rsmb->total = SysMemTbl.maxpage;
  480:         pk_rsmb->free  = SysMemTbl.freepage;
  481:         UnlockMEM();
  482: 
  483:         return E_OK;
  484: }
  485: 
  486: /* ------------------------------------------------------------------------ */
  487: 
  488: /*
  489:  * Memory management initialization sequence
  490:  *      Initialization prior to T-Kernel/OS startup
  491:  */
  492: EXPORT ER init_memmgr( void )
  493: {
  494: /* Low-level memory management information */
  495: IMPORT  void     *lowmem_top, *lowmem_limit;
  496:         void   *memend;
  497:         ER     ercd;
  498: 
  499:         /* Acquire system configuration definition information */
  500:         ercd = _tk_get_cfn(SCTAG_REALMEMEND, (INT*)&memend, 1);
  501:         if ( ercd < 1 || (UINT)memend > (UINT)lowmem_limit ) {
  502:                 memend = lowmem_limit;
  503:         }
  504: 
  505:         /* System memory management table initialization */
  506:         ercd = initPageTbl(lowmem_top, memend, &SysMemTbl);
  507:         if ( ercd < E_OK ) {
  508:                 goto err_ret;
  509:         }
  510: 
  511:         lowmem_top = memend;  /* Update memory free space */
  512: 
  513: #if USE_NOCACHE_MEMTBL
  514:         /* Non-cache area memory management table initialization */
  515:         ercd = initPageTbl(NoCacheMemoryTop, NoCacheMemoryEnd, &NoCacheMemTbl);
  516:         if ( ercd < E_OK ) {
  517:                 goto err_ret;
  518:         }
  519: #endif
  520: 
  521:         return E_OK;
  522: 
  523: err_ret:
  524:         TM_DEBUG_PRINT(("init_memmgr ercd = %d\n", ercd));
  525:         return ercd;
  526: }
  527: 
  528: /*
  529:  * Memory management start sequence
  530:  *      Initialization directly after T-Kernel/OS startup
  531:  */
  532: EXPORT ER start_memmgr( void )
  533: {
  534:         ER     ercd;
  535: 
  536:         /* Generate exclusion control lock */
  537:         ercd = CreateLock(&MemLock, OBJNAME_MMLOCK);
  538:         if ( ercd < E_OK ) {
  539:                 goto err_ret;
  540:         }
  541: 
  542:         return E_OK;
  543: 
  544: err_ret:
  545:         TM_DEBUG_PRINT(("start_memmgr ercd = %d\n", ercd));
  546:         return ercd;
  547: }
  548: 
  549: /*
  550:  * Memory management start sequence
  551:  */
  552: EXPORT ER finish_memmgr( void )
  553: {
  554:         return E_OK;
  555: }