diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-03-20 16:16:53 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-03-22 07:01:35 +0100 |
commit | a7fa9e9172deef4164d9d81c8da43ec0229c34ad (patch) | |
tree | 502ff7d31f1025206f37cd031464ffae99bee0bf /bsps/i386 | |
parent | bsp/atsam: Fix GMAC Rx Descriptor fields. (diff) | |
download | rtems-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/i386')
-rw-r--r-- | bsps/i386/pc386/start/cpuModel.S | 273 | ||||
-rw-r--r-- | bsps/i386/pc386/start/displayCpu.c | 243 | ||||
-rw-r--r-- | bsps/i386/pc386/start/idtr.S | 115 | ||||
-rw-r--r-- | bsps/i386/pc386/start/page.c | 519 |
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; +} |