Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
/**
 * 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);
}
Example #4
0
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;
}
Example #5
0
/**
 * 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);
}
Example #6
0
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);
}
Example #7
0
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;
}
Example #8
0
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);
}
Example #9
0
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);
}
Example #10
0
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;
}
Example #11
0
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);
}
Example #12
0
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);
}
Example #13
0
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;
}
Example #14
0
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;
}
Example #15
0
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;
}
Example #16
0
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;
}
Example #17
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);
}
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));
}
Example #21
0
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));
}
Example #22
0
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;
}
Example #23
0
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;
}
Example #24
0
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));
}
Example #25
0
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));
}
Example #26
0
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);
}
Example #27
0
/**
 * 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);
}
Example #28
0
/**
 * 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?
}
Example #29
0
/**
 * 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();
}
Example #30
0
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;
}