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

Last change on this file since 328bd35 was 328bd35, checked in by Joel Sherrill <joel@…>, on Jan 23, 2016 at 7:06:22 PM

i386: refactor libcpu/cpu.h into rtems/score/i386.h

Fixes #2515.

  • 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 the file LICENSE in this distribution or at
17 *  http://www.rtems.org/license/LICENSE.
18 */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <rtems.h>
24#include <rtems/score/cpu.h>
25#include <libcpu/page.h>
26
27#define MEMORY_SIZE 0x4000000           /* 64Mo */
28
29static int directoryEntry=0;
30static int tableEntry=0;
31static page_directory *pageDirectory;
32
33extern uint32_t   bsp_mem_size;
34
35/*************************************************************************/
36/************** IT IS A ONE-TO-ONE TRANSLATION ***************************/
37/*************************************************************************/
38
39
40/*
41 * Disable the paging
42 */
43void _CPU_disable_paging(void)
44{
45  unsigned int regCr0;
46
47  rtems_cache_flush_entire_data();
48  regCr0 = i386_get_cr0();
49  regCr0 &= ~(CR0_PAGING);
50  i386_set_cr0( regCr0 );
51}
52
53/*
54 * Enable the paging
55 */
56void _CPU_enable_paging(void)
57{
58  unsigned int regCr0;
59
60  regCr0 = i386_get_cr0();
61  regCr0 |= CR0_PAGING;
62  i386_set_cr0( regCr0 );
63  rtems_cache_flush_entire_data();
64}
65
66
67/*
68 * Initialize the paging with 1-to-1 mapping
69 */
70
71int init_paging(void)
72{
73  int nbPages;
74  int nbInitPages;
75  char *Tables;
76  unsigned int regCr3;
77  page_table *pageTable;
78  unsigned int physPage;
79  int nbTables=0;
80
81  nbPages = ( (bsp_mem_size - 1) / PG_SIZE ) + 1;
82  nbTables = ( (bsp_mem_size - 1) / FOUR_MB ) + 2;
83
84  /* allocate 1 page more to page alignement */
85  Tables = (char *)malloc( (nbTables + 1)*sizeof(page_table) );
86  if ( Tables == NULL ){
87    return -1; /*unable to allocate memory */
88  }
89
90  /* 4K-page alignement */
91  Tables += (PG_SIZE - (int)Tables) & 0xFFF;
92
93  /* Reset Tables */
94  memset( Tables, 0, nbTables*sizeof(page_table) );
95  pageDirectory = (page_directory *) Tables;
96  pageTable     = (page_table *)((int)Tables + PG_SIZE);
97
98  nbInitPages = 0;
99  directoryEntry = 0;
100  tableEntry = 0;
101  physPage = 0;
102
103  while ( nbInitPages != nbPages ){
104    if ( tableEntry == 0 ){
105      pageDirectory->pageDirEntry[directoryEntry].bits.page_frame_address = (unsigned int)pageTable >> 12;
106      pageDirectory->pageDirEntry[directoryEntry].bits.available      = 0;
107      pageDirectory->pageDirEntry[directoryEntry].bits.page_size      = 0;
108      pageDirectory->pageDirEntry[directoryEntry].bits.accessed       = 0;
109      pageDirectory->pageDirEntry[directoryEntry].bits.cache_disable  = 0;
110      pageDirectory->pageDirEntry[directoryEntry].bits.write_through  = 0;
111      pageDirectory->pageDirEntry[directoryEntry].bits.user           = 1;
112      pageDirectory->pageDirEntry[directoryEntry].bits.writable       = 1;
113      pageDirectory->pageDirEntry[directoryEntry].bits.present        = 1;
114    }
115    pageTable->pageTableEntry[tableEntry].bits.page_frame_address = physPage;
116    pageTable->pageTableEntry[tableEntry].bits.available      = 0;
117    pageTable->pageTableEntry[tableEntry].bits.dirty          = 0;
118    pageTable->pageTableEntry[tableEntry].bits.accessed       = 0;
119    pageTable->pageTableEntry[tableEntry].bits.cache_disable  = 0;
120    pageTable->pageTableEntry[tableEntry].bits.write_through  = 0;
121    pageTable->pageTableEntry[tableEntry].bits.user           = 1;
122    pageTable->pageTableEntry[tableEntry].bits.writable       = 1;
123    pageTable->pageTableEntry[tableEntry].bits.present        = 1;
124
125    physPage ++;
126    tableEntry ++;
127
128    if (tableEntry >= MAX_ENTRY){
129      tableEntry = 0;
130      directoryEntry ++;
131      pageTable ++;
132    }
133
134    nbInitPages++;
135  }
136
137  regCr3 &= ~(CR3_PAGE_WRITE_THROUGH);
138  regCr3 &= ~(CR3_PAGE_CACHE_DISABLE);
139  /*regCr3.cr3.page_directory_base    = (unsigned int)pageDirectory >> 12;*/
140  regCr3 = (unsigned int)pageDirectory & CR3_PAGE_DIRECTORY_MASK;
141
142  i386_set_cr3( regCr3 );
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  unsigned int regCr0;
156
157  regCr0 = 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  unsigned int regCr0;
167
168  regCr0 = 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 char pagingWasEnabled;
339
340  pagingWasEnabled = 0;
341
342  if (_CPU_is_paging_enabled()){
343    pagingWasEnabled = 1;
344    _CPU_disable_paging();
345  }
346
347  linearAddr.address = (unsigned int)mappedAddress;
348  lastAddr = (unsigned int)mappedAddress + (size - 1);
349
350  while (1){
351
352    if ((linearAddr.address & ~MASK_OFFSET) > (lastAddr & ~MASK_OFFSET))
353      break;
354
355    if (pageDirectory->pageDirEntry[linearAddr.bits.directory].bits.present == 0){
356      if (pagingWasEnabled)
357        _CPU_enable_paging();
358      return -1;
359    }
360
361    localPageTable = (page_table *)(pageDirectory->
362                                    pageDirEntry[linearAddr.bits.directory].bits.
363                                    page_frame_address << 12);
364
365    if (localPageTable->pageTableEntry[linearAddr.bits.page].bits.present == 0){
366      if (pagingWasEnabled)
367        _CPU_enable_paging();
368      return -1;
369    }
370
371    localPageTable->pageTableEntry[linearAddr.bits.page].bits.present = 0;
372
373    linearAddr.address += PG_SIZE ;
374  }
375  Paging_Table_Compress();
376  if (pagingWasEnabled)
377    _CPU_enable_paging();
378
379  return 0;
380}
381
382/*
383 * Modify the flags PRESENT, WRITABLE, USER, WRITE_TROUGH, CACHE_DISABLE
384 * of the page's descriptor.
385 */
386
387int _CPU_change_memory_mapping_attribute(
388  void         **newAddress,
389  void          *mappedAddress,
390  unsigned int   size,
391  unsigned int   flag
392)
393{
394
395  linear_address linearAddr;
396  page_table *localPageTable;
397  unsigned int lastAddr ;
398  unsigned char pagingWasEnabled;
399
400  pagingWasEnabled = 0;
401
402  if (_CPU_is_paging_enabled()){
403    pagingWasEnabled = 1;
404    _CPU_disable_paging();
405  }
406
407  linearAddr.address  = (unsigned int)mappedAddress;
408  lastAddr = (unsigned int)mappedAddress + (size - 1);
409
410  while (1){
411
412    if ((linearAddr.address & ~MASK_OFFSET) > (lastAddr & ~MASK_OFFSET))
413      break;
414
415    if (pageDirectory->pageDirEntry[linearAddr.bits.directory].bits.present == 0){
416      if (pagingWasEnabled)
417        _CPU_enable_paging();
418      return -1;
419    }
420    localPageTable = (page_table *)(pageDirectory->
421                                    pageDirEntry[linearAddr.bits.directory].bits.
422                                    page_frame_address << 12);
423
424    if (localPageTable->pageTableEntry[linearAddr.bits.page].bits.present == 0){
425      if (pagingWasEnabled)
426        _CPU_enable_paging();
427      return -1;
428    }
429
430    localPageTable->pageTableEntry[linearAddr.bits.page].table_entry &= ~MASK_FLAGS ;
431    localPageTable->pageTableEntry[linearAddr.bits.page].table_entry |= flag ;
432
433    linearAddr.address += PG_SIZE ;
434  }
435
436  if (newAddress != NULL)
437    *newAddress = mappedAddress ;
438
439  if (pagingWasEnabled)
440    _CPU_enable_paging();
441
442  return 0;
443}
444
445/*
446 * Display the page descriptor flags
447 * CACHE_DISABLE of the whole memory
448 */
449
450#include <rtems/bspIo.h>
451
452int  _CPU_display_memory_attribute(void)
453{
454  unsigned int dirCount, pageCount;
455  unsigned int regCr0;
456  page_table *localPageTable;
457  unsigned int prevCache;
458  unsigned int prevPresent;
459  unsigned int maxPage;
460  unsigned char pagingWasEnabled;
461
462  regCr0 = i386_get_cr0();
463
464  printk("\n\n********* MEMORY CACHE CONFIGURATION *****\n");
465
466  printk("CR0 -> paging           : %s\n",((regCr0 & CR0_PAGING) ? "ENABLE ":"DISABLE"));
467  printk("       page-level cache : %s\n\n",((regCr0 & CR0_PAGE_LEVEL_CACHE_DISABLE) ? "DISABLE":"ENABLE"));
468
469  if ((regCr0 & CR0_PAGING) == 0)
470    return 0;
471
472  prevPresent = 0;
473  prevCache   = 1;
474
475  pagingWasEnabled = 0;
476
477  if (_CPU_is_paging_enabled()){
478    pagingWasEnabled = 1;
479    _CPU_disable_paging();
480  }
481
482  for (dirCount = 0; dirCount < directoryEntry+1; dirCount++) {
483
484    localPageTable = (page_table *)(pageDirectory->
485                                    pageDirEntry[dirCount].bits.
486                                    page_frame_address << 12);
487
488    maxPage = MAX_ENTRY;
489    /*if ( dirCount == (directoryEntry-1))
490      maxPage = tableEntry;*/
491    for (pageCount = 0; pageCount < maxPage; pageCount++) {
492
493      if (localPageTable->pageTableEntry[pageCount].bits.present != 0){
494        if (prevPresent == 0){
495          prevPresent = 1;
496          printk ("present page from address %x \n", ((dirCount << 22)|(pageCount << 12)));
497        }
498        if (prevCache != localPageTable->pageTableEntry[pageCount].bits.cache_disable ) {
499          prevCache = localPageTable->pageTableEntry[pageCount].
500            bits.cache_disable;
501          printk ("    cache %s from %x <phy %x>\n",
502                  (prevCache ? "DISABLE" : "ENABLE "),
503                  ((dirCount << 22)|(pageCount << 12)),
504                  localPageTable->pageTableEntry[pageCount].bits.page_frame_address << 12);
505        }
506      }
507      else {
508        if (prevPresent == 1){
509          prevPresent = 0;
510          printk ("Absent from %x \n", ((dirCount << 22)|(pageCount << 12)));
511        }
512      }
513    }
514  }
515  if (pagingWasEnabled)
516    _CPU_enable_paging();
517
518  return 0;
519}
Note: See TracBrowser for help on using the repository browser.