📄 kernelpage.c
字号:
// Grab the value from the page table *entry = (void *) (table->virtual->page[pageNumber] & 0xFFFFF000); return (status = 0);}static inline int getNumPages(unsigned size){ // Turn a size into a number of pages return ((size / MEMORY_PAGE_SIZE) + ((size % MEMORY_PAGE_SIZE) != 0));}static int areFreePagesAt(kernelPageDirectory *directory, int pages, void *virtualAddress,int kernel) // lst param by Davide Airaghi{ // This function will return 1 if the requested number of pages are unused // at the requested address in the supplied page directory. int numberFree = 0; kernelPageTable *table = NULL; int tableNumber = 0; int maxTableNumber = 0; int pageNumber = 0; if (directory == kernelPageDir) maxTableNumber = PAGE_TABLES_PER_DIR; else maxTableNumber = (getTableNumber(KERNEL_VIRTUAL_ADDRESS) - 1); tableNumber = getTableNumber(virtualAddress); pageNumber = getPageNumber(virtualAddress); // Loop through the supplied page directory. for ( ; tableNumber < maxTableNumber; tableNumber++) { // Get a pointer to this page table. table = findPageTable(directory, tableNumber); if (table == NULL) { // Create the page table table = createPageTable(directory, tableNumber,kernel); if (table == NULL) return (0); } // Loop through the pages in this page table. If we find a used // page before 'numberFree' equals 'pages', return 0 for ( ; pageNumber < PAGE_PAGES_PER_TABLE; pageNumber++) { if (table->virtual->page[pageNumber] != NULL) return (0); numberFree++; if (numberFree >= pages) return (1); } // If we fall through, we're moving on to the next page table. pageNumber = 0; } // If we fall through, we're out of range return (0);}static int map(kernelPageDirectory *directory, void *physicalAddress, void **virtualAddress, unsigned size, int flags, int kernel) // last by Davide Airaghi{ // This function is used by the rest of the kernel to map physical memory // pages in the address space of a process. This will map the physical // memory to the first range of the process' unused pages that is large // enough to handle the request. By default, it will make all pages that // it maps writable. int status = 0; kernelPageTable *pageTable = NULL; void *currentVirtualAddress = NULL; void *currentPhysicalAddress = NULL; int tableNumber = 0; unsigned pageNumber = 0; unsigned numPages = 0; // Make sure that our arguments are reasonable. The wrapper functions // that are used to call us from external locations do not check them. if (size == 0) return (status = ERR_INVALID); // Make sure the pointer to virtualAddress is not NULL if (virtualAddress == NULL) return (status = ERR_NULLPARAMETER); if ((unsigned) physicalAddress % MEMORY_PAGE_SIZE) return (status = ERR_ALIGN); // Determine how many pages we need to map numPages = getNumPages(size); if (flags == PAGE_MAP_ANY) { // Are there enough free pages in this page directory (plus 1 for // the next page table)? If not, add more page tables until we have // enough. while (((numPages + 1) >= countFreePages(directory)) || (findFreePages(directory, numPages, virtualAddress) < 0)) { if (createPageTable(directory, findFreeTableNumber(directory),kernel) == NULL) //modified by Davide Airaghi return (status = ERR_NOFREE); } } else if (flags == PAGE_MAP_EXACT) { if ((unsigned) *virtualAddress % MEMORY_PAGE_SIZE) return (status = ERR_ALIGN); if (!areFreePagesAt(directory, numPages, *virtualAddress,kernel)) // last by Davide Airaghi return (status = ERR_NOFREE); // Make sure there's enough for the next page table if ((numPages + 1) >= countFreePages(directory)) { if (createPageTable(directory, findFreeTableNumber(directory),kernel) == NULL) // modified by Davide Airaghi return (status = ERR_NOFREE); if (!areFreePagesAt(directory, numPages, *virtualAddress,kernel)) // modified by Davide Airaghi return (status = ERR_NOFREE); } } else return (status = ERR_INVALID); currentPhysicalAddress = physicalAddress; currentVirtualAddress = *virtualAddress; // Change the entries in the page table while (numPages > 0) { pageNumber = getPageNumber(currentVirtualAddress); if ((pageTable == NULL) || (pageNumber == 0)) { // Get the address of the page table. Figure out the page table // number based on the virtual address we're currently working with, // and get the page table. tableNumber = getTableNumber(currentVirtualAddress); pageTable = findPageTable(directory, tableNumber); if (pageTable == NULL) // We're hosed. This table should already exist. return (status = ERR_NOSUCHENTRY); } // Put the real address into the page table entry. Set the // writable bit and the page present bit. pageTable->virtual->page[pageNumber] = (unsigned) currentPhysicalAddress; pageTable->virtual->page[pageNumber] |= (PAGEFLAG_WRITABLE | PAGEFLAG_PRESENT); if (directory == kernelPageDir) // Set the 'global' bit, so that if this is a Pentium Pro or better // processor, the page table won't be invalidated during a context // switch pageTable->virtual->page[pageNumber] |= PAGEFLAG_GLOBAL; // Set the 'user' bit, if this page is not privileged if (directory->privilege != PRIVILEGE_SUPERVISOR || (kernel == 0)) // last cond by DAvide Airaghi pageTable->virtual->page[pageNumber] |= PAGEFLAG_USER; // Decrease the count of free pages pageTable->freePages--; // Increment the working memory addresses currentVirtualAddress += MEMORY_PAGE_SIZE; currentPhysicalAddress += MEMORY_PAGE_SIZE; // Decrement the number of pages left to map numPages--; // Loop again } // Return success return (status = 0);}static int unmap(kernelPageDirectory *directory, void *virtualAddress, unsigned size){ // This function is used by the rest of the kernel to unmap virtual memory // pages from the address space of a process. int status = 0; kernelPageTable *pageTable = NULL; unsigned tableNumber = 0; unsigned pageNumber = 0; unsigned numPages = 0; // Make sure that our arguments are reasonable. The wrapper functions // that are used to call us from external locations do not check them. if (size == 0) return (status = ERR_INVALID); if (((unsigned) virtualAddress % MEMORY_PAGE_SIZE) != 0) return (status = ERR_ALIGN); // Determine how many pages we need to unmap numPages = getNumPages(size); // Change the entries in the page table while (numPages > 0) { pageNumber = getPageNumber(virtualAddress); if ((pageTable == NULL) || (pageNumber == 0)) { // Get the address of the page table. Figure out the page table // number based on the virtual address we're currently working with, // and get the page table. tableNumber = getTableNumber(virtualAddress); pageTable = findPageTable(directory, tableNumber); if (pageTable == NULL) // We're hosed. This table should already exist. return (status = ERR_NOSUCHENTRY); } // Clear out the physical address from the page table entry pageTable->virtual->page[pageNumber] = NULL; // Clear the TLB entry for this page kernelProcessorClearAddressCache(virtualAddress); // Increase the count of free pages pageTable->freePages++; // Is the table now unused? if (pageTable->freePages == PAGE_PAGES_PER_TABLE) // Try to deallocate it deletePageTable(directory, pageTable); // Increment the working memory addresses virtualAddress += MEMORY_PAGE_SIZE; // Decrement the number of pages left to map numPages--; // Loop again } // Return success return (status = 0);}static kernelPageDirectory *createPageDirectory(int processId, int privilege, int kernel) // last by Davide Airaghi{ // This function creates an empty page directory by allocating physical // memory for it, and on success, returns a pointer to a // kernelPageDirectory holding information about the directory. Returns // NULL on error. int status = 0; kernelPageDirectory *directory = NULL; kernelPageDirPhysicalMem *physicalAddr = NULL; kernelPageDirVirtualMem *virtualAddr = NULL; // Get some physical memory for the page directory physicalAddr = (kernelPageDirPhysicalMem *) kernelMemoryGetPhysical(sizeof(kernelPageDirPhysicalMem), MEMORY_PAGE_SIZE, "page directory"); if (physicalAddr == NULL) return (directory = NULL); // Map it into the kernel's virtual address space. status = map(kernelPageDir, (void *) physicalAddr, (void **) &virtualAddr, sizeof(kernelPageDirPhysicalMem), PAGE_MAP_ANY, kernel); // last by Davide Airaghi if (status < 0) return (directory = NULL); // Clear this memory block, since kernelMemoryGetPhysical can't do it for us kernelMemClear((void *) virtualAddr, sizeof(kernelPageDirPhysicalMem)); // Put it in the next available kernelPageDirectory slot, and increase // the count of kernelPageDirectories directory = pageDirList[numberPageDirectories++]; kernelMemClear((void *) directory, sizeof(kernelPageDirectory)); // Fill in this page directory directory->processId = processId; directory->numberShares = 0; directory->parent = 0; // next by Davide Airaghi directory->kernel = kernel; directory->privilege = privilege; directory->physical = physicalAddr; directory->virtual = virtualAddr; // Return the directory return (directory);}static kernelPageDirectory *findPageDirectory(int processId){ // This function just finds the page directory structure that belongs // to the requested process. Returns NULL on failure. kernelPageDirectory *dir = NULL; int count; if (processId == KERNELPROCID) return (dir = kernelPageDir); for (count = 0; count < numberPageDirectories; count ++) if (pageDirList[count]->processId == processId) { // If this page directory is 'shared' from another page directory, // then we need to recurse to find the parent (since this one will, // essentially, be 'empty') if (pageDirList[count]->parent) dir = findPageDirectory(pageDirList[count]->parent); else dir = pageDirList[count]; break; } return (dir);}static int deletePageDirectory(kernelPageDirectory *directory){ // This function is for the maintenance of our dynamic list of // page directory pointers. It will remove the supplied page // directory from the list and deallocate the memory that was // reserved for the directory. Returns 0 on success, negative // otherwise. int status = 0; kernelPageDirectory *parent = NULL; int listPosition = 0; // Make sure this page directory isn't currently shared. If it is, // we can't delete it. if (directory->numberShares) return (status = ERR_BUSY); // Figure out whether this page directory is 'sharing' from another // page directory. If so, we don't need to do much other than remove // it from the list, and decrement the refcount in the parent if (directory->parent) { // Find the parent page directory parent = findPageDirectory(directory->parent); if (parent == NULL) return (status = ERR_NOSUCHENTRY); parent->numberShares--; } else { // It's a 'real' page table. Deallocate the dynamic memory that // this directory is occupying kernelMemoryReleasePhysical((void *) directory->physical); // Unmap the directory from kernel memory status = unmap(kernelPageDir, (void *) directory->virtual, sizeof(kernelPageDirVirtualMem)); if (status < 0) return (status); } // Now we need to remove it from the list. First find its position // in the list. for (listPosition = 0; listPosition < numberPageDirectories; ) if (pageDirList[listPosition] == directory) break; else listPosition++; if ((listPosition == numberPageDirectories) || (pageDirList[listPosition] != directory)) return (status = ERR_NOSUCHENTRY); // This list is the same as several other lists in the kernel. We remove // this pointer from the list by swapping its pointer in the list with // that of the last item in the list and decrementing the count // (UNLESS: this is the last one, or the only one). // Decrement the count of page directories BEFORE the following operation numberPageDirectories--; if ((numberPageDirectories > 0) && (listPosition < numberPageDirectories)) { // Swap this item with the last item pageDirList[listPosition] = pageDirList[numberPageDirectories]; pageDirList[numberPageDirectories] = directory; } // Return success return (status = 0);}static int firstPageDirectory(void){ // This will create the first page directory, specifically for the // kernel. This presents some special problems, since 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 directory on success, NULL on failure.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -