mirror of
https://github.com/jakcron/nstool
synced 2024-12-25 06:01:12 +00:00
[nx] Add NpdmHeader.
This commit is contained in:
parent
7b0dbc753f
commit
60e1b8a328
4 changed files with 481 additions and 0 deletions
278
lib/nx/NpdmHeader.cpp
Normal file
278
lib/nx/NpdmHeader.cpp
Normal file
|
@ -0,0 +1,278 @@
|
|||
#include "NpdmHeader.h"
|
||||
|
||||
|
||||
|
||||
nx::NpdmHeader::NpdmHeader()
|
||||
{
|
||||
clearVariables();
|
||||
}
|
||||
|
||||
nx::NpdmHeader::NpdmHeader(const NpdmHeader & other)
|
||||
{
|
||||
copyFrom(other);
|
||||
}
|
||||
|
||||
nx::NpdmHeader::NpdmHeader(const u8 * bytes)
|
||||
{
|
||||
importBinary(bytes);
|
||||
}
|
||||
|
||||
bool nx::NpdmHeader::operator==(const NpdmHeader & other) const
|
||||
{
|
||||
return isEqual(other);
|
||||
}
|
||||
|
||||
bool nx::NpdmHeader::operator!=(const NpdmHeader & other) const
|
||||
{
|
||||
return isEqual(other);
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::operator=(const NpdmHeader & other)
|
||||
{
|
||||
copyFrom(other);
|
||||
}
|
||||
|
||||
const u8 * nx::NpdmHeader::getBytes() const
|
||||
{
|
||||
return mBinaryBlob.getBytes();
|
||||
}
|
||||
|
||||
size_t nx::NpdmHeader::getSize() const
|
||||
{
|
||||
return mBinaryBlob.getSize();
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::clearVariables()
|
||||
{
|
||||
mBinaryBlob.clear();
|
||||
mInstructionType = INSTR_64BIT;
|
||||
mProcAddressSpaceType = ADDR_SPACE_64BIT;
|
||||
mMainThreadPriority = 0;
|
||||
mMainThreadCoreNumber = 0;
|
||||
mVersion = 0;
|
||||
mMainThreadStackSize = 0;
|
||||
mName.clear();
|
||||
mProductCode.clear();
|
||||
mAciPos.offset = 0;
|
||||
mAciPos.size = 0;
|
||||
mAcidPos.offset = 0;
|
||||
mAcidPos.size = 0;
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::calculateOffsets()
|
||||
{
|
||||
mAcidPos.offset = align(sizeof(sNpdmHeader), kNpdmAlignSize);
|
||||
mAciPos.offset = mAcidPos.offset + align(mAcidPos.size, kNpdmAlignSize);
|
||||
}
|
||||
|
||||
bool nx::NpdmHeader::isEqual(const NpdmHeader & other) const
|
||||
{
|
||||
return (mInstructionType == other.mInstructionType) \
|
||||
&& (mProcAddressSpaceType == other.mProcAddressSpaceType) \
|
||||
&& (mMainThreadPriority == other.mMainThreadPriority) \
|
||||
&& (mMainThreadCoreNumber == other.mMainThreadCoreNumber) \
|
||||
&& (mVersion == other.mVersion) \
|
||||
&& (mMainThreadStackSize == other.mMainThreadStackSize) \
|
||||
&& (mName == other.mName) \
|
||||
&& (mProductCode == other.mProductCode) \
|
||||
&& (mAciPos == other.mAciPos) \
|
||||
&& (mAcidPos == other.mAcidPos);
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::copyFrom(const NpdmHeader & other)
|
||||
{
|
||||
if (other.getSize())
|
||||
{
|
||||
importBinary(other.getBytes(), other.getSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
mInstructionType = other.mInstructionType;
|
||||
mProcAddressSpaceType = other.mProcAddressSpaceType;
|
||||
mMainThreadPriority = other.mMainThreadPriority;
|
||||
mMainThreadCoreNumber = other.mMainThreadCoreNumber;
|
||||
mVersion = other.mVersion;
|
||||
mMainThreadStackSize = other.mMainThreadStackSize;
|
||||
mName = other.mName;
|
||||
mProductCode = other.mProductCode;
|
||||
mAciPos = other.mAciPos;
|
||||
mAcidPos = other.mAcidPos;
|
||||
}
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::exportBinary()
|
||||
{
|
||||
mBinaryBlob.alloc(sizeof(sNpdmHeader));
|
||||
sNpdmHeader* hdr = (sNpdmHeader*)mBinaryBlob.getBytes();
|
||||
|
||||
hdr->set_signature(kNpdmStructSig.c_str());
|
||||
u8 flag = ((u8)(mInstructionType & 1) | (u8)((mProcAddressSpaceType & 3) << 1)) & 0xf;
|
||||
hdr->set_flags(flag);
|
||||
hdr->set_main_thread_priority(mMainThreadPriority);
|
||||
hdr->set_main_thread_core_number(mMainThreadCoreNumber);
|
||||
hdr->set_version(mVersion);
|
||||
hdr->set_main_thread_stack_size(mMainThreadStackSize);
|
||||
hdr->set_name(mName.c_str());
|
||||
hdr->set_product_code(mProductCode.c_str());
|
||||
|
||||
calculateOffsets();
|
||||
hdr->aci().set_offset(mAciPos.offset);
|
||||
hdr->aci().set_size(mAciPos.size);
|
||||
hdr->acid().set_offset(mAcidPos.offset);
|
||||
hdr->acid().set_size(mAcidPos.size);
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::importBinary(const u8 * bytes)
|
||||
{
|
||||
mBinaryBlob.alloc(sizeof(sNpdmHeader));
|
||||
memcpy(mBinaryBlob.getBytes(), bytes, mBinaryBlob.getSize());
|
||||
sNpdmHeader* hdr = (sNpdmHeader*)mBinaryBlob.getBytes();
|
||||
|
||||
if (memcmp(kNpdmStructSig.c_str(), hdr->signature(), 4) != 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "NPDM header corrupt");
|
||||
}
|
||||
|
||||
u8 flag = hdr->flags() & 0xf;
|
||||
mInstructionType = (InstructionType)(flag & 1);
|
||||
mProcAddressSpaceType = (ProcAddrSpaceType)((flag >> 1) & 3);
|
||||
mMainThreadPriority = hdr->main_thread_priority();
|
||||
mMainThreadCoreNumber = hdr->main_thread_core_number();
|
||||
mVersion = hdr->version();
|
||||
mMainThreadStackSize = hdr->main_thread_stack_size();
|
||||
mName = std::string(hdr->name(), kNameMaxLen);
|
||||
mProductCode = std::string(hdr->product_code(), kProductCodeMaxLen);
|
||||
mAciPos.offset = hdr->aci().offset();
|
||||
mAciPos.size = hdr->aci().size();
|
||||
mAcidPos.offset = hdr->acid().offset();
|
||||
mAcidPos.size = hdr->acid().size();
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::importBinary(const u8 * bytes, size_t len)
|
||||
{
|
||||
if (len < sizeof(sNpdmHeader))
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "NPDM header too small");
|
||||
}
|
||||
importBinary(bytes);
|
||||
}
|
||||
|
||||
size_t nx::NpdmHeader::getNpdmSize() const
|
||||
{
|
||||
return MAX(mAcidPos.offset + mAcidPos.size, mAciPos.offset + mAciPos.size);
|
||||
}
|
||||
|
||||
nx::NpdmHeader::InstructionType nx::NpdmHeader::getInstructionType() const
|
||||
{
|
||||
return mInstructionType;
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::setInstructionType(InstructionType type)
|
||||
{
|
||||
mInstructionType = type;
|
||||
}
|
||||
|
||||
nx::NpdmHeader::ProcAddrSpaceType nx::NpdmHeader::getProcAddressSpaceType() const
|
||||
{
|
||||
return mProcAddressSpaceType;
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::setProcAddressSpaceType(ProcAddrSpaceType type)
|
||||
{
|
||||
mProcAddressSpaceType = type;
|
||||
}
|
||||
|
||||
u8 nx::NpdmHeader::getMainThreadPriority() const
|
||||
{
|
||||
return mMainThreadPriority;
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::setMainThreadPriority(u8 priority)
|
||||
{
|
||||
if (priority > kMaxPriority)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Illegal main thread priority (range 0-63)");
|
||||
}
|
||||
|
||||
mMainThreadPriority = priority;
|
||||
}
|
||||
|
||||
u8 nx::NpdmHeader::getMainThreadCoreNumber() const
|
||||
{
|
||||
return mMainThreadCoreNumber;
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::setMainThreadCoreNumber(u8 core_num)
|
||||
{
|
||||
mMainThreadCoreNumber = core_num;
|
||||
}
|
||||
|
||||
u32 nx::NpdmHeader::getVersion() const
|
||||
{
|
||||
return mVersion;
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::setVersion(u32 version)
|
||||
{
|
||||
mVersion = version;
|
||||
}
|
||||
|
||||
u32 nx::NpdmHeader::getMainThreadStackSize() const
|
||||
{
|
||||
return mMainThreadStackSize;
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::setMainThreadStackSize(u32 size)
|
||||
{
|
||||
mMainThreadStackSize = size;
|
||||
}
|
||||
|
||||
const std::string & nx::NpdmHeader::getName() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::setName(const std::string & name)
|
||||
{
|
||||
if (name.length() > kNameMaxLen)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Name is too long");
|
||||
}
|
||||
|
||||
mName = name;
|
||||
}
|
||||
|
||||
const std::string & nx::NpdmHeader::getProductCode() const
|
||||
{
|
||||
return mProductCode;
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::setProductCode(const std::string & product_code)
|
||||
{
|
||||
if (product_code.length() > kProductCodeMaxLen)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Product Code is too long");
|
||||
}
|
||||
|
||||
mProductCode = product_code;
|
||||
}
|
||||
|
||||
const nx::NpdmHeader::sSection & nx::NpdmHeader::getAciPos() const
|
||||
{
|
||||
return mAciPos;
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::setSetAciSize(size_t size)
|
||||
{
|
||||
mAciPos.size = size;
|
||||
}
|
||||
|
||||
const nx::NpdmHeader::sSection & nx::NpdmHeader::getAcidPos() const
|
||||
{
|
||||
return mAcidPos;
|
||||
}
|
||||
|
||||
void nx::NpdmHeader::setSetAcidSize(size_t size)
|
||||
{
|
||||
mAcidPos.size = size;
|
||||
}
|
195
lib/nx/NpdmHeader.h
Normal file
195
lib/nx/NpdmHeader.h
Normal file
|
@ -0,0 +1,195 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/memory_blob.h>
|
||||
#include <nx/ISerialiseableBinary.h>
|
||||
|
||||
namespace nx
|
||||
{
|
||||
class NpdmHeader :
|
||||
public nx::ISerialiseableBinary
|
||||
{
|
||||
public:
|
||||
enum InstructionType
|
||||
{
|
||||
INSTR_32BIT,
|
||||
INSTR_64BIT,
|
||||
};
|
||||
|
||||
enum ProcAddrSpaceType
|
||||
{
|
||||
ADDR_SPACE_64BIT = 1,
|
||||
ADDR_SPACE_32BIT,
|
||||
ADDR_SPACE_32BIT_NO_RESERVED,
|
||||
};
|
||||
|
||||
struct sSection
|
||||
{
|
||||
size_t offset;
|
||||
size_t size;
|
||||
|
||||
void operator=(const sSection& other)
|
||||
{
|
||||
offset = other.offset;
|
||||
size = other.size;
|
||||
}
|
||||
|
||||
bool operator==(const sSection& other) const
|
||||
{
|
||||
return (offset == other.offset) \
|
||||
&& (size == other.size);
|
||||
}
|
||||
|
||||
bool operator!=(const sSection& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
};
|
||||
|
||||
NpdmHeader();
|
||||
NpdmHeader(const NpdmHeader& other);
|
||||
NpdmHeader(const u8* bytes);
|
||||
|
||||
bool operator==(const NpdmHeader& other) const;
|
||||
bool operator!=(const NpdmHeader& other) const;
|
||||
void operator=(const NpdmHeader& other);
|
||||
|
||||
// to be used after export
|
||||
const u8* getBytes() const;
|
||||
size_t getSize() const;
|
||||
|
||||
// export/import binary
|
||||
void exportBinary();
|
||||
void importBinary(const u8* bytes);
|
||||
void importBinary(const u8* bytes, size_t len);
|
||||
|
||||
// variables
|
||||
size_t getNpdmSize() const;
|
||||
|
||||
InstructionType getInstructionType() const;
|
||||
void setInstructionType(InstructionType type);
|
||||
|
||||
ProcAddrSpaceType getProcAddressSpaceType() const;
|
||||
void setProcAddressSpaceType(ProcAddrSpaceType type);
|
||||
|
||||
u8 getMainThreadPriority() const;
|
||||
void setMainThreadPriority(u8 priority);
|
||||
|
||||
u8 getMainThreadCoreNumber() const;
|
||||
void setMainThreadCoreNumber(u8 core_num);
|
||||
|
||||
u32 getVersion() const;
|
||||
void setVersion(u32 version);
|
||||
|
||||
u32 getMainThreadStackSize() const;
|
||||
void setMainThreadStackSize(u32 size);
|
||||
|
||||
const std::string& getName() const;
|
||||
void setName(const std::string& name);
|
||||
|
||||
const std::string& getProductCode() const;
|
||||
void setProductCode(const std::string& product_code);
|
||||
|
||||
const sSection& getAciPos() const;
|
||||
void setSetAciSize(size_t size);
|
||||
|
||||
const sSection& getAcidPos() const;
|
||||
void setSetAcidSize(size_t size);
|
||||
private:
|
||||
const std::string kModuleName = "NPDM_HEADER";
|
||||
const std::string kNpdmStructSig = "META";
|
||||
static const size_t kNameMaxLen = 0x10;
|
||||
static const size_t kProductCodeMaxLen = 0x10;
|
||||
static const u8 kMaxPriority = 63;
|
||||
static const size_t kNpdmAlignSize = 0x10;
|
||||
|
||||
|
||||
enum FlagBits
|
||||
{
|
||||
IS_64BIT_INSTRUCTION_SET = BIT(0)
|
||||
};
|
||||
|
||||
#pragma pack (push, 1)
|
||||
struct sNpdmHeader
|
||||
{
|
||||
private:
|
||||
u8 signature_[4]; // be"META"
|
||||
u8 reserved_0[8];
|
||||
u8 flags_;
|
||||
u8 reserved_1;
|
||||
u8 main_thread_priority_; // 0-63 inclusive
|
||||
u8 main_thread_core_number_;
|
||||
u8 reserved_2[8];
|
||||
u32 version_;
|
||||
u32 main_thread_stack_size_; // default 4096
|
||||
u8 name_[kNameMaxLen]; // important
|
||||
u8 product_code_[kProductCodeMaxLen]; // can be empty
|
||||
u8 reserved_3[48];
|
||||
// Access Control Info
|
||||
struct sNpdmSection
|
||||
{
|
||||
private:
|
||||
u32 offset_;
|
||||
u32 size_;
|
||||
public:
|
||||
u32 offset() const { return le_word(offset_); }
|
||||
void set_offset(u32 offset) { offset_ = le_word(offset); }
|
||||
|
||||
u32 size() const { return le_word(size_); }
|
||||
void set_size(u32 size) { size_ = le_word(size); }
|
||||
} aci_, acid_;
|
||||
public:
|
||||
const char* signature() const { return (const char*)signature_; }
|
||||
void set_signature(const char* signature) { memcpy(signature_, signature, 4); }
|
||||
|
||||
u8 flags() const { return flags_; }
|
||||
void set_flags(u8 flags) { flags_ = flags; }
|
||||
|
||||
u8 main_thread_priority() const { return main_thread_priority_; }
|
||||
void set_main_thread_priority(u8 priority) { main_thread_priority_ = priority; }
|
||||
|
||||
u8 main_thread_core_number() const { return main_thread_core_number_; }
|
||||
void set_main_thread_core_number(u8 core_number) { main_thread_core_number_ = core_number; }
|
||||
|
||||
u32 version() const { return le_word(version_); }
|
||||
void set_version(u32 version) { version_ = le_word(version); }
|
||||
|
||||
u32 main_thread_stack_size() const { return le_word(main_thread_stack_size_); }
|
||||
void set_main_thread_stack_size(u32 size) { main_thread_stack_size_ = le_word(size); }
|
||||
|
||||
const char* name() const { return (const char*)name_; }
|
||||
void set_name(const char* name) { strncpy((char*)name_, name, kNameMaxLen); }
|
||||
|
||||
const char* product_code() const { return (const char*)product_code_; }
|
||||
void set_product_code(const char* product_code) { strncpy((char*)product_code_, product_code, kProductCodeMaxLen); }
|
||||
|
||||
const sNpdmSection& aci() const { return aci_; }
|
||||
sNpdmSection& aci() { return aci_; }
|
||||
|
||||
const sNpdmSection& acid() const { return acid_; }
|
||||
sNpdmSection& acid() { return acid_; }
|
||||
};
|
||||
#pragma pack (pop)
|
||||
|
||||
// raw binary
|
||||
fnd::MemoryBlob mBinaryBlob;
|
||||
|
||||
// variables
|
||||
InstructionType mInstructionType;
|
||||
ProcAddrSpaceType mProcAddressSpaceType;
|
||||
u8 mMainThreadPriority;
|
||||
u8 mMainThreadCoreNumber;
|
||||
u32 mVersion;
|
||||
u32 mMainThreadStackSize;
|
||||
std::string mName;
|
||||
std::string mProductCode;
|
||||
sSection mAciPos;
|
||||
sSection mAcidPos;
|
||||
|
||||
void clearVariables();
|
||||
void calculateOffsets();
|
||||
bool isEqual(const NpdmHeader& other) const;
|
||||
void copyFrom(const NpdmHeader& other);
|
||||
};
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
<ClInclude Include="FacBinary.h" />
|
||||
<ClInclude Include="FacHeader.h" />
|
||||
<ClInclude Include="ISerialiseableBinary.h" />
|
||||
<ClInclude Include="NpdmHeader.h" />
|
||||
<ClInclude Include="NcaHeader.h" />
|
||||
<ClInclude Include="NXCrypto.h" />
|
||||
<ClInclude Include="SacBinary.h" />
|
||||
|
@ -32,6 +33,7 @@
|
|||
<ClCompile Include="AciHeader.cpp" />
|
||||
<ClCompile Include="FacBinary.cpp" />
|
||||
<ClCompile Include="FacHeader.cpp" />
|
||||
<ClCompile Include="NpdmHeader.cpp" />
|
||||
<ClCompile Include="NcaHeader.cpp" />
|
||||
<ClCompile Include="SacBinary.cpp" />
|
||||
<ClCompile Include="SacEntry.cpp" />
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
<ClInclude Include="SacBinary.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NpdmHeader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="NcaHeader.cpp">
|
||||
|
@ -59,5 +62,8 @@
|
|||
<ClCompile Include="SacBinary.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NpdmHeader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in a new issue