gonzui


Format: Advanced Search

t2ex/t2ex_source/kernel/extension/memory/t2ex/memmgr.cbare sourcepermlink (0.03 seconds)

Search this content:

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