/***************************************************************************************** Copyright (c) 2002 The UbixOS Project All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions, the following disclaimer and the list of authors. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, the following disclaimer and the list of authors in the documentation and/or other materials provided with the distribution. Neither the name of the UbixOS Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. $Log$ Revision 1.4 2004/06/10 22:23:56 reddawg Volatiles Revision 1.3 2004/06/10 15:24:35 reddawg Fixed an asm statement Revision 1.2 2004/05/22 21:46:37 reddawg Fixed some bugs Revision 1.1.1.1 2004/04/15 12:06:52 reddawg UbixOS v1.0 Revision 1.30 2004/04/13 16:36:34 reddawg Changed our copyright, it is all now under a BSD-Style license $Id$ *****************************************************************************************/ #include <vmm/vmm.h> #include <lib/kprintf.h> #include <lib/kmalloc.h> #include <ubixos/types.h> #include <ubixos/kpanic.h> #include <ubixos/sched.h> uInt32 *kernelPageDirectory = 0x0; /************************************************************************ Function: int vmmPagingInit() Description: This Function Will Initialize The Operating Systems Paging Abilities. Notes: 02/20/2004 - Looked Over Code And Have Approved Its Quality ************************************************************************/ int vmmPagingInit() { uInt32 i = 0x0, x = 0x0; uInt32 *pageTable = 0x0; /* Allocate A Page Of Memory For Kernels Page Directory */ kernelPageDirectory = (uInt32 *) vmmFindFreePage(sysID); if (kernelPageDirectory == 0x0) { kpanic("Error: vmmFindFreePage Failed"); return (-1); } /* Clear The Memory To Ensure There Is No Garbage */ for (i = 0; i < pageEntries; i++) { (uInt32) kernelPageDirectory[i] = (uInt32) 0x0; } /* Allocate A Page For The First 4MB Of Memory */ pageTable = (uInt32 *) vmmFindFreePage(sysID); if (pageTable == 0x0) { kpanic("Error: vmmFindFreePage Failed"); return (-1); } /* Map The First Page Table For The First 4MB Of Memory */ kernelPageDirectory[0] = (uInt32) ((uInt32) (pageTable) | pagePresent | pageWrite | pageUser); /* Make Sure The Page Table Is Clean */ for (i = 0; i < pageEntries; i++) { (uInt32) pageTable[i] = (uInt32) 0x0; } /* Map The First 1MB Of Memory To The Kernel VM Space */ for (i = 0; i < (pageEntries / 4); i++) { pageTable[i] = (uInt32) ((i * 0x1000) | pagePresent | pageWrite | pageUser); } /* * Create Page Tables For The Top 1GB Of VM Space This Is To Be Shared With * All VM Spaces */ for (i = 768; i < pageEntries; i++) { /* Allocate Page Table */ pageTable = (uInt32 *) vmmFindFreePage(sysID); if (pageTable == 0x0) { kpanic("Error: vmmFindFreePage Failed"); return (-1); } /* Make Sure The Page Table Is Clean */ for (x = 0; x < pageEntries; x++) { (uInt32) pageTable[x] = (uInt32) 0x0; } /* Map In The Page Directory */ kernelPageDirectory[i] = (uInt32) ((uInt32) (pageTable) | pagePresent | pageWrite); } /* Allocate Page Table 767 To Be The Map Of All Page Tables Used In Page Directory pageTable = (uInt32 *) vmmFindFreePage(sysID); if (pageTable == 0x0) { kpanic("Error: vmmFindFreePage Failed"); return (0x1); } /* Clean Page Table */ for (x = 0; x < pageEntries; x++) { (uInt32) pageTable[x] = (uInt32) 0x0; } kernelPageDirectory[767] = ((uInt32) pageTable | pagePresent | pageWrite); for (i = 0; i < pageEntries; i++) { pageTable[i] = kernelPageDirectory[i]; } /* Also Set Up Page Directory To Be The The First Page In 0xE0400000 */ pageTable = (uInt32 *) (kernelPageDirectory[0] & 0xFFFFF000); pageTable[256] = (uInt32) ((uInt32) (kernelPageDirectory) | pagePresent | pageWrite); /* Now Lets Turn On Paging With This Initial Page Table */ asm volatile( "movl %0,%%eax \n" "movl %%eax,%%cr3 \n" "movl %%cr0,%%eax \n" "orl $0x80010000,%%eax \n" /* Flags To Enable Paging With * Protection */ "movl %%eax,%%cr0 \n" : : "d"((uInt32 *) (kernelPageDirectory)) ); /* Remap The Memory List */ for (i = 0x101000; i <= (0x101000 + (numPages * sizeof(mMap))); i += 0x1000) { vmmRemapPage(i, (vmmMemoryMapAddr + (i - 0x101000))); } /* Set New Address For Memory Map Since Its Relocation */ vmmMemoryMap = (mMap *) vmmMemoryMapAddr; /* Print information on paging */ kprintf("paging0 - Address: [0x%X], PagingISR Address: [0x%X]\n", kernelPageDirectory, &_vmmPageFault); /* Return so we know everything went well */ return (0x0); } /************************************************************************ Function: int vmmRemapPage(Physical Source,Virtual Destination) Description: This Function Will Remap A Physical Page Into Virtual Space Notes: 07/29/02 - Rewrote This To Work With Our New Paging System 07/30/02 - Changed Address Of Page Tables And Page Directory ************************************************************************/ int vmmRemapPage(uInt32 source, uInt32 dest) { uInt16 destPageDirectoryIndex = 0, destPageTableIndex = 0; uInt32 *pageDir, *pageTable; int i = 0x0; /* * Set Pointer pageDirectory To Point To The Virtual Mapping Of The Page * Directory */ pageDir = (uInt32 *) parentPageDirAddr; /* Check To See If Page Table Exists */ destPageDirectoryIndex = (dest / (1024 * 4096)); if ((pageDir[destPageDirectoryIndex] & pagePresent) != pagePresent) { /* If Page Table Is Non Existant Then Set It Up */ pageDir[destPageDirectoryIndex] = (uInt32) vmmFindFreePage(sysID) | pageDefault; i = 1; /* Also Add It To Virtual Space So We Can Make Changes Later */ pageTable = (uInt32 *) (tablesBaseAddress + (4096 * 767)); pageTable[destPageDirectoryIndex] = pageDir[destPageDirectoryIndex]; /* Reload Page Directory */ asm volatile( "movl %cr3,%eax\n" "movl %eax,%cr3\n" ); } /* Set Address To Page Table */ pageTable = (uInt32 *) (tablesBaseAddress + (4096 * destPageDirectoryIndex)); if (i != 0x0) { for (i=0x0;i<pageEntries;i++) { pageTable[i] = (uInt32) 0x0; } } /* Get The Index To The Page Table */ destPageTableIndex = ((dest - (destPageDirectoryIndex * (1024 * 4096))) / 4096); /* If The Page Is Mapped In Free It Before We Remap */ if ((pageTable[destPageTableIndex] & pagePresent) == pagePresent) { /* Clear The Page First For Security Reasons */ freePage(((uInt32) pageTable[destPageTableIndex] & 0xFFFFF000)); } /* Set The Source Address In The Destination */ pageTable[destPageTableIndex] = (uInt32) (source | pageDefault); /* Reload The Page Table; */ asm volatile( "movl %cr3,%eax\n" "movl %eax,%cr3\n" ); /* Return */ return (source); } /************************************************************************ Function: void *vmmGetFreeKernelPage(pidType pid); Description: Returns A Free Page Mapped To The VM Space Notes: 07/30/02 - This Returns A Free Page In The Top 1GB For The Kernel ************************************************************************/ void * vmmGetFreeKernelPage(pidType pid, uInt16 count) { int x = 0, y = 0, c = 0; uInt32 *pageTableSrc = 0x0; /* Lets Search For A Free Page */ for (x = 768; x < 1024; x++) { /* Set Page Table Address */ pageTableSrc = (uInt32 *) (tablesBaseAddress + (4096 * x)); for (y = 0; y < 1024; y++) { /* Loop Through The Page Table Find An UnAllocated Page */ if ((uInt32) pageTableSrc[y] == (uInt32) 0x0) { if (count > 1) { for (c = 0; c < count; c++) { if ((uInt32) pageTableSrc[y + c] != (uInt32) 0x0) { c = -1; break; } } if (c != -1) { for (c = 0; c < count; c++) { vmmRemapPage((uInt32) vmmFindFreePage(pid), ((x * (1024 * 4096)) + ((y + c) * 4096))); vmmClearVirtualPage((uInt32) ((x * (1024 * 4096)) + ((y + c) * 4096))); } return ((void *)((x * (1024 * 4096)) + (y * 4096))); } } else { /* Map A Physical Page To The Virtual Page */ /* * vmmRemapPage((uInt32)vmmFindFreePage(pid),((x*(1024*4096))+(y*409 * 6)),pid); */ vmmRemapPage((uInt32) vmmFindFreePage(pid), ((x * (1024 * 4096)) + (y * 4096))); /* Clear This Page So No Garbage Is There */ vmmClearVirtualPage((uInt32) ((x * (1024 * 4096)) + (y * 4096))); /* Return The Address Of The Newly Allocate Page */ return ((void *)((x * (1024 * 4096)) + (y * 4096))); } } } } /* If No Free Page Was Found Return NULL */ return (0x0); } /************************************************************************ Function: void vmmClearVirtualPage(uInt32 pageAddr); Description: This Will Null Out A Page Of Memory Notes: ************************************************************************/ int vmmClearVirtualPage(uInt32 pageAddr) { uInt32 *src = 0x0; int counter = 0x0; /* Set Source Pointer To Virtual Page Address */ src = (uInt32 *) pageAddr; /* Clear Out The Page */ for (counter = 0x0; counter < pageEntries; counter++) { (uInt32) src[counter] = (uInt32) 0x0; } /* Return */ return (0x0); } void *vmmMapFromTask(pidType pid,void *ptr,uInt32 size) { kTask_t *child = 0x0; uInt32 i = 0x0,x = 0x0,y = 0x0,count = ((size+4095)/0x1000),c = 0x0; uInt16 dI = 0x0,tI = 0x0; uInt32 baseAddr = 0x0,offset = 0x0; uInt32 *childPageDir = (uInt32 *)0x5A00000; uInt32 *childPageTable = 0x0; uInt32 *pageTableSrc = 0x0; offset = (uInt32)ptr & 0xFFF; baseAddr = (uInt32)ptr & 0xFFFFF000; child = schedFindTask(pid); //Calculate The Page Table Index And Page Directory Index dI = (baseAddr/(1024*4096)); tI = ((baseAddr-(dI*(1024*4096)))/4096); vmmRemapPage(child->tss.cr3,0x5A00000); for (i=0;i<0x1000;i++) { vmmRemapPage(childPageDir[i],0x5A01000 + (i * 0x1000)); } for (x=(_current->oInfo.vmStart/(1024*4096));x<1024;x++) { pageTableSrc = (uInt32 *)(tablesBaseAddress + (4096*x)); for (y=0;y<1024;y++) { //Loop Through The Page Table Find An UnAllocated Page if ((uInt32)pageTableSrc[y] == (uInt32)0x0) { if (count > 1) { for (c=0;((c<count) && (y+c < 1024));c++) { if ((uInt32)pageTableSrc[y+c] != (uInt32)0x0) { c = -1; break; } } if (c != -1) { for (c=0;c<count;c++) { if ((tI + c) >= 0x1000) { dI++; tI = 0-c; } childPageTable = (uInt32 *)(0x5A01000 + (0x1000 * dI)); vmmRemapPage(childPageTable[tI+c],((x*(1024*4096))+((y+c)*4096))); } vmmUnmapPage(0x5A00000,1); for (i=0;i<0x1000;i++) { vmmUnmapPage((0x5A01000 + (i*0x1000)),1); } return((void *)((x*(1024*4096))+(y*4096)+offset)); } } else { //Map A Physical Page To The Virtual Page childPageTable = (uInt32 *)(0x5A01000 + (0x1000 * dI)); vmmRemapPage(childPageTable[tI],((x*(1024*4096))+(y*4096))); //Return The Address Of The Mapped In Memory vmmUnmapPage(0x5A00000,1); for (i=0;i<0x1000;i++) { vmmUnmapPage((0x5A01000 + (i*0x1000)),1); } return((void *)((x*(1024*4096))+(y*4096)+offset)); } } } } return(0x0); } /*** END ***/