📄 kernelpage.c
字号:
int status = 0; // Make it occupy the first spot. kernelPageDir = pageDirList[numberPageDirectories++]; // Get some physical memory for the page directory. The physical // address we use for this is static, and is defined in kernelParameters.h if ((kernelPagingData % MEMORY_PAGE_SIZE) != 0) return (status = ERR_ALIGN); kernelPageDir->physical = (kernelPageDirPhysicalMem *) kernelPagingData; // Make the virtual address be physical for now kernelPageDir->virtual = kernelPageDir->physical; // Clear the physical memory kernelMemClear((void *) kernelPageDir->physical, sizeof(kernelPageDirPhysicalMem)); kernelPageDir->processId = KERNELPROCID; kernelPageDir->numberShares = 0; kernelPageDir->parent = 0; kernelPageDir->privilege = PRIVILEGE_SUPERVISOR; return (status = 0);}static int firstPageTable(void){ // This will create the first page table, specifically for the // kernel. Just as like the first page directory, we don't want to map // it into the current, temporary page directory set up by the loader. // We have to do this one manually. Returns a pointer to the first table // on success, NULL on failure. int status = 0; int tableNumber = 0; kernelPageTable *table = NULL; // Assign the page table to a slot table = pageTableList[numberPageTables++]; // Get some physical memory for the page table. The base physical // address we use for this is static, and is defined in // kernelParameters.h if ((kernelPagingData % MEMORY_PAGE_SIZE) != 0) return (status = ERR_ALIGN); tableNumber = getTableNumber(KERNEL_VIRTUAL_ADDRESS); table->directory = kernelPageDir; table->tableNumber = tableNumber; table->freePages = PAGE_PAGES_PER_TABLE; table->physical = (kernelPageTablePhysicalMem *) (kernelPagingData + sizeof(kernelPageDirPhysicalMem)); // Make the virtual address be physical, for now table->virtual = table->physical; // Clear the physical memory kernelMemClear((void *) table->physical, sizeof(kernelPageTablePhysicalMem)); // Now we actually go into the page directory memory and add the // real page table to the requested slot number. // Write the page table entry into the kernel's page directory. // Enable read/write and page-present kernelPageDir->physical->table[tableNumber] = (unsigned) table->physical; kernelPageDir->physical->table[tableNumber] |= (PAGEFLAG_WRITABLE | PAGEFLAG_PRESENT); return (status = 0);}static int kernelPaging(unsigned kernelMemory){ // This function will reinitialize the paging environment at kernel // startup. This needs to be handled differently than when regular // processes are created. int status = 0; kernelPageDirPhysicalMem *oldPageDirectory = NULL; kernelPageTablePhysicalMem *oldPageTable = NULL; kernelPageTable *newPageTable = NULL; int tableNumber = 0; int pageNumber = 0; void *kernelAddress; // Interrupts should currently be disabled at this point. kernelProcessorSuspendInts(status); // The kernel is currently located at kernelVirtualAddress (virtually). // We need to locate the current, temporary page directory, then the page // table that corresponds to kernelVirtualAddress. From there, we need // to copy the contents of the page table(s) until all of the kernel's // current memory set has been remapped. // Get the address of the old page directory. In this special instance, // the physical address we get back from this call can be used like // a virtual address, since the lower part of memory should presently // be identity-mapped. kernelProcessorGetCR3(oldPageDirectory); oldPageDirectory = (kernelPageDirPhysicalMem *) ((unsigned) oldPageDirectory & 0xFFFFF800); // The index of the page table can be determined from the virtual // address of the kernel. This will be the same value we use in our // new page directory. tableNumber = getTableNumber(KERNEL_VIRTUAL_ADDRESS); // Get the old page table address. The number of the old page table // can be used as an index into the old page directory. We mask out // the lower 12 bits of the value we find at that index, and voila, we // have a pointer to the old page table. Again, we could normally // not use this for much since it's a physical address, but again, // this time it's also a virtual address. oldPageTable = (kernelPageTablePhysicalMem *) (oldPageDirectory->table[tableNumber] & 0xFFFFF000); if (oldPageTable == NULL) return (status = ERR_NOTINITIALIZED); // Create a new page directory for the kernel. We have to do this // differently, as opposed to calling createPageDirectory(), since this // should not be "mapped" into the current, temporary page directory. status = firstPageDirectory(); if (status < 0) return (status = ERR_NOTINITIALIZED); // Create a new, initial page table for the kernel. Again, we have to // do this manually, as opposed to calling createPageTable(), since // this should also not be mapped into the current, temporary page // directory. status = firstPageTable(); if (status < 0) return (status = ERR_NOTINITIALIZED); // The index of the first page in the page table can also be determined // from the virtual address of the kernel. This will be the same value // we use to start our new page tables. pageNumber = getPageNumber(KERNEL_VIRTUAL_ADDRESS); // Copy the RELEVANT contents of the old page table into the new // page table. This suggests that some of the data in the old page // table might be irrelevant. That would be correct. You see, the // loader might (presently DOES) map pages gratuitously, irrespective // of how many pages the kernel actually uses. We will only copy the // pages that the kernel uses, based on the kernelSize. The following // code needs to assume that the kernel does not cross a 4-Mb boundary. newPageTable = findPageTable(kernelPageDir, tableNumber); if (newPageTable == NULL) return (status = ERR_NOTINITIALIZED); // Map the kernel memory into the existing page directory and page // table kernelAddress = (void *) KERNEL_VIRTUAL_ADDRESS; // Map the kernel itself at the prescribed virtual address status = map(kernelPageDir, (void *) KERNEL_LOAD_ADDRESS, &kernelAddress, kernelMemory, PAGE_MAP_EXACT, 1); // last by Davide Airaghi if (status < 0) return (status); status = map(kernelPageDir, (void *) kernelPageDir->physical, (void **) &(kernelPageDir->virtual), sizeof(kernelPageDirPhysicalMem), PAGE_MAP_ANY, 1); // last by Davide Airaghi if (status < 0) return (status); status = map(kernelPageDir, (void *) newPageTable->physical, (void **) &(newPageTable->virtual), sizeof(kernelPageTablePhysicalMem), PAGE_MAP_ANY, 1 ); // last by Davide Airaghi if (status < 0) return (status); // Now we should be able to switch the processor to our new page // directory and table(s). kernelProcessorSetCR3((unsigned) kernelPageDir->physical); // Return success return (status = 0);}static void shareKernelPages(kernelPageDirectory *directory){ // This routine will put pointers to the kernel's page tables into the // supplied page directory. This effectively puts the kernel "into // the virtual address space" of the process that owns the directory. int kernelStartingTable = 0; int count; // Determine the starting page table of the kernel's address space kernelStartingTable = getTableNumber(KERNEL_VIRTUAL_ADDRESS); // We will do a loop, copying the table entries from the kernel's // page directory to the target page directory. for (count = kernelStartingTable; count < PAGE_TABLES_PER_DIR; count ++) directory->virtual->table[count] = kernelPageDir->virtual->table[count]; // Return return;}static int setPageAttrs(kernelPageDirectory *directory, int set, unsigned char flags, void *virtualAddress, int pages){ // This allows the setting/clearing of page attributes int status = 0; kernelPageTable *pageTable = NULL; int pageNumber = 0; while (pages > 0) { pageTable = findPageTable(directory, getTableNumber(virtualAddress)); if (pageTable == NULL) return (status = ERR_NOSUCHENTRY); pageNumber = getPageNumber(virtualAddress); for ( ; (pages > 0) && (pageNumber < PAGE_PAGES_PER_TABLE); pageNumber ++) { if (!pageTable->virtual->page[pageNumber]) { kernelError(kernel_error, "Virtual address %08x is not mapped", virtualAddress); return (status = ERR_NODATA); } if (set) pageTable->virtual->page[pageNumber] |= (flags & 0x0FFF); else pageTable->virtual->page[pageNumber] &= ~(flags & 0x0FFF); virtualAddress += MEMORY_PAGE_SIZE; pages -= 1; } } return (status = 0);}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Below here, the functions are exported for external use////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////int kernelPageInitialize(unsigned kernelMemory){ // This function will initialize the page manager and call the kernelPaging // routine to create a set of new page tables for the kernel environment. // (This is based on the assumptions that paging has been enabled prior // to the kernel starting, and that there must be an existing set of // basic page tables created by the loader). Returns 0 on success, // negative on error. int status = 0; int count; // Clear out the memory we'll use to keep track of all the page // directories and page tables, and set both counters to zero. kernelMemClear((void *) pageDirMemory, (sizeof(kernelPageDirectory) * MAX_PROCESSES)); kernelMemClear((void *) pageTableMemory, (sizeof(kernelPageTable) * MAX_PROCESSES)); // Loop through both of the dynamic lists that we'll use to keep // pointers to the memory space we just reserved for (count = 0; count < MAX_PROCESSES; count ++) { pageDirList[count] = &pageDirMemory[count]; pageTableList[count] = &pageTableMemory[count]; } numberPageDirectories = 0; numberPageTables = 0; // Calculate the physical memory location where we'll store the kernel's // paging data. kernelPagingData = (KERNEL_LOAD_ADDRESS + kernelMemory); // Initialize the kernel's paging environment, which is done differently // than for a normal process. status = kernelPaging(kernelMemory); if (status < 0) return (status); // Make note that we're initialized initialized = 1; // Return success return (status = 0);}void *kernelPageGetDirectory(int processId){ // This is an accessor function, which just returns the physical address of // the requested page directory (suitable for putting in the CR3 register). // Returns NULL on failure int status = 0; kernelPageDirectory *directory = NULL; void *physicalAddress = NULL; // Have we been initialized? if (!initialized) return (NULL); // Find the appropriate page directory directory = findPageDirectory(processId); if (directory == NULL) return (NULL); status = kernelLockGet(&(directory->dirLock)); if (status < 0) return (physicalAddress = NULL); physicalAddress = (void *) directory->physical; kernelLockRelease(&(directory->dirLock)); return (physicalAddress);}void *kernelPageNewDirectory(int processId, int privilege){ // This function will create a new page directory and one page table for // a new process. int status = 0; kernelPageDirectory *directory = NULL; kernelPageTable *table = NULL; void *physicalAddress = NULL; // next by Davide Airaghi int kernel = 0; // Have we been initialized? if (!initialized) return (physicalAddress = NULL); // Make sure privilege is legal if ((privilege != PRIVILEGE_USER) && (privilege != PRIVILEGE_SUPERVISOR)) return (physicalAddress = NULL); // by Davide Airaghi if (privilege != PRIVILEGE_SUPERVISOR && kernel) return (physicalAddress = NULL); // normal user can't be at ring0! // next 5 lines by Davide Airaghi kernel = kernelMultitaskerIsLowLevelProcess(processId); if (kernel < 0) kernel = 0; else kernel = 1; // Create a page directory for the process directory = createPageDirectory(processId, privilege, kernel); // last by Davide Airaghi if (directory == NULL) return (physicalAddress = NULL); status = kernelLockGet(&(directory->dirLock)); if (status < 0) return (physicalAddress = NULL); // Create an initial page table in the page directory, in the first spot table = createPageTable(directory, 0, kernel ); // slot 0, last by Davide Airaghi if (table == NULL) { // Deallocate the page directory we created. Don't unlock it since // it's going away deletePageDirectory(directory); return (physicalAddress = NULL); } // Finally, we need to map the kernel's address space into that of this // new process. The process will not receive copies of the kernel's // page tables. It will only get mappings in its page directory. shareKernelPages(directory); physicalAddress = (void *) directory->physical; kernelLockRelease(&(directory->dirLock)); // Return the physical address of the new page directory. return (physicalAddress);}void *kernelPageShareDirectory(int parentId, int childId){ // This function will allow a new process thread to share the page // directory of its parent. int status = 0; kernelPageDirectory *parentDirectory = NULL; kernelPageDirectory *childDirectory = NULL; void *physicalAddress = NULL; // Have we been initialized? if (!initialized) return (physicalAddress = NULL); // Find the page directory belonging to the parent process parentDirectory = findPageDirectory(parentId);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -