⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kernelpage.c

📁 上一个上传的有问题,这个是好的。visopsys包括系统内核和GUI的全部SOURCE code ,还包括一些基本的docs文档。里面src子目录对应所有SOURCE code.对于想研究操作系统的朋
💻 C
📖 第 1 页 / 共 4 页
字号:
////  Visopsys//  Copyright (C) 1998-2005 J. Andrew McLaughlin// //  This program is free software; you can redistribute it and/or modify it//  under the terms of the GNU General Public License as published by the Free//  Software Foundation; either version 2 of the License, or (at your option)//  any later version.// //  This program is distributed in the hope that it will be useful, but//  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY//  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License//  for more details.//  //  You should have received a copy of the GNU General Public License along//  with this program; if not, write to the Free Software Foundation, Inc.,//  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.////  kernelPage.c//// This file contains the C functions belonging to the kernel's // paging manager.  It keeps lists of page directories and page tables,// and performs all the work of mapping and unmapping pages in the tables.#include "kernelPage.h"#include "kernelParameters.h"#include "kernelMemory.h"#include "kernelMultitasker.h"#include "kernelProcessorX86.h"#include "kernelLog.h"#include "kernelMisc.h"#include "kernelError.h"#include <string.h>// The kernel's page directory and first page tablestatic kernelPageDirectory *kernelPageDir = NULL;// A list of all the page directories and page tables we've created, so we // can keep track of all the physical vs. virtual addresses of these.static kernelPageDirectory pageDirMemory[MAX_PROCESSES];static kernelPageDirectory *pageDirList[MAX_PROCESSES];static volatile int numberPageDirectories = 0;static kernelPageTable pageTableMemory[MAX_PROCESSES];static kernelPageTable *pageTableList[MAX_PROCESSES];static volatile int numberPageTables = 0;// The physical memory location where we'll store the kernel's paging data.static unsigned kernelPagingData = 0;static volatile int initialized = 0;// Macros used internally#define getTableNumber(address) ((((unsigned) address) >> 22) & 0x000003FF)#define getPageNumber(address) ((((unsigned) address) >> 12) & 0x000003FF)static kernelPageTable *findPageTable(kernelPageDirectory *directory,				      int tableNumber){  kernelPageTable *table = NULL;  int count;  for (count = 0; count < numberPageTables; count ++)    {      if (pageTableList[count]->directory == directory)	if (pageTableList[count]->tableNumber == tableNumber)	  {	    table = pageTableList[count];	    break;	  }    }  return (table);}static unsigned countFreePages(kernelPageDirectory *directory){  // Returns the number of unallocated pages in all the page tables  // of the supplied page directory  kernelPageTable *table;  int freePages = 0;  int tableNumber = 0;  int maxTableNumber = 0;  if (directory == kernelPageDir)    {      tableNumber = getTableNumber(KERNEL_VIRTUAL_ADDRESS);      maxTableNumber = PAGE_TABLES_PER_DIR;    }  else    {      tableNumber = 0;      maxTableNumber = (getTableNumber(KERNEL_VIRTUAL_ADDRESS) - 1);    }  // Loop through all of the page tables  for ( ; tableNumber < maxTableNumber; tableNumber ++)    {      table = findPageTable(directory, tableNumber);      if (table)	freePages += table->freePages;    }  return (freePages);}static int findFreeTableNumber(kernelPageDirectory *directory){  // This returns the first unused page table number.  int tableNumber = 0;  int maxTableNumber = 0;    if (directory == kernelPageDir)    {      tableNumber = getTableNumber(KERNEL_VIRTUAL_ADDRESS);      maxTableNumber = PAGE_TABLES_PER_DIR;    }  else    {      tableNumber = 0;      maxTableNumber = (getTableNumber(KERNEL_VIRTUAL_ADDRESS) - 1);    }  for ( ; tableNumber < maxTableNumber; tableNumber ++)    if (findPageTable(directory, tableNumber) == NULL)      return (tableNumber);  return (tableNumber = -1);}static int findFreePages(kernelPageDirectory *directory, int pages,			 void **virtualAddress){  // This function will find a range of unused pages in the supplied  // page directory that is as large as the number of pages requested.  // Sets a pointer representing the virtual address of the free pages  // on success, and returns 0.  On failure it returns negative.  int status = 0;  void *startAddress = NULL;  int numberFree = 0;  kernelPageTable *table = NULL;  int tableNumber = 0;  int maxTableNumber = 0;  int pageNumber = 0;  if (directory == kernelPageDir)    {      tableNumber = getTableNumber(KERNEL_VIRTUAL_ADDRESS);      maxTableNumber = PAGE_TABLES_PER_DIR;    }  else    {      tableNumber = 0;      maxTableNumber = (getTableNumber(KERNEL_VIRTUAL_ADDRESS) - 1);    }  // Loop through the supplied page directory.  for ( ; tableNumber < maxTableNumber; tableNumber++)    {      // Get a pointer to this page table.      table = findPageTable(directory, tableNumber);      if (table == NULL)	{	  numberFree = 0;	  startAddress = NULL;	  continue;	}      // Loop through the pages in this page table.  If we find a free      // page and numberFree is zero, set freeSpace to the corresponding      // virtual address.  If we find a used page, we reset both numberFree      // and freeStart to NULL.  If the table number is zero, skip the      // first page      for (pageNumber = (tableNumber == 0) ;	   pageNumber < PAGE_PAGES_PER_TABLE; pageNumber++)	{	  if (table->virtual->page[pageNumber] == NULL)	    {	      if (numberFree == 0)		startAddress =		  (void *) ((tableNumber << 22) | (pageNumber << 12));	      	      numberFree++;	      if (numberFree >= pages)		{		  *virtualAddress = startAddress;		  return (status = 0);		}	    }	  else	    {	      numberFree = 0;	      startAddress = NULL;	    }	}      // If we fall through here, we're moving on to the next page table.     }  // If we fall through to here, we did not find enough free memory  return (status = ERR_NOFREE);}static kernelPageTable *createPageTable(kernelPageDirectory *directory,					int number, int kernel) // last param by Davide Airaghi{  // This function creates an empty page table and maps it into the  // supplied page directory.  int status = 0;  kernelPageTablePhysicalMem *physicalAddr = NULL;  kernelPageTableVirtualMem *virtualAddr = NULL;  int kernelTableNumber = 0;  int kernelPageNumber = 0;  kernelPageTable *kernelTable = NULL;  kernelPageTable *newTable = NULL;  int count;  // Allocate some physical memory for the page table  physicalAddr = kernelMemoryGetPhysical(sizeof(kernelPageTablePhysicalMem),					 MEMORY_PAGE_SIZE, "page table");  if (physicalAddr == NULL)    return (newTable = NULL);  // Map it into the kernel's virtual address space.  We can't use the  // map function because it is the one that calls this function (we  // don't want to get into a loop) when page table space is low.  // If the directory is not the kernel directory, we have to be careful  // to make sure that there's always one more free page available  // in the kernel's directory for its own next page table  if ((directory != kernelPageDir) && (countFreePages(kernelPageDir) < 2))    {      // Recurse      if (createPageTable(kernelPageDir,			  findFreeTableNumber(kernelPageDir),kernel) == NULL) // modified by Davide Airaghi	// This is probably trouble for the kernel.  We certainly don't care	// about this user process	return (newTable = NULL);    }  // Try to find 1 free page in kernel space for the table to occupy  status = findFreePages(kernelPageDir, 1, (void **) &virtualAddr);  if (status < 0)    // Didn't find one    return (newTable = NULL);  // Get the kernel's kernelPageTable into which this new one will be mapped.  kernelTableNumber = getTableNumber(virtualAddr);  kernelPageNumber = getPageNumber(virtualAddr);  kernelTable = findPageTable(kernelPageDir, kernelTableNumber);  if (kernelTable == NULL)    return (newTable = NULL);  // Put the real address into the page table entry.  Set the global bit, the  // writable bit, and the page present bit.  kernelTable->virtual->page[kernelPageNumber] = (unsigned) physicalAddr;  kernelTable->virtual->page[kernelPageNumber] |=    (PAGEFLAG_GLOBAL | PAGEFLAG_WRITABLE | PAGEFLAG_PRESENT);  kernelTable->freePages--;  // Clear this memory block, since kernelMemoryGetPhysical can't do it for us  kernelMemClear((void *) virtualAddr, sizeof(kernelPageTableVirtualMem));  // Put our new table in the next available kernelPageTable slot of the  // page table list, and increase the count of kernelPageTables  newTable = pageTableList[numberPageTables++];  kernelMemClear((void *) newTable, sizeof(kernelPageTable));  // Fill in this page table  newTable->directory = directory;  newTable->tableNumber = number;  newTable->freePages = PAGE_PAGES_PER_TABLE;  newTable->physical = physicalAddr;  newTable->virtual = virtualAddr;  // Now we actually go into the page directory memory and add the  // real page table to the requested slot number.  Always enable   // read/write and page-present  directory->virtual->table[number] = (unsigned) newTable->physical;  directory->virtual->table[number] |= (PAGEFLAG_WRITABLE | PAGEFLAG_PRESENT);  // Set the 'user' bit, if this page table is not privileged  if (directory->privilege != PRIVILEGE_SUPERVISOR || (kernel==0)) // last condition by Davide Airaghi    directory->virtual->table[number] |= PAGEFLAG_USER;  // A couple of extra things we do if this new page table belongs to the  // kernel or one of its threads  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      directory->virtual->table[number] |= PAGEFLAG_GLOBAL;      // It needs to be 'shared' with all of the other real page directories.      for (count = 0; count < numberPageDirectories; count ++)	if (!(pageDirList[count]->parent))	  pageDirList[count]->virtual->table[number] =	    kernelPageDir->virtual->table[number];    }  // Return the table  return (newTable);}static int deletePageTable(kernelPageDirectory *directory,			   kernelPageTable *table){  // This function is for the maintenance of our dynamic list of page table  // pointers.  It will remove the supplied page table from the list and  // deallocate the memory that was reserved for it.  Returns 0 on success,  // negative otherwise.  int status = 0;  int kernelTableNumber = 0;  int kernelPageNumber = 0;  kernelPageTable *kernelTable = NULL;  int listPosition = 0;  int count;  // First remove the table from the directory  directory->virtual->table[table->tableNumber] = NULL;  // If this page table belonged to the kernel or one of its threads, it  // needs to be 'unshared' from all of the other real page directories.  if (directory == kernelPageDir)    for (count = 0; count < numberPageDirectories; count ++)      if (!(pageDirList[count]->parent))	pageDirList[count]->virtual->table[table->tableNumber] = NULL;  // Unmap it from the kernel's virtual address space.  We can't use the  // unmap function because it is the one that calls this function (we  // don't want to get into a loop) when when a page table is empty  // Get the kernel's kernelPageTable from which this new one will be  // unmapped.  kernelTableNumber = getTableNumber(table->virtual);  kernelPageNumber = getPageNumber(table->virtual);  kernelTable = findPageTable(kernelPageDir, kernelTableNumber);  if (kernelTable == NULL)    return (status = ERR_NOSUCHENTRY);  // Erase the entry for the page of kernel memory that this table used  kernelTable->virtual->page[kernelPageNumber] = NULL;  kernelTable->freePages++;  // Clear the TLB entry for the table's virtual memory  kernelProcessorClearAddressCache(table->virtual);    // Release the physical memory used by the table  status = kernelMemoryReleasePhysical((void *) table->physical);  if (status < 0)    return (status = ERR_NOSUCHENTRY);    // Now move the table to the unused list.  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).  // Ok, now we need to find this page table in the list.  for (listPosition = 0; listPosition < numberPageTables; )    if (pageTableList[listPosition] == table)      break;    else      listPosition++;  if ((listPosition == numberPageTables) ||      (pageTableList[listPosition] != table))    return (status = ERR_NOSUCHENTRY);  // Decrease the count of page tables BEFORE the following operation  numberPageTables--;  if ((numberPageTables > 0) && (listPosition < numberPageTables))    {      // Swap this item with the last item      pageTableList[listPosition] = pageTableList[numberPageTables];      pageTableList[numberPageTables] = table;    }  // Return success  return (status = 0);}static int findPageTableEntry(kernelPageDirectory *directory,			      void *virtualAddress, void **entry){  // Given a page directory and a virtual address, this function will find  // the appropriate page table entry and return it.    int status = 0;  int tableNumber = 0;  kernelPageTable *table = NULL;  int pageNumber = 0;  // virtualAddress is allowed to be NULL.  if ((unsigned) virtualAddress % MEMORY_PAGE_SIZE)    return (status = ERR_ALIGN);  // Figure out which page table corresponds to this virtual address, and  // get the page table  tableNumber = getTableNumber(virtualAddress);  pageNumber = getPageNumber(virtualAddress);  table = findPageTable(directory, tableNumber);  if (table == NULL)    // We're hosed.  This table should already exist.    return (status = ERR_NODATA);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -