core/core: Move process execution start to System's Load()

This gives us significantly more control over where in the
initialization process we start execution of the main process.

Previously we were running the main process before the CPU or GPU
threads were initialized (not good). This amends execution to start
after all of our threads are properly set up.
master
Lioncash 2019-04-09 17:03:04 +07:00
parent 32a6ceb4e5
commit 612e1388df
20 changed files with 144 additions and 107 deletions

@ -168,7 +168,7 @@ struct System::Impl {
}
auto main_process = Kernel::Process::Create(system, "main");
const Loader::ResultStatus load_result{app_loader->Load(*main_process)};
const auto [load_result, load_parameters] = app_loader->Load(*main_process);
if (load_result != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
Shutdown();
@ -183,6 +183,10 @@ struct System::Impl {
gpu_core->Start();
cpu_core_manager.StartThreads();
// All threads are started, begin main process execution, now that we're in the clear.
main_process->Run(load_parameters->main_thread_priority,
load_parameters->main_thread_stack_size);
status = ResultStatus::Success;
return status;
}

@ -28,12 +28,12 @@ namespace {
*
* @param owner_process The parent process for the main thread
* @param kernel The kernel instance to create the main thread under.
* @param entry_point The address at which the thread should start execution
* @param priority The priority to give the main thread
*/
void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_point, u32 priority) {
// Initialize new "main" thread
const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress();
void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) {
const auto& vm_manager = owner_process.VMManager();
const VAddr entry_point = vm_manager.GetCodeRegionBaseAddress();
const VAddr stack_top = vm_manager.GetTLSIORegionEndAddress();
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0,
owner_process.GetIdealCore(), stack_top, owner_process);
@ -117,7 +117,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
return handle_table.SetSize(capabilities.GetHandleTableSize());
}
void Process::Run(VAddr entry_point, s32 main_thread_priority, u64 stack_size) {
void Process::Run(s32 main_thread_priority, u64 stack_size) {
// The kernel always ensures that the given stack size is page aligned.
main_thread_stack_size = Common::AlignUp(stack_size, Memory::PAGE_SIZE);
@ -133,7 +133,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u64 stack_size) {
vm_manager.LogLayout();
ChangeStatus(ProcessStatus::Running);
SetupMainThread(*this, kernel, entry_point, main_thread_priority);
SetupMainThread(*this, kernel, main_thread_priority);
}
void Process::PrepareForTermination() {

@ -225,9 +225,12 @@ public:
ResultCode LoadFromMetadata(const FileSys::ProgramMetadata& metadata);
/**
* Applies address space changes and launches the process main thread.
* Starts the main application thread for this process.
*
* @param main_thread_priority The priority for the main thread.
* @param stack_size The stack size for the main thread in bytes.
*/
void Run(VAddr entry_point, s32 main_thread_priority, u64 stack_size);
void Run(s32 main_thread_priority, u64 stack_size);
/**
* Prepares a process for termination by stopping all of its threads

@ -86,25 +86,29 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::Virtua
return FileType::Error;
}
ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) {
AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirectory::Load(
Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
if (dir == nullptr) {
if (file == nullptr)
return ResultStatus::ErrorNullFile;
if (file == nullptr) {
return {ResultStatus::ErrorNullFile, {}};
}
dir = file->GetContainingDirectory();
}
// Read meta to determine title ID
FileSys::VirtualFile npdm = dir->GetFile("main.npdm");
if (npdm == nullptr)
return ResultStatus::ErrorMissingNPDM;
if (npdm == nullptr) {
return {ResultStatus::ErrorMissingNPDM, {}};
}
ResultStatus result = metadata.Load(npdm);
const ResultStatus result = metadata.Load(npdm);
if (result != ResultStatus::Success) {
return result;
return {result, {}};
}
if (override_update) {
@ -114,23 +118,24 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
// Reread in case PatchExeFS affected the main.npdm
npdm = dir->GetFile("main.npdm");
if (npdm == nullptr)
return ResultStatus::ErrorMissingNPDM;
if (npdm == nullptr) {
return {ResultStatus::ErrorMissingNPDM, {}};
}
ResultStatus result2 = metadata.Load(npdm);
const ResultStatus result2 = metadata.Load(npdm);
if (result2 != ResultStatus::Success) {
return result2;
return {result2, {}};
}
metadata.Print();
const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit ||
arch_bits == FileSys::ProgramAddressSpaceType::Is32BitNoMap) {
return ResultStatus::Error32BitISA;
return {ResultStatus::Error32BitISA, {}};
}
if (process.LoadFromMetadata(metadata).IsError()) {
return ResultStatus::ErrorUnableToParseKernelMetadata;
return {ResultStatus::ErrorUnableToParseKernelMetadata, {}};
}
const FileSys::PatchManager pm(metadata.GetTitleID());
@ -150,7 +155,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
const auto tentative_next_load_addr =
AppLoader_NSO::LoadModule(process, *module_file, load_addr, should_pass_arguments, pm);
if (!tentative_next_load_addr) {
return ResultStatus::ErrorLoadingNSO;
return {ResultStatus::ErrorLoadingNSO, {}};
}
next_load_addr = *tentative_next_load_addr;
@ -159,8 +164,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
}
process.Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize());
// Find the RomFS by searching for a ".romfs" file in this directory
const auto& files = dir->GetFiles();
const auto romfs_iter =
@ -175,7 +178,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
}
is_loaded = true;
return ResultStatus::Success;
return {ResultStatus::Success,
LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}};
}
ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) {

@ -37,7 +37,7 @@ public:
return IdentifyType(file);
}
ResultStatus Load(Kernel::Process& process) override;
LoadResult Load(Kernel::Process& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;

@ -382,13 +382,15 @@ FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
ResultStatus AppLoader_ELF::Load(Kernel::Process& process) {
if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded;
AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
std::vector<u8> buffer = file->ReadAllBytes();
if (buffer.size() != file->GetSize())
return ResultStatus::ErrorIncorrectELFFileSize;
if (buffer.size() != file->GetSize()) {
return {ResultStatus::ErrorIncorrectELFFileSize, {}};
}
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
ElfReader elf_reader(&buffer[0]);
@ -396,10 +398,9 @@ ResultStatus AppLoader_ELF::Load(Kernel::Process& process) {
const VAddr entry_point = codeset.entrypoint;
process.LoadModule(std::move(codeset), entry_point);
process.Run(entry_point, 48, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
return {ResultStatus::Success, LoadParameters{48, Memory::DEFAULT_STACK_SIZE}};
}
} // namespace Loader

@ -26,7 +26,7 @@ public:
return IdentifyType(file);
}
ResultStatus Load(Kernel::Process& process) override;
LoadResult Load(Kernel::Process& process) override;
};
} // namespace Loader

@ -131,6 +131,12 @@ std::ostream& operator<<(std::ostream& os, ResultStatus status);
/// Interface for loading an application
class AppLoader : NonCopyable {
public:
struct LoadParameters {
s32 main_thread_priority;
u64 main_thread_stack_size;
};
using LoadResult = std::pair<ResultStatus, std::optional<LoadParameters>>;
explicit AppLoader(FileSys::VirtualFile file);
virtual ~AppLoader();
@ -145,7 +151,7 @@ public:
* @param process The newly created process.
* @return The status result of the operation.
*/
virtual ResultStatus Load(Kernel::Process& process) = 0;
virtual LoadResult Load(Kernel::Process& process) = 0;
/**
* Loads the system mode that this application needs.

@ -41,31 +41,37 @@ FileType AppLoader_NAX::GetFileType() const {
return IdentifyTypeImpl(*nax);
}
ResultStatus AppLoader_NAX::Load(Kernel::Process& process) {
AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
if (nax->GetStatus() != ResultStatus::Success)
return nax->GetStatus();
const auto nax_status = nax->GetStatus();
if (nax_status != ResultStatus::Success) {
return {nax_status, {}};
}
const auto nca = nax->AsNCA();
if (nca == nullptr) {
if (!Core::Crypto::KeyManager::KeyFileExists(false))
return ResultStatus::ErrorMissingProductionKeyFile;
return ResultStatus::ErrorNAXInconvertibleToNCA;
if (!Core::Crypto::KeyManager::KeyFileExists(false)) {
return {ResultStatus::ErrorMissingProductionKeyFile, {}};
}
return {ResultStatus::ErrorNAXInconvertibleToNCA, {}};
}
if (nca->GetStatus() != ResultStatus::Success)
return nca->GetStatus();
const auto nca_status = nca->GetStatus();
if (nca_status != ResultStatus::Success) {
return {nca_status, {}};
}
const auto result = nca_loader->Load(process);
if (result != ResultStatus::Success)
if (result.first != ResultStatus::Success) {
return result;
}
is_loaded = true;
return ResultStatus::Success;
return result;
}
ResultStatus AppLoader_NAX::ReadRomFS(FileSys::VirtualFile& dir) {

@ -33,7 +33,7 @@ public:
FileType GetFileType() const override;
ResultStatus Load(Kernel::Process& process) override;
LoadResult Load(Kernel::Process& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
u64 ReadRomFSIVFCOffset() const override;

@ -30,36 +30,38 @@ FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
ResultStatus AppLoader_NCA::Load(Kernel::Process& process) {
AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
const auto result = nca->GetStatus();
if (result != ResultStatus::Success) {
return result;
return {result, {}};
}
if (nca->GetType() != FileSys::NCAContentType::Program)
return ResultStatus::ErrorNCANotProgram;
if (nca->GetType() != FileSys::NCAContentType::Program) {
return {ResultStatus::ErrorNCANotProgram, {}};
}
const auto exefs = nca->GetExeFS();
if (exefs == nullptr)
return ResultStatus::ErrorNoExeFS;
if (exefs == nullptr) {
return {ResultStatus::ErrorNoExeFS, {}};
}
directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs, true);
const auto load_result = directory_loader->Load(process);
if (load_result != ResultStatus::Success)
if (load_result.first != ResultStatus::Success) {
return load_result;
}
if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0)
if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0) {
Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
}
is_loaded = true;
return ResultStatus::Success;
return load_result;
}
ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {

@ -33,7 +33,7 @@ public:
return IdentifyType(file);
}
ResultStatus Load(Kernel::Process& process) override;
LoadResult Load(Kernel::Process& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
u64 ReadRomFSIVFCOffset() const override;

@ -201,25 +201,25 @@ bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& fi
return LoadNroImpl(process, file.ReadAllBytes(), file.GetName(), load_base);
}
ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
// Load NRO
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
if (!LoadNro(process, *file, base_address)) {
return ResultStatus::ErrorLoadingNRO;
return {ResultStatus::ErrorLoadingNRO, {}};
}
if (romfs != nullptr)
if (romfs != nullptr) {
Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
}
is_loaded = true;
return ResultStatus::Success;
return {ResultStatus::Success,
LoadParameters{Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE}};
}
ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {

@ -37,7 +37,7 @@ public:
return IdentifyType(file);
}
ResultStatus Load(Kernel::Process& process) override;
LoadResult Load(Kernel::Process& process) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadProgramId(u64& out_program_id) override;

@ -169,22 +169,21 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
return load_base + image_size;
}
ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
// Load module
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
if (!LoadModule(process, *file, base_address, true)) {
return ResultStatus::ErrorLoadingNSO;
return {ResultStatus::ErrorLoadingNSO, {}};
}
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
return {ResultStatus::Success,
LoadParameters{Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE}};
}
} // namespace Loader

@ -84,7 +84,7 @@ public:
VAddr load_base, bool should_pass_arguments,
std::optional<FileSys::PatchManager> pm = {});
ResultStatus Load(Kernel::Process& process) override;
LoadResult Load(Kernel::Process& process) override;
};
} // namespace Loader

@ -72,37 +72,45 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
ResultStatus AppLoader_NSP::Load(Kernel::Process& process) {
AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
if (title_id == 0)
return ResultStatus::ErrorNSPMissingProgramNCA;
if (title_id == 0) {
return {ResultStatus::ErrorNSPMissingProgramNCA, {}};
}
if (nsp->GetStatus() != ResultStatus::Success)
return nsp->GetStatus();
const auto nsp_status = nsp->GetStatus();
if (nsp_status != ResultStatus::Success) {
return {nsp_status, {}};
}
if (nsp->GetProgramStatus(title_id) != ResultStatus::Success)
return nsp->GetProgramStatus(title_id);
const auto nsp_program_status = nsp->GetProgramStatus(title_id);
if (nsp_program_status != ResultStatus::Success) {
return {nsp_program_status, {}};
}
if (nsp->GetNCA(title_id, FileSys::ContentRecordType::Program) == nullptr) {
if (!Core::Crypto::KeyManager::KeyFileExists(false))
return ResultStatus::ErrorMissingProductionKeyFile;
return ResultStatus::ErrorNSPMissingProgramNCA;
if (!Core::Crypto::KeyManager::KeyFileExists(false)) {
return {ResultStatus::ErrorMissingProductionKeyFile, {}};
}
return {ResultStatus::ErrorNSPMissingProgramNCA, {}};
}
const auto result = secondary_loader->Load(process);
if (result != ResultStatus::Success)
if (result.first != ResultStatus::Success) {
return result;
}
FileSys::VirtualFile update_raw;
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr)
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
Service::FileSystem::SetPackedUpdate(std::move(update_raw));
}
is_loaded = true;
return ResultStatus::Success;
return result;
}
ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& file) {

@ -35,7 +35,7 @@ public:
return IdentifyType(file);
}
ResultStatus Load(Kernel::Process& process) override;
LoadResult Load(Kernel::Process& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
u64 ReadRomFSIVFCOffset() const override;

@ -48,31 +48,35 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
ResultStatus AppLoader_XCI::Load(Kernel::Process& process) {
AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process) {
if (is_loaded) {
return ResultStatus::ErrorAlreadyLoaded;
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
if (xci->GetStatus() != ResultStatus::Success)
return xci->GetStatus();
if (xci->GetStatus() != ResultStatus::Success) {
return {xci->GetStatus(), {}};
}
if (xci->GetProgramNCAStatus() != ResultStatus::Success)
return xci->GetProgramNCAStatus();
if (xci->GetProgramNCAStatus() != ResultStatus::Success) {
return {xci->GetProgramNCAStatus(), {}};
}
if (!xci->HasProgramNCA() && !Core::Crypto::KeyManager::KeyFileExists(false))
return ResultStatus::ErrorMissingProductionKeyFile;
if (!xci->HasProgramNCA() && !Core::Crypto::KeyManager::KeyFileExists(false)) {
return {ResultStatus::ErrorMissingProductionKeyFile, {}};
}
const auto result = nca_loader->Load(process);
if (result != ResultStatus::Success)
if (result.first != ResultStatus::Success) {
return result;
}
FileSys::VirtualFile update_raw;
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr)
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
Service::FileSystem::SetPackedUpdate(std::move(update_raw));
}
is_loaded = true;
return ResultStatus::Success;
return result;
}
ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& file) {

@ -35,7 +35,7 @@ public:
return IdentifyType(file);
}
ResultStatus Load(Kernel::Process& process) override;
LoadResult Load(Kernel::Process& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
u64 ReadRomFSIVFCOffset() const override;