void SetUseMask(BufferPage page, bool available) { auto useMaskPageBits = 8 * sizeof(vuint64_t); auto useMaskPageIndex = page.index / (useMaskPageBits * useMaskPageItemCount); auto useMaskPageBitIndex = page.index % (useMaskPageBits * useMaskPageItemCount); auto useMaskPageItem = INDEX_USEMASK_USEMASKBEGIN + useMaskPageBitIndex / useMaskPageBits; auto useMaskPageShift = useMaskPageBitIndex % useMaskPageBits; bool newPage = false; BufferPage useMaskPage = BufferPage::Invalid(); if (useMaskPageIndex == useMaskPages.Count()) { newPage = true; BufferPage lastPage{useMaskPages[useMaskPageIndex - 1]}; useMaskPage = AppendPage(); useMaskPages.Add(useMaskPage.index); auto pageDesc = MapPage(lastPage); vuint64_t* numbers = (vuint64_t*)pageDesc->address; numbers[INDEX_USEMASK_NEXTUSEMASKPAGE] = useMaskPage.index; msync(numbers, pageSize, MS_SYNC); } else { useMaskPage.index = useMaskPages[useMaskPageIndex]; } auto pageDesc = MapPage(useMaskPage); vuint64_t* numbers = (vuint64_t*)pageDesc->address; if (newPage) { numbers[INDEX_USEMASK_NEXTUSEMASKPAGE] = INDEX_INVALID; } auto& item = numbers[useMaskPageItem]; if (available) { vuint64_t mask = ((vuint64_t)1) << useMaskPageShift; item |= mask; } else { vuint64_t mask = ~(((vuint64_t)1) << useMaskPageShift); item &= mask; } msync(numbers, pageSize, MS_SYNC); }
void InitializeEmptySource() { initialPages.Clear(); useMaskPages.Clear(); { BufferPage page{INDEX_PAGE_INITIAL}; auto pageDesc = MapPage(page); vuint64_t* numbers = (vuint64_t*)pageDesc->address; memset(numbers, 0, pageSize); numbers[INDEX_INITIAL_NEXTINITIALPAGE] = INDEX_INVALID; numbers[INDEX_INITIAL_FREEPAGEITEMS] = 0; msync(numbers, pageSize, MS_SYNC); initialPages.Add(page.index); activeInitialPageIndex = 0; totalPageCount = 3; } { BufferPage page{INDEX_PAGE_USEMASK}; auto pageDesc = MapPage(page); vuint64_t* numbers = (vuint64_t*)pageDesc->address; memset(numbers, 0, pageSize); numbers[INDEX_USEMASK_NEXTUSEMASKPAGE] = INDEX_INVALID; msync(numbers, pageSize, MS_SYNC); useMaskPages.Add(page.index); } { BufferPage page{INDEX_PAGE_INDEX}; MapPage(page); } { BufferPage page{INDEX_PAGE_INITIAL}; SetUseMask(page, true); } { BufferPage page{INDEX_PAGE_USEMASK}; SetUseMask(page, true); } { BufferPage page{INDEX_PAGE_INDEX}; SetUseMask(page, true); } }
void InitializeExistingSource() { initialPages.Clear(); useMaskPages.Clear(); { struct stat fileState; fstat(fileDescriptor, &fileState); totalPageCount = fileState.st_size / pageSize; } { BufferPage page{INDEX_PAGE_INITIAL}; while(page.index != INDEX_INVALID) { initialPages.Add(page.index); auto pageDesc = MapPage(page); vuint64_t* numbers = (vuint64_t*)pageDesc->address; page.index = numbers[INDEX_INITIAL_NEXTINITIALPAGE]; if (numbers[INDEX_INITIAL_FREEPAGEITEMS] != 0) { activeInitialPageIndex = initialPages.Count() - 1; } } if (activeInitialPageIndex == -1) { activeInitialPageIndex = 0; } } { BufferPage page{INDEX_PAGE_USEMASK}; while(page.index != INDEX_INVALID) { useMaskPages.Add(page.index); auto pageDesc = MapPage(page); vuint64_t* numbers = (vuint64_t*)pageDesc->address; page.index = numbers[INDEX_USEMASK_NEXTUSEMASKPAGE]; } } }
void PushFreePage(BufferPage page) { BufferPage initialPage{initialPages[activeInitialPageIndex]}; auto pageDesc = MapPage(initialPage); vuint64_t* numbers = (vuint64_t*)pageDesc->address; vuint64_t& count = numbers[INDEX_INITIAL_FREEPAGEITEMS]; if (count == initialPageItemCount) { if (activeInitialPageIndex == initialPages.Count() - 1) { BufferPage newInitialPage{totalPageCount}; numbers[INDEX_INITIAL_NEXTINITIALPAGE] = newInitialPage.index; msync(numbers, pageSize, MS_SYNC); auto newPageDesc = MapPage(newInitialPage); numbers = (vuint64_t*)newPageDesc->address; memset(numbers, 0, pageSize); numbers[INDEX_INITIAL_NEXTINITIALPAGE] = INDEX_INVALID; numbers[INDEX_INITIAL_FREEPAGEITEMS] = 1; numbers[INDEX_INITIAL_FREEPAGEITEMBEGIN] = page.index; msync(numbers, pageSize, MS_SYNC); initialPages.Add(newInitialPage.index); SetUseMask(newInitialPage, true); } else { BufferPage newInitialPage{initialPages[activeInitialPageIndex + 1]}; auto newPageDesc = MapPage(newInitialPage); numbers = (vuint64_t*)newPageDesc->address; numbers[INDEX_INITIAL_FREEPAGEITEMS] = 1; numbers[INDEX_INITIAL_FREEPAGEITEMBEGIN] = page.index; msync(numbers, pageSize, MS_SYNC); } activeInitialPageIndex++; } else { numbers[INDEX_INITIAL_FREEPAGEITEMBEGIN + count] = page.index; count++; msync(numbers, pageSize, MS_SYNC); } }
BufferPage AppendPage() { BufferPage page{totalPageCount}; if (auto pageDesc = MapPage(page)) { SetUseMask(page, true); return page; } else { return BufferPage::Invalid(); } }
void load_exec(UID pid, const char *exec) { void *exec_loc = NULL; uint64_t exec_size = 0; Initrd_GetFile(exec, &exec_loc, &exec_size); uint64_t orig_exec_size = exec_size; exec_size += EXEC_ENTRY_POINT % PAGE_SIZE; if(exec_size % PAGE_SIZE) exec_size += (PAGE_SIZE - exec_size % PAGE_SIZE); //Map the executable into the process ProcessInformation *pinfo = NULL; if(GetProcessReference(pid, &pinfo) != ProcessErrors_None) return; for(uint32_t i = 0; i < exec_size / PAGE_SIZE; i++) { uint64_t p_addr = AllocatePhysicalPage(); uint64_t v_addr = (EXEC_ENTRY_POINT - EXEC_ENTRY_POINT % PAGE_SIZE) + i * PAGE_SIZE; MapPage(pinfo->PageTable, p_addr, v_addr, PAGE_SIZE, CachingModeWriteBack, MemoryAllocationType_Application, MemoryAllocationFlags_Read | MemoryAllocationFlags_Write | MemoryAllocationFlags_User | MemoryAllocationFlags_Exec | MemoryAllocationFlags_Present); } uint8_t* write_target = (uint8_t*)SetupTemporaryWriteMap(pinfo->PageTable, EXEC_ENTRY_POINT - (EXEC_ENTRY_POINT % PAGE_SIZE), exec_size); memcpy(write_target + (EXEC_ENTRY_POINT % PAGE_SIZE), exec_loc, orig_exec_size); UninstallTemporaryWriteMap((uint64_t)write_target, exec_size); CreateThread(pid, ThreadPermissionLevel_User, (ThreadEntryPoint)EXEC_ENTRY_POINT, NULL); StartProcess(pid); return; }
bool GetUseMask(BufferPage page) { auto useMaskPageBits = 8 * sizeof(vuint64_t); auto useMaskPageIndex = page.index / (useMaskPageBits * useMaskPageItemCount); auto useMaskPageBitIndex = page.index % (useMaskPageBits * useMaskPageItemCount); auto useMaskPageItem = INDEX_USEMASK_USEMASKBEGIN + useMaskPageBitIndex / useMaskPageBits; auto useMaskPageShift = useMaskPageBitIndex % useMaskPageBits; BufferPage useMaskPage{useMaskPages[useMaskPageIndex]}; auto pageDesc = MapPage(useMaskPage); vuint64_t* numbers = (vuint64_t*)pageDesc->address; auto& item = numbers[useMaskPageItem]; bool result = ((item >> useMaskPageShift) & ((vuint64_t)1)) == 1; msync(numbers, pageSize, MS_SYNC); return result; }
void* LockPage(BufferPage page)override { if (page.index >= totalPageCount) { return nullptr; } if (!GetUseMask(page)) return nullptr; if (auto pageDesc = MapPage(page)) { if (pageDesc->locked) return nullptr; pageDesc->locked = true; return pageDesc->address; } else { return nullptr; } }
BufferPage PopFreePage() { BufferPage page = BufferPage::Invalid(); BufferPage initialPage{initialPages[activeInitialPageIndex]}; auto pageDesc = MapPage(initialPage); vuint64_t* numbers = (vuint64_t*)pageDesc->address; vuint64_t& count = numbers[INDEX_INITIAL_FREEPAGEITEMS]; if (count == 0 && initialPage.index == INDEX_PAGE_INITIAL) { return page; } count--; page.index = numbers[INDEX_INITIAL_FREEPAGEITEMBEGIN + count]; msync(numbers, pageSize, MS_SYNC); if (count == 0) { activeInitialPageIndex--; } return page; }
void VirtMemManager::ResolvePageFault(uintptr fault_address, bool write_error, bool protection_error, bool user_mode) { // If its a page not present fault, check for a matching section if(!protection_error) { int i, c; c = CurrentThread->proc->Sections->Count(); Section::Extent ae; ae.Lower = fault_address; ae.Upper = fault_address; protection_error = true; // Set this back to false if we find a valid section for(i = 0; i < c; i++) { Section::Extent se; Section &s = CurrentThread->proc->Sections->GetItem(i); if(s.CheckExtents(&se)) { if(ae == se) { // Its part of this section. Allow expanding sections if(s.Flags & Section::AutoExpand) { if((fault_address < s.Base) && ((s.Base - fault_address) <= s.ExpandDown)) { s.ExpandDown -= (s.Base - fault_address); s.Base = fault_address; protection_error = false; } if((fault_address >= (s.Base + s.Length)) && ((fault_address - (s.Base + s.Length)) <= s.ExpandUp)) { s.ExpandUp -= (fault_address - (s.Base + s.Length)); s.Length = fault_address - s.Base + 1; protection_error = false; } } if((fault_address >= s.Base) && (fault_address < (s.Base + s.Length))) protection_error = false; if(!protection_error) { // Map the page physaddr_t paddr = NULL; if(s.Flags & Section::Bits) paddr = (fault_address - s.Base + s.MemSource) & GetPageMask(); MapPage(fault_address & GetPageMask(), NULL, false, NULL, (fault_address - s.Base + s.MemSource) & GetPageMask(), (s.Flags & Section::KernelSection) ? false : true, (s.Flags & Section::Write) ? true : false); break; } } } } } // Check for errors if(protection_error) { // A bad error a.kconsole->Printf("PAGE FAULT! Invalid attempt by "); if(user_mode) a.kconsole->Printf("process "); else a.kconsole->Printf("kernel "); a.kconsole->Printf("to "); if(write_error) a.kconsole->Printf("write to "); else a.kconsole->Printf("read from "); a.kconsole->Printf("address %x whilst executing %s\n", fault_address, CurrentThread->proc->name); a.Panic(); } }