Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:41

0001 /*
0002  * page.c :- This file contains implementation of C function to
0003  *           Instanciate paging. More detailled information
0004  *       can be found on Intel site and more precisely in
0005  *           the following book :
0006  *
0007  *      Pentium Processor familly
0008  *      Developper's Manual
0009  *
0010  *      Volume 3 : Architecture and Programming Manual
0011  *
0012  * Copyright (C) 1999  Emmanuel Raguet (raguet@crf.canon.fr)
0013  *                     Canon Centre Recherche France.
0014  *
0015  *  The license and distribution terms for this file may be
0016  *  found in the file LICENSE in this distribution or at
0017  *  http://www.rtems.org/license/LICENSE.
0018  */
0019 
0020 #include <stdio.h>
0021 #include <stdlib.h>
0022 #include <string.h>
0023 #include <rtems.h>
0024 #include <rtems/score/cpu.h>
0025 #include <libcpu/page.h>
0026 
0027 #define MEMORY_SIZE 0x4000000       /* 64Mo */
0028 
0029 static int directoryEntry=0;
0030 static int tableEntry=0;
0031 static page_directory *pageDirectory;
0032 
0033 extern uint32_t   bsp_mem_size;
0034 
0035 /*************************************************************************/
0036 /************** IT IS A ONE-TO-ONE TRANSLATION ***************************/
0037 /*************************************************************************/
0038 
0039 
0040 /*
0041  * Disable the paging
0042  */
0043 void _CPU_disable_paging(void)
0044 {
0045   unsigned int regCr0;
0046 
0047   rtems_cache_flush_entire_data();
0048   regCr0 = i386_get_cr0();
0049   regCr0 &= ~(CR0_PAGING);
0050   i386_set_cr0( regCr0 );
0051 }
0052 
0053 /*
0054  * Enable the paging
0055  */
0056 void _CPU_enable_paging(void)
0057 {
0058   unsigned int regCr0;
0059 
0060   regCr0 = i386_get_cr0();
0061   regCr0 |= CR0_PAGING;
0062   i386_set_cr0( regCr0 );
0063   rtems_cache_flush_entire_data();
0064 }
0065 
0066 
0067 /*
0068  * Initialize the paging with 1-to-1 mapping
0069  */
0070 
0071 int init_paging(void)
0072 {
0073   int nbPages;
0074   int nbInitPages;
0075   char *Tables;
0076   unsigned int regCr3;
0077   page_table *pageTable;
0078   unsigned int physPage;
0079   int nbTables=0;
0080 
0081   nbPages = ( (bsp_mem_size - 1) / PG_SIZE ) + 1;
0082   nbTables = ( (bsp_mem_size - 1) / FOUR_MB ) + 2;
0083 
0084   /* allocate 1 page more to page alignement */
0085   Tables = (char *)malloc( (nbTables + 1)*sizeof(page_table) );
0086   if ( Tables == NULL ){
0087     return -1; /*unable to allocate memory */
0088   }
0089 
0090   /* 4K-page alignement */
0091   Tables += (PG_SIZE - (int)Tables) & 0xFFF;
0092 
0093   /* Reset Tables */
0094   memset( Tables, 0, nbTables*sizeof(page_table) );
0095   pageDirectory = (page_directory *) Tables;
0096   pageTable     = (page_table *)((int)Tables + PG_SIZE);
0097 
0098   nbInitPages = 0;
0099   directoryEntry = 0;
0100   tableEntry = 0;
0101   physPage = 0;
0102 
0103   while ( nbInitPages != nbPages ){
0104     if ( tableEntry == 0 ){
0105       pageDirectory->pageDirEntry[directoryEntry].bits.page_frame_address = (unsigned int)pageTable >> 12;
0106       pageDirectory->pageDirEntry[directoryEntry].bits.available      = 0;
0107       pageDirectory->pageDirEntry[directoryEntry].bits.page_size      = 0;
0108       pageDirectory->pageDirEntry[directoryEntry].bits.accessed       = 0;
0109       pageDirectory->pageDirEntry[directoryEntry].bits.cache_disable  = 0;
0110       pageDirectory->pageDirEntry[directoryEntry].bits.write_through  = 0;
0111       pageDirectory->pageDirEntry[directoryEntry].bits.user           = 1;
0112       pageDirectory->pageDirEntry[directoryEntry].bits.writable       = 1;
0113       pageDirectory->pageDirEntry[directoryEntry].bits.present        = 1;
0114     }
0115     pageTable->pageTableEntry[tableEntry].bits.page_frame_address = physPage;
0116     pageTable->pageTableEntry[tableEntry].bits.available      = 0;
0117     pageTable->pageTableEntry[tableEntry].bits.dirty          = 0;
0118     pageTable->pageTableEntry[tableEntry].bits.accessed       = 0;
0119     pageTable->pageTableEntry[tableEntry].bits.cache_disable  = 0;
0120     pageTable->pageTableEntry[tableEntry].bits.write_through  = 0;
0121     pageTable->pageTableEntry[tableEntry].bits.user           = 1;
0122     pageTable->pageTableEntry[tableEntry].bits.writable       = 1;
0123     pageTable->pageTableEntry[tableEntry].bits.present        = 1;
0124 
0125     physPage ++;
0126     tableEntry ++;
0127 
0128     if (tableEntry >= MAX_ENTRY){
0129       tableEntry = 0;
0130       directoryEntry ++;
0131       pageTable ++;
0132     }
0133 
0134     nbInitPages++;
0135   }
0136 
0137   regCr3 &= ~(CR3_PAGE_WRITE_THROUGH);
0138   regCr3 &= ~(CR3_PAGE_CACHE_DISABLE);
0139   /*regCr3.cr3.page_directory_base    = (unsigned int)pageDirectory >> 12;*/
0140   regCr3 = (unsigned int)pageDirectory & CR3_PAGE_DIRECTORY_MASK;
0141 
0142   i386_set_cr3( regCr3 );
0143 
0144   _CPU_enable_cache();
0145   _CPU_enable_paging();
0146 
0147   return 0;
0148 }
0149 
0150 /*
0151  * Is cache enable
0152  */
0153 int  _CPU_is_cache_enabled(void)
0154 {
0155   unsigned int regCr0;
0156 
0157   regCr0 = i386_get_cr0();
0158   return( ~(regCr0 & CR0_PAGE_LEVEL_CACHE_DISABLE) );
0159 }
0160 
0161 /*
0162  * Is paging enable
0163  */
0164 int  _CPU_is_paging_enabled(void)
0165 {
0166   unsigned int regCr0;
0167 
0168   regCr0 = i386_get_cr0();
0169   return(regCr0 & CR0_PAGING);
0170 }
0171 
0172 
0173 /*
0174  * Translate the physical address in the virtual space and return
0175  * the translated address in mappedAddress
0176  */
0177 
0178 int _CPU_map_phys_address(
0179   void **mappedAddress,
0180   void  *physAddress,
0181   int    size,
0182   int    flag
0183 )
0184 {
0185   page_table *localPageTable;
0186   unsigned int lastAddress, countAddress;
0187   char *Tables;
0188   linear_address virtualAddress;
0189   unsigned char pagingWasEnabled;
0190 
0191   pagingWasEnabled = 0;
0192 
0193   if (_CPU_is_paging_enabled()){
0194     pagingWasEnabled = 1;
0195     _CPU_disable_paging();
0196   }
0197 
0198   countAddress = (unsigned int)physAddress;
0199   lastAddress = (unsigned int)physAddress + (size - 1);
0200   virtualAddress.address = 0;
0201 
0202   while (1) {
0203 
0204     if ((countAddress & ~MASK_OFFSET) > (lastAddress & ~MASK_OFFSET))
0205       break;
0206 
0207     /* Need to allocate a new page table */
0208     if (pageDirectory->pageDirEntry[directoryEntry].bits.page_frame_address == 0){
0209       /* We allocate 2 pages to perform 4k-page alignement */
0210       Tables = (char *)malloc(2*sizeof(page_table));
0211       if ( Tables == NULL ){
0212     if (pagingWasEnabled)
0213       _CPU_enable_paging();
0214     return -1; /* unable to allocate memory */
0215       }
0216       /* 4K-page alignement */
0217       Tables += (PG_SIZE - (int)Tables) & 0xFFF;
0218 
0219       /* Reset Table */
0220       memset( Tables, 0, sizeof(page_table) );
0221       pageDirectory->pageDirEntry[directoryEntry].bits.page_frame_address =
0222     (unsigned int)Tables >> 12;
0223       pageDirectory->pageDirEntry[directoryEntry].bits.available      = 0;
0224       pageDirectory->pageDirEntry[directoryEntry].bits.page_size      = 0;
0225       pageDirectory->pageDirEntry[directoryEntry].bits.accessed       = 0;
0226       pageDirectory->pageDirEntry[directoryEntry].bits.cache_disable  = 0;
0227       pageDirectory->pageDirEntry[directoryEntry].bits.write_through  = 0;
0228       pageDirectory->pageDirEntry[directoryEntry].bits.user           = 1;
0229       pageDirectory->pageDirEntry[directoryEntry].bits.writable       = 1;
0230       pageDirectory->pageDirEntry[directoryEntry].bits.present        = 1;
0231     }
0232 
0233 
0234     localPageTable = (page_table *)(pageDirectory->
0235                     pageDirEntry[directoryEntry].bits.
0236                     page_frame_address << 12);
0237 
0238     if (virtualAddress.address == 0){
0239       virtualAddress.bits.directory = directoryEntry;
0240       virtualAddress.bits.page      = tableEntry;
0241       virtualAddress.bits.offset    = (unsigned int)physAddress & MASK_OFFSET;
0242     }
0243 
0244     localPageTable->pageTableEntry[tableEntry].bits.page_frame_address =
0245       ((unsigned int)countAddress & ~MASK_OFFSET) >> 12;
0246     localPageTable->pageTableEntry[tableEntry].bits.available      = 0;
0247     localPageTable->pageTableEntry[tableEntry].bits.dirty          = 0;
0248     localPageTable->pageTableEntry[tableEntry].bits.accessed       = 0;
0249     localPageTable->pageTableEntry[tableEntry].bits.cache_disable  = 0;
0250     localPageTable->pageTableEntry[tableEntry].bits.write_through  = 0;
0251     localPageTable->pageTableEntry[tableEntry].bits.user           = 1;
0252     localPageTable->pageTableEntry[tableEntry].bits.writable       = 0;
0253     localPageTable->pageTableEntry[tableEntry].bits.present        = 1;
0254 
0255     localPageTable->pageTableEntry[tableEntry].table_entry |= flag ;
0256 
0257     countAddress += PG_SIZE;
0258     tableEntry++;
0259     if (tableEntry >= MAX_ENTRY){
0260       tableEntry = 0;
0261       directoryEntry++;
0262     }
0263   }
0264 
0265   if (mappedAddress != 0)
0266     *mappedAddress = (void *)(virtualAddress.address);
0267   if (pagingWasEnabled)
0268     _CPU_enable_paging();
0269   return 0;
0270 }
0271 
0272 /*
0273  * "Compress" the Directory and Page tables to avoid
0274  * important loss of address range
0275  */
0276 static void Paging_Table_Compress(void)
0277 {
0278   unsigned int dirCount, pageCount;
0279   page_table *localPageTable;
0280 
0281   if (tableEntry == 0){
0282     dirCount  = directoryEntry - 1;
0283     pageCount = MAX_ENTRY - 1;
0284   }
0285   else {
0286     dirCount  = directoryEntry;
0287     pageCount = tableEntry - 1;
0288   }
0289 
0290   while (1){
0291 
0292     localPageTable = (page_table *)(pageDirectory->
0293                     pageDirEntry[dirCount].bits.
0294                     page_frame_address << 12);
0295 
0296     if (localPageTable->pageTableEntry[pageCount].bits.present == 1){
0297       pageCount++;
0298       if (pageCount >= MAX_ENTRY){
0299     pageCount = 0;
0300     dirCount++;
0301       }
0302       break;
0303     }
0304 
0305 
0306     if (pageCount == 0) {
0307       if (dirCount == 0){
0308     break;
0309       }
0310       else {
0311     pageCount = MAX_ENTRY - 1;
0312     dirCount-- ;
0313       }
0314     }
0315     else
0316       pageCount-- ;
0317   }
0318 
0319   directoryEntry = dirCount;
0320   tableEntry = pageCount;
0321 }
0322 
0323 
0324 /*
0325  * Unmap the virtual address from the tables
0326  * (we do not deallocate the table already allocated)
0327  */
0328 
0329 int _CPU_unmap_virt_address(
0330   void *mappedAddress,
0331   int   size
0332 )
0333 {
0334 
0335   linear_address linearAddr;
0336   page_table *localPageTable;
0337   unsigned int lastAddr ;
0338   unsigned char pagingWasEnabled;
0339 
0340   pagingWasEnabled = 0;
0341 
0342   if (_CPU_is_paging_enabled()){
0343     pagingWasEnabled = 1;
0344     _CPU_disable_paging();
0345   }
0346 
0347   linearAddr.address = (unsigned int)mappedAddress;
0348   lastAddr = (unsigned int)mappedAddress + (size - 1);
0349 
0350   while (1){
0351 
0352     if ((linearAddr.address & ~MASK_OFFSET) > (lastAddr & ~MASK_OFFSET))
0353       break;
0354 
0355     if (pageDirectory->pageDirEntry[linearAddr.bits.directory].bits.present == 0){
0356       if (pagingWasEnabled)
0357     _CPU_enable_paging();
0358       return -1;
0359     }
0360 
0361     localPageTable = (page_table *)(pageDirectory->
0362                     pageDirEntry[linearAddr.bits.directory].bits.
0363                     page_frame_address << 12);
0364 
0365     if (localPageTable->pageTableEntry[linearAddr.bits.page].bits.present == 0){
0366       if (pagingWasEnabled)
0367     _CPU_enable_paging();
0368       return -1;
0369     }
0370 
0371     localPageTable->pageTableEntry[linearAddr.bits.page].bits.present = 0;
0372 
0373     linearAddr.address += PG_SIZE ;
0374   }
0375   Paging_Table_Compress();
0376   if (pagingWasEnabled)
0377     _CPU_enable_paging();
0378 
0379   return 0;
0380 }
0381 
0382 /*
0383  * Modify the flags PRESENT, WRITABLE, USER, WRITE_TROUGH, CACHE_DISABLE
0384  * of the page's descriptor.
0385  */
0386 
0387 int _CPU_change_memory_mapping_attribute(
0388   void         **newAddress,
0389   void          *mappedAddress,
0390   unsigned int   size,
0391   unsigned int   flag
0392 )
0393 {
0394 
0395   linear_address linearAddr;
0396   page_table *localPageTable;
0397   unsigned int lastAddr ;
0398   unsigned char pagingWasEnabled;
0399 
0400   pagingWasEnabled = 0;
0401 
0402   if (_CPU_is_paging_enabled()){
0403     pagingWasEnabled = 1;
0404     _CPU_disable_paging();
0405   }
0406 
0407   linearAddr.address  = (unsigned int)mappedAddress;
0408   lastAddr = (unsigned int)mappedAddress + (size - 1);
0409 
0410   while (1){
0411 
0412     if ((linearAddr.address & ~MASK_OFFSET) > (lastAddr & ~MASK_OFFSET))
0413       break;
0414 
0415     if (pageDirectory->pageDirEntry[linearAddr.bits.directory].bits.present == 0){
0416       if (pagingWasEnabled)
0417     _CPU_enable_paging();
0418       return -1;
0419     }
0420     localPageTable = (page_table *)(pageDirectory->
0421                     pageDirEntry[linearAddr.bits.directory].bits.
0422                     page_frame_address << 12);
0423 
0424     if (localPageTable->pageTableEntry[linearAddr.bits.page].bits.present == 0){
0425       if (pagingWasEnabled)
0426     _CPU_enable_paging();
0427       return -1;
0428     }
0429 
0430     localPageTable->pageTableEntry[linearAddr.bits.page].table_entry &= ~MASK_FLAGS ;
0431     localPageTable->pageTableEntry[linearAddr.bits.page].table_entry |= flag ;
0432 
0433     linearAddr.address += PG_SIZE ;
0434   }
0435 
0436   if (newAddress != NULL)
0437     *newAddress = mappedAddress ;
0438 
0439   if (pagingWasEnabled)
0440     _CPU_enable_paging();
0441 
0442   return 0;
0443 }
0444 
0445 /*
0446  * Display the page descriptor flags
0447  * CACHE_DISABLE of the whole memory
0448  */
0449 
0450 #include <rtems/bspIo.h>
0451 
0452 int  _CPU_display_memory_attribute(void)
0453 {
0454   unsigned int dirCount, pageCount;
0455   unsigned int regCr0;
0456   page_table *localPageTable;
0457   unsigned int prevCache;
0458   unsigned int prevPresent;
0459   unsigned int maxPage;
0460   unsigned char pagingWasEnabled;
0461 
0462   regCr0 = i386_get_cr0();
0463 
0464   printk("\n\n********* MEMORY CACHE CONFIGURATION *****\n");
0465 
0466   printk("CR0 -> paging           : %s\n",((regCr0 & CR0_PAGING) ? "ENABLE ":"DISABLE"));
0467   printk("       page-level cache : %s\n\n",((regCr0 & CR0_PAGE_LEVEL_CACHE_DISABLE) ? "DISABLE":"ENABLE"));
0468 
0469   if ((regCr0 & CR0_PAGING) == 0)
0470     return 0;
0471 
0472   prevPresent = 0;
0473   prevCache   = 1;
0474 
0475   pagingWasEnabled = 0;
0476 
0477   if (_CPU_is_paging_enabled()){
0478     pagingWasEnabled = 1;
0479     _CPU_disable_paging();
0480   }
0481 
0482   for (dirCount = 0; dirCount < directoryEntry+1; dirCount++) {
0483 
0484     localPageTable = (page_table *)(pageDirectory->
0485                     pageDirEntry[dirCount].bits.
0486                     page_frame_address << 12);
0487 
0488     maxPage = MAX_ENTRY;
0489     /*if ( dirCount == (directoryEntry-1))
0490       maxPage = tableEntry;*/
0491     for (pageCount = 0; pageCount < maxPage; pageCount++) {
0492 
0493       if (localPageTable->pageTableEntry[pageCount].bits.present != 0){
0494     if (prevPresent == 0){
0495       prevPresent = 1;
0496       printk ("present page from address %x \n", ((dirCount << 22)|(pageCount << 12)));
0497     }
0498     if (prevCache != localPageTable->pageTableEntry[pageCount].bits.cache_disable ) {
0499       prevCache = localPageTable->pageTableEntry[pageCount].
0500         bits.cache_disable;
0501       printk ("    cache %s from %x <phy %x>\n",
0502           (prevCache ? "DISABLE" : "ENABLE "),
0503           ((dirCount << 22)|(pageCount << 12)),
0504           localPageTable->pageTableEntry[pageCount].bits.page_frame_address << 12);
0505     }
0506       }
0507       else {
0508     if (prevPresent == 1){
0509       prevPresent = 0;
0510       printk ("Absent from %x \n", ((dirCount << 22)|(pageCount << 12)));
0511     }
0512       }
0513     }
0514   }
0515   if (pagingWasEnabled)
0516     _CPU_enable_paging();
0517 
0518   return 0;
0519 }