bsp/pc386: Move libcpu content to bsps

This patch is a part of the BSP source reorganization.

Update #3285.
This commit is contained in:
Sebastian Huber
2018-03-20 16:16:53 +01:00
parent 4c36a525d3
commit a7fa9e9172
7 changed files with 4 additions and 45 deletions

View File

@@ -171,6 +171,10 @@ libbsp_a_SOURCES += wd8003/wd8003.c
endif
libbsp_a_SOURCES += ../../../../../../bsps/i386/shared/cache/cache.c
libbsp_a_SOURCES += ../../../../../../bsps/i386/pc386/start/cpuModel.S
libbsp_a_SOURCES += ../../../../../../bsps/i386/pc386/start/displayCpu.c
libbsp_a_SOURCES += ../../../../../../bsps/i386/pc386/start/idtr.S
libbsp_a_SOURCES += ../../../../../../bsps/i386/pc386/start/page.c
libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/page.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/score.rel

View File

@@ -1,17 +0,0 @@
ACLOCAL_AMFLAGS = -I ../../../aclocal
noinst_PROGRAMS =
include $(top_srcdir)/../../../automake/compile.am
noinst_PROGRAMS += score.rel
score_rel_SOURCES = displayCpu.c cpuModel.S cpuModel.h idtr.S cpu.h
score_rel_CPPFLAGS = $(AM_CPPFLAGS)
score_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += page.rel
page_rel_SOURCES = page.c page.h
page_rel_CPPFLAGS = $(AM_CPPFLAGS)
page_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
include $(top_srcdir)/../../../automake/local.am

View File

@@ -1,28 +0,0 @@
## Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([rtems-c-src-lib-libcpu-i386],[_RTEMS_VERSION],[https://devel.rtems.org/newticket])
AC_CONFIG_SRCDIR([idtr.S])
RTEMS_TOP([../../../../..],[../../..])
RTEMS_SOURCE_TOP
RTEMS_BUILD_TOP
RTEMS_CANONICAL_TARGET_CPU
AM_INIT_AUTOMAKE([no-define foreign subdir-objects 1.12.2])
AM_MAINTAINER_MODE
RTEMS_ENV_RTEMSBSP
RTEMS_PROJECT_ROOT
RTEMS_PROG_CC_FOR_TARGET
AM_PROG_CC_C_O
RTEMS_CANONICALIZE_TOOLS
RTEMS_PROG_CCAS
RTEMS_AMPOLISH3
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

View File

@@ -1,273 +0,0 @@
/* cpuModel.S
*
* This file contains all assembly code for the Intel Cpu identification.
* It is based on linux cpu detection code.
*
* Intel also provides public similar code in the book
* called :
*
* Pentium Processor Family
* Developer Family
* Volume 3 : Architecture and Programming Manual
*
* At the following place :
*
* Chapter 5 : Feature determination
* Chapter 25: CPUID instruction
*
* COPYRIGHT (c) 1998 valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems/asm.h>
#include <rtems/score/registers.h>
BEGIN_CODE
PUBLIC(checkCPUtypeSetCr0);
/*
* check Processor type: 386, 486, 6x86(L) or CPUID capable processor
*/
SYM (checkCPUtypeSetCr0):
/*
* Assume 386 for now
*/
movl $3, SYM (x86)
/*
* Start using the EFLAGS AC bit determination method described in
* the book mentioned above page 5.1. If this bit can be set we
* have a 486 or above.
*/
pushfl /* save EFLAGS */
pushfl /* Get EFLAGS in EAX */
popl eax
movl eax,ecx /* save original EFLAGS in ECX */
xorl $EFLAGS_ALIGN_CHECK,eax /* flip AC bit in EAX */
pushl eax /* set EAX as EFLAGS */
popfl
pushfl /* Get new EFLAGS in EAX */
popl eax
xorl ecx,eax /* check if AC bit changed */
andl $EFLAGS_ALIGN_CHECK,eax
je is386 /* If not : we have a 386 */
/*
* Assume 486 for now
*/
movl $4,SYM (x86)
movl ecx,eax /* Restore orig EFLAGS in EAX */
xorl $EFLAGS_ID,eax /* flip ID flag */
pushl eax /* set EAX as EFLAGS */
popfl
pushfl /* Get new EFLAGS in EAX */
popl eax
xorl ecx,eax /* check if ID bit changed */
andl $EFLAGS_ID,eax
/*
* if we are on a straight 486DX,
* SX, or 487SX we can't change it
* OTOH 6x86MXs and MIIs check OK
* Also if we are on a Cyrix 6x86(L)
*/
je is486x
isnew:
/*
* restore original EFLAGS
*/
popfl
incl SYM(have_cpuid) /* we have CPUID instruction */
/*
* Addressable Processor Ids
*
* CPUID.(EAX=4, ECX=0):EAX[31:26] + 1 = Y)
*/
movl $4, eax
movl $0, ecx
cpuid
movl eax,SYM(x86_capability_cores)
/* use it to get :
* processor type,
* processor model,
* processor mask,
* by using it with EAX = 1
*/
movl $1, eax
cpuid
movl ebx,SYM(x86_capability_ebx) /* store ebx feature info */
movl ecx,SYM(x86_capability_x) /* store ecx feature flags */
movb al, cl /* save reg for future use */
andb $0x0f,ah /* mask processor family */
movb ah,SYM (x86) /* put result in x86 var */
andb $0xf0, al /* get model */
shrb $4, al
movb al,SYM (x86_model) /* store it in x86_model */
andb $0x0f, cl /* get mask revision */
movb cl,SYM (x86_mask) /* store it in x86_mask */
movl edx,SYM(x86_capability) /* store feature flags in x86_capability */
/* get vendor info by using CPUID with EXA = 0 */
xorl eax, eax
cpuid
/*
* store results contained in ebx, edx, ecx in
* x86_vendor_id variable.
*/
movl ebx,SYM(x86_vendor_id)
movl edx,SYM(x86_vendor_id)+4
movl ecx,SYM(x86_vendor_id)+8
movl cr0,eax /* 486+ */
andl $(CR0_PAGING | CR0_PROTECTION_ENABLE | CR0_EXTENSION_TYPE), eax
orl $(CR0_ALIGMENT_MASK | CR0_WRITE_PROTECT | CR0_NUMERIC_ERROR | CR0_MONITOR_COPROC),eax
jmp 2f
/* Now we test if we have a Cyrix 6x86(L). We didn't test before to avoid
* clobbering the new BX chipset used with the Pentium II, which has a register
* at the same addresses as those used to access the Cyrix special configuration
* registers (CCRs).
*/
/*
* A Cyrix/IBM 6x86(L) preserves flags after dividing 5 by 2
* (and it _must_ be 5 divided by 2) while other CPUs change
* them in undefined ways. We need to know this since we may
* need to enable the CPUID instruction at least.
* We couldn't use this test before since the PPro and PII behave
* like Cyrix chips in this respect.
*/
is486x: xor ax,ax
sahf
movb $5,al
movb $2,bl
div bl
lahf
cmpb $2,ah
jne ncyrix
/*
* N.B. The pattern of accesses to 0x22 and 0x23 is *essential*
* so do not try to "optimize" it! For the same reason we
* do all this with interrupts off.
*/
#define setCx86(reg, val) \
movb reg,al; \
outb al,$0x22; \
movb val,al; \
outb al,$0x23
#define getCx86(reg) \
movb reg,al; \
outb al,$0x22; \
inb $0x23,al
cli
getCx86($0xc3) /* get CCR3 */
movb al,cl /* Save old value */
movb al,bl
andb $0x0f,bl /* Enable access to all config registers */
orb $0x10,bl /* by setting bit 4 */
setCx86($0xc3,bl)
getCx86($0xe8) /* now we can get CCR4 */
orb $0x80,al /* and set bit 7 (CPUIDEN) */
movb al,bl /* to enable CPUID execution */
setCx86($0xe8,bl)
getCx86($0xfe) /* DIR0 : let's check this is a 6x86(L) */
andb $0xf0,al /* should be 3xh */
cmpb $0x30,al
jne n6x86
getCx86($0xe9) /* CCR5 : we reset the SLOP bit */
andb $0xfd,al /* so that udelay calculation */
movb al,bl /* is correct on 6x86(L) CPUs */
setCx86($0xe9,bl)
setCx86($0xc3,cl) /* Restore old CCR3 */
sti
jmp isnew /* We enabled CPUID now */
n6x86: setCx86($0xc3,cl) /* Restore old CCR3 */
sti
ncyrix: /* restore original EFLAGS */
popfl
movl cr0,eax /* 486 */
andl $(CR0_PAGING | CR0_EXTENSION_TYPE | CR0_PROTECTION_ENABLE),eax /* Save PG,PE,ET */
orl $(CR0_ALIGMENT_MASK | CR0_WRITE_PROTECT | CR0_NUMERIC_ERROR | CR0_MONITOR_COPROC),eax /* set AM, WP, NE and MP */
jmp 2f
is386: /* restore original EFLAGS */
popfl
movl cr0,eax /* 386 */
andl $(CR0_PAGING | CR0_EXTENSION_TYPE | CR0_PROTECTION_ENABLE),eax /* Save PG,PE,ET */
orl $CR0_MONITOR_COPROC,eax /* set MP */
2: movl eax,cr0
call check_x87
ret
/*
* We depend on ET to be correct. This checks for 287/387.
*/
check_x87:
movb $0,SYM(hard_math)
clts
fninit
fstsw ax
cmpb $0,al
je 1f
movl cr0,eax /* no coprocessor: have to set bits */
xorl $4,eax /* set EM */
movl eax,cr0
ret
.align 16
1: movb $1,SYM(hard_math)
.byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
ret
END_CODE
BEGIN_DATA
PUBLIC(x86)
PUBLIC(have_cpuid)
PUBLIC(x86_model)
PUBLIC(x86_mask)
PUBLIC(x86_capability)
PUBLIC(x86_capability_ebx)
PUBLIC(x86_capability_x)
PUBLIC(x86_capability_cores)
PUBLIC(x86_vendor_id)
PUBLIC(hard_math)
SYM(x86):
.byte 0
SYM(have_cpuid):
.long 0
SYM(x86_model):
.byte 0
SYM(x86_mask):
.byte 0
SYM(x86_capability):
.long 0
SYM(x86_capability_ebx):
.long 0
SYM(x86_capability_x):
.long 0
SYM(x86_capability_cores):
.long 0
SYM(x86_vendor_id):
.zero 13
SYM(hard_math):
.byte 0
END_DATA

