Address MemoryServer::findFreeRange(ProcessID procID, Size size) { Address *pageDir, *pageTab, vaddr, vbegin; /* Initialize variables. */ vbegin = ZERO; vaddr = 1024 * 1024 * 16; pageDir = PAGETABADDR_FROM(PAGETABFROM, PAGEUSERFROM); pageTab = PAGETABADDR_FROM(vaddr, PAGEUSERFROM); /* Map page tables. */ VMCtl(procID, MapTables); /* Scan tables. */ for (Size inc = PAGESIZE; DIRENTRY(vaddr) < PAGEDIR_MAX ; vaddr += inc) { /* Is the hole big enough? */ if (vbegin && vaddr - vbegin >= size) { break; } /* Increment per page table. */ inc = PAGETAB_MAX * PAGESIZE; /* Try the current address. */ if (pageDir[DIRENTRY(vaddr)] & PAGE_RESERVED) { vbegin = ZERO; continue; } else if (pageDir[DIRENTRY(vaddr)] & PAGE_PRESENT) { /* Look further into the page table. */ inc = PAGESIZE; pageTab = PAGETABADDR_FROM(vaddr, PAGEUSERFROM); if (pageTab[TABENTRY(vaddr)] & PAGE_PRESENT) { vbegin = ZERO; continue; } } /* Reset start address if needed. */ if (!vbegin) { vbegin = vaddr; } } /* Clean up. */ VMCtl(procID, UnMapTables); /* Done. */ return vbegin; }
Address X86Memory::findFree(Address pageTabFrom, Address *pageDirPtr) { Address vaddr = 0xa0000000; Address *pageTabPtr = PAGETABADDR_FROM(vaddr, pageTabFrom); /* Find a free virtual address. */ while (pageDirPtr[DIRENTRY(vaddr)] & PAGE_PRESENT && pageTabPtr[TABENTRY(vaddr)] & PAGE_PRESENT) { /* Look for the next page in line. */ vaddr += PAGESIZE; pageTabPtr = PAGETABADDR_FROM(vaddr, pageTabFrom); } return vaddr; }
void MemoryServer::reservePrivate(MemoryMessage *msg) { Address *pageDir; /* Verify virtual addresses. */ if (!(msg->virtualAddress >= 1024*1024*16)) { msg->result = EINVAL; return; } /* Point page directory. */ pageDir = (Address *) PAGETABADDR_FROM(PAGETABFROM, PAGEUSERFROM); /* Map page directory. */ VMCtl(msg->from, MapTables); /* Loop directory. Mark them reserved. */ for (Address i = msg->virtualAddress; i < msg->virtualAddress + msg->bytes; i += (PAGESIZE * PAGETAB_MAX)) { pageDir[DIRENTRY(i)] |= PAGE_RESERVED; } /* Unmap. */ VMCtl(msg->from, UnMapTables); /* Done. */ msg->result = ESUCCESS; }
void X86Memory::releaseAll(X86Process *p) { /* Map page tables. */ mapRemote(p, 0x0); /* Mark all our physical pages free. */ for (Size i = 0; i < 1024; i++) { /* May we release these physical pages? */ if ((remPageDir[i] & PAGE_PRESENT) && !(remPageDir[i] & PAGE_PINNED)) { /* Repoint page table. */ remPageTab = PAGETABADDR_FROM(i * PAGESIZE * 1024, PAGETABFROM_REMOTE); /* Scan page table. */ for (Size j = 0; j < 1024; j++) { if (remPageTab[j] & PAGE_PRESENT && !(remPageTab[j] & PAGE_PINNED)) { memory->releasePhysical(remPageTab[j]); } } } } }
void X86Memory::mapRemote(X86Process *p, Address pageTabAddr, Address pageDirAddr, ulong prot) { /* Map remote page directory and page table. */ myPageDir[DIRENTRY(pageDirAddr)] = p->getPageDirectory() | (PAGE_PRESENT|PAGE_RW|PAGE_PINNED|prot); remPageTab = PAGETABADDR_FROM(pageTabAddr, PAGETABFROM_REMOTE); /* Refresh entire TLB cache. */ tlb_flush_all(); }
bool X86Memory::access(X86Process *p, Address vaddr, Size sz, ulong prot) { Size bytes = 0; Address vfrom = vaddr; /* Map remote pages. */ mapRemote(p, vaddr); /* Verify protection bits. */ while (bytes < sz && remPageDir[DIRENTRY(vaddr)] & prot && remPageTab[TABENTRY(vaddr)] & prot) { vaddr += PAGESIZE; bytes += ((vfrom & PAGEMASK) + PAGESIZE) - vfrom; vfrom = vaddr & PAGEMASK; remPageTab = PAGETABADDR_FROM(vaddr, PAGETABFROM_REMOTE); } /* Do we have a match? */ return (bytes >= sz); }
Address X86Memory::mapVirtual(X86Process *p, Address paddr, Address vaddr, ulong prot) { /* Map remote pages. */ mapRemote(p, vaddr); /* Virtual address specified? */ if (vaddr == ZERO) { vaddr = findFree(PAGETABFROM_REMOTE, remPageDir); } /* Repoint to the correct (remote) page table. */ remPageTab = PAGETABADDR_FROM(vaddr, PAGETABFROM_REMOTE); /* Does the remote process have the page table in memory? */ if (!(remPageDir[DIRENTRY(vaddr)] & PAGE_PRESENT)) { /* Nope, allocate a page table first. */ Address newPageTab = memory->allocatePhysical(PAGESIZE); newPageTab |= PAGE_PRESENT | PAGE_RW | prot; /* Map the new page table into remote memory. */ remPageDir[DIRENTRY(vaddr)] = newPageTab; /* Update caches. */ tlb_flush(remPageTab); /* Zero the new page. */ memset(remPageTab, 0, PAGESIZE); } /* Map physical address to remote virtual address. */ remPageTab[TABENTRY(vaddr)] = (paddr & PAGEMASK) | prot; tlb_flush(vaddr); /* Success. */ return (Address) vaddr; }