summaryrefslogtreecommitdiffstats
path: root/bsps
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-03-20 16:16:53 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-03-22 07:01:35 +0100
commita7fa9e9172deef4164d9d81c8da43ec0229c34ad (patch)
tree502ff7d31f1025206f37cd031464ffae99bee0bf /bsps
parentbsp/atsam: Fix GMAC Rx Descriptor fields. (diff)
downloadrtems-a7fa9e9172deef4164d9d81c8da43ec0229c34ad.tar.bz2
bsp/pc386: Move libcpu content to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps')
-rw-r--r--bsps/i386/pc386/start/cpuModel.S273
-rw-r--r--bsps/i386/pc386/start/displayCpu.c243
-rw-r--r--bsps/i386/pc386/start/idtr.S115
-rw-r--r--bsps/i386/pc386/start/page.c519
4 files changed, 1150 insertions, 0 deletions
diff --git a/bsps/i386/pc386/start/cpuModel.S b/bsps/i386/pc386/start/cpuModel.S
new file mode 100644
index 0000000000..b2e4ddce9e
--- /dev/null
+++ b/bsps/i386/pc386/start/cpuModel.S
@@ -0,0 +1,273 @@
+/* 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
diff --git a/bsps/i386/pc386/start/displayCpu.c b/bsps/i386/pc386/start/displayCpu.c
new file mode 100644
index 0000000000..f451194d96
--- /dev/null
+++ b/bsps/i386/pc386/start/displayCpu.c
@@ -0,0 +1,243 @@
+/*
+ * 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);
+}
diff --git a/bsps/i386/pc386/start/idtr.S b/bsps/i386/pc386/start/idtr.S
new file mode 100644
index 0000000000..48ce1df8c4
--- /dev/null
+++ b/bsps/i386/pc386/start/idtr.S
@@ -0,0 +1,115 @@
+/* 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
diff --git a/bsps/i386/pc386/start/page.c b/bsps/i386/pc386/start/page.c
new file mode 100644
index 0000000000..f05e145f51
--- /dev/null
+++ b/bsps/i386/pc386/start/page.c
@@ -0,0 +1,519 @@
+/*
+ * 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;
+}