public vm() { //Initialize devices; cpu = new CPU(this); // Initializes the cpu ram = new Memory(PAGE_DIRECTORY_SIZE * Frame.FRAME_SIZE); //Allocates enough ram to fit number of page tables allowed hdi = new HDI("disk0"); //Maps a folder to the hard disk interface disk0 = new VirtualDataDisk("vhd.nvmd"); // Virtual data disk devices = new VMDevice[] { cpu, // Processer, device 0 ram, // RAM, device 1 hdi, // Hard drive Interface, device 3 disk0, // Virtual Data Disk, device 4 }; callstack = new CallStack(this,ram); pager = new Pager(ram, PAGE_DIRECTORY_SIZE); //setup premade page for callstack and bios BPG = pager.CreatePageEntry(Pager.PAGE_KERNEL_MODE); CSP = pager.getVAT(1024,pager.getEntry(BPG)); //bios will be loaded at 0 to 1023 CBP = CSP; CR3I = BPG; CR3 = pager.getEntry(CR3I); }
public Pager(Memory RAM, int PDSize) { //machine = Machine; ram = RAM; PageDirectory = new PageDirectoryEntry[PDSize]; for (int i = 0; i < PDSize; i++) { PageDirectory[i] = new PageDirectoryEntry() { PTAddress = 0, AccessLevel = false, InUse = false }; } }
public void AddPage(PageDirectoryEntry entry) { //Find free frame Frame freeFrame = ram.findFreeFrame(); freeFrame.IsFree = false; for(int i = 0; i < PageDirectory.Length; i++) { if(PageDirectory[i].PTAddress == entry.PTAddress) { freeFrame.PageTable = i; break; } } //Add frame to PT for (int i = 0; i < Pager.PAGE_TABLE_SIZE / 4; i++) { if (ram.ReadUInt((uint)(entry.PTAddress + i * 4)) == 0) { ram.Write((uint)(entry.PTAddress + i * 4),freeFrame.Address); break; } } }
public string ReadString(uint address, PageDirectoryEntry entry) { int len = ReadInt(address, entry); address += 4; char[] chr = new char[len]; for (int i = 0; i < len; i++) { chr[i] = (char)Read ((uint)(address + i), entry); } return new String(chr); }
public uint ReadUInt(uint address, PageDirectoryEntry entry) { return ram.ReadUInt(getVAT(address,entry)); }
public void SwitchPage(int newpage) { CR3I = newpage; CR3 = pager.getEntry(CR3I); SP = CR3.stack_pointer; HP = CR3.heap_pointer; BP = CR3.base_pointer; }
public void FreePageTable(PageDirectoryEntry entry) { uint addr = entry.PTAddress; //Read pages for (int i = 0; i < PAGE_TABLE_SIZE / 4; i++) { uint frameAddr = ram.ReadUInt((uint)(addr + (i*4))); int frameindex = (int)(frameAddr / Frame.FRAME_SIZE); Frame frame = ram.getFrame(frameindex); frame.IsFree = true; // Set frame to free, clears the frame } }
public void WritePageTable(PageDirectoryEntry entry) { //Write page table uint addr = entry.PTAddress; // Get page table address // Write: Page addresses for (int i = 0; i < PAGE_TABLE_SIZE / 4; i++) { ram.Write((uint)(addr + (i*4)), 0u); } //Write first page address start ram.Write(addr,addr + PAGE_TABLE_SIZE + 4); }
///<summary> ///Check if the address will overflow to the next page with the given size ///</summary> ///<returns> ///False if the address overflows ///</returns> public bool checkVAT(uint address, uint size, PageDirectoryEntry entry) { uint addr1 = getVAT(address,entry); uint addr2 = getVAT(address + size,entry); return (addr2 - addr1 == size); }
/// <summary> /// Setup the heap memory allocation for the page table /// </summary> /// <param name='entry'> /// Page table to setup /// </param> public void SetupMemoryAllocation(PageDirectoryEntry entry) { entry.free_pointer = entry.heap_pointer; //set free-list pointer to start of heap ram.Write(getVAT(entry.heap_pointer,entry),0); // write 0 because there is no next block ram.Write(getVAT(entry.heap_pointer,entry) + 4,(uint)(GetPageDirectoryEntrySize(entry) - entry.heap_pointer)); //Write size of free block (total size of heap) }
public void LoadProgram(byte[] data, PageDirectoryEntry entry) { uint origin = getVAT (0u, entry); if (checkVAT (0u, (uint)data.Length, entry)) { //does the program fit in the first page? for (int i = 0; i < data.Length; i++) { ram.Write ((uint)(origin + i), data[i]); //this should be safe } } else { //oooh boy //get length of program uint length = (uint)data.Length; uint writtenbytes = 0; //loop through pages for (int i = 0; i < GetPageDirectoryEntrySize(entry); i++) { //get page start uint origio = getVAT(writtenbytes,entry); //get length of current page uint curlen = (uint)(i == 0 ? Frame.FRAME_SIZE - PAGE_TABLE_SIZE : Frame.FRAME_SIZE); //write through each page for (int j = 0; j < curlen; j++) { ram.Write((uint)(origio + j), data[writtenbytes]); writtenbytes++; } } } }
public uint GetPageDirectoryEntrySize(PageDirectoryEntry entry) { uint addr = entry.PTAddress; uint count = 0; for(int i = 0; i < PAGE_TABLE_SIZE / 4; i++) { uint a = ram.ReadUInt((uint)(addr + i*4)); if(a != 0) { count++; } } return count * Frame.FRAME_SIZE; }
public string PopString(PageDirectoryEntry entry) { uint size = ram.ReadUInt(getVAT(entry.stack_pointer,entry)); if (entry.stack_pointer + size + 4 >= entry.heap_pointer) { throw new Exception("No more items in stack!"); } string val = ""; if(checkVAT(entry.stack_pointer,size,entry)) { //check for page overflow val = ram.ReadString(getVAT(entry.stack_pointer,entry)); } else { val = ReadString(entry.stack_pointer,entry); //use method for safe writing under page overflow } entry.stack_pointer += size + 4; return val; }
public byte PopByte(PageDirectoryEntry entry) { if (entry.stack_pointer + 1 >= entry.heap_pointer) { throw new Exception("No more items in stack!"); } byte val = ram.Read(getVAT(entry.stack_pointer,entry)); entry.stack_pointer++; return val; }
public void MergeFreeBlocks(PageDirectoryEntry entry) { uint pdsize = GetPageDirectoryEntrySize(entry); for (uint addr = entry.free_pointer; addr < pdsize;) { uint nextblock = ram.ReadUInt(getVAT(addr, entry)); //read address of next free block if(nextblock == 0) { break; //end of list } uint blocksize = ram.ReadUInt(getVAT(addr + 4, entry)); //read size of current free block if(addr + blocksize >= nextblock) { uint nextsize = ram.ReadUInt(getVAT(nextblock + 4, entry)); //read size of next block uint newsize = blocksize + nextsize; uint nextpointer = ram.ReadUInt(getVAT(nextblock, entry)); ram.Write(getVAT(addr,entry),nextpointer); ram.Write(getVAT(addr + 4,entry),newsize); } addr = nextblock; } }
/// <summary> /// Allocate a new block of memory in the page table with the specified size /// </summary> /// <param name='size'> /// Size of memory to allocate /// </param> /// <param name='entry'> /// Page table to use /// </param> /// <returns> /// The address of the allocated block /// </returns> public uint Malloc(uint size,PageDirectoryEntry entry) { uint lastaddr = entry.free_pointer; //last free block pointer bool isfirst = true; //loop through freelist , check for large enough chunk uint pdsize = GetPageDirectoryEntrySize(entry); for (uint addr = entry.free_pointer; addr < pdsize; ) { uint nextblock = ram.ReadUInt(getVAT(addr, entry)); //read address of next free block uint blocksize = ram.ReadUInt(getVAT(addr + 4, entry)); //read size of current free block if (blocksize >= size) { uint newsize = blocksize - size; //get new size of free block uint newaddr = addr + size; //get new address of free block if (newsize >= 8) { //if size < 8, block is gone cause we can't store the next block pointer ram.Write(getVAT(newaddr,entry),nextblock); // set next block pointer ram.Write(getVAT(newaddr + 4,entry),newsize); //write new size of new freeblock ram.Write(getVAT(lastaddr,entry),getVAT(newaddr,entry)); //set pointer of last block to point to this new one if (isfirst) { entry.free_pointer = newaddr; //update first freepointer } } else //set pointer to skip unexisting block { ram.Write(getVAT(lastaddr,entry),getVAT(nextblock,entry)); } return addr; //return address of allocated space } if (nextblock == 0) { // there is no next block, break from loop break; } addr = nextblock; isfirst = false; } throw new OutOfMemoryException(String.Format("No more free blocks to allocate memory in page table: {0}",entry.PTAddress)); }
/// <summary> /// Setup the heap and stack for the page table /// </summary> /// <param name='entry'> /// Page directory entry /// </param> /// <param name='stack_pointer'> /// New stack_pointer, relative address. /// </param> /// <param name='heap_pointer'> /// New heap_pointer, relative address /// </param> public void SetupMemory(PageDirectoryEntry entry, uint stack_start, uint heap_start) { entry.stack_pointer = heap_start - 1; entry.base_pointer = stack_start; entry.heap_pointer = heap_start; }
public void Write(uint address, float value, PageDirectoryEntry entry) { byte[] convertedValues = BitConverter.GetBytes(value); ram.Write(getVAT(address + 0,entry),convertedValues[0]); ram.Write(getVAT(address + 1,entry),convertedValues[1]); ram.Write(getVAT(address + 2,entry),convertedValues[2]); ram.Write(getVAT(address + 3,entry),convertedValues[3]); }
public uint PopUInt(PageDirectoryEntry entry) { if (entry.stack_pointer + 4 >= entry.heap_pointer) { throw new Exception("No more items in stack!"); } uint val = ram.ReadUInt(getVAT(entry.stack_pointer,entry)); entry.stack_pointer += 4; return val; }
///<summary> ///Translates the page relative address to a 'physical' one ///</summary> public uint getVAT(uint address, PageDirectoryEntry entry) { // Get address uint ptaddr = entry.PTAddress; //The 4 and 5 is for keeping space for integers stored to keep stuff from overflowing to different pages, strings need their own logic to do this. if(address < Frame.FRAME_SIZE - PAGE_TABLE_SIZE - 4) { //address is in the first frame return ptaddr + PAGE_TABLE_SIZE + address; } else { //address is after first frame int page = (int)(address / Frame.FRAME_SIZE); int offset = (int)(address - page * Frame.FRAME_SIZE + PAGE_TABLE_SIZE); if(offset > Frame.FRAME_SIZE - 5) { //fix for addresses over framesize - 512 page++; offset -= Frame.FRAME_SIZE; } uint pageaddr = ram.ReadUInt((uint)(ptaddr + (page * 4))); return (uint)(pageaddr + offset); } /* // Get Page id int page = (int)(address / Frame.FRAME_SIZE); int offset = (int)(address - page * Frame.FRAME_SIZE); // Get page table entry address uint pageaddr = ram.ReadUInt((uint)(ptaddr + (page * 4))); // Get address return (uint)(pageaddr + offset); */ }
// ------- CUSTOM OVERLOADS FOR RAM METHODS USING VAT (WARNING SLOW!)------- //Write methods public void Write(uint address, byte value, PageDirectoryEntry entry) { ram.Write(getVAT(address,entry),value); }
public void Push(float data,PageDirectoryEntry entry) { if (entry.stack_pointer - 4 < entry.base_pointer) { throw new Exception("No more space in stack!"); } entry.stack_pointer -= 4; ram.Write(getVAT(entry.stack_pointer,entry),data); }
public void Write(uint address, string value, PageDirectoryEntry entry) { Write((uint)(address), (uint)value.Length, entry); address += 4; for (int i = 0; i < value.Length; i++) { Write((uint)(address + i), ((byte)value[i]), entry); } }
public void Push(string data,PageDirectoryEntry entry) { if (entry.stack_pointer - (data.Length + 4) < entry.base_pointer) { throw new Exception("No more space in stack!"); } entry.stack_pointer -= (uint)(data.Length + 4); if(checkVAT(entry.stack_pointer,(uint)(data.Length + 4),entry)) { //check for overflow to next page ram.Write(getVAT(entry.stack_pointer,entry),data); } else { Write(entry.stack_pointer,data,entry); //use paging method to write, slower } }
internal ushort ReadUInt16(uint address, PageDirectoryEntry entry) { return ram.ReadUInt16(getVAT(address,entry)); }
public byte Read(uint address, PageDirectoryEntry entry) { return ram.Read(getVAT(address,entry)); }
public int CreatePageEntry(bool mode) { //Declare stuff int index = 0; //Find free entry in page directory PageDirectoryEntry entry = new PageDirectoryEntry(); for (int i = 0; i < PageDirectory.Length; i++) { if (!PageDirectory[i].InUse) { entry = PageDirectory[i]; index = i; break; } } //Find a free ram frame for the first page Frame mainFrame = ram.findFreeFrame(); mainFrame.IsFree = false; mainFrame.PageTable = index; entry.PTAddress = mainFrame.Address; entry.AccessLevel = mode; entry.InUse = true; //Write page table to ram for entry WritePageTable(entry); PageDirectory[index] = entry; return index; }
public float ReadFloat(uint address, PageDirectoryEntry entry) { return ram.ReadFloat(getVAT(address,entry)); }
public uint[] ReadPageTable(PageDirectoryEntry entry) { uint[] array = new uint[PAGE_TABLE_SIZE / 4]; for (int i = 0; i < PAGE_TABLE_SIZE / 4; i++) { uint addr = ram.ReadUInt((uint)(entry.PTAddress + i * 4)); array[i] = addr; } return array; }
public void FreePageEntry(PageDirectoryEntry entry) { FreePageTable(entry); entry.InUse = false; }