View File

@@ -1,243 +0,0 @@
/*
* This file contains code for displaying the Intel Cpu identification
* that has been performed by checkCPUtypeSetCr0 function.
*/
/*
* This file was updated by Joel Sherrill <joel.sherrill@oarcorp.com>
* to define more capability bits, pick up more CPU model information,
* and add more model strings. --joel (April 2010)
*
* COPYRIGHT (c) 1998 valette@crf.canon.fr
* COPYRIGHT (c) 2010 OAR Corporation
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
/*
* Tell us the machine setup..
*/
#include <stdio.h>
#include <rtems/score/cpu.h>
#include <string.h>
#include <libcpu/cpuModel.h>
#include <rtems/bspIo.h>
#include <rtems.h>
unsigned char Cx86_step = 0;
static const char *Cx86_type[] = {
"unknown", "1.3", "1.4", "1.5", "1.6",
"2.4", "2.5", "2.6", "2.7 or 3.7", "4.2"
};
static const char *i486model(unsigned int nr)
{
static const char *model[] = {
"0","DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4","DX/4-WB",
"10","11","12","13","Am5x86-WT","Am5x86-WB"
};
if (nr < sizeof(model)/sizeof(char *))
return model[nr];
return NULL;
}
static const char * i586model(unsigned int nr)
{
static const char *model[] = {
"0", "Pentium 60/66","Pentium 75+","OverDrive PODP5V83",
"Pentium MMX", NULL, NULL, "Mobile Pentium 75+",
"Mobile Pentium MMX"
};
if (nr < sizeof(model)/sizeof(char *))
return model[nr];
return NULL;
}
static const char *Cx86model(void)
{
unsigned char nr6x86 = 0;
static const char *model[] = {
"unknown", "6x86", "6x86L", "6x86MX", "MII"
};
switch (x86) {
case 5:
/* cx8 flag only on 6x86L */
nr6x86 = ((x86_capability & (1 << 8)) ? 2 : 1);
break;
case 6:
nr6x86 = 3;
break;
default:
nr6x86 = 0;
}
/* We must get the stepping number by reading DIR1 */
outport_byte(0x22,0xff);
inport_byte(0x23, x86_mask);
switch (x86_mask) {
case 0x03:
Cx86_step = 1; /* 6x86MX Rev 1.3 */
break;
case 0x04:
Cx86_step = 2; /* 6x86MX Rev 1.4 */
break;
case 0x05:
Cx86_step = 3; /* 6x86MX Rev 1.5 */
break;
case 0x06:
Cx86_step = 4; /* 6x86MX Rev 1.6 */
break;
case 0x14:
Cx86_step = 5; /* 6x86 Rev 2.4 */
break;
case 0x15:
Cx86_step = 6; /* 6x86 Rev 2.5 */
break;
case 0x16:
Cx86_step = 7; /* 6x86 Rev 2.6 */
break;
case 0x17:
Cx86_step = 8; /* 6x86 Rev 2.7 or 3.7 */
break;
case 0x22:
Cx86_step = 9; /* 6x86L Rev 4.2 */
break;
default:
Cx86_step = 0;
}
return model[nr6x86];
}
static const char * i686model(unsigned int nr)
{
static const char *model[] = {
"PPro A-step",
"Pentium Pro"
};
if (nr < sizeof(model)/sizeof(char *))
return model[nr];
return NULL;
}
struct cpu_model_info {
int x86;
char *model_names[16];
};
static struct cpu_model_info amd_models[] = {
{ 4,
{ NULL, NULL, NULL, "DX/2", NULL, NULL, NULL, "DX/2-WB", "DX/4",
"DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", "Am5x86-WB" }},
{ 5,
{ "K5/SSA5 (PR-75, PR-90, PR-100)", "K5 (PR-120, PR-133)",
"K5 (PR-166)", "K5 (PR-200)", NULL, NULL,
"K6 (166 - 266)", "K6 (166 - 300)", "K6-2 (200 - 450)",
"K6-3D-Plus (200 - 450)", NULL, NULL, NULL, NULL, NULL, NULL }},
};
static const char * AMDmodel(void)
{
const char *p=NULL;
int i;
if (x86_model < 16)
for (i=0; i<sizeof(amd_models)/sizeof(struct cpu_model_info); i++)
if (amd_models[i].x86 == x86) {
p = amd_models[i].model_names[(int)x86_model];
break;
}
return p;
}
static const char * getmodel(int x86, int model)
{
const char *p = NULL;
static char nbuf[12];
if (strncmp(x86_vendor_id, "Cyrix", 5) == 0)
p = Cx86model();
else if(strcmp(x86_vendor_id, "AuthenticAMD")==0)
p = AMDmodel();
else {
switch (x86) {
case 4:
p = i486model(model);
break;
case 5:
p = i586model(model);
break;
case 6:
p = i686model(model);
break;
}
}
if (p)
return p;
sprintf(nbuf, "%d", model);
return nbuf;
}
void printCpuInfo(void)
{
int i,j;
static const char *x86_cap_flags[] = {
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
"cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
"pat", "pse36", "psn", "cflsh", "20", "ds", "acpi", "mmx",
"fxsr", "sse", "sse2", "ss", "htt", "tm", "30", "pbe"
};
static const char *x86_cap_x_flags[] = {
"sse3", "pclmulqdq", "dtes64", "monitor", "ds-cpl", "vmx", "smx", "est",
"tm2", "ssse3", "cnxt-id", "11", "12", "cmpxchg16b", "xtpr", "pdcm",
"16", "pcid", "dca", "sse4.1", "sse4.2", "x2APIC", "movbe", "popcnt"
"24", "aesni", "xsave", "xsave", "avx", "29", "30", "31"
};
printk("cpu : %c86\n", x86+'0');
printk("model : %s\n",
have_cpuid ? getmodel(x86, x86_model) : "unknown");
if (x86_vendor_id [0] == '\0')
strcpy(x86_vendor_id, "unknown");
printk("vendor_id : %s\n", x86_vendor_id);
if (x86_mask) {
if (strncmp(x86_vendor_id, "Cyrix", 5) != 0) {
printk("stepping : %d\n", x86_mask);
}
else { /* we have a Cyrix */
printk("stepping : %s\n", Cx86_type[Cx86_step]);
}
} else
printk("stepping : unknown\n");
printk("fpu : %s\n", (hard_math ? "yes" : "no"));
printk("cpuid : %s\n", (have_cpuid ? "yes" : "no"));
printk("flags :");
for ( i = j = 0 ; i < 32 ; i++ ) {
if ( x86_capability & (1 << i) ) {
if ( j && 0 == (j & 7) )
printk("\n ");
printk(" %s", x86_cap_flags[i]);
j++;
}
}
printk("\n");
printk("flags (ext.):");
for ( i = j = 0 ; i < 32 ; i++ ) {
if ( x86_capability_x & (1 << i) ) {
if ( j && 0 == (j & 7) )
printk("\n ");
printk(" %s", x86_cap_x_flags[i]);
j++;
}
}
printk("\n");
printk( "x86_capability_ebx=0x%08x\n", x86_capability_ebx);
printk( "x86_capability_cores=0x%08x\n", x86_capability_cores);
}

