diff --git a/lib/libnx/include/nx/NpdmBinary.h b/lib/libnx/include/nx/NpdmBinary.h index e65ac85..c64f2d8 100644 --- a/lib/libnx/include/nx/NpdmBinary.h +++ b/lib/libnx/include/nx/NpdmBinary.h @@ -1,7 +1,8 @@ #pragma once #include #include -#include +#include +#include #include #include @@ -9,7 +10,7 @@ namespace nx { class NpdmBinary : - public NpdmHeader + public fnd::ISerialisable { public: NpdmBinary(); @@ -27,6 +28,30 @@ namespace nx // variables void clear(); + npdm::InstructionType getInstructionType() const; + void setInstructionType(npdm::InstructionType type); + + npdm::ProcAddrSpaceType getProcAddressSpaceType() const; + void setProcAddressSpaceType(npdm::ProcAddrSpaceType type); + + byte_t getMainThreadPriority() const; + void setMainThreadPriority(byte_t priority); + + byte_t getMainThreadCpuId() const; + void setMainThreadCpuId(byte_t cpu_id); + + uint32_t getVersion() const; + void setVersion(uint32_t version); + + uint32_t getMainThreadStackSize() const; + void setMainThreadStackSize(uint32_t 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 AccessControlInfoBinary& getAci() const; void setAci(const AccessControlInfoBinary& aci); @@ -39,6 +64,14 @@ namespace nx fnd::Vec mRawBinary; // variables + npdm::InstructionType mInstructionType; + npdm::ProcAddrSpaceType mProcAddressSpaceType; + byte_t mMainThreadPriority; + byte_t mMainThreadCpuId; + uint32_t mVersion; + uint32_t mMainThreadStackSize; + std::string mName; + std::string mProductCode; AccessControlInfoBinary mAci; AccessControlInfoDescBinary mAcid; }; diff --git a/lib/libnx/include/nx/NpdmHeader.h b/lib/libnx/include/nx/NpdmHeader.h deleted file mode 100644 index f258ade..0000000 --- a/lib/libnx/include/nx/NpdmHeader.h +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace nx -{ - class NpdmHeader : - public fnd::ISerialisable - { - public: - 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); - - void operator=(const NpdmHeader& other); - bool operator==(const NpdmHeader& other) const; - bool operator!=(const NpdmHeader& other) const; - - // export/import binary - void toBytes(); - void fromBytes(const byte_t* bytes, size_t len); - const fnd::Vec& getBytes() const; - - // variables - void clear(); - size_t getNpdmSize() const; - - npdm::InstructionType getInstructionType() const; - void setInstructionType(npdm::InstructionType type); - - npdm::ProcAddrSpaceType getProcAddressSpaceType() const; - void setProcAddressSpaceType(npdm::ProcAddrSpaceType type); - - byte_t getMainThreadPriority() const; - void setMainThreadPriority(byte_t priority); - - byte_t getMainThreadCpuId() const; - void setMainThreadCpuId(byte_t cpu_id); - - uint32_t getVersion() const; - void setVersion(uint32_t version); - - uint32_t getMainThreadStackSize() const; - void setMainThreadStackSize(uint32_t 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 setAciSize(size_t size); - - const sSection& getAcidPos() const; - void setAcidSize(size_t size); - private: - const std::string kModuleName = "NPDM_HEADER"; - - // raw binary - fnd::Vec mRawBinary; - - // variables - npdm::InstructionType mInstructionType; - npdm::ProcAddrSpaceType mProcAddressSpaceType; - byte_t mMainThreadPriority; - byte_t mMainThreadCpuId; - uint32_t mVersion; - uint32_t mMainThreadStackSize; - std::string mName; - std::string mProductCode; - sSection mAciPos; - sSection mAcidPos; - - void calculateOffsets(); - }; -} - diff --git a/lib/libnx/include/nx/npdm.h b/lib/libnx/include/nx/npdm.h index 96bdbf5..8271f39 100644 --- a/lib/libnx/include/nx/npdm.h +++ b/lib/libnx/include/nx/npdm.h @@ -9,8 +9,8 @@ namespace nx static const uint32_t kNpdmStructMagic = _MAKE_STRUCT_MAGIC("META"); static const size_t kNameMaxLen = 0x10; static const size_t kProductCodeMaxLen = 0x10; - static const uint32_t kMaxPriority = BIT(6) -1; - static const size_t kNpdmAlignSize = 0x10; + static const uint32_t kMaxPriority = BIT(6) - 1; + static const size_t kSectionAlignSize = 0x10; static const uint32_t kDefaultMainThreadStackSize = 4096; enum InstructionType diff --git a/lib/libnx/source/NpdmBinary.cpp b/lib/libnx/source/NpdmBinary.cpp index f5ea3dd..3a77972 100644 --- a/lib/libnx/source/NpdmBinary.cpp +++ b/lib/libnx/source/NpdmBinary.cpp @@ -2,37 +2,42 @@ #include -nx::NpdmBinary::NpdmBinary() : - mAci(), - mAcid() +nx::NpdmBinary::NpdmBinary() { clear(); } nx::NpdmBinary::NpdmBinary(const NpdmBinary & other) : - mAci(), - mAcid() + NpdmBinary() { *this = other; } void nx::NpdmBinary::operator=(const NpdmBinary & other) { - if (other.getBytes().size()) - { - fromBytes(other.getBytes().data(), other.getBytes().size()); - } - else - { - NpdmHeader::operator=(other); - mAci = other.mAci; - mAcid = other.mAcid; - } + mRawBinary = other.mRawBinary; + mInstructionType = other.mInstructionType; + mProcAddressSpaceType = other.mProcAddressSpaceType; + mMainThreadPriority = other.mMainThreadPriority; + mMainThreadCpuId = other.mMainThreadCpuId; + mVersion = other.mVersion; + mMainThreadStackSize = other.mMainThreadStackSize; + mName = other.mName; + mProductCode = other.mProductCode; + mAci = other.mAci; + mAcid = other.mAcid; } bool nx::NpdmBinary::operator==(const NpdmBinary & other) const { - return (NpdmHeader::operator==(other)) \ + return (mInstructionType == other.mInstructionType) \ + && (mProcAddressSpaceType == other.mProcAddressSpaceType) \ + && (mMainThreadPriority == other.mMainThreadPriority) \ + && (mMainThreadCpuId == other.mMainThreadCpuId) \ + && (mVersion == other.mVersion) \ + && (mMainThreadStackSize == other.mMainThreadStackSize) \ + && (mName == other.mName) \ + && (mProductCode == other.mProductCode) \ && (mAci == other.mAci) \ && (mAcid == other.mAcid); } @@ -44,35 +49,121 @@ bool nx::NpdmBinary::operator!=(const NpdmBinary & other) const void nx::NpdmBinary::toBytes() { - throw fnd::Exception(kModuleName, "toBytes() not implemented."); + if (mAcid.getBytes().size() == 0) + mAcid.toBytes(); + + if (mAci.getBytes().size() == 0) + mAci.toBytes(); + + + // determine section layout + struct sLayout { + uint32_t offset, size; + } acid, aci; + + acid.offset = align(sizeof(sNpdmHeader), npdm::kSectionAlignSize); + acid.size = (uint32_t)mAcid.getBytes().size(); + aci.offset = acid.offset + align(acid.size, npdm::kSectionAlignSize); + aci.size = (uint32_t)mAci.getBytes().size(); + + + // get total size + size_t total_size = _MAX(_MAX(acid.offset + acid.size, aci.offset + aci.size), align(sizeof(sNpdmHeader), npdm::kSectionAlignSize)); + + mRawBinary.alloc(total_size); + sNpdmHeader* hdr = (sNpdmHeader*)mRawBinary.data(); + + // set type + hdr->st_magic = npdm::kNpdmStructMagic; + + // set variables + byte_t flag = ((byte_t)(mInstructionType & 1) | (byte_t)((mProcAddressSpaceType & 3) << 1)) & 0xf; + hdr->flags = flag; + hdr->main_thread_priority = mMainThreadPriority; + hdr->main_thread_cpu_id = mMainThreadCpuId; + hdr->version = mVersion; + hdr->main_thread_stack_size = mMainThreadStackSize; + strncpy(hdr->name, mName.c_str(), npdm::kNameMaxLen); + strncpy(hdr->product_code, mProductCode.c_str(), npdm::kProductCodeMaxLen); + + // set offset/size + hdr->aci.offset = aci.offset; + hdr->aci.size = aci.size; + hdr->acid.offset = acid.offset; + hdr->acid.size = acid.size; + + // write aci & acid + if (mAci.getBytes().size() > 0) + { + memcpy(mRawBinary.data() + aci.offset, mAci.getBytes().data(), mAci.getBytes().size()); + } + if (mAcid.getBytes().size() > 0) + { + memcpy(mRawBinary.data() + acid.offset, mAcid.getBytes().data(), mAcid.getBytes().size()); + } } void nx::NpdmBinary::fromBytes(const byte_t* data, size_t len) { - // clear + // check size + if (len < sizeof(sNpdmHeader)) + { + throw fnd::Exception(kModuleName, "NPDM binary is too small"); + } + + // clear variables clear(); - // import header - NpdmHeader::fromBytes(data, len); + // save a copy of the header + sNpdmHeader hdr; + memcpy((void*)&hdr, data, sizeof(sNpdmHeader)); + + // check magic + if (hdr.st_magic.get() != npdm::kNpdmStructMagic) + { + throw fnd::Exception(kModuleName, "NPDM header corrupt"); + } + + // save variables + byte_t flag = hdr.flags & 0xf; + mInstructionType = (npdm::InstructionType)(flag & 1); + mProcAddressSpaceType = (npdm::ProcAddrSpaceType)((flag >> 1) & 3); + mMainThreadPriority = hdr.main_thread_priority; + mMainThreadCpuId = hdr.main_thread_cpu_id; + mVersion = hdr.version.get(); + mMainThreadStackSize = hdr.main_thread_stack_size.get(); + mName = std::string(hdr.name, npdm::kNameMaxLen); + if (mName[0] == '\0') + { + mName.clear(); + } + mProductCode = std::string(hdr.product_code, npdm::kProductCodeMaxLen); + if (mProductCode[0] == '\0') + { + mProductCode.clear(); + } + + // total size + size_t total_size = _MAX(_MAX(hdr.acid.offset.get() + hdr.acid.size.get(), hdr.aci.offset.get() + hdr.aci.size.get()), sizeof(sNpdmHeader)); // check size - if (getNpdmSize() > len) + if (total_size > len) { throw fnd::Exception(kModuleName, "NPDM binary too small"); } // save local copy - mRawBinary.alloc(getNpdmSize()); + mRawBinary.alloc(total_size); memcpy(mRawBinary.data(), data, mRawBinary.size()); // import Aci/Acid - if (getAciPos().size) + if (hdr.aci.size.get()) { - mAci.fromBytes(mRawBinary.data() + getAciPos().offset, getAciPos().size); + mAci.fromBytes(mRawBinary.data() + hdr.aci.offset.get(), hdr.aci.size.get()); } - if (getAcidPos().size) + if (hdr.acid.size.get()) { - mAcid.fromBytes(mRawBinary.data() + getAcidPos().offset, getAcidPos().size); + mAcid.fromBytes(mRawBinary.data() + hdr.acid.offset.get(), hdr.acid.size.get()); } } @@ -83,11 +174,114 @@ const fnd::Vec& nx::NpdmBinary::getBytes() const void nx::NpdmBinary::clear() { - NpdmHeader::clear(); + mRawBinary.clear(); + mInstructionType = npdm::INSTR_64BIT; + mProcAddressSpaceType = npdm::ADDR_SPACE_64BIT; + mMainThreadPriority = 0; + mMainThreadCpuId = 0; + mVersion = 0; + mMainThreadStackSize = 0; + mName.clear(); + mProductCode.clear(); mAci.clear(); mAcid.clear(); } +nx::npdm::InstructionType nx::NpdmBinary::getInstructionType() const +{ + return mInstructionType; +} + +void nx::NpdmBinary::setInstructionType(npdm::InstructionType type) +{ + mInstructionType = type; +} + +nx::npdm::ProcAddrSpaceType nx::NpdmBinary::getProcAddressSpaceType() const +{ + return mProcAddressSpaceType; +} + +void nx::NpdmBinary::setProcAddressSpaceType(npdm::ProcAddrSpaceType type) +{ + mProcAddressSpaceType = type; +} + +byte_t nx::NpdmBinary::getMainThreadPriority() const +{ + return mMainThreadPriority; +} + +void nx::NpdmBinary::setMainThreadPriority(byte_t priority) +{ + if (priority > npdm::kMaxPriority) + { + throw fnd::Exception(kModuleName, "Illegal main thread priority (range 0-63)"); + } + + mMainThreadPriority = priority; +} + +byte_t nx::NpdmBinary::getMainThreadCpuId() const +{ + return mMainThreadCpuId; +} + +void nx::NpdmBinary::setMainThreadCpuId(byte_t core_num) +{ + mMainThreadCpuId = core_num; +} + +uint32_t nx::NpdmBinary::getVersion() const +{ + return mVersion; +} + +void nx::NpdmBinary::setVersion(uint32_t version) +{ + mVersion = version; +} + +uint32_t nx::NpdmBinary::getMainThreadStackSize() const +{ + return mMainThreadStackSize; +} + +void nx::NpdmBinary::setMainThreadStackSize(uint32_t size) +{ + mMainThreadStackSize = size; +} + +const std::string & nx::NpdmBinary::getName() const +{ + return mName; +} + +void nx::NpdmBinary::setName(const std::string & name) +{ + if (name.length() > npdm::kNameMaxLen) + { + throw fnd::Exception(kModuleName, "Name is too long"); + } + + mName = name; +} + +const std::string & nx::NpdmBinary::getProductCode() const +{ + return mProductCode; +} + +void nx::NpdmBinary::setProductCode(const std::string & product_code) +{ + if (product_code.length() > npdm::kProductCodeMaxLen) + { + throw fnd::Exception(kModuleName, "Product Code is too long"); + } + + mProductCode = product_code; +} + const nx::AccessControlInfoBinary & nx::NpdmBinary::getAci() const { return mAci; diff --git a/lib/libnx/source/NpdmHeader.cpp b/lib/libnx/source/NpdmHeader.cpp deleted file mode 100644 index 2a57fc1..0000000 --- a/lib/libnx/source/NpdmHeader.cpp +++ /dev/null @@ -1,264 +0,0 @@ -#include - -nx::NpdmHeader::NpdmHeader() -{ - clear(); -} - -nx::NpdmHeader::NpdmHeader(const NpdmHeader & other) -{ - *this = other; -} - -void nx::NpdmHeader::operator=(const NpdmHeader & other) -{ - if (other.getBytes().size()) - { - fromBytes(other.getBytes().data(), other.getBytes().size()); - } - else - { - clear(); - mInstructionType = other.mInstructionType; - mProcAddressSpaceType = other.mProcAddressSpaceType; - mMainThreadPriority = other.mMainThreadPriority; - mMainThreadCpuId = other.mMainThreadCpuId; - mVersion = other.mVersion; - mMainThreadStackSize = other.mMainThreadStackSize; - mName = other.mName; - mProductCode = other.mProductCode; - mAciPos = other.mAciPos; - mAcidPos = other.mAcidPos; - } -} - -bool nx::NpdmHeader::operator==(const NpdmHeader & other) const -{ - return (mInstructionType == other.mInstructionType) \ - && (mProcAddressSpaceType == other.mProcAddressSpaceType) \ - && (mMainThreadPriority == other.mMainThreadPriority) \ - && (mMainThreadCpuId == other.mMainThreadCpuId) \ - && (mVersion == other.mVersion) \ - && (mMainThreadStackSize == other.mMainThreadStackSize) \ - && (mName == other.mName) \ - && (mProductCode == other.mProductCode) \ - && (mAciPos == other.mAciPos) \ - && (mAcidPos == other.mAcidPos); -} - -bool nx::NpdmHeader::operator!=(const NpdmHeader & other) const -{ - return !(*this == other); -} - -void nx::NpdmHeader::toBytes() -{ - mRawBinary.alloc(sizeof(sNpdmHeader)); - sNpdmHeader* hdr = (sNpdmHeader*)mRawBinary.data(); - - hdr->st_magic = npdm::kNpdmStructMagic; - byte_t flag = ((byte_t)(mInstructionType & 1) | (byte_t)((mProcAddressSpaceType & 3) << 1)) & 0xf; - hdr->flags = flag; - hdr->main_thread_priority = mMainThreadPriority; - hdr->main_thread_cpu_id = mMainThreadCpuId; - hdr->version = mVersion; - hdr->main_thread_stack_size = mMainThreadStackSize; - strncpy(hdr->name, mName.c_str(), npdm::kNameMaxLen); - strncpy(hdr->product_code, mProductCode.c_str(), npdm::kProductCodeMaxLen); - - calculateOffsets(); - hdr->aci.offset = (uint32_t)mAciPos.offset; - hdr->aci.size = (uint32_t)mAciPos.size; - hdr->acid.offset = (uint32_t)mAcidPos.offset; - hdr->acid.size = (uint32_t)mAcidPos.size; -} - -void nx::NpdmHeader::fromBytes(const byte_t* data, size_t len) -{ - if (len < sizeof(sNpdmHeader)) - { - throw fnd::Exception(kModuleName, "NPDM header too small"); - } - - // clear internal members - clear(); - - mRawBinary.alloc(sizeof(sNpdmHeader)); - memcpy(mRawBinary.data(), data, mRawBinary.size()); - sNpdmHeader* hdr = (sNpdmHeader*)mRawBinary.data(); - - if (hdr->st_magic.get() != npdm::kNpdmStructMagic) - { - throw fnd::Exception(kModuleName, "NPDM header corrupt"); - } - - byte_t flag = hdr->flags & 0xf; - mInstructionType = (npdm::InstructionType)(flag & 1); - mProcAddressSpaceType = (npdm::ProcAddrSpaceType)((flag >> 1) & 3); - mMainThreadPriority = hdr->main_thread_priority; - mMainThreadCpuId = hdr->main_thread_cpu_id; - mVersion = hdr->version.get(); - mMainThreadStackSize = hdr->main_thread_stack_size.get(); - mName = std::string(hdr->name, npdm::kNameMaxLen); - if (mName[0] == '\0') - { - mName.clear(); - } - mProductCode = std::string(hdr->product_code, npdm::kProductCodeMaxLen); - if (mProductCode[0] == '\0') - { - mProductCode.clear(); - } - mAciPos.offset = hdr->aci.offset.get(); - mAciPos.size = hdr->aci.size.get(); - mAcidPos.offset = hdr->acid.offset.get(); - mAcidPos.size = hdr->acid.size.get(); -} - -const fnd::Vec& nx::NpdmHeader::getBytes() const -{ - return mRawBinary; -} - -void nx::NpdmHeader::clear() -{ - mRawBinary.clear(); - mInstructionType = npdm::INSTR_64BIT; - mProcAddressSpaceType = npdm::ADDR_SPACE_64BIT; - mMainThreadPriority = 0; - mMainThreadCpuId = 0; - mVersion = 0; - mMainThreadStackSize = 0; - mName.clear(); - mProductCode.clear(); - mAciPos.offset = 0; - mAciPos.size = 0; - mAcidPos.offset = 0; - mAcidPos.size = 0; -} - -size_t nx::NpdmHeader::getNpdmSize() const -{ - return _MAX(mAcidPos.offset + mAcidPos.size, mAciPos.offset + mAciPos.size); -} - -nx::npdm::InstructionType nx::NpdmHeader::getInstructionType() const -{ - return mInstructionType; -} - -void nx::NpdmHeader::setInstructionType(npdm::InstructionType type) -{ - mInstructionType = type; -} - -nx::npdm::ProcAddrSpaceType nx::NpdmHeader::getProcAddressSpaceType() const -{ - return mProcAddressSpaceType; -} - -void nx::NpdmHeader::setProcAddressSpaceType(npdm::ProcAddrSpaceType type) -{ - mProcAddressSpaceType = type; -} - -byte_t nx::NpdmHeader::getMainThreadPriority() const -{ - return mMainThreadPriority; -} - -void nx::NpdmHeader::setMainThreadPriority(byte_t priority) -{ - if (priority > npdm::kMaxPriority) - { - throw fnd::Exception(kModuleName, "Illegal main thread priority (range 0-63)"); - } - - mMainThreadPriority = priority; -} - -byte_t nx::NpdmHeader::getMainThreadCpuId() const -{ - return mMainThreadCpuId; -} - -void nx::NpdmHeader::setMainThreadCpuId(byte_t core_num) -{ - mMainThreadCpuId = core_num; -} - -uint32_t nx::NpdmHeader::getVersion() const -{ - return mVersion; -} - -void nx::NpdmHeader::setVersion(uint32_t version) -{ - mVersion = version; -} - -uint32_t nx::NpdmHeader::getMainThreadStackSize() const -{ - return mMainThreadStackSize; -} - -void nx::NpdmHeader::setMainThreadStackSize(uint32_t size) -{ - mMainThreadStackSize = size; -} - -const std::string & nx::NpdmHeader::getName() const -{ - return mName; -} - -void nx::NpdmHeader::setName(const std::string & name) -{ - if (name.length() > npdm::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() > npdm::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::setAciSize(size_t size) -{ - mAciPos.size = size; -} - -const nx::NpdmHeader::sSection & nx::NpdmHeader::getAcidPos() const -{ - return mAcidPos; -} - -void nx::NpdmHeader::setAcidSize(size_t size) -{ - mAcidPos.size = size; -} - -void nx::NpdmHeader::calculateOffsets() -{ - mAcidPos.offset = align(sizeof(sNpdmHeader), npdm::kNpdmAlignSize); - mAciPos.offset = mAcidPos.offset + align(mAcidPos.size, npdm::kNpdmAlignSize); -} \ No newline at end of file diff --git a/programs/nstool/source/NpdmProcess.cpp b/programs/nstool/source/NpdmProcess.cpp index 3d26e17..c87cc65 100644 --- a/programs/nstool/source/NpdmProcess.cpp +++ b/programs/nstool/source/NpdmProcess.cpp @@ -529,7 +529,7 @@ void NpdmProcess::validateAciFromAcid(const nx::AccessControlInfoBinary& aci, co } } -void NpdmProcess::displayNpdmHeader(const nx::NpdmHeader& hdr) +void NpdmProcess::displayNpdmHeader(const nx::NpdmBinary& hdr) { printf("[NPDM HEADER]\n"); printf(" Process Architecture Params:\n"); diff --git a/programs/nstool/source/NpdmProcess.h b/programs/nstool/source/NpdmProcess.h index 8c24d01..12264c8 100644 --- a/programs/nstool/source/NpdmProcess.h +++ b/programs/nstool/source/NpdmProcess.h @@ -35,7 +35,7 @@ private: void validateAcidSignature(const nx::AccessControlInfoDescBinary& acid); void validateAciFromAcid(const nx::AccessControlInfoBinary& aci, const nx::AccessControlInfoDescBinary& acid); - void displayNpdmHeader(const nx::NpdmHeader& hdr); + void displayNpdmHeader(const nx::NpdmBinary& hdr); void displayAciHdr(const nx::AccessControlInfoBinary& aci); void displayAciDescHdr(const nx::AccessControlInfoDescBinary& aci); void displayFac(const nx::FileSystemAccessControlBinary& fac);