/* * page.c :- This file contains implementation of C function to * Instanciate paging. More detailled information * can be found on Intel site and more precisely in * the following book : * * Pentium Processor familly * Developper's Manual * * Volume 3 : Architecture and Programming Manual * * Copyright (C) 1999 Emmanuel Raguet (raguet@crf.canon.fr) * Canon Centre Recherche France. * * The license and distribution terms for this file may be * found in found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * * $Header$ */ #include #include #include #include #include #define MEMORY_SIZE 0x4000000 /* 64Mo */ static int directoryEntry=0; static int tableEntry=0; static page_directory *pageDirectory; extern uint32_t rtemsFreeMemStart; /*************************************************************************/ /************** IT IS A ONE-TO-ONE TRANSLATION ***************************/ /*************************************************************************/ /* * Disable the paging */ void _CPU_disable_paging() { cr0 regCr0; rtems_cache_flush_entire_data(); regCr0.i = i386_get_cr0(); regCr0.cr0.paging = 0; i386_set_cr0( regCr0.i ); } /* * Enable the paging */ void _CPU_enable_paging() { cr0 regCr0; regCr0.i = i386_get_cr0(); regCr0.cr0.paging = 1; i386_set_cr0( regCr0.i ); rtems_cache_flush_entire_data(); } /* * Initialize the paging with 1-to-1 mapping */ int init_paging() { int memorySize; int nbPages; int nbInitPages; char *Tables; cr3 regCr3; page_table *pageTable; unsigned int physPage; int nbTables=0; /* * rtemsFreeMemStart is the last valid 32-bits address * so the size is rtemsFreeMemStart + 4 */ memorySize = rtemsFreeMemStart + 4; nbPages = ( (memorySize - 1) / PG_SIZE ) + 1; nbTables = ( (memorySize - 1) / FOUR_MB ) + 2; /* allocate 1 page more to page alignement */ Tables = (char *)malloc( (nbTables + 1)*sizeof(page_table) ); if ( Tables == NULL ){ return -1; /*unable to allocate memory */ } /* 4K-page alignement */ Tables += (PG_SIZE - (int)Tables) & 0xFFF; /* Reset Tables */ memset( Tables, 0, nbTables*sizeof(page_table) ); pageDirectory = (page_directory *) Tables; pageTable = (page_table *)((int)Tables + PG_SIZE); nbInitPages = 0; directoryEntry = 0; tableEntry = 0; physPage = 0; while ( nbInitPages != nbPages ){ if ( tableEntry == 0 ){ pageDirectory->pageDirEntry[directoryEntry].bits.page_frame_address = (unsigned int)pageTable >> 12; pageDirectory->pageDirEntry[directoryEntry].bits.available = 0; pageDirectory->pageDirEntry[directoryEntry].bits.page_size = 0; pageDirectory->pageDirEntry[directoryEntry].bits.accessed = 0; pageDirectory->pageDirEntry[directoryEntry].bits.cache_disable = 0; pageDirectory->pageDirEntry[directoryEntry].bits.write_through = 0; pageDirectory->pageDirEntry[directoryEntry].bits.user = 1; pageDirectory->pageDirEntry[directoryEntry].bits.writable = 1; pageDirectory->pageDirEntry[directoryEntry].bits.present = 1; } pageTable->pageTableEntry[tableEntry].bits.page_frame_address = physPage; pageTable->pageTableEntry[tableEntry].bits.available = 0; pageTable->pageTableEntry[tableEntry].bits.dirty = 0; pageTable->pageTableEntry[tableEntry].bits.accessed = 0; pageTable->pageTableEntry[tableEntry].bits.cache_disable = 0; pageTable->pageTableEntry[tableEntry].bits.write_through = 0; pageTable->pageTableEntry[tableEntry].bits.user = 1; pageTable->pageTableEntry[tableEntry].bits.writable = 1; pageTable->pageTableEntry[tableEntry].bits.present = 1; physPage ++; tableEntry ++; if (tableEntry >= MAX_ENTRY){ tableEntry = 0; directoryEntry ++; pageTable ++; } nbInitPages++; } regCr3.cr3.page_write_transparent = 0; regCr3.cr3.page_cache_disable = 0; regCr3.cr3.page_directory_base = (unsigned int)pageDirectory >> 12; i386_set_cr3( regCr3.i ); _CPU_enable_cache(); _CPU_enable_paging(); return 0; } /* * Is cache enable */ int _CPU_is_cache_enabled() { cr0 regCr0; regCr0.i = i386_get_cr0(); return( ~(regCr0.cr0.page_level_cache_disable) ); } /* * Is paging enable */ int _CPU_is_paging_enabled() { cr0 regCr0; regCr0.i = i386_get_cr0(); return(regCr0.cr0.paging); } /* * Translate the physical address in the virtual space and return * the translated address in mappedAddress */ int _CPU_map_phys_address (void **mappedAddress, void *physAddress, int size, int flag){ page_table *localPageTable; unsigned int lastAddress, countAddress; char *Tables; linear_address virtualAddress; unsigned char pagingWasEnabled; pagingWasEnabled = 0; if (_CPU_is_paging_enabled()){ pagingWasEnabled = 1; _CPU_disable_paging(); } countAddress = (unsigned int)physAddress; lastAddress = (unsigned int)physAddress + (size - 1); virtualAddress.address = 0; while (1){ if ((countAddress & ~MASK_OFFSET) > (lastAddress & ~MASK_OFFSET)) break; /* Need to allocate a new page table */ if (pageDirectory->pageDirEntry[directoryEntry].bits.page_frame_address == 0){ /* We allocate 2 pages to perform 4k-page alignement */ Tables = (char *)malloc(2*sizeof(page_table)); if ( Tables == NULL ){ if (pagingWasEnabled) _CPU_enable_paging(); return -1; /* unable to allocate memory */ } /* 4K-page alignement */ Tables += (PG_SIZE - (int)Tables) & 0xFFF; /* Reset Table */ memset( Tables, 0, sizeof(page_table) ); pageDirectory->pageDirEntry[directoryEntry].bits.page_frame_address = (unsigned int)Tables >> 12; pageDirectory->pageDirEntry[directoryEntry].bits.available = 0; pageDirectory->pageDirEntry[directoryEntry].bits.page_size = 0; pageDirectory->pageDirEntry[directoryEntry].bits.accessed = 0; pageDirectory->pageDirEntry[directoryEntry].bits.cache_disable = 0; pageDirectory->pageDirEntry[directoryEntry].bits.write_through = 0; pageDirectory->pageDirEntry[directoryEntry].bits.user = 1; pageDirectory->pageDirEntry[directoryEntry].bits.writable = 1; pageDirectory->pageDirEntry[directoryEntry].bits.present = 1; } localPageTable = (page_table *)(pageDirectory-> pageDirEntry[directoryEntry].bits. page_frame_address << 12); if (virtualAddress.address == 0){ virtualAddress.bits.directory = directoryEntry; virtualAddress.bits.page = tableEntry; virtualAddress.bits.offset = (unsigned int)physAddress & MASK_OFFSET; } localPageTable->pageTableEntry[tableEntry].bits.page_frame_address = ((unsigned int)countAddress & ~MASK_OFFSET) >> 12; localPageTable->pageTableEntry[tableEntry].bits.available = 0; localPageTable->pageTableEntry[tableEntry].bits.dirty = 0; localPageTable->pageTableEntry[tableEntry].bits.accessed = 0; localPageTable->pageTableEntry[tableEntry].bits.cache_disable = 0; localPageTable->pageTableEntry[tableEntry].bits.write_through = 0; localPageTable->pageTableEntry[tableEntry].bits.user = 1; localPageTable->pageTableEntry[tableEntry].bits.writable = 0; localPageTable->pageTableEntry[tableEntry].bits.present = 1; localPageTable->pageTableEntry[tableEntry].table_entry |= flag ; countAddress += PG_SIZE; tableEntry++; if (tableEntry >= MAX_ENTRY){ tableEntry = 0; directoryEntry++; } } if (mappedAddress != 0) *mappedAddress = (void *)(virtualAddress.address); if (pagingWasEnabled) _CPU_enable_paging(); return 0; } /* * "Compress" the Directory and Page tables to avoid * important loss of address range */ static void Paging_Table_Compress() { unsigned int dirCount, pageCount; page_table *localPageTable; if (tableEntry == 0){ dirCount = directoryEntry - 1; pageCount = MAX_ENTRY - 1; } else { dirCount = directoryEntry; pageCount = tableEntry - 1; } while (1){ localPageTable = (page_table *)(pageDirectory-> pageDirEntry[dirCount].bits. page_frame_address << 12); if (localPageTable->pageTableEntry[pageCount].bits.present == 1){ pageCount++; if (pageCount >= MAX_ENTRY){ pageCount = 0; dirCount++; } break; } if (pageCount == 0) { if (dirCount == 0){ break; } else { pageCount = MAX_ENTRY - 1; dirCount-- ; } } else pageCount-- ; } directoryEntry = dirCount; tableEntry = pageCount; } /* * Unmap the virtual address from the tables * (we do not deallocate the table already allocated) */ int _CPU_unmap_virt_address(void *mappedAddress, int size){ linear_address linearAddr; page_table *localPageTable; unsigned int lastAddr ; unsigned int dirCount ; unsigned char pagingWasEnabled; pagingWasEnabled = 0; if (_CPU_is_paging_enabled()){ pagingWasEnabled = 1; _CPU_disable_paging(); } linearAddr.address = (unsigned int)mappedAddress; lastAddr = (unsigned int)mappedAddress + (size - 1); dirCount = linearAddr.bits.directory; while (1){ if ((linearAddr.address & ~MASK_OFFSET) > (lastAddr & ~MASK_OFFSET)) break; if (pageDirectory->pageDirEntry[linearAddr.bits.directory].bits.present == 0){ if (pagingWasEnabled) _CPU_enable_paging(); return -1; } localPageTable = (page_table *)(pageDirectory-> pageDirEntry[linearAddr.bits.directory].bits. page_frame_address << 12); if (localPageTable->pageTableEntry[linearAddr.bits.page].bits.present == 0){ if (pagingWasEnabled) _CPU_enable_paging(); return -1; } localPageTable->pageTableEntry[linearAddr.bits.page].bits.present = 0; linearAddr.address += PG_SIZE ; } Paging_Table_Compress(); if (pagingWasEnabled) _CPU_enable_paging(); return 0; } /* * Modify the flags PRESENT, WRITABLE, USER, WRITE_TROUGH, CACHE_DISABLE * of the page's descriptor. */ int _CPU_change_memory_mapping_attribute (void **newAddress, void *mappedAddress, unsigned int size, unsigned int flag){ linear_address linearAddr; page_table *localPageTable; unsigned int lastAddr ; unsigned char pagingWasEnabled; pagingWasEnabled = 0; if (_CPU_is_paging_enabled()){ pagingWasEnabled = 1; _CPU_disable_paging(); } linearAddr.address = (unsigned int)mappedAddress; lastAddr = (unsigned int)mappedAddress + (size - 1); while (1){ if ((linearAddr.address & ~MASK_OFFSET) > (lastAddr & ~MASK_OFFSET)) break; if (pageDirectory->pageDirEntry[linearAddr.bits.directory].bits.present == 0){ if (pagingWasEnabled) _CPU_enable_paging(); return -1; } localPageTable = (page_table *)(pageDirectory-> pageDirEntry[linearAddr.bits.directory].bits. page_frame_address << 12); if (localPageTable->pageTableEntry[linearAddr.bits.page].bits.present == 0){ if (pagingWasEnabled) _CPU_enable_paging(); return -1; } localPageTable->pageTableEntry[linearAddr.bits.page].table_entry &= ~MASK_FLAGS ; localPageTable->pageTableEntry[linearAddr.bits.page].table_entry |= flag ; linearAddr.address += PG_SIZE ; } if (newAddress != NULL) *newAddress = mappedAddress ; if (pagingWasEnabled) _CPU_enable_paging(); return 0; } /* * Display the page descriptor flags * CACHE_DISABLE of the whole memory */ #include int _CPU_display_memory_attribute(){ unsigned int dirCount, pageCount; cr0 regCr0; page_table *localPageTable; unsigned int prevCache; unsigned int prevPresent; unsigned int maxPage; unsigned char pagingWasEnabled; regCr0.i = i386_get_cr0(); printk("\n\n >>>>>>>>> MEMORY CACHE CONFIGURATION <<<<<<<<<<\n\n"); printk("CR0 -> paging : %s\n",(regCr0.cr0.paging ? "ENABLE ":"DISABLE")); printk(" page-level cache : %s\n\n",(regCr0.cr0.page_level_cache_disable ? "DISABLE":"ENABLE")); if (regCr0.cr0.paging == 0) return 0; prevPresent = 0; prevCache = 1; pagingWasEnabled = 0; if (_CPU_is_paging_enabled()){ pagingWasEnabled = 1; _CPU_disable_paging(); } for (dirCount = 0; dirCount < directoryEntry+1; dirCount++) { localPageTable = (page_table *)(pageDirectory-> pageDirEntry[dirCount].bits. page_frame_address << 12); maxPage = MAX_ENTRY; /*if ( dirCount == (directoryEntry-1)) maxPage = tableEntry;*/ for (pageCount = 0; pageCount < maxPage; pageCount++) { if (localPageTable->pageTableEntry[pageCount].bits.present != 0){ if (prevPresent == 0){ prevPresent = 1; printk ("present page from address %x \n", ((dirCount << 22)|(pageCount << 12))); } if (prevCache != localPageTable->pageTableEntry[pageCount].bits.cache_disable ) { prevCache = localPageTable->pageTableEntry[pageCount]. bits.cache_disable; printk (" cache %s from %x \n", (prevCache ? "DISABLE" : "ENABLE "), ((dirCount << 22)|(pageCount << 12)), localPageTable->pageTableEntry[pageCount].bits.page_frame_address << 12); } } else { if (prevPresent == 1){ prevPresent = 0; printk ("Absent from %x \n", ((dirCount << 22)|(pageCount << 12))); } } } } if (pagingWasEnabled) _CPU_enable_paging(); return 0; }