View File

@@ -1,115 +0,0 @@
/* cpu_asm.S
*
* This file contains all assembly code for the Intel i386 IDT
* manipulation.
*
* COPYRIGHT (c) 1998 valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems/asm.h>
BEGIN_CODE
/*
* C callable function enabling to get easilly usable info from
* the actual value of IDT register.
*
extern void i386_get_info_from_IDTR (interrupt_gate_descriptor** table,
unsigned* limit);
*/
PUBLIC (i386_get_info_from_IDTR)
PUBLIC (i386_set_IDTR)
PUBLIC (i386_get_info_from_GDTR)
PUBLIC (i386_set_GDTR)
SYM (i386_get_info_from_IDTR):
movl 4(esp), ecx /* get location where table address */
/* must be stored */
movl 8(esp), edx /* get location table size must be stored */
subl $6, esp /* let room to prepare 48 bit IDTR */
sidt (esp) /* get 48 bit IDTR value */
movl 2(esp), eax /* get base */
movl eax, (ecx)
movzwl (esp), eax /* get limit */
movl eax, (edx)
addl $6, esp /* restore %esp */
ret
/*
* C callable function enabling to change the value of IDT register. Must be called
* with inmterrupt masked at processor level!!!.
*
extern void i386_set_IDTR (interrupt_gate_descriptor* table,
unsigned limit);
*/
SYM (i386_set_IDTR):
leal 4(esp), edx /* load in edx address of input */
/* parameter "table" */
movl (edx), eax /* load base into eax */
movl 4(edx), ecx /* load limit into ecx */
movw cx, (edx) /* prepare 48 bit pointer */
movl eax, 2(edx)
lidt (edx)
ret
/*
*
* C callable function enabling to get easilly usable info from
* the actual value of GDT register.
extern void i386_get_info_from_GDTR (segment_descriptors** table,
uint16_t* limit);
*/
SYM (i386_get_info_from_GDTR):
movl 4(esp), ecx /* get location where table address */
/* must be stored */
movl 8(esp), edx /* get location table size must be stored */
subl $6, esp /* let room to prepare 48 bit GDTR */
sgdt (esp) /* get 48 bit GDTR value */
movl 2(esp), eax /* get base */
movl eax, (ecx)
movzwl (esp), eax /* get limit */
movw ax, (edx)
addl $6, esp /* restore %esp */
ret
/*
* C callable function enabling to change the value of GDT register.
* Must be called with interrupts masked at processor level!!!.
* extern void i386_set_GDTR (segment_descriptors*, uint16_t limit);
*/
SYM (i386_set_GDTR):
leal 4(esp), edx /* load in edx address of input */
/* parameter "table" */
movl (edx), eax /* load base into eax */
movl 4(edx), ecx /* load limit into ecx */
movw cx, (edx) /* prepare 48 bit pointer */
movl eax, 2(edx)
lgdt (edx)
ret
END_CODE
END

