diff --git a/lib/libhac/include/nn/hac/IniHeader.h b/lib/libhac/include/nn/hac/IniHeader.h new file mode 100644 index 0000000..4463397 --- /dev/null +++ b/lib/libhac/include/nn/hac/IniHeader.h @@ -0,0 +1,46 @@ +#pragma once +#include +#include +#include +#include + +namespace nn +{ +namespace hac +{ + class IniHeader : + public fnd::IByteModel + { + public: + IniHeader(); + IniHeader(const IniHeader& other); + + void operator=(const IniHeader& other); + bool operator==(const IniHeader& other) const; + bool operator!=(const IniHeader& other) const; + + // IByteModel + void toBytes(); + void fromBytes(const byte_t* data, size_t len); + const fnd::Vec& getBytes() const; + + // variables + void clear(); + + uint32_t getSize() const; + void setSize(uint32_t size); + + uint32_t getKipNum() const; + void setKipNum(uint32_t num); + private: + const std::string kModuleName = "INI_HEADER"; + + // raw binary + fnd::Vec mRawBinary; + + // variables + uint32_t mSize; + uint32_t mKipNum; + }; +} +} \ No newline at end of file diff --git a/lib/libhac/include/nn/hac/KernelInitialProcessHeader.h b/lib/libhac/include/nn/hac/KernelInitialProcessHeader.h new file mode 100644 index 0000000..cf476a6 --- /dev/null +++ b/lib/libhac/include/nn/hac/KernelInitialProcessHeader.h @@ -0,0 +1,137 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace nn +{ +namespace hac +{ + class KernelInitialProcessHeader : + public fnd::IByteModel + { + public: + struct sLayout + { + uint32_t offset; + uint32_t size; + + void operator=(const sLayout& other) + { + offset = other.offset; + size = other.size; + } + + bool operator==(const sLayout& other) const + { + return (offset == other.offset) \ + && (size == other.size); + } + + bool operator!=(const sLayout& other) const + { + return !(*this == other); + } + }; + + struct sCodeSegment + { + sLayout file_layout; + sLayout memory_layout; + bool is_compressed; + + void operator=(const sCodeSegment& other) + { + file_layout = other.file_layout; + memory_layout = other.memory_layout; + is_compressed = other.is_compressed; + } + + bool operator==(const sCodeSegment& other) const + { + return (file_layout == other.file_layout) \ + && (memory_layout == other.memory_layout) \ + && (is_compressed == other.is_compressed); + } + + bool operator!=(const sCodeSegment& other) const + { + return !(*this == other); + } + }; + + KernelInitialProcessHeader(); + KernelInitialProcessHeader(const KernelInitialProcessHeader& other); + + void operator=(const KernelInitialProcessHeader& other); + bool operator==(const KernelInitialProcessHeader& other) const; + bool operator!=(const KernelInitialProcessHeader& other) const; + + // export/import binary + void toBytes(); + void fromBytes(const byte_t* data, size_t len); + const fnd::Vec& getBytes() const; + + // variables + void clear(); + + const std::string& getName() const; + void setName(const std::string& name); + + uint64_t getTitleId() const; + void setTitleId(uint64_t title_id); + + kip::ProcessCategory getProcessCategory() const; + void setProcessCategory(kip::ProcessCategory cat); + + const fnd::List& getFlagList() const; + void setFlagList(const fnd::List& flags); + + byte_t getMainThreadPriority() const; + void setMainThreadPriority(byte_t priority); + + byte_t getMainThreadCpuId() const; + void setMainThreadCpuId(byte_t cpu_id); + + uint32_t getMainThreadStackSize() const; + void setMainThreadStackSize(uint32_t size); + + const sCodeSegment& getTextSegmentInfo() const; + void setTextSegmentInfo(const sCodeSegment& info); + + const sCodeSegment& getRoSegmentInfo() const; + void setRoSegmentInfo(const sCodeSegment& info); + + const sCodeSegment& getDataSegmentInfo() const; + void setDataSegmentInfo(const sCodeSegment& info); + + uint32_t getBssSize() const; + void setBssSize(uint32_t size); + + const nn::hac::KernelCapabilityControl& getKernelCapabilities() const; + void setKernelCapabilities(const KernelCapabilityControl& kc); + + private: + const std::string kModuleName = "KERNEL_INITIAL_PROCESS_HEADER"; + + // raw binary + fnd::Vec mRawBinary; + + // variables + std::string mName; + uint64_t mTitleId; + kip::ProcessCategory mProcessCategory; + fnd::List mFlagList; + byte_t mMainThreadPriority; + byte_t mMainThreadCpuId; + uint32_t mMainThreadStackSize; + sCodeSegment mTextInfo; + sCodeSegment mRoInfo; + sCodeSegment mDataInfo; + uint32_t mBssSize; + nn::hac::KernelCapabilityControl mKernelCapabilities; + }; +} +} \ No newline at end of file diff --git a/lib/libhac/include/nn/hac/define/ini.h b/lib/libhac/include/nn/hac/define/ini.h new file mode 100644 index 0000000..d51a3aa --- /dev/null +++ b/lib/libhac/include/nn/hac/define/ini.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include + +namespace nn +{ +namespace hac +{ + namespace ini + { + static const uint32_t kIniStructMagic = _MAKE_STRUCT_MAGIC_U32("INI1"); + static const size_t kMaxKipNum = 0x50; + } + +#pragma pack(push,1) + struct sIniHeader + { + le_uint32_t st_magic; + le_uint32_t size; + le_uint32_t kip_num; + byte_t reserved_01[0x4]; + }; +#pragma pack(pop) +} +} \ No newline at end of file diff --git a/lib/libhac/include/nn/hac/define/kip.h b/lib/libhac/include/nn/hac/define/kip.h new file mode 100644 index 0000000..c1a9360 --- /dev/null +++ b/lib/libhac/include/nn/hac/define/kip.h @@ -0,0 +1,65 @@ +#pragma once +#include +#include +#include + +namespace nn +{ +namespace hac +{ + namespace kip + { + static const uint32_t kKipStructMagic = _MAKE_STRUCT_MAGIC_U32("KIP1"); + static const size_t kNameMaxLen = 0xC; + static const size_t kKernCapabilityNum = 0x20; + static const size_t kKernCapabilitySize = kKernCapabilityNum * sizeof(uint32_t); + + enum ProcessCategory + { + PROCCAT_REGULAR, + PROCCAT_KERNAL_KIP + }; + + enum HeaderFlags + { + FLAG_TEXT_COMPRESS, + FLAG_RO_COMPRESS, + FLAG_DATA_COMPRESS, + FLAG_INSTRUCTION_64BIT, + FLAG_ADDR_SPACE_64BIT, + FLAG_USE_SYSTEM_POOL_PARTITION + }; + } + +#pragma pack(push,1) + struct sKipCodeSegment + { + le_uint32_t memory_offset; + le_uint32_t memory_size; + le_uint32_t file_size; + }; + + struct sKipHeader + { + le_uint32_t st_magic; + char name[kip::kNameMaxLen]; + le_uint64_t title_id; + le_uint32_t process_category; + byte_t main_thread_priority; + byte_t main_thread_cpu_id; + byte_t reserved_01; + byte_t flags; + sKipCodeSegment text; + byte_t reserved_02[4]; + sKipCodeSegment ro; + le_uint32_t main_thread_stack_size; + sKipCodeSegment data; + byte_t reserved_03[4]; + sKipCodeSegment bss; + byte_t reserved_04[4]; + byte_t reserved_05[0x20]; + byte_t capabilities[kip::kKernCapabilitySize]; + }; +#pragma pack(pop) +} +} \ No newline at end of file diff --git a/lib/libhac/source/IniHeader.cpp b/lib/libhac/source/IniHeader.cpp new file mode 100644 index 0000000..15c2689 --- /dev/null +++ b/lib/libhac/source/IniHeader.cpp @@ -0,0 +1,114 @@ +#include + +nn::hac::IniHeader::IniHeader() +{ + clear(); +} + +nn::hac::IniHeader::IniHeader(const IniHeader& other) +{ + *this = other; +} + +void nn::hac::IniHeader::operator=(const IniHeader& other) +{ + clear(); + this->mSize = other.mSize; + this->mKipNum = other.mKipNum; +} + +bool nn::hac::IniHeader::operator==(const IniHeader& other) const +{ + return (this->mSize == other.mSize) \ + && (this->mKipNum == other.mKipNum); +} + +bool nn::hac::IniHeader::operator!=(const IniHeader& other) const +{ + return !(*this == other); +} + +void nn::hac::IniHeader::toBytes() +{ + mRawBinary.alloc(sizeof(sIniHeader)); + nn::hac::sIniHeader* hdr = (nn::hac::sIniHeader*)mRawBinary.data(); + + // set header identifers + hdr->st_magic = ini::kIniStructMagic; + + if (mKipNum > ini::kMaxKipNum) + { + throw fnd::Exception(kModuleName, "Cannot generate INI Header (Too many KIPs)"); + } + + // write variables + hdr->size = mSize; + hdr->kip_num = mKipNum; +} + +void nn::hac::IniHeader::fromBytes(const byte_t* data, size_t len) +{ + // check input data size + if (len < sizeof(sIniHeader)) + { + throw fnd::Exception(kModuleName, "INI header corrupt (header size is too small)"); + } + + // clear internal members + clear(); + + // allocate internal local binary copy + mRawBinary.alloc(sizeof(sIniHeader)); + memcpy(mRawBinary.data(), data, mRawBinary.size()); + + // get sIniHeader ptr + const nn::hac::sIniHeader* hdr = (const nn::hac::sIniHeader*)mRawBinary.data(); + + // check INI signature + if (hdr->st_magic.get() != ini::kIniStructMagic) + { + throw fnd::Exception(kModuleName, "INI header corrupt (unrecognised header signature)"); + } + + // check KIP num + if (hdr->kip_num.get() > ini::kMaxKipNum) + { + throw fnd::Exception(kModuleName, "INI header corrupt (too many KIPs)"); + } + + // save variables + mSize = hdr->size.get(); + mKipNum = hdr->kip_num.get(); +} + +const fnd::Vec& nn::hac::IniHeader::getBytes() const +{ + return mRawBinary; +} + +void nn::hac::IniHeader::clear() +{ + mRawBinary.clear(); + mSize = 0; + mKipNum = 0; +} + +uint32_t nn::hac::IniHeader::getSize() const +{ + return mSize; +} + +void nn::hac::IniHeader::setSize(uint32_t size) +{ + mSize = size; +} + +uint32_t nn::hac::IniHeader::getKipNum() const +{ + return mKipNum; +} + +void nn::hac::IniHeader::setKipNum(uint32_t num) +{ + mKipNum = num; +} \ No newline at end of file diff --git a/lib/libhac/source/KernelInitialProcessHeader.cpp b/lib/libhac/source/KernelInitialProcessHeader.cpp new file mode 100644 index 0000000..988c95e --- /dev/null +++ b/lib/libhac/source/KernelInitialProcessHeader.cpp @@ -0,0 +1,341 @@ +#include + +nn::hac::KernelInitialProcessHeader::KernelInitialProcessHeader() +{ + clear(); +} + +nn::hac::KernelInitialProcessHeader::KernelInitialProcessHeader(const KernelInitialProcessHeader& other) +{ + *this = other; +} + +void nn::hac::KernelInitialProcessHeader::operator=(const KernelInitialProcessHeader& other) +{ + clear(); + this->mName = other.mName; + this->mTitleId = other.mTitleId; + this->mProcessCategory = other.mProcessCategory; + this->mFlagList = other.mFlagList; + this->mMainThreadPriority = other.mMainThreadPriority; + this->mMainThreadCpuId = other.mMainThreadCpuId; + this->mMainThreadStackSize = other.mMainThreadStackSize; + this->mTextInfo = other.mTextInfo; + this->mRoInfo = other.mRoInfo; + this->mDataInfo = other.mDataInfo; + this->mBssSize = other.mBssSize; + this->mKernelCapabilities = other.mKernelCapabilities; +} + +bool nn::hac::KernelInitialProcessHeader::operator==(const KernelInitialProcessHeader& other) const +{ + return (this->mName == other.mName) \ + && (this->mTitleId == other.mTitleId) \ + && (this->mProcessCategory == other.mProcessCategory) \ + && (this->mFlagList == other.mFlagList) \ + && (this->mMainThreadPriority == other.mMainThreadPriority) \ + && (this->mMainThreadCpuId == other.mMainThreadCpuId) \ + && (this->mMainThreadStackSize == other.mMainThreadStackSize) \ + && (this->mTextInfo == other.mTextInfo) \ + && (this->mRoInfo == other.mRoInfo) \ + && (this->mDataInfo == other.mDataInfo) \ + && (this->mBssSize == other.mBssSize) \ + && (this->mKernelCapabilities == other.mKernelCapabilities); +} + +bool nn::hac::KernelInitialProcessHeader::operator!=(const KernelInitialProcessHeader& other) const +{ + return !(*this == other); +} + +void nn::hac::KernelInitialProcessHeader::toBytes() +{ + mRawBinary.alloc(sizeof(sKipHeader)); + nn::hac::sKipHeader* hdr = (nn::hac::sKipHeader*)mRawBinary.data(); + + // set header identifers + hdr->st_magic = kip::kKipStructMagic; + + // variable to store flags before commiting to header + byte_t flags = 0; + + // properties + strncpy(hdr->name, mName.c_str(), kip::kNameMaxLen); + hdr->title_id = mTitleId; + hdr->process_category = mProcessCategory; + hdr->main_thread_priority = mMainThreadPriority; + hdr->main_thread_cpu_id = mMainThreadCpuId; + hdr->main_thread_stack_size = mMainThreadStackSize; + + // kernel caps + mKernelCapabilities.toBytes(); + if (mKernelCapabilities.getBytes().size() > kip::kKernCapabilitySize) + { + throw fnd::Exception(kModuleName, "Too many kernel capabilities"); + } + memcpy(hdr->capabilities, mKernelCapabilities.getBytes().data(), mKernelCapabilities.getBytes().size()); + //memset(hdr->capabilities + mKernelCapabilities.getBytes().size(), 0xff, kip::kKernCapabilitySize - mKernelCapabilities.getBytes().size()); + + // flags + for (size_t i = 0; i < mFlagList.size(); i++) + { + switch(mFlagList[i]) + { + case (kip::FLAG_TEXT_COMPRESS) : + case (kip::FLAG_RO_COMPRESS) : + case (kip::FLAG_DATA_COMPRESS) : + break; + default: + flags |= _BIT(mFlagList[i] & 7); + break; + } + } + + // set bss size + hdr->bss.file_size = 0; + hdr->bss.memory_offset = 0; + hdr->bss.memory_size = mBssSize; + + // set text segment + hdr->text.memory_offset = mTextInfo.memory_layout.offset; + hdr->text.memory_size = mTextInfo.memory_layout.size; + hdr->text.file_size = mTextInfo.file_layout.size; + if (mTextInfo.is_compressed) + { + flags |= _BIT(kip::FLAG_TEXT_COMPRESS); + } + + // set ro segment + hdr->ro.memory_offset = mRoInfo.memory_layout.offset; + hdr->ro.memory_size = mRoInfo.memory_layout.size; + hdr->ro.file_size = mRoInfo.file_layout.size; + if (mRoInfo.is_compressed) + { + flags |= _BIT(kip::FLAG_TEXT_COMPRESS); + } + + // set data segment + hdr->data.memory_offset = mDataInfo.memory_layout.offset; + hdr->data.memory_size = mDataInfo.memory_layout.size; + hdr->data.file_size = mDataInfo.file_layout.size; + if (mDataInfo.is_compressed) + { + flags |= _BIT(kip::FLAG_TEXT_COMPRESS); + } + + hdr->flags = flags; +} + +void nn::hac::KernelInitialProcessHeader::fromBytes(const byte_t* data, size_t len) +{ + // check input data size + if (len < sizeof(sKipHeader)) + { + throw fnd::Exception(kModuleName, "KIP header size is too small"); + } + + // clear internal members + clear(); + + // allocate internal local binary copy + mRawBinary.alloc(sizeof(sKipHeader)); + memcpy(mRawBinary.data(), data, mRawBinary.size()); + + // get sKipHeader ptr + const nn::hac::sKipHeader* hdr = (const nn::hac::sKipHeader*)mRawBinary.data(); + + // check KIP signature + if (hdr->st_magic.get() != kip::kKipStructMagic) + { + throw fnd::Exception(kModuleName, "KIP header corrupt (unrecognised header signature)"); + } + + // properties + if (hdr->name[0] != 0) + mName = std::string(hdr->name, _MIN(strlen(hdr->name), kip::kNameMaxLen)); + mTitleId = hdr->title_id.get(); + mProcessCategory = (kip::ProcessCategory)hdr->process_category.get(); + mMainThreadPriority = hdr->main_thread_priority; + mMainThreadCpuId = hdr->main_thread_cpu_id; + mMainThreadStackSize = hdr->main_thread_stack_size.get(); + mKernelCapabilities.fromBytes(hdr->capabilities, kip::kKernCapabilitySize); + + for (byte_t i = 0; i < 8; i++) + { + if (_HAS_BIT(hdr->flags, i)) + { + switch(i) + { + case (kip::FLAG_TEXT_COMPRESS) : + case (kip::FLAG_RO_COMPRESS) : + case (kip::FLAG_DATA_COMPRESS) : + break; + default: + mFlagList.addElement((kip::HeaderFlags)i); + break; + } + } + } + + // code segment info + mTextInfo.file_layout.offset = sizeof(sKipHeader); + mTextInfo.file_layout.size = hdr->text.file_size.get(); + mTextInfo.memory_layout.offset = hdr->text.memory_offset.get(); + mTextInfo.memory_layout.size = hdr->text.memory_size.get(); + mTextInfo.is_compressed = _HAS_BIT(hdr->flags, kip::FLAG_TEXT_COMPRESS); + + mRoInfo.file_layout.offset = mTextInfo.file_layout.offset + mTextInfo.file_layout.size; + mRoInfo.file_layout.size = hdr->ro.file_size.get(); + mRoInfo.memory_layout.offset = hdr->ro.memory_offset.get(); + mRoInfo.memory_layout.size = hdr->ro.memory_size.get(); + mRoInfo.is_compressed = _HAS_BIT(hdr->flags, kip::FLAG_RO_COMPRESS); + + mDataInfo.file_layout.offset = mRoInfo.file_layout.offset + mRoInfo.file_layout.size; + mDataInfo.file_layout.size = hdr->data.file_size.get(); + mDataInfo.memory_layout.offset = hdr->data.memory_offset.get(); + mDataInfo.memory_layout.size = hdr->data.memory_size.get(); + mDataInfo.is_compressed = _HAS_BIT(hdr->flags, kip::FLAG_DATA_COMPRESS); + + mBssSize = hdr->bss.memory_size.get(); +} + +const fnd::Vec& nn::hac::KernelInitialProcessHeader::getBytes() const +{ + return mRawBinary; +} + +void nn::hac::KernelInitialProcessHeader::clear() +{ + mRawBinary.clear(); + mName.clear(); + mTitleId = 0; + mProcessCategory = (kip::ProcessCategory)0; + mFlagList.clear(); + mMainThreadPriority = 0; + mMainThreadCpuId = 0; + mMainThreadStackSize = 0; + mTextInfo = sCodeSegment(); + mRoInfo = sCodeSegment(); + mDataInfo = sCodeSegment(); + mBssSize = 0; + mKernelCapabilities.clear();; +} + +const std::string& nn::hac::KernelInitialProcessHeader::getName() const +{ + return mName; +} + +void nn::hac::KernelInitialProcessHeader::setName(const std::string& name) +{ + mName = name; +} + +uint64_t nn::hac::KernelInitialProcessHeader::getTitleId() const +{ + return mTitleId; +} + +void nn::hac::KernelInitialProcessHeader::setTitleId(uint64_t title_id) +{ + mTitleId = title_id; +} + +nn::hac::kip::ProcessCategory nn::hac::KernelInitialProcessHeader::getProcessCategory() const +{ + return mProcessCategory; +} + +void nn::hac::KernelInitialProcessHeader::setProcessCategory(kip::ProcessCategory cat) +{ + mProcessCategory = cat; +} + +const fnd::List& nn::hac::KernelInitialProcessHeader::getFlagList() const +{ + return mFlagList; +} +void nn::hac::KernelInitialProcessHeader::setFlagList(const fnd::List& flags) +{ + mFlagList = flags; +} + +byte_t nn::hac::KernelInitialProcessHeader::getMainThreadPriority() const +{ + return mMainThreadPriority; +} + +void nn::hac::KernelInitialProcessHeader::setMainThreadPriority(byte_t priority) +{ + mMainThreadPriority = priority; +} + +byte_t nn::hac::KernelInitialProcessHeader::getMainThreadCpuId() const +{ + return mMainThreadCpuId; +} + +void nn::hac::KernelInitialProcessHeader::setMainThreadCpuId(byte_t cpu_id) +{ + mMainThreadCpuId = cpu_id; +} + +uint32_t nn::hac::KernelInitialProcessHeader::getMainThreadStackSize() const +{ + return mMainThreadStackSize; +} + +void nn::hac::KernelInitialProcessHeader::setMainThreadStackSize(uint32_t size) +{ + mMainThreadStackSize = size; +} + +const nn::hac::KernelInitialProcessHeader::sCodeSegment& nn::hac::KernelInitialProcessHeader::getTextSegmentInfo() const +{ + return mTextInfo; +} + +void nn::hac::KernelInitialProcessHeader::setTextSegmentInfo(const sCodeSegment& info) +{ + mTextInfo = info; +} + +const nn::hac::KernelInitialProcessHeader::sCodeSegment& nn::hac::KernelInitialProcessHeader::getRoSegmentInfo() const +{ + return mRoInfo; +} + +void nn::hac::KernelInitialProcessHeader::setRoSegmentInfo(const sCodeSegment& info) +{ + mRoInfo = info; +} + +const nn::hac::KernelInitialProcessHeader::sCodeSegment& nn::hac::KernelInitialProcessHeader::getDataSegmentInfo() const +{ + return mDataInfo; +} + +void nn::hac::KernelInitialProcessHeader::setDataSegmentInfo(const sCodeSegment& info) +{ + mDataInfo = info; +} + +uint32_t nn::hac::KernelInitialProcessHeader::getBssSize() const +{ + return mBssSize; +} + +void nn::hac::KernelInitialProcessHeader::setBssSize(uint32_t size) +{ + mBssSize = size; +} + +const nn::hac::KernelCapabilityControl& nn::hac::KernelInitialProcessHeader::getKernelCapabilities() const +{ + return mKernelCapabilities; +} + +void nn::hac::KernelInitialProcessHeader::setKernelCapabilities(const KernelCapabilityControl& kc) +{ + mKernelCapabilities = kc; +} \ No newline at end of file