[nx] Add NpdmHeader.

This commit is contained in:
jakcron 2017-07-07 10:18:33 +10:00
parent 7b0dbc753f
commit 60e1b8a328
4 changed files with 481 additions and 0 deletions

278
lib/nx/NpdmHeader.cpp Normal file
View 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
View 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);
};
}

View file

@ -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" />

View file

@ -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>