View File

@@ -1,519 +0,0 @@
/*
* 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 the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rtems.h>
#include <rtems/score/cpu.h>
#include <libcpu/page.h>
#define MEMORY_SIZE 0x4000000 /* 64Mo */
static int directoryEntry=0;
static int tableEntry=0;
static page_directory *pageDirectory;
extern uint32_t bsp_mem_size;
/*************************************************************************/
/************** IT IS A ONE-TO-ONE TRANSLATION ***************************/
/*************************************************************************/
/*
* Disable the paging
*/
void _CPU_disable_paging(void)
{
unsigned int regCr0;
rtems_cache_flush_entire_data();
regCr0 = i386_get_cr0();
regCr0 &= ~(CR0_PAGING);
i386_set_cr0( regCr0 );
}
/*
* Enable the paging
*/
void _CPU_enable_paging(void)
{
unsigned int regCr0;
regCr0 = i386_get_cr0();
regCr0 |= CR0_PAGING;
i386_set_cr0( regCr0 );
rtems_cache_flush_entire_data();
}
/*
* Initialize the paging with 1-to-1 mapping
*/
int init_paging(void)
{
int nbPages;
int nbInitPages;
char *Tables;
unsigned int regCr3;
page_table *pageTable;
unsigned int physPage;
int nbTables=0;
nbPages = ( (bsp_mem_size - 1) / PG_SIZE ) + 1;
nbTables = ( (bsp_mem_size - 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_THROUGH);
regCr3 &= ~(CR3_PAGE_CACHE_DISABLE);
/*regCr3.cr3.page_directory_base = (unsigned int)pageDirectory >> 12;*/
regCr3 = (unsigned int)pageDirectory & CR3_PAGE_DIRECTORY_MASK;
i386_set_cr3( regCr3 );
_CPU_enable_cache();
_CPU_enable_paging();
return 0;
}
/*
* Is cache enable
*/
int _CPU_is_cache_enabled(void)
{
unsigned int regCr0;
regCr0 = i386_get_cr0();
return( ~(regCr0 & CR0_PAGE_LEVEL_CACHE_DISABLE) );
}
/*
* Is paging enable
*/
int _CPU_is_paging_enabled(void)
{
unsigned int regCr0;
regCr0 = 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(void)
{
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 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].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(void)
{
unsigned int dirCount, pageCount;
unsigned int regCr0;
page_table *localPageTable;
unsigned int prevCache;
unsigned int prevPresent;
unsigned int maxPage;
unsigned char pagingWasEnabled;
regCr0 = i386_get_cr0();
printk("\n\n********* MEMORY CACHE CONFIGURATION *****\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;
}