00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <const.h>
00023
00024 #include <arch/i386.h>
00025 #include <arch/mem.h>
00026 #include <arch/mmx.h>
00027
00028 #include <kernel/console.h>
00029 #include <kernel/multiboot.h>
00030 #include <kernel/kernel_map.h>
00031 #include <kernel/keyboard.h>
00032 #include <kernel/speaker.h>
00033 #include <kernel/task.h>
00034
00035 #include <arch/paging.h>
00036
00037
00038 volatile dword PHYS_MEM_DIM;
00039
00040
00041
00042 extern dword KERNEL_TOP, KERNEL_END_TEXT;
00043
00044
00045 dword *K_VIR_END;
00046
00047
00048 dword *free_frames = (dword *)&KERNEL_TOP;
00049
00050
00051 volatile dword K_PDBR[PAGE_SIZE/sizeof(dword)];
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 dword pop_frame()
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
00077 SET_IF(IF);
00078 return(NULL);
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088 void push_frame(dword p_addr)
00089 {
00090 dword IF = GET_IF();
00091
00092 disable();
00093
00094
00095 if ((dword)free_frames > ((dword)&KERNEL_TOP))
00096 {
00097 *(--free_frames)=p_addr;
00098 }
00099
00100 SET_IF(IF);
00101 }
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 bool map_page(dword vir_addr, dword phys_addr, word attribs)
00116 {
00117 dword *PTE;
00118 dword i;
00119 dword IF = GET_IF();
00120
00121
00122 vir_addr = PAGE_ALIGN(vir_addr);
00123 phys_addr = PAGE_ALIGN(phys_addr);
00124
00125
00126 attribs &= (PAGE_SIZE-1);
00127
00128 disable();
00129
00130
00131 if (*ADDR_TO_PDE(vir_addr) == NULL)
00132 {
00133
00134 PTE = (dword *)(pop_frame() * PAGE_SIZE);
00135 if (PTE == NULL)
00136 {
00137
00138 SET_IF(IF);
00139 return(FALSE);
00140 }
00141
00142
00143 *ADDR_TO_PDE(vir_addr) = (dword)PTE | P_PRESENT | P_USER | P_WRITE;
00144
00145
00146 flush_tlb_all();
00147
00148
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
00155 if (vir_addr >= K_VIR_START)
00156 K_PDBR[vir_addr/(PAGE_SIZE*1024)] = *ADDR_TO_PDE(vir_addr);
00157 }
00158
00159
00160 *ADDR_TO_PTE(vir_addr) = (dword)phys_addr | attribs;
00161
00162
00163 flush_tlb_single(vir_addr);
00164
00165 SET_IF(IF);
00166 return(TRUE);
00167 }
00168
00169
00170
00171
00172 void unmap_page(dword vir_addr)
00173 {
00174 dword temp;
00175 dword IF = GET_IF();
00176
00177
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
00186 *ADDR_TO_PTE(vir_addr) = NULL;
00187
00188
00189 flush_tlb_single(vir_addr);
00190
00191
00192
00193
00194
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
00207 push_frame(*ADDR_TO_PDE(vir_addr)/PAGE_SIZE);
00208 *ADDR_TO_PDE(vir_addr) = NULL;
00209
00210
00211 flush_tlb_all();
00212
00213
00214 if (vir_addr >= K_VIR_START)
00215 K_PDBR[vir_addr/(PAGE_SIZE*1024)] = NULL;
00216
00217 SET_IF(IF);
00218 }
00219
00220
00221
00222
00223
00224 void delete_page(dword vir_addr)
00225 {
00226 dword temp;
00227 dword IF = GET_IF();
00228
00229
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
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
00245 *ADDR_TO_PTE(vir_addr) = NULL;
00246
00247
00248 flush_tlb_single(vir_addr);
00249
00250
00251
00252
00253
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
00266 push_frame(*ADDR_TO_PDE(vir_addr)/PAGE_SIZE);
00267 *ADDR_TO_PDE(vir_addr) = NULL;
00268
00269
00270 flush_tlb_all();
00271
00272
00273 if (vir_addr >= K_VIR_START)
00274 K_PDBR[vir_addr/(PAGE_SIZE*1024)] = NULL;
00275
00276 SET_IF(IF);
00277 }
00278
00279
00280
00281
00282
00283
00284
00285 void *get_temp_page()
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
00303 SET_IF(IF);
00304 return( NULL );
00305 }
00306 continue;
00307 }
00308 }
00309
00310
00311
00312
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 }
00326
00327
00328
00329
00330
00331
00332
00333 void free_temp_page(void *p, bool do_delete)
00334 {
00335
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 }
00344
00345
00346
00347
00348
00349
00350 dword vir_to_phys(dword vir_addr)
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 }
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367 int page_fault_handler(dword err_code, dword cr2)
00368 {
00369 dword phys_addr;
00370
00371 #ifdef PAGE_DEBUG
00372 kprintf("\n\rPAGE_FAULT : %#010x", cr2);
00373 #endif
00374 if( cr2==NULL )
00375 {
00376
00377 return( -1 );
00378 }
00379
00380
00381 phys_addr = pop_frame()*PAGE_SIZE;
00382
00383
00384 if (phys_addr == NULL)
00385 {
00386 set_color(LIGHT_RED);
00387 kprintf("\n\rPage fault handler panic: Out of memory!!!");
00388 set_color(DEFAULT_COLOR);
00389 return(-1);
00390 }
00391
00392
00393 err_code &= (P_PRESENT | P_WRITE | P_USER);
00394
00395
00396 if (cr2 >= K_VIR_START)
00397 {
00398 if (!(map_page(cr2, phys_addr, P_PRESENT | P_WRITE)))
00399 {
00400
00401 set_color(LIGHT_RED);
00402 kprintf("\n\rPage fault handler panic: Out of memory!!!");
00403 set_color(DEFAULT_COLOR);
00404 return( -1 );
00405 }
00406 }
00407 else
00408 {
00409 if (!(map_page(cr2, phys_addr, P_PRESENT | P_WRITE | P_USER)))
00410 {
00411
00412 set_color(LIGHT_RED);
00413 kprintf("\n\rPage fault handler panic: Out of memory!!!");
00414 set_color(DEFAULT_COLOR);
00415 return( -1 );
00416 }
00417 }
00418
00419
00420 fast_clear_page((void *)PAGE_ALIGN(cr2));
00421 return( 0 );
00422 }
00423
00424
00425
00426
00427
00428
00429
00430
00431 void init_free_frames()
00432 {
00433
00434
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
00444
00445 *K_VIR_END=NULL;
00446 }
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456 void init_paging()
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
00468 halt();
00469 }
00470
00471
00472 init_free_frames();
00473
00474
00475 *ADDR_TO_PDE(0) = NULL;
00476
00477
00478 flush_tlb_all();
00479
00480
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
00485 for (addr=0; addr<1024; addr++)
00486 K_PDBR[addr] = ((dword *)PAGE_DIR_MAP)[addr];
00487 }
00488
00489
00490
00491
00492
00493 void dump_dirty_pages()
00494 {
00495
00496
00497 dword vir_addr;
00498 dword display=1;
00499
00500
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 }
00517
00518
00519
00520 void dump_free_frames()
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 }
00540
00541
00542
00543
00544
00545 void check_free_frames_integrity()
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 }