2018-02-25 02:34:19 -08:00
|
|
|
// Copyright 2018 yuzu emulator team
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
#include "common/bit_field.h"
|
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "common/swap.h"
|
2018-09-03 18:58:19 -07:00
|
|
|
#include "core/file_sys/vfs.h"
|
2018-02-25 02:34:19 -08:00
|
|
|
|
|
|
|
namespace Loader {
|
2018-08-11 21:56:22 -07:00
|
|
|
enum class ResultStatus : u16;
|
2018-02-25 02:34:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace FileSys {
|
|
|
|
|
|
|
|
enum class ProgramAddressSpaceType : u8 {
|
2018-09-22 17:09:32 -07:00
|
|
|
Is32Bit = 0,
|
|
|
|
Is36Bit = 1,
|
|
|
|
Is32BitNoMap = 2,
|
|
|
|
Is39Bit = 3,
|
2018-02-25 02:34:19 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
enum class ProgramFilePermission : u64 {
|
|
|
|
MountContent = 1ULL << 0,
|
|
|
|
SaveDataBackup = 1ULL << 5,
|
|
|
|
SdCard = 1ULL << 21,
|
|
|
|
Calibration = 1ULL << 34,
|
|
|
|
Bit62 = 1ULL << 62,
|
|
|
|
Everything = 1ULL << 63,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper which implements an interface to parse Program Description Metadata (NPDM)
|
|
|
|
* Data can either be loaded from a file path or with data and an offset into it.
|
|
|
|
*/
|
|
|
|
class ProgramMetadata {
|
|
|
|
public:
|
2018-09-19 16:19:05 -07:00
|
|
|
ProgramMetadata();
|
|
|
|
~ProgramMetadata();
|
|
|
|
|
2018-07-18 18:07:11 -07:00
|
|
|
Loader::ResultStatus Load(VirtualFile file);
|
2018-02-25 02:34:19 -08:00
|
|
|
|
|
|
|
bool Is64BitProgram() const;
|
|
|
|
ProgramAddressSpaceType GetAddressSpaceType() const;
|
|
|
|
u8 GetMainThreadPriority() const;
|
|
|
|
u8 GetMainThreadCore() const;
|
|
|
|
u32 GetMainThreadStackSize() const;
|
|
|
|
u64 GetTitleID() const;
|
|
|
|
u64 GetFilesystemPermissions() const;
|
|
|
|
|
|
|
|
void Print() const;
|
|
|
|
|
|
|
|
private:
|
2018-07-18 18:07:11 -07:00
|
|
|
// TODO(DarkLordZach): BitField is not trivially copyable.
|
2018-02-25 02:34:19 -08:00
|
|
|
struct Header {
|
|
|
|
std::array<char, 4> magic;
|
|
|
|
std::array<u8, 8> reserved;
|
|
|
|
union {
|
|
|
|
u8 flags;
|
|
|
|
|
|
|
|
BitField<0, 1, u8> has_64_bit_instructions;
|
|
|
|
BitField<1, 3, ProgramAddressSpaceType> address_space_type;
|
|
|
|
BitField<4, 4, u8> reserved_2;
|
|
|
|
};
|
|
|
|
u8 reserved_3;
|
|
|
|
u8 main_thread_priority;
|
|
|
|
u8 main_thread_cpu;
|
|
|
|
std::array<u8, 8> reserved_4;
|
|
|
|
u32_le process_category;
|
|
|
|
u32_le main_stack_size;
|
|
|
|
std::array<u8, 0x10> application_name;
|
|
|
|
std::array<u8, 0x40> reserved_5;
|
|
|
|
u32_le aci_offset;
|
|
|
|
u32_le aci_size;
|
|
|
|
u32_le acid_offset;
|
|
|
|
u32_le acid_size;
|
|
|
|
};
|
|
|
|
|
|
|
|
static_assert(sizeof(Header) == 0x80, "NPDM header structure size is wrong");
|
|
|
|
|
2018-07-18 18:07:11 -07:00
|
|
|
// TODO(DarkLordZach): BitField is not trivially copyable.
|
2018-02-25 02:34:19 -08:00
|
|
|
struct AcidHeader {
|
|
|
|
std::array<u8, 0x100> signature;
|
|
|
|
std::array<u8, 0x100> nca_modulus;
|
|
|
|
std::array<char, 4> magic;
|
|
|
|
u32_le nca_size;
|
|
|
|
std::array<u8, 0x4> reserved;
|
|
|
|
union {
|
|
|
|
u32 flags;
|
|
|
|
|
|
|
|
BitField<0, 1, u32> is_retail;
|
|
|
|
BitField<1, 31, u32> flags_unk;
|
|
|
|
};
|
|
|
|
u64_le title_id_min;
|
|
|
|
u64_le title_id_max;
|
|
|
|
u32_le fac_offset;
|
|
|
|
u32_le fac_size;
|
|
|
|
u32_le sac_offset;
|
|
|
|
u32_le sac_size;
|
|
|
|
u32_le kac_offset;
|
|
|
|
u32_le kac_size;
|
2018-02-25 15:18:55 -08:00
|
|
|
INSERT_PADDING_BYTES(0x8);
|
2018-02-25 02:34:19 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
static_assert(sizeof(AcidHeader) == 0x240, "ACID header structure size is wrong");
|
|
|
|
|
|
|
|
struct AciHeader {
|
|
|
|
std::array<char, 4> magic;
|
|
|
|
std::array<u8, 0xC> reserved;
|
|
|
|
u64_le title_id;
|
2018-02-25 15:18:55 -08:00
|
|
|
INSERT_PADDING_BYTES(0x8);
|
2018-02-25 02:34:19 -08:00
|
|
|
u32_le fah_offset;
|
|
|
|
u32_le fah_size;
|
|
|
|
u32_le sac_offset;
|
|
|
|
u32_le sac_size;
|
|
|
|
u32_le kac_offset;
|
|
|
|
u32_le kac_size;
|
2018-02-25 15:18:55 -08:00
|
|
|
INSERT_PADDING_BYTES(0x8);
|
2018-02-25 02:34:19 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
static_assert(sizeof(AciHeader) == 0x40, "ACI0 header structure size is wrong");
|
|
|
|
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
|
|
|
|
struct FileAccessControl {
|
|
|
|
u8 version;
|
2018-02-25 15:18:55 -08:00
|
|
|
INSERT_PADDING_BYTES(3);
|
2018-02-25 02:34:19 -08:00
|
|
|
u64_le permissions;
|
|
|
|
std::array<u8, 0x20> unknown;
|
|
|
|
};
|
|
|
|
|
|
|
|
static_assert(sizeof(FileAccessControl) == 0x2C, "FS access control structure size is wrong");
|
|
|
|
|
|
|
|
struct FileAccessHeader {
|
|
|
|
u8 version;
|
2018-02-25 15:18:55 -08:00
|
|
|
INSERT_PADDING_BYTES(3);
|
2018-02-25 02:34:19 -08:00
|
|
|
u64_le permissions;
|
|
|
|
u32_le unk_offset;
|
|
|
|
u32_le unk_size;
|
|
|
|
u32_le unk_offset_2;
|
|
|
|
u32_le unk_size_2;
|
|
|
|
};
|
|
|
|
|
|
|
|
static_assert(sizeof(FileAccessHeader) == 0x1C, "FS access header structure size is wrong");
|
|
|
|
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
Header npdm_header;
|
|
|
|
AciHeader aci_header;
|
|
|
|
AcidHeader acid_header;
|
|
|
|
|
|
|
|
FileAccessControl acid_file_access;
|
|
|
|
FileAccessHeader aci_file_access;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace FileSys
|