📄 memorymanager.cs
字号:
// ------------------------------------------------------------------------------
// <copyright from='2002' to='2002' company='Scott Hanselman'>
// Copyright (c) Scott Hanselman. All Rights Reserved.
// </copyright>
// ------------------------------------------------------------------------------
//
// Scott Hanselman's Tiny Academic Virtual CPU and OS
// Copyright (c) 2002, Scott Hanselman (scott@hanselman.com)
// All rights reserved.
//
// A BSD License
// 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 and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// Neither the name of Scott Hanselman 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.
//
using System;
using System.Collections;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Serialization;
using System.Diagnostics;
using System.Threading;
using System.Text;
using System.Configuration;
using System.Runtime.Serialization.Formatters.Binary;
namespace Hanselman.CST352
{
/// <summary>
/// The MemoryManager for the <see cref="OS"/>. All memory accesses by a <see cref="Process"/>
/// go through this class.
/// </summary>
/// <example>
/// theOS.memoryMgr[processId, 5]; //accesses memory at address 5
/// </example>
public class MemoryManager
{
private ArrayList _pageTable;
//BitArray freePhysicalPages = new BitArray((int)(CPU.physicalMemory.Length/CPU.pageSize), true);
private bool[] freePhysicalPages = new bool[(int)(CPU.physicalMemory.Length/CPU.pageSize)];
/// <summary>
/// Total ammount of addressable memory. This is set in the Constructor.
/// Once set, it is readonly
/// </summary>
public readonly uint virtualMemSize = 0;
/// <summary>
///
/// </summary>
/// <param name="virtualMemSizeIn"></param>
public MemoryManager(uint virtualMemSizeIn)
{
//
// Find a size for addressableMemory that is on a page boundary
//
virtualMemSize = CPU.UtilRoundToBoundary(virtualMemSizeIn, CPU.pageSize);
//
// Size of memory must be a factor of CPU.pageSize
// This was asserted when the CPU initialized memory
//
uint physicalpages = (uint)(CPU.physicalMemory.Length/CPU.pageSize);
uint addressablepages = (uint)(virtualMemSize/CPU.pageSize);
_pageTable = new ArrayList((int)addressablepages);
// Delete all our Swap Files
foreach (string f in Directory.GetFiles(".","*.xml"))
File.Delete(f);
// For all off addressable memory...
// Make the pages in physical and the pages that aren't in physical
for (uint i = 0;i < virtualMemSize; i+=CPU.pageSize)
{
// Mark the Pages that are in physical memory as "false" or "not free"
MemoryPage p;
if (i < CPU.physicalMemory.Length)
{
p = new MemoryPage(i, true);
freePhysicalPages[(int)(i/CPU.pageSize)] = false;
}
else p = new MemoryPage(i, false);
_pageTable.Add(p);
}
//
// Cordon off some shared memory regions...these are setting the AppSettings
//
uint SharedRegionsSize = uint.Parse(ConfigurationSettings.AppSettings["SharedMemoryRegionSize"]);
uint SharedRegions = uint.Parse(ConfigurationSettings.AppSettings["NumOfSharedMemoryRegions"]);
if (SharedRegions > 0 && SharedRegionsSize > 0)
{
uint TotalPagesNeeded = (uint)(SharedRegions*SharedRegionsSize/CPU.pageSize);
uint pagesPerRegion = TotalPagesNeeded/SharedRegions;
// ForExample:
// I need 2 regions
// 64 bytes needed for each
// 4 pages each
// 8 total pages needed
// Because I pre-allocate shared memory I'll have the luxury of contigous pages of memory.
// I'll exploit this hack in MapSharedMemoryToProcess
foreach (MemoryPage page in _pageTable)
{
// Do we still need pages?
if (TotalPagesNeeded > 0)
{
// If this page is assigned to the OS, take it
if (page.SharedMemoryRegion == 0)
{
// Now assign it to us
page.SharedMemoryRegion = SharedRegions;
TotalPagesNeeded--;
if (TotalPagesNeeded % pagesPerRegion == 0)
SharedRegions--;
}
}
else //We have all we need
break;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="p">The Process</param>
/// <param name="bytesRequested">The number of bytes requested. Will be rounded up to the nearest page</param>
/// <returns>The Start Address of the Alloc'ed memory</returns>
public uint ProcessHeapAlloc(Process p, uint bytesRequested)
{
// Round up to the nearest page boundary
uint pagesRequested = MemoryManager.BytesToPages(bytesRequested);
uint addrStart = 0;
//
// Finds n *Contiguous* Pages
//
// Start with a list of potentialPages...
ArrayList potentialPages = new ArrayList();
// Look through all the pages in our heap
for (int i = 0; i < p.PCB.heapPageTable.Count; i++)
{
// The pages must be contiguous
bool bContiguous = true;
//From this start page, check for contiguous free pages nearby
MemoryPage startPage = (MemoryPage)p.PCB.heapPageTable[i];
//Is this page, and x ahead of it free?
if (startPage.heapAllocationAddr == 0)
{
potentialPages.Clear();
potentialPages.Add(startPage);
//Is this page, and x ahead of it free?
for (int j = 1; j < pagesRequested;j++)
{
// Have we walked past the end of the heap?
if ((i+j) >= p.PCB.heapPageTable.Count)
throw new HeapException(p.PCB.pid, pagesRequested*CPU.pageSize);
MemoryPage nextPage = (MemoryPage)p.PCB.heapPageTable[i+j];
if (nextPage.heapAllocationAddr == 0)
potentialPages.Add(nextPage);
else
bContiguous = false;
}
// If we make it here, we've found enough contiguous pages, break and continue
if (bContiguous == true)
break;
}
}
// Did we not find enough pages?
if (potentialPages.Count != pagesRequested)
throw new HeapException(p.PCB.pid, pagesRequested*CPU.pageSize);
// Mark each page with the address of the original alloc
// so we can Free them later
addrStart = ((MemoryPage)potentialPages[0]).addrProcessIndex;
foreach (MemoryPage page in potentialPages)
page.heapAllocationAddr = addrStart;
return addrStart;
}
/// <summary>
/// For debugging only. The value used to "zero out" memory when doing a FreeMemory.
/// </summary>
private static int memoryClearInt;
/// <summary>
/// Releases pages that were Alloc'ed from the Process's Heap
/// </summary>
/// <param name="p">The Processes</param>
/// <param name="startAddr">The Process address that the allocation began at</param>
/// <returns></returns>
public uint ProcessHeapFree(Process p, uint startAddr)
{
uint pageCount = 0;
foreach (MemoryPage page in p.PCB.heapPageTable)
{
if (page.heapAllocationAddr == startAddr)
{
page.heapAllocationAddr = 0;
pageCount++;
}
}
//
// For Heap Debugging, uncomment this line,
// this incrementing value will be used to
// clear memory out when releasing heap blocks
//
//memoryClearInt++;
memoryClearInt = 0;
SetMemoryOfProcess(p.PCB.pid, startAddr, pageCount*CPU.pageSize, (byte)memoryClearInt);
return 0;
}
/// <summary>
/// Adds all the pages allocated to a Process's heap to a PCB specific table of memory pages
/// </summary>
/// <param name="p">The Process</param>
public void CreateHeapTableForProcess(Process p)
{
foreach (MemoryPage page in _pageTable)
{
if (page.pidOwner == p.PCB.pid)
{
if (page.addrProcessIndex >= p.PCB.heapAddrStart && page.addrProcessIndex < p.PCB.heapAddrEnd)
{
p.PCB.heapPageTable.Add(page);
}
}
}
}
/// <summary>
/// Gets a 4 byte unsigned integer (typically an opCode param) from memory
/// </summary>
/// <param name="processid">The calling processid</param>
/// <param name="processIndex">The address in memory from the Process's point of view</param>
/// <returns></returns>
public uint getUIntFrom(uint processid, uint processIndex)
{
return CPU.BytesToUInt(getBytesFrom(processid, processIndex, 4));
}
/// <summary>
/// Sets a 4 byte unsigned integer (typically an opCode param) to memory
/// </summary>
/// <param name="processid">The calling processid</param>
/// <param name="processIndex">The address in memory from the Process's point of view</param>
/// <param name="avalue">The new value</param>
public void setUIntAt(uint processid, uint processIndex, uint avalue)
{
setBytesAt(processid, processIndex, CPU.UIntToBytes(avalue));
}
/// <summary>
/// Gets an array of "length" bytes from a specific process's memory address
/// </summary>
/// <param name="processid">The calling process's id</param>
/// <param name="processIndex">The address in memory from the Process's point of view</param>
/// <param name="length">how many bytes</param>
/// <returns>an initialized byte array containing the contents of memory</returns>
public byte[] getBytesFrom(uint processid, uint processIndex, uint length)
{
byte[] bytes = new byte[length];
for (uint i = 0; i < length; i++)
{
bytes[i] = this[processid, processIndex + i];
}
return bytes;
}
/// <summary>
/// Sets an array of bytes to a specific process's memory address
/// </summary>
/// <param name="processid">The calling processid</param>
/// <param name="processIndex">The address in memory from the Process's point of view</param>
/// <param name="pageValue">The source array of bytes</param>
public void setBytesAt(uint processid, uint processIndex, byte[] pageValue)
{
for (uint i = 0; i < pageValue.Length; i++)
{
this[processid, processIndex+i] = pageValue[i];
}
}
/// <summary>
/// Translates a Process's address space into physical address space
/// </summary>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -