int clone_area(const char name[], void **clone_addr, int searchFlags, PageProtection protection, int sourceArea) { Area *area = static_cast<Area*>(GetResource(sourceArea, OBJ_AREA)); if (area == 0) { printf("clone_area: source area id %08x is invalid\n", sourceArea); return E_BAD_HANDLE; } unsigned int addr = INVALID_PAGE; if (searchFlags & EXACT_ADDRESS) addr = reinterpret_cast<unsigned int>(*clone_addr); // It is important that CreateArea not incur a fault! char nameCopy[OS_NAME_LENGTH]; if (!CopyUser(nameCopy, name, OS_NAME_LENGTH)) return E_BAD_ADDRESS; Area *newArea = AddressSpace::GetCurrentAddressSpace()->CreateArea(nameCopy, area->GetSize(), AREA_NOT_WIRED, protection | USER_READ | SYSTEM_READ | ((protection & USER_WRITE) ? SYSTEM_WRITE : 0), area->GetPageCache(), 0, addr, searchFlags); area->ReleaseRef(); if (newArea == 0) return E_ERROR; *clone_addr = reinterpret_cast<void*>(newArea->GetBaseAddress()); return OpenHandle(newArea); }
int create_area(const char name[], void **requestAddr, int flags, unsigned int size, AreaWiring lock, PageProtection protection) { unsigned int va = INVALID_PAGE; if (flags & EXACT_ADDRESS) va = reinterpret_cast<unsigned int>(*requestAddr); PageCache *cache = new PageCache; if (cache == 0) return E_NO_MEMORY; // It is important that CreateArea not incur a fault! char nameCopy[OS_NAME_LENGTH]; if (!CopyUser(nameCopy, name, OS_NAME_LENGTH)) return E_BAD_ADDRESS; Area *newArea = AddressSpace::GetCurrentAddressSpace()->CreateArea(nameCopy, size, lock, protection | USER_READ | SYSTEM_READ | ((protection & USER_WRITE) ? SYSTEM_WRITE : 0), cache, 0, va, flags); if (newArea == 0) { delete cache; return E_NO_MEMORY; } *requestAddr = reinterpret_cast<void*>(newArea->GetBaseAddress()); return OpenHandle(newArea); }
status_t AddressSpace::HandleFault(unsigned int va, bool write, bool user) { va &= ~(PAGE_SIZE - 1); // Round down to a page boundry. fAreaLock.LockRead(); int lastChangeCount = fChangeCount; Area *area = static_cast<Area*>(fAreas.Find(va)); if (area == 0) { fAreaLock.UnlockRead(); return E_BAD_ADDRESS; } PageProtection protection = area->GetProtection(); if ((user && write && !(protection & USER_WRITE)) || (user && !write && !(protection & USER_READ)) || (!user && write && !(protection & SYSTEM_WRITE)) || (!user && !write && !(protection & SYSTEM_READ))) { fAreaLock.UnlockRead(); return E_NOT_ALLOWED; } PageCache *cache = area->GetPageCache(); if (cache == 0) { fAreaLock.UnlockRead(); return E_NOT_ALLOWED; } bool copy = cache->IsCopy(); cache->AcquireRef(); fAreaLock.UnlockRead(); off_t offset = va - area->GetBaseAddress() + area->GetCacheOffset(); Page *page = cache->GetPage(offset, write && cache->IsCopy()); cache->ReleaseRef(); if (page == 0) return E_IO; fAreaLock.LockRead(); if (lastChangeCount != fChangeCount) { // Changes have occured to this address. Make sure that // the area hasn't changed underneath the fault handler. Area *newArea = static_cast<Area*>(fAreas.Find(va)); if (newArea != area || newArea->GetPageCache() != cache || newArea->GetCacheOffset() != offset) fAreaLock.UnlockRead(); return E_BAD_ADDRESS; } // If this is a read from copy-on-write page, it is shared with the // original cache. Mark it read only. if (copy && !write) protection &= ~(USER_WRITE | SYSTEM_WRITE); fPhysicalMap->Map(va, page->GetPhysicalAddress(), protection); fAreaLock.UnlockRead(); AtomicAdd(&fFaultCount, 1); return E_NO_ERROR; }