Main Page | Modules | File List | File Members

memory.c

00001 /* ndk - [ memory.c ]
00002  *
00003  * ndk maintains "page stacks" in order to manage memory in the physical
00004  * address space.  This code relies heavily on the paging hardware and
00005  * interface described in the pager source.
00006  *
00007  * If done correctly, it should be able to create an rZero implementation
00008  * of this memory management code, and the pager, to allow for
00009  * interchangeable methods of managing memory.  The two modules, however,
00010  * would probably have to be combined into one rZero module, due to
00011  * their reliance on one another.
00012  *
00013  * Please see:
00014  *   /doc/memoryManagement.kwd
00015  *   /doc/memoryMap.kwd
00016  *   /src/pager.{c,h}
00017  *
00018  * (c)2002 dcipher / neuraldk
00019  *           www.neuraldk.org
00020  */
00021 
00022 #include "memory.h"
00023 
00024 // global variables describing memory size
00025 long totalMemory, totalPages;
00026 long dmaMemorySize, appMemorySize;
00027 long dmaMemoryPages, appMemoryPages;
00028 
00029 // staring and ending pages which the kernel occupies
00030 long kernelStart;
00031 long kernelEnd;
00032 
00033 pageStack appStack;  // memory available for apps (and kernel...)
00034 pageStack dmaStack;  // memory below 16MB, used for DMA
00035 
00036 void memoryInit(void) {
00037   /* currently ndk only reserves 4MB for DMA... and it
00038    * should be noted the OS itself is withen the first 4MB.
00039    * I might port this to an rZero module and allow it to
00040    * be run time configureable (through rZero module's
00041    * "init" routine).
00042    */
00043 
00044   consoleOut("Usable memory: [Lower: %dkb, Upper %dkb]\n",
00045                              multibootInfo->mem_lower,
00046                              multibootInfo->mem_upper);
00047 
00048   // don't use mem_lower to calculate total memory... it'll return
00049   // 640k (ie, it doesn't include the bios).  Use 1024k (ie, 1MB)
00050   totalMemory = (multibootInfo->mem_upper + 1024) * 1024;
00051   totalPages  = totalMemory / PAGE_SIZE;
00052 
00053   // calculate the size (in bytes and pages) of the dma memory range
00054   dmaMemorySize  = 4*1024*1024;
00055   dmaMemoryPages = dmaMemorySize / PAGE_SIZE;
00056 
00057   // calculate the size (in bytes and pages) of the app memory range
00058   appMemorySize  = totalMemory - dmaMemorySize;
00059   appMemoryPages = totalPages - dmaMemoryPages;
00060 
00061   // output some info about or stacks
00062   //consoleOut("bssEnd: 0x%x\n", bssEnd);
00063   consoleOut("DMA Stack: %d pages\n", dmaMemoryPages);
00064   consoleOut("App Stack: %d pages\n", appMemoryPages);
00065 
00066   // kernel is currently always fixed @ 1MB mark, but could be any length
00067   // Use bssEnd to calculate total space used by kernel, remember to round
00068   // kernelEnd _UP_ to the nearest page.
00069   kernelStart = (1024 * 1024) / PAGE_SIZE;
00070   kernelEnd = ((long)&bssEnd + PAGE_SIZE - ((long)&bssEnd & (PAGE_SIZE-1))) / PAGE_SIZE;
00071 
00072   // create both the dma and app stacks in memory above the kernel and
00073   // rZero modules
00074   memoryCreateStacks();
00075   //memoryAllocateKernel();
00076 
00077   return;
00078 }
00079 
00080 /* find a place to put the memory stack, above the kernel
00081  * and rZero modules
00082  * the kernel loads itself @1MB, with rZero modules afterwards
00083  * therefore, to find the end of the kernel, find the end of
00084  * the last rZero module
00085  */
00086 void memoryCreateStacks(void) {
00087   module_t *mod;
00088   long addr;
00089   int i;
00090 
00091   // get the end address of the last module
00092   mod  = (module_t *) multibootInfo->mods_addr;
00093   addr = (long)mod[multibootInfo->mods_count-1].mod_end;
00094 
00095   // make sure it's at least dword aligned (rounding up!)
00096   addr += 4 - (addr & 3);
00097   consoleOut("addr: 0x%8x\n", addr);
00098 
00099   /* The following calculations gave me much grief when
00100    * initially developing this code.  I had replaced addr
00101    * with dmaStack.base, or appStack.base when calculating
00102    * the used base pointer... although the two are exactly
00103    * equivalent (consoleOut confirms), the calculation came
00104    * out wrong!  Just a word of warning...
00105    */
00106 
00107   // first put the dma stack, then the app stack
00108   consoleOut("Creating DMA stack at: 0x%8x\n", addr);
00109   dmaStack.total           = dmaMemoryPages;
00110   dmaStack.avail.flags     = STACK_EXPAND_DOWN;
00111   dmaStack.avail.pointer   = 0; //dmaStack.total - 1;
00112   dmaStack.avail.base      = addr;
00113   dmaStack.used.flags      = STACK_EXPAND_UP;
00114   dmaStack.used.base       = (addr + 4 * dmaMemoryPages);
00115   dmaStack.used.pointer    = 0;
00116   //memoryStackSpecs(&dmaStack);
00117 
00118   addr = (long)dmaStack.used.base;  // NOTE: + 4 needed?
00119   consoleOut("Creating Application stack at: 0x%8x\n", addr);
00120   appStack.total           = appMemoryPages;
00121   appStack.avail.flags     = STACK_EXPAND_DOWN;
00122   appStack.avail.pointer   = 0; //appStack.total - 1;
00123   appStack.avail.base      = addr;
00124   appStack.used.flags      = STACK_EXPAND_UP;
00125   appStack.used.base       = (addr + 4 * appMemoryPages);
00126   appStack.used.pointer    = 0;
00127   //memoryStackSpecs(&appStack);
00128 
00129   // fill the dma stack with all pages (unless they're already in
00130   // use, by the kernel)
00131   for(i = 0; i < dmaStack.total; i++) {
00132     if(!memoryPageUsedByKernel(i))
00133       stackPush(&dmaStack.avail, i * PAGE_SIZE);
00134   }
00135 
00136   // fill the app stack with all pages (unless in use by kernel)
00137   for(i = dmaMemoryPages; i < (appStack.total + dmaMemoryPages); i++) {
00138     if(!memoryPageUsedByKernel(i))
00139       stackPush(&appStack.avail, i * PAGE_SIZE);
00140   }
00141 
00142   // print some info 'bout kernel and stacks
00143   consoleOut("Kernel start %d, end %d\n", kernelStart, kernelEnd);
00144 
00145   // what about bss of last module?
00146   // its dynamically allocated by this memory manager, and
00147   // linked in by the rZero code... it's all good! :)
00148 }
00149 
00150 /* Quick and dirty method to tell memoryCreateStacks wether a
00151  * certain page is already in use by the kernel (ie, it was used
00152  * before memory management was introduced).  If it's in use,
00153  * the page isn't included into the page stack.
00154  *
00155  * It should also be noted that it currently isn't included in
00156  * the "used" portion of the stack... there really isn't any
00157  * need for this, either... we aren't going to deallocate the
00158  * kernel!
00159  */
00160 long memoryPageUsedByKernel(long page) {
00161   // if page is withen 0xA0000 and 0xF0000, inclusive, it's the
00162   // bios... don't allow this to be allocated! :)
00163   if(page >= 0xA0000/PAGE_SIZE && page <= 0xF0000/PAGE_SIZE)
00164     return 1;
00165 
00166   // if page is withen 0x90000 and 0x93000 (inc), it's being used for
00167   // system and vm86 page directory + first table, allocate it
00168   if(page >= 0x90000/PAGE_SIZE && page <= 0x93000/PAGE_SIZE)
00169     return 1;
00170 
00171   // if page is withen kernel address range, allocate it
00172   if(page >= kernelStart && page <= kernelEnd)
00173     return 1;
00174 
00175   // first two pages used by pmode idt + gdt and real mode idt
00176   if(page == 0 || page == 1) return 1;
00177 
00178   // we could also provide provisions to allocate the rZero modules
00179   // at this point... but this is already pretty slow... doing this
00180   // check on every single page in the system?  Eh...
00181   return 0;
00182 }
00183 
00184 /* Allocates one (4096) page, returning the physical address.
00185  * The function makes no attempt at mapping into the linear
00186  * address space!
00187  */
00188 void *memoryAllocUnmappedPage(void) {
00189   long physAddr;
00190 
00191   if(appStack.avail.pointer == 0) {
00192     consoleOut("Not enough physical memory!\n");
00193     return 0;
00194   }
00195 
00196   // place the physical address onto the used stack, and
00197   // return it
00198   physAddr = stackPop(&appStack.avail);
00199   stackPush(&appStack.used, physAddr);
00200 
00201   return (void *)physAddr;
00202 }
00203 
00204 void *memoryAllocPage(void) {
00205   long physAddr;
00206   long linAddr;
00207 
00208   physAddr = (long)memoryAllocUnmappedPage();
00209   //consoleOut("Physical Addr: 0x%x\n", physAddr);
00210   linAddr = (long)memoryMapPage((void *)physAddr);
00211   //consoleOut("Linear Addr:   0x%x\n", linAddr);
00212 
00213   return (void *)linAddr;
00214 }
00215 
00216 // NOTE: untested!!!
00217 void *memoryAllocPages(long total) {
00218   long firstPagePhys;
00219   long firstPageLin;
00220   long pagePhys;
00221   long pageLin;
00222 
00223   if(total == 0) return NULL;
00224   if(total == 1) return memoryAllocPage();
00225 
00226   // we now know we want at least two pages, exactly enough to
00227   // fit a "multi-page" entry in the page stack
00228 
00229   // grab those two pages
00230   firstPagePhys = (long)stackPop(&appStack.avail);
00231   pagePhys      = (long)stackPop(&appStack.avail);
00232 
00233   // convert the first page to a linear address (and map it)
00234   firstPageLin = (long)memoryMapPage((void *)firstPagePhys);
00235 
00236   // and add the multi-page entry into the used stack
00237   stackPush(&appStack.used, firstPageLin & MULTI_PAGE_ENTRY);
00238   stackPush(&appStack.used, total);
00239 
00240   // we've just allocated two pages... account for them...
00241   total -= 2;
00242 
00243   // allocate all other pages
00244   while(total--) {
00245     // get a new page
00246     pagePhys = (long)stackPop(&appStack.avail);
00247     // and map it (we don't care about the return value)
00248     memoryMapPage((void *)pagePhys);
00249   }
00250 
00251   return (void *)firstPageLin;
00252 }
00253 
00254 // NOTE: This is not MULTI_PAGE_ENTRY aware yet!!!
00255 void memoryFreePage(void *linAddr) {
00256   long *pages = (long *)0xffc00000;
00257   long  physAddr;
00258   pageStack *pStack;
00259   long  i = 0;
00260   long  pTable, pTableIndex;
00261   unsigned long pageOffset;
00262 
00263   // convert the linear address to a physical one
00264   // NOTE: because of the "and" mask, this function will
00265   // deallocate addresses that aren't page aligned.
00266   // ie, 0x1005 will remove 0x1000
00267   linAddr  = (void *)((long)linAddr & 0xfffff000);
00268   physAddr = (long)pagerLinToPhys(linAddr);
00269   consoleOut("removing physical address 0x%8x\n", physAddr);
00270 
00271   // select the correct page stack, based on where the physical
00272   // address resides
00273   if((long)physAddr < TOP_OF_DMA_STACK) pStack = &dmaStack;
00274   else pStack = &appStack;
00275 
00276   // find the physical address in the used stack
00277   while(stackPeek(&pStack->used, i) != physAddr) {
00278     i++;
00279     if(i == pStack->used.pointer) {
00280       consoleOut("Cannot deallocate 0x%8x; Not allocated!\n", physAddr);
00281       return;
00282     }
00283   }
00284 
00285   consoleOut("Copying from used to available stack\n");
00286   // copy address from used stack, to available stack
00287   // and "increment" pointers accordingly.
00288   stackRemove(&pStack->used, i, 1);
00289   stackPush(&pStack->avail, physAddr);
00290 
00291 
00292   // now remove page from page directory (include in pager.c?!)
00293   pageOffset = (unsigned long)linAddr >> 12;
00294   consoleOut("Removing from page directory (%d)\n", pageOffset);
00295 
00296   consoleOut("Invalidating TLB (0x%8x)\n", (unsigned long)linAddr);
00297   invalidatePage( (unsigned long)linAddr );
00298 
00299   pages[(unsigned long)pageOffset] = 0;
00300 
00301   return;
00302 }
00303 
00304 /*
00305 void *memoryAllocatePages(long numPages) {
00306   void *linStartAddr;
00307   long  physStartAddr;
00308   long  i, pointer;
00309 
00310   // check if there's enough pages available
00311   if(appStack.pointer < numPages) {
00312     consoleOut("Not enough physical memory!\n");
00313     return 0;
00314   } else {
00315     // remove these pages from the stack right away, so any other
00316     // attempt to call this function won't allocate the same
00317     // range of memory... or should I loop through this one at a time... (yes)
00318     pointer = appStack.pointer;
00319     appStack.pointer -= numPages;
00320   }
00321 
00322   // keep track of the starting page in physical and linear address space
00323   physStartAddr = appStack.base[pointer--];
00324   consoleOut("First page, physical: 0x%8x ", physStartAddr);
00325 
00326   // find a chunk in linear address space that'll hold the newly allocated
00327   // memory
00328   linStartAddr = (void *)memoryFindLinearChunk(numPages);
00329   if(linStartAddr = 0x0) {
00330     consoleOut("Not enough linear memory!\n");
00331     return 0;
00332   }
00333   //linStartAddr = (void *)pagerMapPage(physStartAddr);
00334   consoleOut("linear 0x%8x\n", linStartAddr);
00335 
00336   // map the rest of the pages into the apps linear address space
00337   for(i = 1; i < numPages; i++) {
00338     consoleOut("Allocating page #%d\n", i);
00339     pagerMapPage(appStack.base[pointer--]);
00340   }
00341 
00342   consoleOut("Marking pages as used\n");
00343   // now mark these pages into the "used" stack
00344   if(numPages > 1) {
00345     consoleOut("  more than one\n");
00346     *(long *)(appStack.used.base - (appStack.used.pointer++)) = numPages;
00347     *(long *)(appStack.used.base - (appStack.used.pointer++)) = physStartAddr &
00348                                                             (MULTI_PAGE_ENTRY);
00349   }
00350   else {
00351     consoleOut("  just one\n");
00352     *(long *)(appStack.used.base - (appStack.used.pointer++)) = physStartAddr;
00353   }
00354   consoleOut("returning\n");
00355   return linStartAddr;
00356 }
00357 */
00358 
00359 /*
00360 void memoryFreePages(void *addr) {
00361   long  pageNum = 0;
00362   long  numPages;
00363   long  pointer;
00364   long *pages;
00365   long  physAddr;
00366   pageStack *pStack;
00367 
00368   // Because the page directory is mapped into itself, as the last
00369   // page table, all physical pages in the linear address space are
00370   // included in the top 4MB...
00371   //
00372   pages = (long *)0xffc00000;
00373 
00374   // addr will be in linear address space... convert it to physical
00375   while(pages[pageNum] != (long)addr) pageNum++;
00376   physAddr = pages[pageNum];
00377 
00378   if((long)physAddr < TOP_OF_DMA_STACK) pStack = &dmaStack;
00379   else pStack = &appStack;
00380 
00381   // now search for this physical address in the used page stack
00382   pointer = pStack->used.pointer;
00383   while( (pStack->used.base[pointer] & 0xfffff000) != physAddr) {
00384     if(pStack->used.base[pointer] & MULTI_PAGE_ENTRY) pointer -= 2;
00385     else pointer -= 1;
00386   }
00387 
00388   // how many pages are associated with this deallocation?
00389   if(pStack->used.base[pointer] & MULTI_PAGE_ENTRY)
00390     numPages = pStack->used.base[pointer-1];
00391   else numPages = 1;
00392 
00393   // remove pages from the used stack...
00394   // copy top of stack overtop of, soon-to-be, deallocated page
00395   pStack->used.base[pointer] = pStack->used.base[pStack->used.pointer];
00396   pStack->used.pointer--;
00397 
00398   // if this is a multi-page deallocation, copy over the page count too
00399   if(numPages > 1) {
00400     pStack->used.base[pointer-1] = pStack->used.base[pStack->used.pointer];
00401     pStack->used.pointer--;
00402   }
00403 
00404   // and, finally, remove these pages from the tasks paging directory
00405   while(numPages--)
00406     pages[pageNum++] = 0;
00407 }
00408 */
00409 
00410 /* Maps physAddr into the linear address space where-ever there
00411  * is an available page (should be in pager.c!?)
00412  */
00413 void *memoryMapPage(void *physAddr) {
00414   long *pages = (long *)0xffc00000;
00415   long  pageNum = ALLOC_OFFSET;
00416   long  pTableNum;
00417 
00418   consoleOut("memoryMapPage: 0x%8x\n", physAddr);
00419   pTableNum = pageNum / 1024;
00420   pageNum &= 1023;
00421   while(1) {
00422     // if the current page table isn't allocated, create it
00423     if(!pagerTableExists(pTableNum))
00424       pagerCreateTable(pTableNum);
00425 
00426     // if this page is empty, use it, and return the
00427     // linear address
00428     // NOTE: pages[pageNum] not correct... pageNum = 0...1023
00429     if(pages[(pTableNum*1024)+pageNum] == 0) {
00430       pages[(pTableNum*1024)+pageNum] = (long) physAddr  | PAGE_PRESENT
00431                                                          | PAGE_READ_WRITE
00432                                                          | PAGE_P3_ACCESS;
00433       return (void *)((pTableNum*1024)*4096)+(pageNum * 4096);
00434     }
00435 
00436     // incrememnt to the next page
00437     pageNum++;
00438 
00439     // if we've gone through 1024 pages, go to the next table
00440     if(pageNum == 1024) {
00441       pTableNum++;
00442       pageNum = 0;
00443     }
00444 
00445     // out of memory!
00446     if(pTableNum == 1024) return 0;
00447   }
00448 }
00449 
00450 /*
00451 void *memoryFindLinearChunk(long size) {
00452   void *linearAddr;
00453   long *pages = 0xffc00000;
00454   //long *pgDir = 0xfffff000;
00455   long  pTableNum;
00456   long  pageNum;
00457   // start allocating pages at the 2GB mark (linear)
00458   long  startAtPage = ALLOC_OFFSET;//524288;
00459   long  remainingPages = size;
00460 
00461   pageNum = startAtPage;
00462   remainingPages = size;
00463   pTableNum = pageNum / 1024;
00464   while(remainingPages) {
00465     if(!pagerTableExists(pTableNum))
00466       pagerCreateTable(pTableNum);
00467 
00468     // is the next page empty?
00469     if(pages[pageNum] == 0) {
00470       remainingPages--;
00471     } else {
00472       remainingPages = size;
00473     }
00474 
00475     // incrememnt to the next page
00476     pageNum++;
00477 
00478     // if we've gone through 1024 pages, go to the next table
00479     if(pageNum == 1024) {
00480       pTableNum++;
00481       pageNum = 0;
00482     }
00483   }
00484 
00485   return linearAddr;
00486 }
00487 */
00488 
00489 /* Allocate only the kernel data, code and bss sections.  The rZero
00490  * modules will be allocated via separate calls to the memory manager,
00491  * so that they may be removed from memory independantly from the
00492  * kernel (such as the splashScreen, which serves no purpose in memory
00493  * past boot up).
00494  */
00495 /*
00496 void memoryAllocateKernel(void) {
00497   // allocate the kernel itself
00498   memoryAllocateUsedPages(kernelStart, kernelEnd - kernelStart);
00499   // allocate the pmode idt + gdt, and real mode idt
00500   memoryAllocateUsedPages(0, 2);
00501   // allocate the kernel + vm86 page directory + table
00502   memoryAllocateUsedPages(0x90000/PAGE_SIZE, 4);
00503 }
00504 */
00505 
00506 /* This function is used the allocate pages that have been used by the
00507  * kernel, prior to memory management being introduced
00508  */
00509 /*
00510 void memoryAllocateUsedPages(long startPage, long totalPages) {
00511   pageStack *ps;
00512   long i;
00513   long startAddr = startPage * PAGE_SIZE;
00514 
00515   // allocate from the correct stack (problems arise
00516   // if the allocation spans tables, but it never should
00517   // at this point... the kernel should pretty much
00518   // always reside withen the dmaStack anyway)
00519   if(startPage < dmaStack.total) pageStack = &dmaStack;
00520   else pageStack = &appStack;
00521 
00522   // find the right page
00523   for(i = 0; i < ps->pointer; i++)
00524     if(startAddr == ps->base[i]) {
00525       // remove these pages from the stack, copying the
00526       // other address upwards
00527       memcpy(&ps->base[i], &ps->base[i] + (totalPages*4),
00528              &ps->base[pointer] - (startPage + totalPages);
00529     }
00530 }
00531 */
00532 
00533 void memoryStackSpecs(pageStack *pStack) {
00534   consoleOut("  Total:     %d\n"
00535          "  pointer:   %d\n"
00536          "  base:      0x%8x\n"
00537          "  Used:\n"
00538          "    pointer: %d\n"
00539          "    base:    0x%8x\n",
00540         pStack->total,
00541         pStack->avail.pointer,
00542         pStack->avail.base,
00543         pStack->used.pointer,
00544         pStack->used.base
00545   );
00546 }

Generated on Sun Nov 21 18:26:11 2004 for ndk by doxygen 1.3.2