#include <const.h>
#include <arch/i386.h>
#include <arch/mem.h>
#include <arch/mmx.h>
#include <kernel/console.h>
#include <kernel/multiboot.h>
#include <kernel/kernel_map.h>
#include <kernel/keyboard.h>
#include <kernel/speaker.h>
#include <kernel/task.h>
#include <arch/paging.h>
Go to the source code of this file.
Functions | |||||||
dword | pop_frame () | ||||||
Pop a free frame from the free frames stack.
| |||||||
void | push_frame (dword p_addr) | ||||||
Push a free frame into the free frames stack.
| |||||||
bool | map_page (dword vir_addr, dword phys_addr, word attribs) | ||||||
Map a physical address into a virtual address for the current address space.
| |||||||
void | unmap_page (dword vir_addr) | ||||||
Unmap a page, but doesn't destroy the physical frame.
| |||||||
void | delete_page (dword vir_addr) | ||||||
Unmap a page and destroy the physical frame where the address is mapped.
| |||||||
void * | get_temp_page () | ||||||
Get a free virtual page from the temporary memory area.
| |||||||
void | free_temp_page (void *p, bool do_delete) | ||||||
Free a virtual temporary page allocated by get_temp_page().
| |||||||
dword | vir_to_phys (dword vir_addr) | ||||||
Translate a virtual address into the physical address.
| |||||||
int | page_fault_handler (dword err_code, dword cr2) | ||||||
This is the page-fault handler. Every time a page-fault occurs, this routine must be invoked.
| |||||||
void | init_free_frames () | ||||||
Initialize the free frames stack.
| |||||||
void | init_paging () | ||||||
Initialize the paging mechanism.
| |||||||
void | dump_dirty_pages () | ||||||
Dump the dirty pages to stdout. | |||||||
void | dump_free_frames () | ||||||
Dump the free frames to stdout. | |||||||
void | check_free_frames_integrity () | ||||||
This process checks the free frames stack integrity.
| |||||||
Variables | |||||||
volatile dword | PHYS_MEM_DIM | ||||||
The physical memory dimension. Initialized in paging.c. | |||||||
dword | KERNEL_TOP | ||||||
The kernel bounds. These variables must be declared externally into the linker script. | |||||||
dword | KERNEL_END_TEXT | ||||||
The kernel bounds. These variables must be declared externally into the linker script. | |||||||
dword * | K_VIR_END | ||||||
End of kernel virtual space. | |||||||
dword * | free_frames = (dword *)&KERNEL_TOP | ||||||
Free-frames stack - placed just above kernel memory. | |||||||
volatile dword | K_PDBR [PAGE_SIZE/sizeof(dword)] | ||||||
Master page directory. |
/* kernel.ld * The GNU linker script for minirighi. * Author: Andrea Righi <drizzt@inwind.it> */ OUTPUT_FORMAT("elf32-i386","elf32-i386","elf32-i386") K_VIR_START = 0xC0000000; K_PHYS_START = 0x100000; K_STACK_SIZE = 0x1000; PAGE_SIZE = 0x1000; ENTRY (_start) SECTIONS { .text K_VIR_START : AT(K_PHYS_START) { KERNEL_TEXT = .; *(.text*) *(.rodata*) . = ALIGN(PAGE_SIZE); KERNEL_END_TEXT = .; } .data : AT(K_PHYS_START + (KERNEL_DATA - KERNEL_TEXT)) { KERNEL_DATA = .; *(.data*) . = ALIGN(PAGE_SIZE); KERNEL_END_DATA = .; } .bss : AT(K_PHYS_START + (KERNEL_BSS - KERNEL_TEXT)) { _stack_end = .; . += K_STACK_SIZE; _stack_start = .; K_STACK_START = .; KERNEL_BSS = .; *(.bss*) . = ALIGN(PAGE_SIZE); *(COMMON*) . = ALIGN(PAGE_SIZE); KERNEL_END_BSS = .; } . = ALIGN(PAGE_SIZE); KERNEL_TOP = .; }
Definition in file paging.c.
|
This process checks the free frames stack integrity.
Definition at line 545 of file paging.c.
00546 { 00547 dword flag, i; 00548 dword *j; 00549 00550 kprintf("\n\rChecking free frames integrity (%s)...\n\r", get_pname()); 00551 for (i=P_ADDR_16MB; i<ADDR_TO_PAGE(PHYS_MEM_DIM); i++) 00552 { 00553 flag=0; 00554 for (j=free_frames; j<K_VIR_END; j++) 00555 { 00556 if (*j == i) flag++; 00557 } 00558 if (flag>1) kprintf("\n\rError! frame:%#010x", i); 00559 } 00560 beep(); 00561 kprintf("\n\rCheck done.\n\r"); 00562 _exit( 0 ); 00563 } |
|
Unmap a page and destroy the physical frame where the address is mapped.
Definition at line 224 of file paging.c.
00225 { 00226 dword temp; 00227 dword IF = GET_IF(); 00228 00229 // Align address to the page boundary // 00230 vir_addr = PAGE_ALIGN(vir_addr); 00231 00232 if (*ADDR_TO_PDE(vir_addr) == NULL) return; 00233 if (*ADDR_TO_PTE(vir_addr) == NULL) return; 00234 00235 disable(); 00236 00237 // Push the physical frame into the free frames stack // 00238 if ( 00239 (vir_to_phys(vir_addr) >= DMA_MEMORY_END) && 00240 (vir_to_phys(vir_addr) < PHYS_MEM_DIM) 00241 ) 00242 push_frame(vir_to_phys(vir_addr)/PAGE_SIZE); 00243 00244 // Unmap the page // 00245 *ADDR_TO_PTE(vir_addr) = NULL; 00246 00247 // Invalidate the page in the TLB cache // 00248 flush_tlb_single(vir_addr); 00249 00250 // Check if it is possible to deallocate the frame 00251 // of the page table used to map the address 00252 // So let's examine all entries in the page table 00253 // where the address is mapped. 00254 00255 for( temp = PAGE_DIR_ALIGN(vir_addr); 00256 temp < PAGE_DIR_ALIGN_UP(vir_addr); 00257 temp += PAGE_SIZE ) 00258 00259 if (*ADDR_TO_PTE(temp) != NULL) 00260 { 00261 SET_IF(IF); 00262 return; 00263 } 00264 00265 // No PTEs found... deallocate the page table! // 00266 push_frame(*ADDR_TO_PDE(vir_addr)/PAGE_SIZE); 00267 *ADDR_TO_PDE(vir_addr) = NULL; 00268 00269 // Ivalidate the whole TLB cache // 00270 flush_tlb_all(); 00271 00272 // ...and update the master page directory! // 00273 if (vir_addr >= K_VIR_START) 00274 K_PDBR[vir_addr/(PAGE_SIZE*1024)] = NULL; 00275 00276 SET_IF(IF); 00277 } |
|
Dump the dirty pages to stdout.
Definition at line 493 of file paging.c.
00494 { 00495 // Show all the dirty pages // 00496 00497 dword vir_addr; 00498 dword display=1; 00499 00500 // Print all the dirty pages // 00501 kprintf("\n\rDirty pages:\n\r"); 00502 for (vir_addr = 0; vir_addr<PAGE_TABLE_MAP; vir_addr += PAGE_SIZE) 00503 if (*ADDR_TO_PDE(vir_addr) != NULL) 00504 if ((*ADDR_TO_PTE(vir_addr) & P_DIRTY) == P_DIRTY) 00505 { 00506 if (!(display = display++ % 24)) 00507 if (kgetchar() == CTRL_C) 00508 { 00509 kprintf("\n\r"); 00510 return; 00511 } 00512 kprintf("\n\rvir_addr = %#010x\tpage_entry = %#010x", 00513 vir_addr, *(ADDR_TO_PTE(vir_addr))); 00514 } 00515 kprintf("\n\r"); 00516 } |
|
Dump the free frames to stdout.
Definition at line 520 of file paging.c.
00521 { 00522 dword *f = free_frames; 00523 dword display=1; 00524 00525 kprintf("\n\rFree frames list: (KERNEL_TOP=%#010x)\n\r", (dword)&KERNEL_TOP); 00526 for(;;) 00527 { 00528 if (*f == NULL) break; 00529 if (!(display = display++ % 24)) 00530 if (kgetchar() == CTRL_C) 00531 { 00532 kprintf("\n\r"); 00533 return; 00534 } 00535 kprintf("\n\rframe=%#010x &frame=%#010x", *f, (dword)f); 00536 f++; 00537 } 00538 kprintf("\n\r"); 00539 } |
|
Free a virtual temporary page allocated by get_temp_page().
Definition at line 333 of file paging.c.
00334 { 00335 // Is the page into the temporary memory range?! // 00336 if ( (((dword)p >= (K_MEM_TEMP_START))) && ((dword)p < K_MEM_TEMP_END) ) 00337 { 00338 if ( do_delete ) 00339 delete_page( (dword)p ); 00340 else 00341 unmap_page( (dword)p ); 00342 } 00343 } |
|
Get a free virtual page from the temporary memory area.
Definition at line 285 of file paging.c.
00286 { 00287 byte *p = (byte *)K_MEM_TEMP_START; 00288 size_t frame; 00289 dword IF = GET_IF(); 00290 00291 disable(); 00292 00293 while(TRUE) 00294 { 00295 if ( *ADDR_TO_PDE((size_t)p) ) 00296 { 00297 if ( *ADDR_TO_PTE((size_t)p) ) 00298 { 00299 p += PAGE_SIZE; 00300 if (p >= (byte *)K_MEM_TEMP_END) 00301 { 00302 // Out of temporary memory! // 00303 SET_IF(IF); 00304 return( NULL ); 00305 } 00306 continue; 00307 } 00308 } 00309 // OK! A free temporary page has been found! // 00310 // Now map this page to a free frame and return the // 00311 // virtual address of this page, or NULL if there is // 00312 // no free frame. 00313 frame = ( pop_frame()*PAGE_SIZE ); 00314 if ( frame==NULL ) 00315 { 00316 p = NULL; 00317 } 00318 else if ( !map_page((dword)p, frame, P_PRESENT | P_WRITE) ) 00319 { 00320 p = NULL; 00321 } 00322 SET_IF(IF); 00323 return( (void *)p ); 00324 } 00325 } |
|
Initialize the free frames stack.
Definition at line 431 of file paging.c.
00432 { 00433 // First physical 16MB are reserved for kernel, BIOS & DMA // 00434 // so let's start with free memory area at 16MB // 00435 register dword p_addr=P_ADDR_16MB; 00436 00437 K_VIR_END = free_frames; 00438 while (p_addr < ADDR_TO_PAGE(PHYS_MEM_DIM)) 00439 { 00440 *K_VIR_END++=p_addr++; 00441 } 00442 00443 // Last frame is NULL => out of physical memory. // 00444 // Kernel virtual address space ends here: // 00445 *K_VIR_END=NULL; 00446 } |
|
Initialize the paging mechanism.
Definition at line 456 of file paging.c.
00457 { 00458 extern multiboot_info_t *boot_info; 00459 size_t addr; 00460 00461 if (boot_info->flags & 0x02) 00462 { 00463 PHYS_MEM_DIM = (boot_info->mem_upper)*1024; 00464 } 00465 else 00466 { 00467 // Error reading multiboot informations... halting!. 00468 halt(); 00469 } 00470 00471 // Initialize free frames stack // 00472 init_free_frames(); 00473 00474 // Unmap first 4MB identical-map pages. 00475 *ADDR_TO_PDE(0) = NULL; 00476 00477 // Flush the whole TLB cache. 00478 flush_tlb_all(); 00479 00480 // Map part of physical memory into the kernel address space // 00481 for (addr=PHYS_MEM_START; addr<PHYS_MEM_END; addr+=PAGE_SIZE) 00482 map_page(addr, addr-PHYS_MEM_START, P_PRESENT | P_WRITE); 00483 00484 // Initialize master page directory // 00485 for (addr=0; addr<1024; addr++) 00486 K_PDBR[addr] = ((dword *)PAGE_DIR_MAP)[addr]; 00487 } |
|
Map a physical address into a virtual address for the current address space.
Definition at line 115 of file paging.c.
00116 { 00117 dword *PTE; 00118 dword i; 00119 dword IF = GET_IF(); 00120 00121 // Round virtual & physical address to the page boundary // 00122 vir_addr = PAGE_ALIGN(vir_addr); 00123 phys_addr = PAGE_ALIGN(phys_addr); 00124 00125 // Get only valid attribs // 00126 attribs &= (PAGE_SIZE-1); 00127 00128 disable(); 00129 00130 // If the page directory entry is NULL must be created // 00131 if (*ADDR_TO_PDE(vir_addr) == NULL) 00132 { 00133 // Create a new page table // 00134 PTE = (dword *)(pop_frame() * PAGE_SIZE); 00135 if (PTE == NULL) 00136 { 00137 // Out of memory!!! // 00138 SET_IF(IF); 00139 return(FALSE); 00140 } 00141 00142 // Set the PDE as present, user level, read-write // 00143 *ADDR_TO_PDE(vir_addr) = (dword)PTE | P_PRESENT | P_USER | P_WRITE; 00144 00145 // Flush the whole TLB cache // 00146 flush_tlb_all(); 00147 00148 // NULL every PTE entry // 00149 for (i=PAGE_DIR_ALIGN(vir_addr); i<PAGE_DIR_ALIGN_UP(vir_addr); i+=PAGE_SIZE) 00150 { 00151 *ADDR_TO_PTE(i) = NULL; 00152 } 00153 00154 // Update master page directory // 00155 if (vir_addr >= K_VIR_START) 00156 K_PDBR[vir_addr/(PAGE_SIZE*1024)] = *ADDR_TO_PDE(vir_addr); 00157 } 00158 00159 // Store the physical address into the page table entry // 00160 *ADDR_TO_PTE(vir_addr) = (dword)phys_addr | attribs; 00161 00162 // Invalidate the page in the TLB cache // 00163 flush_tlb_single(vir_addr); 00164 00165 SET_IF(IF); 00166 return(TRUE); 00167 } |
|
Pop a free frame from the free frames stack.
Definition at line 61 of file paging.c.
00062 { 00063 dword ret; 00064 dword IF = GET_IF(); 00065 00066 disable(); 00067 00068 if (*free_frames != NULL) 00069 { 00070 ret = *free_frames++; 00071 00072 SET_IF(IF); 00073 return(ret); 00074 } 00075 00076 // Out of memory!!! // 00077 SET_IF(IF); 00078 return(NULL); 00079 } |
|
Push a free frame into the free frames stack.
Definition at line 88 of file paging.c.
00089 { 00090 dword IF = GET_IF(); 00091 00092 disable(); 00093 00094 // Push the frame into free frames stack // 00095 if ((dword)free_frames > ((dword)&KERNEL_TOP)) 00096 { 00097 *(--free_frames)=p_addr; 00098 } 00099 00100 SET_IF(IF); 00101 } |
|
Unmap a page, but doesn't destroy the physical frame.
Definition at line 172 of file paging.c.
00173 { 00174 dword temp; 00175 dword IF = GET_IF(); 00176 00177 // Align address to the page boundary // 00178 vir_addr = PAGE_ALIGN(vir_addr); 00179 00180 if (*ADDR_TO_PDE(vir_addr) == NULL) return; 00181 if (*ADDR_TO_PTE(vir_addr) == NULL) return; 00182 00183 disable(); 00184 00185 // Unmap the page // 00186 *ADDR_TO_PTE(vir_addr) = NULL; 00187 00188 // Invalidate the page in the TLB cache // 00189 flush_tlb_single(vir_addr); 00190 00191 // Check if it is possible to deallocate the frame 00192 // of the page table used to map the address 00193 // So let's examine all entries in the page table 00194 // where the address is mapped. 00195 00196 for( temp = PAGE_DIR_ALIGN(vir_addr); 00197 temp < PAGE_DIR_ALIGN_UP(vir_addr); 00198 temp += PAGE_SIZE) 00199 00200 if (*ADDR_TO_PTE(temp) != NULL) 00201 { 00202 SET_IF(IF); 00203 return; 00204 } 00205 00206 // No PTEs found... deallocate the page table! // 00207 push_frame(*ADDR_TO_PDE(vir_addr)/PAGE_SIZE); 00208 *ADDR_TO_PDE(vir_addr) = NULL; 00209 00210 // Invalidate the whole TLB cache // 00211 flush_tlb_all(); 00212 00213 // ...and update the master page directory! // 00214 if (vir_addr >= K_VIR_START) 00215 K_PDBR[vir_addr/(PAGE_SIZE*1024)] = NULL; 00216 00217 SET_IF(IF); 00218 } |
|
Translate a virtual address into the physical address.
Definition at line 350 of file paging.c.
00351 { 00352 if (*ADDR_TO_PDE(vir_addr) == NULL) return(NULL); 00353 return ((*ADDR_TO_PTE(vir_addr) & -PAGE_SIZE) + (vir_addr % PAGE_SIZE)); 00354 } |
|
Free-frames stack - placed just above kernel memory.
|
|
Master page directory.
|
|
End of kernel virtual space.
|
|
The kernel bounds. These variables must be declared externally into the linker script.
|
|
The kernel bounds. These variables must be declared externally into the linker script.
|