forked from Imagelibrary/rtems
* cpu.c, cpu.h, cpuModel.S, cpuModel.h, displayCpu.c, idtr.S, page.c: URL for license changed.
516 lines
14 KiB
C
516 lines
14 KiB
C
/*
|
|
* 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <rtems.h>
|
|
#include <libcpu/cpu.h>
|
|
|
|
#define MEMORY_SIZE 0x4000000 /* 64Mo */
|
|
|
|
static int directoryEntry=0;
|
|
static int tableEntry=0;
|
|
static page_directory *pageDirectory;
|
|
|
|
extern rtems_unsigned32 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 <rtems/bspIo.h>
|
|
|
|
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 <phy %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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|