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

4.104.115
Last change on this file since 359e537 was a1d47823, checked in by Joel Sherrill <joel.sherrill@…>, on 05/06/09 at 16:36:52

2009-05-06 Joel Sherrill <joel.sherrill@…>

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