mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 07:05:40 +12:00
[Kernel] ExitThread [FS] Start implement archive 0x2345678A
This commit is contained in:
parent
7c2dd34eba
commit
4e64f722e5
11 changed files with 215 additions and 131 deletions
|
@ -67,8 +67,8 @@ set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA
|
||||||
set(RENDERER_GL_SOURCE_FILES src/core/renderer_gl/renderer_gl.cpp)
|
set(RENDERER_GL_SOURCE_FILES src/core/renderer_gl/renderer_gl.cpp)
|
||||||
|
|
||||||
set(LOADER_SOURCE_FILES src/core/loader/elf.cpp src/core/loader/ncsd.cpp src/core/loader/ncch.cpp)
|
set(LOADER_SOURCE_FILES src/core/loader/elf.cpp src/core/loader/ncsd.cpp src/core/loader/ncch.cpp)
|
||||||
set(FS_SOURCE_FILES src/core/fs/archive_ncch.cpp src/core/fs/archive_save_data.cpp src/core/fs/archive_sdmc.cpp
|
set(FS_SOURCE_FILES src/core/fs/archive_self_ncch.cpp src/core/fs/archive_save_data.cpp src/core/fs/archive_sdmc.cpp
|
||||||
src/core/fs/archive_ext_save_data.cpp
|
src/core/fs/archive_ext_save_data.cpp src/core/fs/archive_ncch.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp include/termcolor.hpp
|
set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp include/termcolor.hpp
|
||||||
|
@ -80,13 +80,13 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc
|
||||||
include/PICA/gpu.hpp include/PICA/regs.hpp include/services/ndm.hpp
|
include/PICA/gpu.hpp include/PICA/regs.hpp include/services/ndm.hpp
|
||||||
include/PICA/shader.hpp include/PICA/shader_unit.hpp include/PICA/float_types.hpp
|
include/PICA/shader.hpp include/PICA/shader_unit.hpp include/PICA/float_types.hpp
|
||||||
include/logger.hpp include/loader/ncch.hpp include/loader/ncsd.hpp include/io_file.hpp
|
include/logger.hpp include/loader/ncch.hpp include/loader/ncsd.hpp include/io_file.hpp
|
||||||
include/loader/lz77.hpp include/fs/archive_base.hpp include/fs/archive_ncch.hpp
|
include/loader/lz77.hpp include/fs/archive_base.hpp include/fs/archive_self_ncch.hpp
|
||||||
include/services/dsp.hpp include/services/cfg.hpp include/services/region_codes.hpp
|
include/services/dsp.hpp include/services/cfg.hpp include/services/region_codes.hpp
|
||||||
include/fs/archive_save_data.hpp include/fs/archive_sdmc.hpp include/services/ptm.hpp
|
include/fs/archive_save_data.hpp include/fs/archive_sdmc.hpp include/services/ptm.hpp
|
||||||
include/services/mic.hpp include/services/cecd.hpp include/renderer_gl/renderer_gl.hpp
|
include/services/mic.hpp include/services/cecd.hpp include/renderer_gl/renderer_gl.hpp
|
||||||
include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp include/services/ac.hpp
|
include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp include/services/ac.hpp
|
||||||
include/services/am.hpp include/services/boss.hpp include/services/frd.hpp include/services/nim.hpp
|
include/services/am.hpp include/services/boss.hpp include/services/frd.hpp include/services/nim.hpp
|
||||||
include/fs/archive_ext_save_data.hpp include/services/shared_font.hpp
|
include/fs/archive_ext_save_data.hpp include/services/shared_font.hpp include/fs/archive_ncch.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp
|
set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp
|
||||||
|
|
|
@ -26,7 +26,9 @@ namespace ArchiveID {
|
||||||
SharedExtSaveData = 7,
|
SharedExtSaveData = 7,
|
||||||
SystemSaveData = 8,
|
SystemSaveData = 8,
|
||||||
SDMC = 9,
|
SDMC = 9,
|
||||||
SDMCWriteOnly = 0xA
|
SDMCWriteOnly = 0xA,
|
||||||
|
|
||||||
|
SavedataAndNcch = 0x2345678A
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string toString(u32 id) {
|
static std::string toString(u32 id) {
|
||||||
|
@ -38,6 +40,7 @@ namespace ArchiveID {
|
||||||
case SystemSaveData: return "SystemSaveData";
|
case SystemSaveData: return "SystemSaveData";
|
||||||
case SDMC: return "SDMC";
|
case SDMC: return "SDMC";
|
||||||
case SDMCWriteOnly: return "SDMC (Write-only)";
|
case SDMCWriteOnly: return "SDMC (Write-only)";
|
||||||
|
case SavedataAndNcch: return "Savedata & NCCH (archive 0x2345678A)";
|
||||||
default: return "Unknown archive";
|
default: return "Unknown archive";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "archive_base.hpp"
|
#include "archive_base.hpp"
|
||||||
|
|
||||||
class SelfNCCHArchive : public ArchiveBase {
|
class NCCHArchive : public ArchiveBase {
|
||||||
public:
|
public:
|
||||||
SelfNCCHArchive(Memory& mem) : ArchiveBase(mem) {}
|
NCCHArchive(Memory& mem) : ArchiveBase(mem) {}
|
||||||
|
|
||||||
u64 getFreeBytes() override { return 0; }
|
u64 getFreeBytes() override { Helpers::panic("NCCH::GetFreeBytes unimplemented"); return 0; }
|
||||||
std::string name() override { return "SelfNCCH"; }
|
std::string name() override { return "NCCH"; }
|
||||||
|
|
||||||
ArchiveBase* openArchive(const FSPath& path) override;
|
ArchiveBase* openArchive(const FSPath& path) override;
|
||||||
CreateFileResult createFile(const FSPath& path, u64 size) override;
|
CreateFileResult createFile(const FSPath& path, u64 size) override;
|
||||||
FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override;
|
FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override;
|
||||||
std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override;
|
std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override;
|
||||||
|
|
||||||
// Returns whether the cart has a RomFS
|
|
||||||
bool hasRomFS() {
|
|
||||||
auto cxi = mem.getCXI();
|
|
||||||
return (cxi != nullptr && cxi->hasRomFS());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns whether the cart has an ExeFS (All executable carts should have an ExeFS. This is just here to be safe)
|
|
||||||
bool hasExeFS() {
|
|
||||||
auto cxi = mem.getCXI();
|
|
||||||
return (cxi != nullptr && cxi->hasExeFS());
|
|
||||||
}
|
|
||||||
};
|
};
|
27
include/fs/archive_self_ncch.hpp
Normal file
27
include/fs/archive_self_ncch.hpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
#include "archive_base.hpp"
|
||||||
|
|
||||||
|
class SelfNCCHArchive : public ArchiveBase {
|
||||||
|
public:
|
||||||
|
SelfNCCHArchive(Memory& mem) : ArchiveBase(mem) {}
|
||||||
|
|
||||||
|
u64 getFreeBytes() override { return 0; }
|
||||||
|
std::string name() override { return "SelfNCCH"; }
|
||||||
|
|
||||||
|
ArchiveBase* openArchive(const FSPath& path) override;
|
||||||
|
CreateFileResult createFile(const FSPath& path, u64 size) override;
|
||||||
|
FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override;
|
||||||
|
std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override;
|
||||||
|
|
||||||
|
// Returns whether the cart has a RomFS
|
||||||
|
bool hasRomFS() {
|
||||||
|
auto cxi = mem.getCXI();
|
||||||
|
return (cxi != nullptr && cxi->hasRomFS());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns whether the cart has an ExeFS (All executable carts should have an ExeFS. This is just here to be safe)
|
||||||
|
bool hasExeFS() {
|
||||||
|
auto cxi = mem.getCXI();
|
||||||
|
return (cxi != nullptr && cxi->hasExeFS());
|
||||||
|
}
|
||||||
|
};
|
|
@ -33,7 +33,8 @@ class Kernel {
|
||||||
Handle errorPortHandle; // Handle for the err:f port used for displaying errors
|
Handle errorPortHandle; // Handle for the err:f port used for displaying errors
|
||||||
|
|
||||||
u32 arbiterCount;
|
u32 arbiterCount;
|
||||||
u32 threadCount;
|
u32 threadCount; // How many threads in our thread pool have been used as of now (Up to 32)
|
||||||
|
u32 aliveThreadCount; // How many of these threads are actually alive?
|
||||||
ServiceManager serviceManager;
|
ServiceManager serviceManager;
|
||||||
|
|
||||||
// Top 8 bits are the major version, bottom 8 are the minor version
|
// Top 8 bits are the major version, bottom 8 are the minor version
|
||||||
|
@ -95,6 +96,7 @@ private:
|
||||||
void createThread();
|
void createThread();
|
||||||
void controlMemory();
|
void controlMemory();
|
||||||
void duplicateHandle();
|
void duplicateHandle();
|
||||||
|
void exitThread();
|
||||||
void mapMemoryBlock();
|
void mapMemoryBlock();
|
||||||
void queryMemory();
|
void queryMemory();
|
||||||
void getProcessID();
|
void getProcessID();
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "fs/archive_ncch.hpp"
|
#include "fs/archive_ncch.hpp"
|
||||||
#include "fs/archive_save_data.hpp"
|
#include "fs/archive_save_data.hpp"
|
||||||
#include "fs/archive_sdmc.hpp"
|
#include "fs/archive_sdmc.hpp"
|
||||||
|
#include "fs/archive_self_ncch.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "kernel_types.hpp"
|
#include "kernel_types.hpp"
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
|
@ -18,11 +19,12 @@ class FSService {
|
||||||
|
|
||||||
MAKE_LOG_FUNCTION(log, fsLogger)
|
MAKE_LOG_FUNCTION(log, fsLogger)
|
||||||
|
|
||||||
// The different filesystem archives (Save data, RomFS+ExeFS, etc)
|
// The different filesystem archives (Save data, SelfNCCH, SDMC, NCCH, ExtData, etc)
|
||||||
SelfNCCHArchive selfNcch;
|
SelfNCCHArchive selfNcch;
|
||||||
SaveDataArchive saveData;
|
SaveDataArchive saveData;
|
||||||
ExtSaveDataArchive sharedExtSaveData;
|
ExtSaveDataArchive sharedExtSaveData;
|
||||||
SDMCArchive sdmc;
|
SDMCArchive sdmc;
|
||||||
|
NCCHArchive ncch;
|
||||||
|
|
||||||
ArchiveBase* getArchiveFromID(u32 id);
|
ArchiveBase* getArchiveFromID(u32 id);
|
||||||
std::optional<Handle> openArchiveHandle(u32 archiveID, const FSPath& path);
|
std::optional<Handle> openArchiveHandle(u32 archiveID, const FSPath& path);
|
||||||
|
@ -45,7 +47,7 @@ class FSService {
|
||||||
u32 priority;
|
u32 priority;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FSService(Memory& mem, Kernel& kernel) : mem(mem), saveData(mem), sharedExtSaveData(mem), sdmc(mem), selfNcch(mem),
|
FSService(Memory& mem, Kernel& kernel) : mem(mem), saveData(mem), sharedExtSaveData(mem), sdmc(mem), selfNcch(mem), ncch(mem),
|
||||||
kernel(kernel)
|
kernel(kernel)
|
||||||
{
|
{
|
||||||
sharedExtSaveData.isShared = true; // Need to do this here because templates and virtual classes do not mix well
|
sharedExtSaveData.isShared = true; // Need to do this here because templates and virtual classes do not mix well
|
||||||
|
|
|
@ -1,110 +1,22 @@
|
||||||
#include "fs/archive_ncch.hpp"
|
#include "fs/archive_ncch.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
// The part of the NCCH archive we're trying to access. Depends on the first 4 bytes of the binary file path
|
CreateFileResult NCCHArchive::createFile(const FSPath& path, u64 size) {
|
||||||
namespace PathType {
|
Helpers::panic("[NCCH] CreateFile not yet supported");
|
||||||
enum : u32 {
|
|
||||||
RomFS = 0,
|
|
||||||
ExeFS = 2
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
CreateFileResult SelfNCCHArchive::createFile(const FSPath& path, u64 size) {
|
|
||||||
Helpers::panic("[SelfNCCH] CreateFile not yet supported");
|
|
||||||
return CreateFileResult::Success;
|
return CreateFileResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptor SelfNCCHArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
FileDescriptor NCCHArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
||||||
if (!hasRomFS()) {
|
Helpers::panic("NCCHArchive::OpenFile: Unimplemented");
|
||||||
printf("Tried to open a SelfNCCH file without a RomFS\n");
|
|
||||||
return FileError;
|
return FileError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.type != PathType::Binary || path.binary.size() != 12) {
|
ArchiveBase* NCCHArchive::openArchive(const FSPath& path) {
|
||||||
printf("Invalid SelfNCCH path type\n");
|
Helpers::panic("NCCHArchive::OpenArchive: Unimplemented");
|
||||||
return FileError;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Where to read the file from. (https://www.3dbrew.org/wiki/Filesystem_services#SelfNCCH_File_Path_Data_Format)
|
|
||||||
// We currently only know how to read from an NCCH's RomFS, ie type = 0
|
|
||||||
const u32 type = *(u32*)&path.binary[0]; // TODO: Get rid of UB here
|
|
||||||
if (type != PathType::RomFS && type != PathType::ExeFS) {
|
|
||||||
Helpers::panic("Read from NCCH's non-RomFS & non-exeFS section!");
|
|
||||||
}
|
|
||||||
|
|
||||||
return NoFile; // No file descriptor needed for RomFS
|
|
||||||
}
|
|
||||||
|
|
||||||
ArchiveBase* SelfNCCHArchive::openArchive(const FSPath& path) {
|
|
||||||
if (path.type != PathType::Empty) {
|
|
||||||
printf("Invalid path type for SelfNCCH archive: %d\n", path.type);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
std::optional<u32> NCCHArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) {
|
||||||
}
|
Helpers::panic("NCCHArchive::ReadFile: Unimplemented");
|
||||||
|
|
||||||
std::optional<u32> SelfNCCHArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) {
|
|
||||||
const FSPath& path = file->path; // Path of the file
|
|
||||||
const u32 type = *(u32*)&path.binary[0]; // Type of the path
|
|
||||||
|
|
||||||
if (type == PathType::RomFS && !hasRomFS()) {
|
|
||||||
Helpers::panic("Tried to read file from non-existent RomFS");
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == PathType::ExeFS && !hasExeFS()) {
|
|
||||||
Helpers::panic("Tried to read file from non-existent RomFS");
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file->isOpen) {
|
|
||||||
printf("Tried to read from closed SelfNCCH file session");
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cxi = mem.getCXI();
|
|
||||||
IOFile& ioFile = mem.CXIFile;
|
|
||||||
|
|
||||||
// Seek to file offset depending on if we're reading from RomFS, ExeFS, etc
|
|
||||||
switch (type) {
|
|
||||||
case PathType::RomFS: {
|
|
||||||
const u32 romFSSize = cxi->romFS.size;
|
|
||||||
const u32 romFSOffset = cxi->romFS.offset;
|
|
||||||
if ((offset >> 32) || (offset >= romFSSize) || (offset + size >= romFSSize)) {
|
|
||||||
Helpers::panic("Tried to read from SelfNCCH with too big of an offset");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ioFile.seek(cxi->fileOffset + romFSOffset + offset + 0x1000)) {
|
|
||||||
Helpers::panic("Failed to seek while reading from RomFS");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PathType::ExeFS: {
|
|
||||||
const u32 exeFSSize = cxi->exeFS.size;
|
|
||||||
const u32 exeFSOffset = cxi->exeFS.offset;
|
|
||||||
if ((offset >> 32) || (offset >= exeFSSize) || (offset + size >= exeFSSize)) {
|
|
||||||
Helpers::panic("Tried to read from SelfNCCH with too big of an offset");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ioFile.seek(cxi->fileOffset + exeFSOffset + offset)) { // TODO: Not sure if this needs the + 0x1000
|
|
||||||
Helpers::panic("Failed to seek while reading from ExeFS");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<u8[]> data(new u8[size]);
|
|
||||||
auto [success, bytesRead] = ioFile.readBytes(&data[0], size);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
Helpers::panic("Failed to read from NCCH archive");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u64 i = 0; i < bytesRead; i++) {
|
|
||||||
mem.write8(dataPointer + i, data[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytesRead;
|
|
||||||
}
|
|
110
src/core/fs/archive_self_ncch.cpp
Normal file
110
src/core/fs/archive_self_ncch.cpp
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
#include "fs/archive_self_ncch.hpp"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// The part of the NCCH archive we're trying to access. Depends on the first 4 bytes of the binary file path
|
||||||
|
namespace PathType {
|
||||||
|
enum : u32 {
|
||||||
|
RomFS = 0,
|
||||||
|
ExeFS = 2
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
CreateFileResult SelfNCCHArchive::createFile(const FSPath& path, u64 size) {
|
||||||
|
Helpers::panic("[SelfNCCH] CreateFile not yet supported");
|
||||||
|
return CreateFileResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileDescriptor SelfNCCHArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
||||||
|
if (!hasRomFS()) {
|
||||||
|
printf("Tried to open a SelfNCCH file without a RomFS\n");
|
||||||
|
return FileError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.type != PathType::Binary || path.binary.size() != 12) {
|
||||||
|
printf("Invalid SelfNCCH path type\n");
|
||||||
|
return FileError;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where to read the file from. (https://www.3dbrew.org/wiki/Filesystem_services#SelfNCCH_File_Path_Data_Format)
|
||||||
|
// We currently only know how to read from an NCCH's RomFS, ie type = 0
|
||||||
|
const u32 type = *(u32*)&path.binary[0]; // TODO: Get rid of UB here
|
||||||
|
if (type != PathType::RomFS && type != PathType::ExeFS) {
|
||||||
|
Helpers::panic("Read from NCCH's non-RomFS & non-exeFS section!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoFile; // No file descriptor needed for RomFS
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveBase* SelfNCCHArchive::openArchive(const FSPath& path) {
|
||||||
|
if (path.type != PathType::Empty) {
|
||||||
|
printf("Invalid path type for SelfNCCH archive: %d\n", path.type);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<u32> SelfNCCHArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) {
|
||||||
|
const FSPath& path = file->path; // Path of the file
|
||||||
|
const u32 type = *(u32*)&path.binary[0]; // Type of the path
|
||||||
|
|
||||||
|
if (type == PathType::RomFS && !hasRomFS()) {
|
||||||
|
Helpers::panic("Tried to read file from non-existent RomFS");
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == PathType::ExeFS && !hasExeFS()) {
|
||||||
|
Helpers::panic("Tried to read file from non-existent RomFS");
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file->isOpen) {
|
||||||
|
printf("Tried to read from closed SelfNCCH file session");
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cxi = mem.getCXI();
|
||||||
|
IOFile& ioFile = mem.CXIFile;
|
||||||
|
|
||||||
|
// Seek to file offset depending on if we're reading from RomFS, ExeFS, etc
|
||||||
|
switch (type) {
|
||||||
|
case PathType::RomFS: {
|
||||||
|
const u32 romFSSize = cxi->romFS.size;
|
||||||
|
const u32 romFSOffset = cxi->romFS.offset;
|
||||||
|
if ((offset >> 32) || (offset >= romFSSize) || (offset + size >= romFSSize)) {
|
||||||
|
Helpers::panic("Tried to read from SelfNCCH with too big of an offset");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ioFile.seek(cxi->fileOffset + romFSOffset + offset + 0x1000)) {
|
||||||
|
Helpers::panic("Failed to seek while reading from RomFS");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PathType::ExeFS: {
|
||||||
|
const u32 exeFSSize = cxi->exeFS.size;
|
||||||
|
const u32 exeFSOffset = cxi->exeFS.offset;
|
||||||
|
if ((offset >> 32) || (offset >= exeFSSize) || (offset + size >= exeFSSize)) {
|
||||||
|
Helpers::panic("Tried to read from SelfNCCH with too big of an offset");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ioFile.seek(cxi->fileOffset + exeFSOffset + offset)) { // TODO: Not sure if this needs the + 0x1000
|
||||||
|
Helpers::panic("Failed to seek while reading from ExeFS");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<u8[]> data(new u8[size]);
|
||||||
|
auto [success, bytesRead] = ioFile.readBytes(&data[0], size);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
Helpers::panic("Failed to read from NCCH archive");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u64 i = 0; i < bytesRead; i++) {
|
||||||
|
mem.write8(dataPointer + i, data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesRead;
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ void Kernel::serviceSVC(u32 svc) {
|
||||||
case 0x01: controlMemory(); break;
|
case 0x01: controlMemory(); break;
|
||||||
case 0x02: queryMemory(); break;
|
case 0x02: queryMemory(); break;
|
||||||
case 0x08: createThread(); break;
|
case 0x08: createThread(); break;
|
||||||
|
case 0x09: exitThread(); break;
|
||||||
case 0x0A: svcSleepThread(); break;
|
case 0x0A: svcSleepThread(); break;
|
||||||
case 0x0B: getThreadPriority(); break;
|
case 0x0B: getThreadPriority(); break;
|
||||||
case 0x0C: setThreadPriority(); break;
|
case 0x0C: setThreadPriority(); break;
|
||||||
|
@ -104,6 +105,7 @@ void Kernel::reset() {
|
||||||
handleCounter = 0;
|
handleCounter = 0;
|
||||||
arbiterCount = 0;
|
arbiterCount = 0;
|
||||||
threadCount = 0;
|
threadCount = 0;
|
||||||
|
aliveThreadCount = 0;
|
||||||
|
|
||||||
for (auto& t : threads) {
|
for (auto& t : threads) {
|
||||||
t.status = ThreadStatus::Dead;
|
t.status = ThreadStatus::Dead;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
#include "arm_defs.hpp"
|
#include "arm_defs.hpp"
|
||||||
|
@ -81,7 +82,14 @@ void Kernel::switchToNextThread() {
|
||||||
|
|
||||||
if (!newThreadIndex.has_value()) {
|
if (!newThreadIndex.has_value()) {
|
||||||
log("Kernel tried to switch to the next thread but none found. Switching to random thread\n");
|
log("Kernel tried to switch to the next thread but none found. Switching to random thread\n");
|
||||||
switchThread(rand() % threadCount);
|
assert(aliveThreadCount != 0);
|
||||||
|
|
||||||
|
int index;
|
||||||
|
do {
|
||||||
|
index = rand() % threadCount;
|
||||||
|
} while (threads[index].status == ThreadStatus::Dead); // TODO: Pray this doesn't hang
|
||||||
|
|
||||||
|
switchThread(index);
|
||||||
} else {
|
} else {
|
||||||
switchThread(newThreadIndex.value());
|
switchThread(newThreadIndex.value());
|
||||||
}
|
}
|
||||||
|
@ -99,12 +107,25 @@ void Kernel::rescheduleThreads() {
|
||||||
|
|
||||||
// Internal OS function to spawn a thread
|
// Internal OS function to spawn a thread
|
||||||
Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, s32 id, u32 arg, ThreadStatus status) {
|
Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, s32 id, u32 arg, ThreadStatus status) {
|
||||||
if (threadCount >= appResourceLimits.maxThreads) {
|
int index; // Index of the created thread in the threads array
|
||||||
Helpers::panic("Overflowed the number of threads");
|
|
||||||
}
|
|
||||||
threadIndices.push_back(threadCount);
|
|
||||||
|
|
||||||
Thread& t = threads[threadCount++]; // Reference to thread data
|
if (threadCount < appResourceLimits.maxThreads) [[likely]] { // If we have not yet created over too many threads
|
||||||
|
index = threadCount++;
|
||||||
|
} else if (aliveThreadCount < appResourceLimits.maxThreads) { // If we have created many threads but at least one is dead & reusable
|
||||||
|
for (int i = 0; i < threads.size(); i++) {
|
||||||
|
if (threads[i].status == ThreadStatus::Dead) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // There is no thread we can use, we're screwed
|
||||||
|
Helpers::panic("Overflowed thread count!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
aliveThreadCount++;
|
||||||
|
|
||||||
|
threadIndices.push_back(index);
|
||||||
|
Thread& t = threads[index]; // Reference to thread data
|
||||||
Handle ret = makeObject(KernelObjectType::Thread);
|
Handle ret = makeObject(KernelObjectType::Thread);
|
||||||
objects[ret].data = &t;
|
objects[ret].data = &t;
|
||||||
|
|
||||||
|
@ -233,7 +254,7 @@ void Kernel::getThreadID() {
|
||||||
|
|
||||||
void Kernel::getThreadPriority() {
|
void Kernel::getThreadPriority() {
|
||||||
const Handle handle = regs[1];
|
const Handle handle = regs[1];
|
||||||
log("GetThreadPriority (handle = %X)\n", handle);
|
logSVC("GetThreadPriority (handle = %X)\n", handle);
|
||||||
|
|
||||||
if (handle == KernelHandles::CurrentThread) {
|
if (handle == KernelHandles::CurrentThread) {
|
||||||
regs[0] = SVCResult::Success;
|
regs[0] = SVCResult::Success;
|
||||||
|
@ -252,7 +273,7 @@ void Kernel::getThreadPriority() {
|
||||||
void Kernel::setThreadPriority() {
|
void Kernel::setThreadPriority() {
|
||||||
const Handle handle = regs[0];
|
const Handle handle = regs[0];
|
||||||
const u32 priority = regs[1];
|
const u32 priority = regs[1];
|
||||||
log("SetThreadPriority (handle = %X, priority = %X)\n", handle, priority);
|
logSVC("SetThreadPriority (handle = %X, priority = %X)\n", handle, priority);
|
||||||
|
|
||||||
if (priority > 0x3F) {
|
if (priority > 0x3F) {
|
||||||
regs[0] = SVCResult::BadThreadPriority;
|
regs[0] = SVCResult::BadThreadPriority;
|
||||||
|
@ -276,6 +297,22 @@ void Kernel::setThreadPriority() {
|
||||||
rescheduleThreads();
|
rescheduleThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Kernel::exitThread() {
|
||||||
|
logSVC("ExitThread\n");
|
||||||
|
|
||||||
|
// Remove the index of this thread from the thread indices vector
|
||||||
|
for (int i = 0; i < threadIndices.size(); i++) {
|
||||||
|
if (threadIndices[i] == currentThreadIndex)
|
||||||
|
threadIndices.erase(threadIndices.begin() + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread& t = threads[currentThreadIndex];
|
||||||
|
t.status = ThreadStatus::Dead;
|
||||||
|
aliveThreadCount--;
|
||||||
|
|
||||||
|
switchToNextThread();
|
||||||
|
}
|
||||||
|
|
||||||
void Kernel::createMutex() {
|
void Kernel::createMutex() {
|
||||||
bool locked = regs[1] != 0;
|
bool locked = regs[1] != 0;
|
||||||
logSVC("CreateMutex (locked = %s)\n", locked ? "yes" : "no");
|
logSVC("CreateMutex (locked = %s)\n", locked ? "yes" : "no");
|
||||||
|
|
|
@ -49,6 +49,7 @@ ArchiveBase* FSService::getArchiveFromID(u32 id) {
|
||||||
case ArchiveID::SaveData: return &saveData;
|
case ArchiveID::SaveData: return &saveData;
|
||||||
case ArchiveID::SharedExtSaveData: return &sharedExtSaveData;
|
case ArchiveID::SharedExtSaveData: return &sharedExtSaveData;
|
||||||
case ArchiveID::SDMC: return &sdmc;
|
case ArchiveID::SDMC: return &sdmc;
|
||||||
|
case ArchiveID::SavedataAndNcch: return &ncch; // This can only access NCCH outside of FSPXI
|
||||||
default:
|
default:
|
||||||
Helpers::panic("Unknown archive. ID: %d\n", id);
|
Helpers::panic("Unknown archive. ID: %d\n", id);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
Loading…
Add table
Reference in a new issue