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

4.104.114.84.95
Last change on this file since adbaa61 was adbaa61, checked in by Joel Sherrill <joel.sherrill@…>, on 02/18/99 at 21:07:15

Patch from Emmanuel Raguet <raguet@…>. Missed adding this file
earlier to CVS.

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