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

4.104.115
Last change on this file since c193baad was fa62f19, checked in by Joel Sherrill <joel.sherrill@…>, on 12/11/09 at 20:52:41

2009-12-11 Joel Sherrill <joel.sherrill@…>

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