Bitu XMS_FreeMemory(Bitu handle) { if (InvalidHandle(handle)) return XMS_INVALID_HANDLE; MEM_ReleasePages(xms_handles[handle].mem); xms_handles[handle].mem=-1; xms_handles[handle].size=0; xms_handles[handle].free=true; return 0; }
Bitu XMS_UnlockMemory(Bitu handle) { if (InvalidHandle(handle)) return XMS_INVALID_HANDLE; if (xms_handles[handle].locked) { xms_handles[handle].locked--; return 0; } return XMS_BLOCK_NOT_LOCKED; }
Bitu XMS_MoveMemory(PhysPt bpt) { /* Read the block with mem_read's */ Bitu length=mem_readd(bpt+offsetof(XMS_MemMove,length)); Bitu src_handle=mem_readw(bpt+offsetof(XMS_MemMove,src_handle)); union { RealPt realpt; Bit32u offset; } src,dest; src.offset=mem_readd(bpt+offsetof(XMS_MemMove,src.offset)); Bitu dest_handle=mem_readw(bpt+offsetof(XMS_MemMove,dest_handle)); dest.offset=mem_readd(bpt+offsetof(XMS_MemMove,dest.offset)); PhysPt srcpt,destpt; if (src_handle) { if (InvalidHandle(src_handle)) { return XMS_INVALID_SOURCE_HANDLE; } if (src.offset>=(xms_handles[src_handle].size*1024U)) { return XMS_INVALID_SOURCE_OFFSET; } if (length>xms_handles[src_handle].size*1024U-src.offset) { return XMS_INVALID_LENGTH; } srcpt=(xms_handles[src_handle].mem*4096)+src.offset; } else { srcpt=Real2Phys(src.realpt); } if (dest_handle) { if (InvalidHandle(dest_handle)) { return XMS_INVALID_DEST_HANDLE; } if (dest.offset>=(xms_handles[dest_handle].size*1024U)) { return XMS_INVALID_DEST_OFFSET; } if (length>xms_handles[dest_handle].size*1024U-dest.offset) { return XMS_INVALID_LENGTH; } destpt=(xms_handles[dest_handle].mem*4096)+dest.offset; } else { destpt=Real2Phys(dest.realpt); } // LOG_MSG("XMS move src %X dest %X length %X",srcpt,destpt,length); mem_memcpy(destpt,srcpt,length); return 0; }
Bitu XMS_ResizeMemory(Bitu handle, Bitu newSize) { if (InvalidHandle(handle)) return XMS_INVALID_HANDLE; // Block has to be unlocked if (xms_handles[handle].locked>0) return XMS_BLOCK_LOCKED; Bitu pages=newSize/4 + ((newSize & 3) ? 1 : 0); if (MEM_ReAllocatePages(xms_handles[handle].mem,pages,true)) { xms_handles[handle].size = newSize; return 0; } else return XMS_OUT_OF_SPACE; }
ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { Archive* archive = GetArchive(archive_handle); if (archive == nullptr) return InvalidHandle(ErrorModule::FS); if (archive->backend->CreateDirectory(path)) return RESULT_SUCCESS; return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::Canceled, ErrorLevel::Status); }
Bitu XMS_GetHandleInformation(Bitu handle, Bit8u& lockCount, Bit8u& numFree, Bit16u& size) { if (InvalidHandle(handle)) return XMS_INVALID_HANDLE; lockCount = xms_handles[handle].locked; /* Find available blocks */ numFree=0; for (Bitu i=1;i<XMS_HANDLES;i++) { if (xms_handles[i].free) numFree++; } size=(Bit16u)(xms_handles[handle].size); return 0; }
ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) { SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); if (0 != shared_memory->base_address) return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset)); LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", handle); // TODO(yuriks): Verify error code. return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidState, ErrorLevel::Permanent); }
/** * Open a Directory from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the Directory inside of the Archive * @return Opened Directory object */ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { Archive* archive = GetArchive(archive_handle); if (archive == nullptr) return InvalidHandle(ErrorModule::FS); std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path); if (backend == nullptr) { return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Permanent); } auto directory = Common::make_unique<Directory>(std::move(backend), path); // TOOD(yuriks): Fix error reporting Handle handle = Kernel::g_handle_table.Create(directory.release()).ValueOr(INVALID_HANDLE); return MakeResult<Handle>(handle); }
/// Synchronize to an OS service static Result SendSyncRequest(Handle handle) { // TODO(yuriks): ObjectPool::Get tries to check the Object type, which fails since this is a generic base Object, // so we are forced to use GetFast and manually verify the handle. if (!Kernel::g_object_pool.IsValid(handle)) { return InvalidHandle(ErrorModule::Kernel).raw; } Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str()); ResultVal<bool> wait = object->SyncRequest(); if (wait.Succeeded() && *wait) { Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? } return wait.Code().raw; }
/** * Maps a shared memory block to an address in system memory * @param handle Shared memory block handle * @param address Address in system memory to map shared memory block to * @param permissions Memory block map permissions (specified by SVC field) * @param other_permissions Memory block map other permissions (specified by SVC field) * @return Result of operation, 0 on success, otherwise error code */ ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, MemoryPermission other_permissions) { if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { LOG_ERROR(Kernel_SVC, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", handle, address); return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); shared_memory->base_address = address; shared_memory->permissions = permissions; shared_memory->other_permissions = other_permissions; return RESULT_SUCCESS; }
ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { Archive* src_archive = GetArchive(src_archive_handle); Archive* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) return InvalidHandle(ErrorModule::FS); if (src_archive == dest_archive) { if (src_archive->backend->RenameDirectory(src_path, dest_path)) return RESULT_SUCCESS; } else { // TODO: Implement renaming across archives return UnimplementedFunction(ErrorModule::FS); } // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't // exist or similar. Verify. return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::NothingHappened, ErrorLevel::Status); }
ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle).get(); if (semaphore == nullptr) return InvalidHandle(ErrorModule::Kernel); if (semaphore->max_count - semaphore->available_count < release_count) return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); *count = semaphore->available_count; semaphore->available_count += release_count; // Notify some of the threads that the semaphore has been released // stop once the semaphore is full again or there are no more waiting threads while (!semaphore->ShouldWait() && semaphore->WakeupNextThread() != nullptr) { semaphore->Acquire(); } return RESULT_SUCCESS; }
void Database::import ( const char * folder, const char * file ) { const ::UINT result = ::MsiDatabaseImport(handle(),folder,file); if ( result != ERROR_SUCCESS ) { if ( result == ERROR_BAD_PATHNAME ) { throw (BadPathName()); } else if ( result == ERROR_FUNCTION_FAILED ) { throw (FunctionFailed()); } else if ( result == ERROR_INVALID_HANDLE ) { throw (InvalidHandle()); } else if ( result == ERROR_INVALID_PARAMETER ) { throw (InvalidParameter()); } UNCHECKED_INSTALLER_ERROR(MsiDatabaseImport,result); } }
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { // TODO(bunnei): Do something with nano_seconds, currently ignoring this bool unlock_all = true; bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld", handle_count, (wait_all ? "true" : "false"), nano_seconds); // Iterate through each handle, synchronize kernel object for (s32 i = 0; i < handle_count; i++) { if (!Kernel::g_object_pool.IsValid(handles[i])) { return InvalidHandle(ErrorModule::Kernel).raw; } Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]); DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(), object->GetName().c_str()); // TODO(yuriks): Verify how the real function behaves when an error happens here ResultVal<bool> wait_result = object->WaitSynchronization(); bool wait = wait_result.Succeeded() && *wait_result; if (!wait && !wait_all) { *out = i; return RESULT_SUCCESS.raw; } else { unlock_all = false; } } if (wait_all && unlock_all) { *out = handle_count; return RESULT_SUCCESS.raw; } // Check for next thread to schedule HLE::Reschedule(__func__); return RESULT_SUCCESS.raw; }
void Database::export_ ( const char * table, const char * folder, const char * file ) { const ::UINT result = ::MsiDatabaseExport( handle(), table, folder, file ); if ( result != ERROR_SUCCESS ) { if ( result == ERROR_BAD_PATHNAME ) { throw (BadPathName()); } else if ( result == ERROR_INVALID_HANDLE ) { throw (InvalidHandle()); } else if ( result == ERROR_INVALID_PARAMETER ) { throw (InvalidParameter()); } UNCHECKED_INSTALLER_ERROR(MsiDatabaseExport,result); } }
ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { Semaphore* semaphore = g_object_pool.Get<Semaphore>(handle); if (semaphore == nullptr) return InvalidHandle(ErrorModule::Kernel); if (semaphore->max_count - semaphore->available_count < release_count) return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); *count = semaphore->available_count; semaphore->available_count += release_count; // Notify some of the threads that the semaphore has been released // stop once the semaphore is full again or there are no more waiting threads while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) { Kernel::ResumeThreadFromWait(semaphore->waiting_threads.front()); semaphore->waiting_threads.pop(); --semaphore->available_count; } return RESULT_SUCCESS; }
void Database::merge ( const Database& other, const char * table ) { const ::UINT result = ::MsiDatabaseMerge( handle(), other.handle(), table ); if ( result != ERROR_SUCCESS ) { if ( result == ERROR_FUNCTION_FAILED ) { throw (FunctionFailed()); } else if ( result == ERROR_INVALID_HANDLE ) { throw (InvalidHandle()); } else if ( result == ERROR_INVALID_TABLE ) { throw (InvalidTable()); } else if ( result == ERROR_DATATYPE_MISMATCH ) { throw (DatatypeMismatch()); } UNCHECKED_INSTALLER_ERROR(MsiDatabaseMerge,result); } }
/// Wait for a handle to synchronize, timeout after the specified nanoseconds static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { // TODO(bunnei): Do something with nano_seconds, currently ignoring this bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated if (!Kernel::g_object_pool.IsValid(handle)) { return InvalidHandle(ErrorModule::Kernel).raw; } Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); _dbg_assert_(KERNEL, object != nullptr); DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); ResultVal<bool> wait = object->WaitSynchronization(); // Check for next thread to schedule if (wait.Succeeded() && *wait) { HLE::Reschedule(__func__); } return wait.Code().raw; }
HandleType Mesh::PrevHandle(HandleType h) const { integer num = GetHandleElementNum(h), id = GetHandleID(h); --id; if( num == 5 ) { if( id < 0 ) num = 4; else return ComposeHandleNum(ElementNum(MESH),0); } while( num >= 0 ) { while(id >= 0 && (links[num][id] == -1)) --id; if( id == -1 ) { --num; if( num > 0 ) id = static_cast<integer>(links[num].size())-1; } else break; } if( num < 0 ) return InvalidHandle(); return ComposeHandleNum(num,id); }
ResultCode CloseArchive(ArchiveHandle handle) { if (handle_map.erase(handle) == 0) return InvalidHandle(ErrorModule::FS); else return RESULT_SUCCESS; }
/// Arbitrate an address ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) { AddressArbiter* object = Kernel::g_handle_table.Get<AddressArbiter>(handle).get(); if (object == nullptr) return InvalidHandle(ErrorModule::Kernel); switch (type) { // Signal thread(s) waiting for arbitrate address... case ArbitrationType::Signal: // Negative value means resume all threads if (value < 0) { ArbitrateAllThreads(address); } else { // Resume first N threads for(int i = 0; i < value; i++) ArbitrateHighestPriorityThread(address); } break; // Wait current thread (acquire the arbiter)... case ArbitrationType::WaitIfLessThan: if ((s32)Memory::Read32(address) <= value) { Kernel::WaitCurrentThread_ArbitrateAddress(address); HLE::Reschedule(__func__); } break; case ArbitrationType::WaitIfLessThanWithTimeout: if ((s32)Memory::Read32(address) <= value) { Kernel::WaitCurrentThread_ArbitrateAddress(address); Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); HLE::Reschedule(__func__); } break; case ArbitrationType::DecrementAndWaitIfLessThan: { s32 memory_value = Memory::Read32(address) - 1; Memory::Write32(address, memory_value); if (memory_value <= value) { Kernel::WaitCurrentThread_ArbitrateAddress(address); HLE::Reschedule(__func__); } break; } case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: { s32 memory_value = Memory::Read32(address) - 1; Memory::Write32(address, memory_value); if (memory_value <= value) { Kernel::WaitCurrentThread_ArbitrateAddress(address); Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); HLE::Reschedule(__func__); } break; } default: LOG_ERROR(Kernel, "unknown type=%d", type); return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage); } return RESULT_SUCCESS; }
bool Storage::isValid() const { return handle != InvalidHandle() && GetMeshLink()->isValidElement(handle); }
Bitu XMS_LockMemory(Bitu handle, Bit32u& address) { if (InvalidHandle(handle)) return XMS_INVALID_HANDLE; if (xms_handles[handle].locked<255) xms_handles[handle].locked++; address = xms_handles[handle].mem*4096; return 0; }