// vmm.c // Author: Josh Holtrop // Date: 09/30/03 PageDirectory *vmm_PDBR = 0; dword vmm_first_virtual_address = 0; void vmm_init() { if (!(vmm_PDBR = mm_palloc(1, PID_KERNEL))) { printf("ERROR! COULD NOT ALLOCATE PAGE FOR INITIAL PAGE DIRECTORY!!\n"); halt(); } vmm_init_pagetable((dword)vmm_PDBR); if (mm_totalmem % 4096) vmm_first_virtual_address = mm_totalmem + (4096 - (mm_totalmem % 4096)); else vmm_first_virtual_address = mm_totalmem; if (vmm_mapn(0, 0, 0x03, mm_totalmem/4096+1)) { printf("Could not page in all physical RAM!\n"); halt(); } //we also need to map in the video framebuffer memory: if (video_mode.PhysBasePtr > 0 && video_mode.BitsPerPixel > 0) { if (vmm_mapn(video_mode.PhysBasePtr, video_mode.PhysBasePtr, 0x03, ((video_mode.BitsPerPixel>>3) * video_mode.XResolution * video_mode.YResolution)/4096+1)) { printf("Could not page in video memory at 0x%x!\n", video_mode.PhysBasePtr); halt(); } } } void vmm_enable_paging() { write_cr3((dword)vmm_PDBR); write_cr0(0x80000000|read_cr0()); } int vmm_map1(dword virtual, dword physical, dword flags) { if (virtual & 0x00000FFF) return 1; // ERROR 1: address not page-aligned if (physical & 0x00000FFF) return 1; // ERROR 1: address not page-aligned int pde = (virtual & 0xFFC00000) >> 22; int pte = (virtual & 0x003FF000) >> 12; if (!(vmm_PDBR->pageTables[pde] & 0x01)) { vmm_PDBR->pageTables[pde] = (dword)mm_palloc(1, PID_KERNEL) | 0x7; //user, r/w, present vmm_init_pagetable(vmm_PDBR->pageTables[pde] & 0xFFFFF000); if (vmm_PDBR->pageTables[pde] == 0x07) return 2; // ERROR 2: page table could not be created } PageTable *ptp = (PageTable *)(vmm_PDBR->pageTables[pde] & 0xFFFFF000); if (ptp->page[pte] & 0x01) return 3; // ERROR 3: page table entry already exists ptp->page[pte] = physical | flags; //invlpg(); return 0; } int vmm_mapn(dword virtual, dword physical, dword flags, dword n) { int mapped; int result = 0; dword va = virtual; dword pa = physical; for (mapped = 0; mapped < n; mapped++) { if (result = vmm_map1(va, pa, flags)) { if (mapped > 0) vmm_unmapn(virtual, mapped); return result; } va += 4096; pa += 4096; } //invlpg(); return 0; } int vmm_unmap1(dword virtual) { if (virtual & 0x00000FFF) return 1; // ERROR 1: address not page-aligned int pde = (virtual & 0xFFC00000) >> 22; int pte = (virtual & 0x003FF000) >> 12; if (!(vmm_PDBR->pageTables[pde] & 0x01)) return 2; // ERROR 2: page table not present PageTable *ptp = (PageTable *)(vmm_PDBR->pageTables[pde] & 0xFFFFF000); ptp->page[pte] = 0; //invlpg(); return 0; } int vmm_unmapn(dword virtual, dword n) { int reslt; int i; for (i = 0; i < n; i++) { if (reslt = vmm_unmap1(virtual)) return reslt; virtual += 4096; } vmm_walkPageTables(); //invlpg(); return 0; } void vmm_init_pagetable(dword address) { PageTable *ptp = (PageTable *)address; int n; for (n = 0; n < 1024; n++) ptp->page[n] = 0; } int vmm_walkPageTables() { int pde; int pte; int used_ptes; PageTable *ptp; for (pde = 0; pde < 1024; pde++) { if (vmm_PDBR->pageTables[pde] & 0x01) { used_ptes = 0; ptp = (PageTable *)(vmm_PDBR->pageTables[pde] & 0xFFFFF000); for (pte = 0; pte < 1024; pte++) { if (ptp->page[pte] & 0x01) //page table entry present used_ptes++; } if (!(used_ptes)) //no used pte's -- remove page table & page directory entry { mm_pfree(ptp); vmm_PDBR->pageTables[pde] = 0; } } } return 0; } void *malloc(dword bytes) { } int free(void *ptr) { }