source: rtems/c/src/lib/libcpu/i386/page.c @ b2b4835

4.104.114.84.95
Last change on this file since b2b4835 was c629812, checked in by Joel Sherrill <joel.sherrill@…>, on 12/13/99 at 22:10:45

Removed warnings.

  • Property mode set to 100644
File size: 14.0 KB
Line 
1/*
2 * page.c :- This file contains implementation of C function to
3 *           Instanciate paging. More detailled information
4 *           can be found on Intel site and more precisely in
5 *           the following book :
6 *
7 *              Pentium Processor familly
8 *              Developper's Manual
9 *
10 *              Volume 3 : Architecture and Programming Manual
11 *
12 * Copyright (C) 1999  Emmanuel Raguet (raguet@crf.canon.fr)
13 *                     Canon Centre Recherche France.
14 *
15 *  The license and distribution terms for this file may be
16 *  found in found in the file LICENSE in this distribution or at
17 *  http://www.OARcorp.com/rtems/license.html.
18 *
19 * $Header$
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <rtems.h>
26#include <libcpu/cpu.h>
27
28#define MEMORY_SIZE 0x4000000           /* 64Mo */
29
30static int directoryEntry=0;
31static int tableEntry=0;
32static page_directory *pageDirectory;
33
34extern rtems_unsigned32 rtemsFreeMemStart;
35
36
37/*************************************************************************/
38/************** IT IS A ONE-TO-ONE TRANSLATION ***************************/
39/*************************************************************************/
40
41
42/*
43 * Disable the paging
44 */
45void _CPU_disable_paging() {
46  cr0 regCr0;
47
48  flush_cache();
49  regCr0.i = i386_get_cr0();
50  regCr0.cr0.paging = 0;
51  i386_set_cr0( regCr0.i );
52}
53
54/*
55 * Enable the paging
56 */
57void _CPU_enable_paging() {
58  cr0 regCr0;
59
60  regCr0.i = i386_get_cr0();
61  regCr0.cr0.paging = 1;
62  i386_set_cr0( regCr0.i );
63  flush_cache();
64}
65
66
67/*
68 * Initialize the paging with 1-to-1 mapping
69 */
70
71int init_paging() {
72
73  int memorySize;
74  int nbPages;
75  int nbInitPages;
76  char *Tables;
77  cr3 regCr3;
78  page_table *pageTable;
79  unsigned int physPage;
80  int nbTables=0;
81 
82  /*
83   * rtemsFreeMemStart is the last valid 32-bits address
84   * so the size is rtemsFreeMemStart + 4
85   */
86  memorySize = rtemsFreeMemStart + 4;
87 
88  nbPages = ( (memorySize - 1) / PG_SIZE ) + 1;
89  nbTables = ( (memorySize - 1) / FOUR_MB ) + 2;
90
91  /* allocate 1 page more to page alignement */
92  Tables = (char *)malloc( (nbTables + 1)*sizeof(page_table) );
93  if ( Tables == NULL ){
94    return -1; /*unable to allocate memory */
95  }
96 
97  /* 4K-page alignement */
98  Tables += (PG_SIZE - (int)Tables) & 0xFFF;
99
100  /* Reset Tables */
101  memset( Tables, 0, nbTables*sizeof(page_table) );
102  pageDirectory = (page_directory *) Tables;
103  pageTable     = (page_table *)((int)Tables + PG_SIZE);
104
105  nbInitPages = 0;
106  directoryEntry = 0;
107  tableEntry = 0;
108  physPage = 0;
109
110  while ( nbInitPages != nbPages ){
111    if ( tableEntry == 0 ){
112      pageDirectory->pageDirEntry[directoryEntry].bits.page_frame_address = (unsigned int)pageTable >> 12;
113      pageDirectory->pageDirEntry[directoryEntry].bits.available      = 0;
114      pageDirectory->pageDirEntry[directoryEntry].bits.page_size      = 0;
115      pageDirectory->pageDirEntry[directoryEntry].bits.accessed       = 0;
116      pageDirectory->pageDirEntry[directoryEntry].bits.cache_disable  = 0;
117      pageDirectory->pageDirEntry[directoryEntry].bits.write_through  = 0;
118      pageDirectory->pageDirEntry[directoryEntry].bits.user           = 1;
119      pageDirectory->pageDirEntry[directoryEntry].bits.writable       = 1;
120      pageDirectory->pageDirEntry[directoryEntry].bits.present        = 1;
121    }
122    pageTable->pageTableEntry[tableEntry].bits.page_frame_address = physPage;
123    pageTable->pageTableEntry[tableEntry].bits.available      = 0;
124    pageTable->pageTableEntry[tableEntry].bits.dirty          = 0;
125    pageTable->pageTableEntry[tableEntry].bits.accessed       = 0;
126    pageTable->pageTableEntry[tableEntry].bits.cache_disable  = 0;
127    pageTable->pageTableEntry[tableEntry].bits.write_through  = 0;
128    pageTable->pageTableEntry[tableEntry].bits.user           = 1;
129    pageTable->pageTableEntry[tableEntry].bits.writable       = 1;
130    pageTable->pageTableEntry[tableEntry].bits.present        = 1;
131
132    physPage ++;
133    tableEntry ++;
134
135    if (tableEntry >= MAX_ENTRY){
136      tableEntry = 0;
137      directoryEntry ++;
138      pageTable ++;
139    }
140     
141    nbInitPages++;
142  }
143
144  regCr3.cr3.page_write_transparent = 0;
145  regCr3.cr3.page_cache_disable     = 0;
146  regCr3.cr3.page_directory_base    = (unsigned int)pageDirectory >> 12;
147
148  i386_set_cr3( regCr3.i );
149
150  _CPU_enable_cache(); 
151  _CPU_enable_paging(); 
152
153  return 0;
154}
155
156/*
157 * Disable the entire cache
158 */
159void _CPU_disable_cache() {
160  cr0 regCr0;
161
162  regCr0.i = i386_get_cr0();
163  regCr0.cr0.page_level_cache_disable = 1;
164  regCr0.cr0.no_write_through = 1;
165  i386_set_cr0( regCr0.i );
166  flush_cache();
167}
168
169/*
170 * Disable the entire cache
171 */
172void _CPU_enable_cache() {
173  cr0 regCr0;
174
175  regCr0.i = i386_get_cr0();
176  regCr0.cr0.page_level_cache_disable = 0;
177  regCr0.cr0.no_write_through = 0;
178  i386_set_cr0( regCr0.i );
179  /*flush_cache();*/
180}
181
182/*
183 * Is cache enable
184 */
185int  _CPU_is_cache_enabled() {
186  cr0 regCr0;
187
188  regCr0.i = i386_get_cr0();
189  return( ~(regCr0.cr0.page_level_cache_disable) );
190}
191
192/*
193 * Is paging enable
194 */
195int  _CPU_is_paging_enabled() {
196  cr0 regCr0;
197
198  regCr0.i = i386_get_cr0();
199  return(regCr0.cr0.paging);
200}
201
202
203/*
204 * Translate the physical address in the virtual space and return
205 * the translated address in mappedAddress
206 */
207
208int _CPU_map_phys_address
209        (void **mappedAddress, void *physAddress, int size, int flag){
210
211  page_table *localPageTable;
212  unsigned int lastAddress, countAddress;
213  char *Tables;
214  linear_address virtualAddress;
215  unsigned char pagingWasEnabled;
216 
217  pagingWasEnabled = 0;
218
219  if (_CPU_is_paging_enabled()){
220    pagingWasEnabled = 1;
221    _CPU_disable_paging();
222  }
223
224  countAddress = (unsigned int)physAddress;
225  lastAddress = (unsigned int)physAddress + (size - 1);
226  virtualAddress.address = 0;
227
228  while (1){
229
230    if ((countAddress & ~MASK_OFFSET) > (lastAddress & ~MASK_OFFSET))
231      break;
232
233    /* Need to allocate a new page table */
234    if (pageDirectory->pageDirEntry[directoryEntry].bits.page_frame_address == 0){
235      /* We allocate 2 pages to perform 4k-page alignement */
236      Tables = (char *)malloc(2*sizeof(page_table));
237      if ( Tables == NULL ){
238        if (pagingWasEnabled)
239          _CPU_enable_paging();
240        return -1; /* unable to allocate memory */
241      }
242      /* 4K-page alignement */
243      Tables += (PG_SIZE - (int)Tables) & 0xFFF;
244
245      /* Reset Table */
246      memset( Tables, 0, sizeof(page_table) );     
247      pageDirectory->pageDirEntry[directoryEntry].bits.page_frame_address =
248        (unsigned int)Tables >> 12;
249      pageDirectory->pageDirEntry[directoryEntry].bits.available      = 0;
250      pageDirectory->pageDirEntry[directoryEntry].bits.page_size      = 0;
251      pageDirectory->pageDirEntry[directoryEntry].bits.accessed       = 0;
252      pageDirectory->pageDirEntry[directoryEntry].bits.cache_disable  = 0;
253      pageDirectory->pageDirEntry[directoryEntry].bits.write_through  = 0;
254      pageDirectory->pageDirEntry[directoryEntry].bits.user           = 1;
255      pageDirectory->pageDirEntry[directoryEntry].bits.writable       = 1;
256      pageDirectory->pageDirEntry[directoryEntry].bits.present        = 1;
257    }
258     
259
260    localPageTable = (page_table *)(pageDirectory->
261                                    pageDirEntry[directoryEntry].bits.
262                                    page_frame_address << 12);
263
264    if (virtualAddress.address == 0){
265      virtualAddress.bits.directory = directoryEntry;
266      virtualAddress.bits.page      = tableEntry;
267      virtualAddress.bits.offset    = (unsigned int)physAddress & MASK_OFFSET;
268    }
269
270    localPageTable->pageTableEntry[tableEntry].bits.page_frame_address =
271      ((unsigned int)countAddress & ~MASK_OFFSET) >> 12;
272    localPageTable->pageTableEntry[tableEntry].bits.available      = 0;
273    localPageTable->pageTableEntry[tableEntry].bits.dirty          = 0;
274    localPageTable->pageTableEntry[tableEntry].bits.accessed       = 0;
275    localPageTable->pageTableEntry[tableEntry].bits.cache_disable  = 0;
276    localPageTable->pageTableEntry[tableEntry].bits.write_through  = 0;
277    localPageTable->pageTableEntry[tableEntry].bits.user           = 1;
278    localPageTable->pageTableEntry[tableEntry].bits.writable       = 0;
279    localPageTable->pageTableEntry[tableEntry].bits.present        = 1;
280
281    localPageTable->pageTableEntry[tableEntry].table_entry |= flag ;
282
283    countAddress += PG_SIZE;
284    tableEntry++;
285    if (tableEntry >= MAX_ENTRY){     
286      tableEntry = 0;
287      directoryEntry++;
288    }
289  }
290
291  if (mappedAddress != 0)
292    *mappedAddress = (void *)(virtualAddress.address);
293  if (pagingWasEnabled)
294    _CPU_enable_paging();
295  return 0;
296}
297
298/*
299 * "Compress" the Directory and Page tables to avoid
300 * important loss of address range
301 */
302static void Paging_Table_Compress() {
303  unsigned int dirCount, pageCount;
304  page_table *localPageTable;
305 
306  if (tableEntry == 0){
307    dirCount  = directoryEntry - 1;
308    pageCount = MAX_ENTRY - 1;
309  }
310  else {
311    dirCount  = directoryEntry;
312    pageCount = tableEntry - 1;
313  }
314   
315  while (1){
316
317    localPageTable = (page_table *)(pageDirectory->
318                                    pageDirEntry[dirCount].bits.
319                                    page_frame_address << 12);
320
321    if (localPageTable->pageTableEntry[pageCount].bits.present == 1){
322      pageCount++;
323      if (pageCount >= MAX_ENTRY){     
324        pageCount = 0;
325        dirCount++;
326      }
327      break;
328    }
329
330
331    if (pageCount == 0) {
332      if (dirCount == 0){       
333        break;
334      }
335      else {
336        pageCount = MAX_ENTRY - 1;
337        dirCount-- ;
338      }
339    }
340    else
341      pageCount-- ;
342  }
343
344  directoryEntry = dirCount;
345  tableEntry = pageCount;
346}
347     
348 
349/*
350 * Unmap the virtual address from the tables
351 * (we do not deallocate the table already allocated)
352 */
353
354int _CPU_unmap_virt_address(void *mappedAddress, int size){
355
356  linear_address linearAddr;
357  page_table *localPageTable;
358  unsigned int lastAddr ;
359  unsigned int dirCount ;
360  unsigned char pagingWasEnabled;
361 
362  pagingWasEnabled = 0;
363
364  if (_CPU_is_paging_enabled()){
365    pagingWasEnabled = 1;
366    _CPU_disable_paging();
367  }
368
369  linearAddr.address = (unsigned int)mappedAddress;
370  lastAddr = (unsigned int)mappedAddress + (size - 1);
371  dirCount = linearAddr.bits.directory;
372
373  while (1){
374
375    if ((linearAddr.address & ~MASK_OFFSET) > (lastAddr & ~MASK_OFFSET))
376      break;
377
378    if (pageDirectory->pageDirEntry[linearAddr.bits.directory].bits.present == 0){
379      if (pagingWasEnabled)
380        _CPU_enable_paging();
381      return -1;
382    }
383
384    localPageTable = (page_table *)(pageDirectory->
385                                    pageDirEntry[linearAddr.bits.directory].bits.
386                                    page_frame_address << 12);
387   
388    if (localPageTable->pageTableEntry[linearAddr.bits.page].bits.present == 0){
389      if (pagingWasEnabled)
390        _CPU_enable_paging();
391      return -1;
392    }
393 
394    localPageTable->pageTableEntry[linearAddr.bits.page].bits.present = 0;   
395   
396    linearAddr.address += PG_SIZE ;
397  }
398  Paging_Table_Compress();
399  if (pagingWasEnabled)
400    _CPU_enable_paging();
401
402  return 0;
403}
404
405/*
406 * Modify the flags PRESENT, WRITABLE, USER, WRITE_TROUGH, CACHE_DISABLE
407 * of the page's descriptor.
408 */
409
410int _CPU_change_memory_mapping_attribute
411    (void **newAddress, void *mappedAddress, unsigned int size, unsigned int flag){
412
413  linear_address linearAddr;
414  page_table *localPageTable;
415  unsigned int lastAddr ;
416  unsigned char pagingWasEnabled;
417 
418  pagingWasEnabled = 0;
419
420  if (_CPU_is_paging_enabled()){
421    pagingWasEnabled = 1;
422    _CPU_disable_paging();
423  }
424 
425  linearAddr.address  = (unsigned int)mappedAddress;
426  lastAddr = (unsigned int)mappedAddress + (size - 1);
427
428  while (1){
429
430    if ((linearAddr.address & ~MASK_OFFSET) > (lastAddr & ~MASK_OFFSET))
431      break;
432
433    if (pageDirectory->pageDirEntry[linearAddr.bits.directory].bits.present == 0){
434      if (pagingWasEnabled)
435        _CPU_enable_paging();
436      return -1;
437    }
438    localPageTable = (page_table *)(pageDirectory->
439                                    pageDirEntry[linearAddr.bits.directory].bits.
440                                    page_frame_address << 12);
441   
442    if (localPageTable->pageTableEntry[linearAddr.bits.page].bits.present == 0){
443      if (pagingWasEnabled)
444        _CPU_enable_paging();
445      return -1;
446    }
447 
448    localPageTable->pageTableEntry[linearAddr.bits.page].table_entry &= ~MASK_FLAGS ;
449    localPageTable->pageTableEntry[linearAddr.bits.page].table_entry |= flag ;
450   
451    linearAddr.address += PG_SIZE ;
452  } 
453
454  if (newAddress != NULL)
455    *newAddress = mappedAddress ;
456
457  if (pagingWasEnabled)
458    _CPU_enable_paging();
459
460  return 0;
461}
462
463/*
464 * Display the page descriptor flags
465 * CACHE_DISABLE of the whole memory
466 */
467
468/* hack to avoid dependency on bsp.h */
469void printk(char *fmt, ...);             /* from 'printk.c' */
470
471int  _CPU_display_memory_attribute(){
472  unsigned int dirCount, pageCount;
473  cr0 regCr0;
474  page_table *localPageTable;
475  unsigned int prevCache;
476  unsigned int prevPresent;
477  unsigned int maxPage;
478  unsigned char pagingWasEnabled;
479 
480  regCr0.i = i386_get_cr0();
481 
482  printk("\n\n >>>>>>>>>  MEMORY CACHE CONFIGURATION <<<<<<<<<<\n\n");
483
484  printk("CR0 -> paging           : %s\n",(regCr0.cr0.paging ? "ENABLE ":"DISABLE"));
485  printk("       page-level cache : %s\n\n",(regCr0.cr0.page_level_cache_disable ? "DISABLE":"ENABLE"));
486
487  if (regCr0.cr0.paging == 0)
488    return 0;
489 
490  prevPresent = 0;
491  prevCache   = 1;
492 
493  pagingWasEnabled = 0;
494
495  if (_CPU_is_paging_enabled()){
496    pagingWasEnabled = 1;
497    _CPU_disable_paging();
498  }
499
500  for (dirCount = 0; dirCount < directoryEntry+1; dirCount++) {
501
502    localPageTable = (page_table *)(pageDirectory->
503                                    pageDirEntry[dirCount].bits.
504                                    page_frame_address << 12);
505
506    maxPage = MAX_ENTRY;
507    /*if ( dirCount == (directoryEntry-1))
508      maxPage = tableEntry;*/
509    for (pageCount = 0; pageCount < maxPage; pageCount++) {
510
511      if (localPageTable->pageTableEntry[pageCount].bits.present != 0){
512        if (prevPresent == 0){
513          prevPresent = 1;
514          printk ("present page from address %x \n", ((dirCount << 22)|(pageCount << 12)));
515        }
516        if (prevCache != localPageTable->pageTableEntry[pageCount].bits.cache_disable ) {
517          prevCache = localPageTable->pageTableEntry[pageCount].
518            bits.cache_disable;
519          printk ("    cache %s from %x <phy %x>\n",
520                  (prevCache ? "DISABLE" : "ENABLE "),
521                  ((dirCount << 22)|(pageCount << 12)),
522                  localPageTable->pageTableEntry[pageCount].bits.page_frame_address << 12);
523        }
524      }
525      else {
526        if (prevPresent == 1){
527          prevPresent = 0;
528          printk ("Absent from %x \n", ((dirCount << 22)|(pageCount << 12)));
529        }
530      }
531    }
532  }
533  if (pagingWasEnabled)
534    _CPU_enable_paging();
535  return 0;
536
537}
538
539
540
541
542
Note: See TracBrowser for help on using the repository browser.