Long overdue clang-format pass on most of the project (#773)
Some checks are pending
Android Build / x64 (release) (push) Waiting to run
Android Build / arm64 (release) (push) Waiting to run
HTTP Server Build / build (push) Waiting to run
Hydra Core Build / Windows (push) Waiting to run
Hydra Core Build / MacOS (push) Waiting to run
Hydra Core Build / Linux (push) Waiting to run
Hydra Core Build / Android-x64 (push) Waiting to run
Hydra Core Build / ARM-Libretro (push) Waiting to run
Linux AppImage Build / build (push) Waiting to run
Linux Build / build (push) Waiting to run
MacOS Build / MacOS-arm64 (push) Waiting to run
MacOS Build / MacOS-x86_64 (push) Waiting to run
MacOS Build / MacOS-Universal (push) Blocked by required conditions
Qt Build / Windows (push) Waiting to run
Qt Build / MacOS-arm64 (push) Waiting to run
Qt Build / MacOS-x86_64 (push) Waiting to run
Qt Build / MacOS-Universal (push) Blocked by required conditions
Qt Build / Linux (push) Waiting to run
Windows Build / build (push) Waiting to run
iOS Simulator Build / build (push) Waiting to run

This commit is contained in:
wheremyfoodat 2025-07-06 18:25:20 +03:00 committed by GitHub
parent d1f4ae2911
commit 8e20bd6220
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
65 changed files with 13445 additions and 26224 deletions

View file

@ -1,12 +1,12 @@
#include "memory.hpp"
#include <cstring>
#include "elfio/elfio.hpp"
#include "memory.hpp"
using namespace ELFIO;
std::optional<u32> Memory::loadELF(std::ifstream& file) {
loadedCXI = std::nullopt; // ELF files don't have a CXI, so set this to null
loadedCXI = std::nullopt; // ELF files don't have a CXI, so set this to null
elfio reader;
if (!file.good() || !reader.load(file)) {
@ -14,56 +14,56 @@ std::optional<u32> Memory::loadELF(std::ifstream& file) {
return std::nullopt;
}
// Allocate stack space. For ELFs we use the default stack size, which is 16KB
// Allocate stack space. For ELFs we use the default stack size, which is 16KB
if (!allocateMainThreadStack(VirtualAddrs::DefaultStackSize)) {
// Should be unreachable
printf("Failed to allocate stack space for ELF file\n");
return std::nullopt;
}
auto segNum = reader.segments.size();
printf("Number of segments: %d\n", segNum);
printf(" # Perms Vaddr File Size Mem Size\n");
for (int i = 0; i < segNum; ++i) {
const auto seg = reader.segments[i];
const auto flags = seg->get_flags();
const u32 vaddr = static_cast<u32>(seg->get_virtual_address()); // Vaddr the segment is loaded in
u32 fileSize = static_cast<u32>(seg->get_file_size()); // Size of segment in file
u32 memorySize = static_cast<u32>(seg->get_memory_size()); // Size of segment in memory
u8* data = (u8*)seg->get_data();
auto segNum = reader.segments.size();
printf("Number of segments: %d\n", segNum);
printf(" # Perms Vaddr File Size Mem Size\n");
for (int i = 0; i < segNum; ++i) {
const auto seg = reader.segments[i];
const auto flags = seg->get_flags();
const u32 vaddr = static_cast<u32>(seg->get_virtual_address()); // Vaddr the segment is loaded in
u32 fileSize = static_cast<u32>(seg->get_file_size()); // Size of segment in file
u32 memorySize = static_cast<u32>(seg->get_memory_size()); // Size of segment in memory
u8* data = (u8*)seg->get_data();
// Get read/write/execute permissions for segment
const bool r = (flags & 0b100) != 0;
const bool w = (flags & 0b010) != 0;
const bool x = (flags & 0b001) != 0;
// Get read/write/execute permissions for segment
const bool r = (flags & 0b100) != 0;
const bool w = (flags & 0b010) != 0;
const bool x = (flags & 0b001) != 0;
printf("[%d] (%c%c%c)\t%08X\t%08X\t%08X\n", i, r ? 'r' : '-', w ? 'w' : '-', x ? 'x' : '-', vaddr, fileSize, memorySize);
// Assert that the segment will be loaded in the executable region. If it isn't then panic.
// The executable region starts at 0x00100000 and has a maximum size of 0x03F00000
u64 endAddress = (u64)vaddr + (u64)fileSize;
const bool isGood = vaddr >= VirtualAddrs::ExecutableStart && endAddress < VirtualAddrs::ExecutableEnd;
if (!isGood) {
// We're ignoring this for now because some ELFs define a segment at the vaddr for IPC buffer mapping
// Helpers::panic("ELF is loaded at invalid place");
// return std::nullopt;
}
printf("[%d] (%c%c%c)\t%08X\t%08X\t%08X\n", i, r ? 'r' : '-', w ? 'w' : '-', x ? 'x' : '-', vaddr, fileSize, memorySize);
if (memorySize & pageMask) {
// Round up the size of the ELF segment to a page (4KB) boundary, as the OS can only alloc this way
memorySize = (memorySize + pageSize - 1) & -pageSize;
Helpers::warn("Rounding ELF segment size to %08X\n", memorySize);
}
// Assert that the segment will be loaded in the executable region. If it isn't then panic.
// The executable region starts at 0x00100000 and has a maximum size of 0x03F00000
u64 endAddress = (u64)vaddr + (u64)fileSize;
const bool isGood = vaddr >= VirtualAddrs::ExecutableStart && endAddress < VirtualAddrs::ExecutableEnd;
if (!isGood) {
// We're ignoring this for now because some ELFs define a segment at the vaddr for IPC buffer mapping
// Helpers::panic("ELF is loaded at invalid place");
// return std::nullopt;
}
// This should also assert that findPaddr doesn't fail
u32 fcramAddr = findPaddr(memorySize).value();
std::memcpy(&fcram[fcramAddr], data, fileSize);
if (memorySize & pageMask) {
// Round up the size of the ELF segment to a page (4KB) boundary, as the OS can only alloc this way
memorySize = (memorySize + pageSize - 1) & -pageSize;
Helpers::warn("Rounding ELF segment size to %08X\n", memorySize);
}
// Allocate the segment on the OS side
allocateMemory(vaddr, fcramAddr, memorySize, true, r, w, x);
}
// This should also assert that findPaddr doesn't fail
u32 fcramAddr = findPaddr(memorySize).value();
std::memcpy(&fcram[fcramAddr], data, fileSize);
// ELF can't specify a region, make it default to USA
region = Regions::USA;
return static_cast<u32>(reader.get_entry());
// Allocate the segment on the OS side
allocateMemory(vaddr, fcramAddr, memorySize, true, r, w, x);
}
// ELF can't specify a region, make it default to USA
region = Regions::USA;
return static_cast<u32>(reader.get_entry());
}

View file

@ -1,79 +1,76 @@
#include "loader/lz77.hpp"
#include <algorithm>
#include <cstring>
#include "loader/lz77.hpp"
// The difference in size between the compressed and decompressed file is stored
// As a footer in the compressed file. To get the decompressed size, we extract the diff
// And add it to the compressed size
u32 CartLZ77::decompressedSize(const u8* buffer, u32 compressedSize) {
u32 sizeDiff;
std::memcpy(&sizeDiff, buffer + compressedSize - 4, sizeof(u32));
return sizeDiff + compressedSize;
u32 sizeDiff;
std::memcpy(&sizeDiff, buffer + compressedSize - 4, sizeof(u32));
return sizeDiff + compressedSize;
}
bool CartLZ77::decompress(std::vector<u8>& output, const std::vector<u8>& input) {
u32 sizeCompressed = u32(input.size() * sizeof(u8));
u32 sizeDecompressed = decompressedSize(input);
output.resize(sizeDecompressed);
u32 sizeCompressed = u32(input.size() * sizeof(u8));
u32 sizeDecompressed = decompressedSize(input);
output.resize(sizeDecompressed);
const u8* compressed = (u8*)input.data();
const u8* footer = compressed + sizeCompressed - 8;
const u8* compressed = (u8*)input.data();
const u8* footer = compressed + sizeCompressed - 8;
u32 bufferTopAndBottom;
std::memcpy(&bufferTopAndBottom, footer, sizeof(u32));
u32 bufferTopAndBottom;
std::memcpy(&bufferTopAndBottom, footer, sizeof(u32));
u32 out = sizeDecompressed; // TODO: Is this meant to be u32 or s32?
u32 index = sizeCompressed - (Helpers::getBits<24, 8>(bufferTopAndBottom));
u32 stopIndex = sizeCompressed - (bufferTopAndBottom & 0xffffff);
u32 out = sizeDecompressed; // TODO: Is this meant to be u32 or s32?
u32 index = sizeCompressed - (Helpers::getBits<24, 8>(bufferTopAndBottom));
u32 stopIndex = sizeCompressed - (bufferTopAndBottom & 0xffffff);
// Set all of the decompressed buffer to 0 and copy the compressed buffer to the start of it
std::fill(output.begin(), output.end(), 0);
std::copy(input.begin(), input.end(), output.begin());
// Set all of the decompressed buffer to 0 and copy the compressed buffer to the start of it
std::fill(output.begin(), output.end(), 0);
std::copy(input.begin(), input.end(), output.begin());
while (index > stopIndex) {
u8 control = compressed[--index];
while (index > stopIndex) {
u8 control = compressed[--index];
for (uint i = 0; i < 8; i++) {
if (index <= stopIndex)
break;
if (index <= 0)
break;
if (out <= 0)
break;
for (uint i = 0; i < 8; i++) {
if (index <= stopIndex) break;
if (index <= 0) break;
if (out <= 0) break;
if (control & 0x80) {
// Check if compression is out of bounds
if (index < 2)
return false;
index -= 2;
if (control & 0x80) {
// Check if compression is out of bounds
if (index < 2) {
return false;
}
index -= 2;
u32 segmentOffset = compressed[index] | (compressed[index + 1] << 8);
u32 segment_size = (Helpers::getBits<12, 4>(segmentOffset)) + 3;
segmentOffset &= 0x0FFF;
segmentOffset += 2;
u32 segmentOffset = compressed[index] | (compressed[index + 1] << 8);
u32 segment_size = (Helpers::getBits<12, 4>(segmentOffset)) + 3;
segmentOffset &= 0x0FFF;
segmentOffset += 2;
// Check if compression is out of bounds
if (out < segment_size)
return false;
// Check if compression is out of bounds
if (out < segment_size) return false;
for (uint j = 0; j < segment_size; j++) {
// Check if compression is out of bounds
if (out + segmentOffset >= sizeDecompressed)
return false;
for (uint j = 0; j < segment_size; j++) {
// Check if compression is out of bounds
if (out + segmentOffset >= sizeDecompressed) return false;
u8 data = output[out + segmentOffset];
output[--out] = data;
}
}
else {
// Check if compression is out of bounds
if (out < 1)
return false;
output[--out] = compressed[--index];
}
control <<= 1;
}
}
u8 data = output[out + segmentOffset];
output[--out] = data;
}
} else {
// Check if compression is out of bounds
if (out < 1) {
return false;
}
output[--out] = compressed[--index];
}
control <<= 1;
}
}
return true;
return true;
}

View file

@ -11,7 +11,7 @@ bool Memory::mapCXI(NCSD& ncsd, NCCH& cxi) {
printf("Data address = %08X, size = %08X\n", cxi.data.address, cxi.data.size);
printf("Stack size: %08X\n", cxi.stackSize);
static constexpr std::array<const char*, 7> regionNames = {"Japan", "North America", "Europe", "Australia", "China", "Korea", "Taiwan" };
static constexpr std::array<const char*, 7> regionNames = {"Japan", "North America", "Europe", "Australia", "China", "Korea", "Taiwan"};
// Set autodetected 3DS region to one of the values allowed by the CXI's SMDH
region = cxi.region.value();