ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions) { if (base_address != 0) { LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s: already mapped at 0x%08X!", GetObjectId(), address, name.c_str(), base_address); // TODO: Verify error code with hardware return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } // TODO(Subv): Return E0E01BEE when permissions and other_permissions don't // match what was specified when the memory block was created. // TODO(Subv): Return E0E01BEE when address should be 0. // Note: Find out when that's the case. if (fixed_address != 0) { if (address != 0 && address != fixed_address) { LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s: fixed_addres is 0x%08X!", GetObjectId(), address, name.c_str(), fixed_address); // TODO: Verify error code with hardware return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } // HACK(yuriks): This is only here to support the APT shared font mapping right now. // Later, this should actually map the memory block onto the address space. return RESULT_SUCCESS; } if (address < Memory::SHARED_MEMORY_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) { LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s outside of shared mem bounds!", GetObjectId(), address, name.c_str()); // TODO: Verify error code with hardware return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } // TODO: Test permissions // HACK: Since there's no way to write to the memory block without mapping it onto the game // process yet, at least initialize memory the first time it's mapped. if (address != this->base_address) { std::memset(Memory::GetPointer(address), 0, size); } this->base_address = address; return RESULT_SUCCESS; }
ResultCode SharedMemory::Unmap(VAddr address) { if (base_address == 0) { // TODO(Subv): Verify what actually happens when you want to unmap a memory block that // was originally mapped with address = 0 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); } if (base_address != address) return ResultCode(ErrorDescription::WrongAddress, ErrorModule::OS, ErrorSummary::InvalidState, ErrorLevel::Usage); base_address = 0; return RESULT_SUCCESS; }
/** * NWM_UDS::Initialize service function * Inputs: * 1 : Unknown * 2-11 : Input Structure * 12 : Unknown u16 * 13 : Value 0 * 14 : Handle * Outputs: * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code * 2 : Value 0 * 3 : Output handle */ static void InitializeWithVersion(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 unk1 = cmd_buff[1]; u32 unk2 = cmd_buff[12]; u32 value = cmd_buff[13]; u32 handle = cmd_buff[14]; // Because NWM service is not implemented at all, we stub the Initialize function with an error // code instead of success to prevent games from using the service and from causing more issues. // The error code is from a real 3DS with wifi off, thus believed to be "network disabled". /* cmd_buff[1] = RESULT_SUCCESS.raw; cmd_buff[2] = 0; cmd_buff[3] = Kernel::g_handle_table.Create(handle_event) .MoveFrom(); // TODO(purpasmart): Verify if this is a event handle */ cmd_buff[0] = IPC::MakeHeader(0x1B, 1, 2); cmd_buff[1] = ResultCode(static_cast<ErrorDescription>(2), ErrorModule::UDS, ErrorSummary::StatusChanged, ErrorLevel::Status) .raw; cmd_buff[2] = 0; cmd_buff[3] = 0; LOG_WARNING(Service_NWM, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, value=%u, handle=0x%08X", unk1, unk2, value, handle); }
ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const u8* data) { SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data()); if (config->total_entries >= CONFIG_FILE_MAX_BLOCK_ENTRIES) return ResultCode(-1); // TODO(Subv): Find the right error code // Insert the block header with offset 0 for now config->block_entries[config->total_entries] = { block_id, 0, size, flags }; if (size > 4) { u32 offset = config->data_entries_offset; // Perform a search to locate the next offset for the new data // use the offset and size of the previous block to determine the new position for (int i = config->total_entries - 1; i >= 0; --i) { // Ignore the blocks that don't have a separate data offset if (config->block_entries[i].size > 4) { offset = config->block_entries[i].offset_or_data + config->block_entries[i].size; break; } } config->block_entries[config->total_entries].offset_or_data = offset; // Write the data at the new offset memcpy(&cfg_config_file_buffer[offset], data, size); } else { // The offset_or_data field in the header contains the data itself if it's 4 bytes or less memcpy(&config->block_entries[config->total_entries].offset_or_data, data, size); } ++config->total_entries; return RESULT_SUCCESS; }
/** * DSP_DSP::WriteProcessPipe service function * Inputs: * 1 : Pipe Number * 2 : Size * 3 : (size << 14) | 0x402 * 4 : Buffer * Outputs: * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code */ static void WriteProcessPipe(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 pipe_index = cmd_buff[1]; u32 size = cmd_buff[2]; u32 buffer = cmd_buff[4]; DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(pipe_index); if (IPC::StaticBufferDesc(size, 1) != cmd_buff[3]) { LOG_ERROR(Service_DSP, "IPC static buffer descriptor failed validation (0x%X). pipe=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], pipe_index, size, buffer); cmd_buff[0] = IPC::MakeHeader(0, 1, 0); cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw; return; } ASSERT_MSG(Memory::IsValidVirtualAddress(buffer), "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer); std::vector<u8> message(size); for (u32 i = 0; i < size; i++) { message[i] = Memory::Read8(buffer + i); } DSP::HLE::PipeWrite(pipe, message); cmd_buff[0] = IPC::MakeHeader(0xD, 1, 0); cmd_buff[1] = RESULT_SUCCESS.raw; // No error LOG_DEBUG(Service_DSP, "pipe=%u, size=0x%X, buffer=0x%08X", pipe_index, size, buffer); }
ResultCode SaveDataArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const { const PathParser path_parser_src(src_path); // TODO: Verify these return codes with HW if (!path_parser_src.IsValid()) { LOG_ERROR(Service_FS, "Invalid src path {}", src_path.DebugStr()); return ERROR_INVALID_PATH; } const PathParser path_parser_dest(dest_path); if (!path_parser_dest.IsValid()) { LOG_ERROR(Service_FS, "Invalid dest path {}", dest_path.DebugStr()); return ERROR_INVALID_PATH; } const auto src_path_full = path_parser_src.BuildHostPath(mount_point); const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point); if (FileUtil::Rename(src_path_full, dest_path_full)) { return RESULT_SUCCESS; } // 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); }
BOOL CTwain::MemoryXfer(void) { ATLASSERT(nState == TRANSFER_READY); TW_IMAGEINFO info; TW_SETUPMEMXFER twsx; TW_IMAGEMEMXFER mx; if (!DS(DG_CONTROL, DAT_SETUPMEMXFER, MSG_GET, &twsx)) { return FALSE; } // Get actual image info if (!DS(DG_IMAGE, DAT_IMAGEINFO, MSG_GET, &info)) { return FALSE; } ATLASSERT(nState == TRANSFER_READY); if (!MemXferReady(info)) { // application aborted transfer return FALSE; } if (!MemXferAlloc(twsx, mx.Memory)) { MemXferDone(FALSE); return FALSE; } int iRow = 0; while (DS(DG_IMAGE, DAT_IMAGEMEMXFER, MSG_GET, &mx)) { // We got a buffer - make sure DS doesn't // feed us rows past the end of the image: mx.Rows = min(mx.Rows, (unsigned)(info.ImageLength - iRow)); // Don't call the buffer-handler with 0 rows if (mx.Rows != 0) { if (!MemXferBuffer(iRow, mx)) { // Buffer callback says to abort break; } iRow += mx.Rows; } if (ResultCode() == TWRC_XFERDONE) { // DS says that was the last buffer: iRow = info.ImageLength; // no matter what, we're done break; } } MemXferFree(mx.Memory); ATLASSERT(nState >= TRANSFER_READY); EndXfer(); // acknowledge & end transfer ATLASSERT(nState == TRANSFER_READY || nState == SOURCE_ENABLED); FlushMessageQueue(); MemXferDone(iRow == info.ImageLength); return TRUE; }
ResultVal<u8*> SharedMemory::GetPointer(u32 offset) { if (base_address != 0) return MakeResult<u8*>(Memory::GetPointer(base_address + offset)); LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId()); // TODO(yuriks): Verify error code. return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidState, ErrorLevel::Permanent); }
ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { Archive* archive = GetArchive(archive_handle); if (archive == nullptr) return InvalidHandle(ErrorModule::FS); if (archive->backend->DeleteDirectory(path)) return RESULT_SUCCESS; return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::Canceled, ErrorLevel::Status); }
ResultCode ConversionConfiguration::SetStandardCoefficient(StandardCoefficient standard_coefficient) { size_t index = static_cast<size_t>(standard_coefficient); if (index >= ARRAY_SIZE(standard_coefficients)) { return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::CAM, ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E053ED } std::memcpy(coefficients.data(), standard_coefficients[index].data(), sizeof(coefficients)); return RESULT_SUCCESS; }
ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_HANDLE; if (archive->CreateDirectory(path)) return RESULT_SUCCESS; return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::Canceled, ErrorLevel::Status); }
ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u32 size) const { std::string full_path = mount_point + path.AsString(); if (FileUtil::Exists(full_path)) return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::FS, ErrorSummary::NothingHappened, ErrorLevel::Info); if (size == 0) { FileUtil::CreateEmptyFile(full_path); return RESULT_SUCCESS; } FileUtil::IOFile file(full_path, "wb"); // Creates a sparse file (or a normal file on filesystems without the concept of sparse files) // We do this by seeking to the right size, then writing a single null byte. if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) return RESULT_SUCCESS; return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource, ErrorLevel::Info); }
ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) { // Construct the binary path to the archive first FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); std::string media_type_directory; if (media_type == MediaType::NAND) { media_type_directory = FileUtil::GetUserPath(D_NAND_IDX); } else if (media_type == MediaType::SDMC) { media_type_directory = FileUtil::GetUserPath(D_SDMC_IDX); } else { LOG_ERROR(Service_FS, "Unsupported media type %u", media_type); return ResultCode(-1); // TODO(Subv): Find the right error code } std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); if (!FileUtil::DeleteDirRecursively(extsavedata_path)) return ResultCode(-1); // TODO(Subv): Find the right error code return RESULT_SUCCESS; }
ResultCode ArchiveManager::CreateSystemSaveData(u32 high, u32 low) { // Construct the binary path to the archive first FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); std::string nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); std::string base_path = FileSys::GetSystemSaveDataContainerPath(nand_directory); std::string systemsavedata_path = FileSys::GetSystemSaveDataPath(base_path, path); if (!FileUtil::CreateFullPath(systemsavedata_path)) return ResultCode(-1); // TODO(Subv): Find the right error code return RESULT_SUCCESS; }
ResultCode DeleteSystemSaveData(u32 high, u32 low) { // Construct the binary path to the archive first FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); std::string base_path = FileSys::GetSystemSaveDataContainerPath(nand_directory); std::string systemsavedata_path = FileSys::GetSystemSaveDataPath(base_path, path); if (!FileUtil::DeleteDirRecursively(systemsavedata_path)) return ResultCode(-1); // TODO(Subv): Find the right error code return RESULT_SUCCESS; }
ResultCode ConversionConfiguration::SetInputLineWidth(u16 width) { if (width == 0 || width > 1024 || width % 8 != 0) { return ResultCode(ErrorDescription::OutOfRange, ErrorModule::CAM, ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E053FD } // Note: The hardware uses the register value 0 to represent a width of 1024, so for a width of // 1024 the `camera` module would set the value 0 here, but we don't need to emulate this // internal detail. this->input_line_width = width; return RESULT_SUCCESS; }
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); }
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, FileSys::Path& path) { LOG_TRACE(Service_FS, "Opening FileSystem with type=%d", type); auto itr = filesystem_map.find(type); if (itr == filesystem_map.end()) { // TODO(bunnei): Find a better error code for this return ResultCode(-1); } return itr->second->Open(path); }
ResultCode Applet::Create(Service::APT::AppletId id) { switch (id) { case Service::APT::AppletId::SoftwareKeyboard1: case Service::APT::AppletId::SoftwareKeyboard2: applets[id] = std::make_shared<SoftwareKeyboard>(id); break; default: // TODO(Subv): Find the right error code return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent); } return RESULT_SUCCESS; }
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(const Path& path) { auto vec = path.AsBinary(); const u32* data = reinterpret_cast<u32*>(vec.data()); std::string file_path = GetSaveDataCheckPath(mount_point, data[1], data[0]); auto file = std::make_shared<FileUtil::IOFile>(file_path, "rb"); if (!file->IsOpen()) { return ResultCode(-1); // TODO(Subv): Find the right error code } auto size = file->GetSize(); auto archive = std::make_unique<IVFCArchive>(file, 0, size); return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); }
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) { std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_program_id); if (!FileUtil::Exists(concrete_mount_point)) { // When a SaveData archive is created for the first time, it is not yet formatted // and the save file/directory structure expected by the game has not yet been initialized. // Returning the NotFormatted error code will signal the game to provision the SaveData archive // with the files and folders that it expects. return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status); } auto archive = Common::make_unique<DiskArchive>(std::move(concrete_mount_point)); return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); }
ResultCode ArchiveManager::DeleteExtSaveData(MediaType media_type, u32 high, u32 low) { // Construct the binary path to the archive first FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); std::string media_type_directory; if (media_type == MediaType::NAND) { media_type_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); } else if (media_type == MediaType::SDMC) { media_type_directory = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir); } else { LOG_ERROR(Service_FS, "Unsupported media type {}", static_cast<u32>(media_type)); return ResultCode(-1); // TODO(Subv): Find the right error code } // Delete all directories (/user, /boss) and the icon file. std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); if (FileUtil::Exists(extsavedata_path) && !FileUtil::DeleteDirRecursively(extsavedata_path)) return ResultCode(-1); // TODO(Subv): Find the right error code return RESULT_SUCCESS; }
ResultCode ConversionConfiguration::SetInputLines(u16 lines) { if (lines == 0 || lines > 1024) { return ResultCode(ErrorDescription::OutOfRange, ErrorModule::CAM, ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E053FD } // Note: In what appears to be a bug, the `camera` module does not set the hardware register at // all if `lines` is 1024, so the conversion uses the last value that was set. The intention // was probably to set it to 0 like in SetInputLineWidth. if (lines != 1024) { this->input_lines = lines; } return RESULT_SUCCESS; }
ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_HANDLE; std::unique_ptr<FileSys::DirectoryBackend> backend = archive->OpenDirectory(path); if (backend == nullptr) { return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Permanent); } auto directory = Kernel::SharedPtr<Directory>(new Directory(std::move(backend), path)); return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory)); }
ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_HANDLE; std::unique_ptr<FileSys::FileBackend> backend = archive->OpenFile(path, mode); if (backend == nullptr) { return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status); } auto file = Kernel::SharedPtr<File>(new File(std::move(backend), path)); return MakeResult<Kernel::SharedPtr<File>>(std::move(file)); }
ResultVal<s32> Semaphore::Release(s32 release_count) { if (max_count - available_count < release_count) return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); s32 previous_count = available_count; 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 (!ShouldWait() && WakeupNextThread() != nullptr) { Acquire(); } return MakeResult<s32>(previous_count); }
/** * 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); }
/** * GSP_GPU::RegisterInterruptRelayQueue service function * Inputs: * 1 : "Flags" field, purpose is unknown * 3 : Handle to GSP synchronization event * Outputs: * 1 : Result of function, 0x2A07 on success, otherwise error code * 2 : Thread index into GSP command buffer * 4 : Handle to GSP shared memory */ static void RegisterInterruptRelayQueue(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 flags = cmd_buff[1]; g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]); ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!"); Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); // This specific code is required for a successful initialization, rather than 0 cmd_buff[1] = ResultCode((ErrorDescription)519, ErrorModule::GX, ErrorSummary::Success, ErrorLevel::Success).raw; cmd_buff[2] = g_thread_id++; // Thread ID cmd_buff[4] = shmem_handle; // GSP shared memory g_interrupt_event->Signal(); // TODO(bunnei): Is this correct? }
/** * Callback that will wake up the thread it was scheduled for * @param thread_handle The handle of the thread that's been awoken * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time */ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>((Handle)thread_handle); if (thread == nullptr) { LOG_CRITICAL(Kernel, "Callback fired for invalid thread %08X", (Handle)thread_handle); return; } if (thread->status == THREADSTATUS_WAIT_SYNCH) { thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, ErrorSummary::StatusChanged, ErrorLevel::Info)); if (thread->wait_set_output) thread->SetWaitSynchronizationOutput(-1); } thread->ResumeFromWait(); }
ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions) { if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X outside of shared mem bounds!", GetObjectId(), address); // TODO: Verify error code with hardware return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } this->base_address = address; this->permissions = permissions; this->other_permissions = other_permissions; return RESULT_SUCCESS; }