Implement real BKTR support

This commit is contained in:
Michael Scire 2018-03-31 16:43:59 -06:00
parent a93a926345
commit 3d12b43f7b
4 changed files with 72 additions and 29 deletions

47
bktr.c
View file

@ -4,23 +4,31 @@
/* Get a relocation entry from offset and relocation block. */
bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uint64_t offset) {
/* Weak check for invalid offset. */
if (offset > block->patch_romfs_size) {
if (offset > block->total_size) {
fprintf(stderr, "Too big offset looked up in BKTR relocation table!\n");
exit(EXIT_FAILURE);
}
if (block->num_entries == 1) { /* Check for edge case, short circuit. */
return &block->entries[0];
bktr_relocation_bucket_t *bucket = &block->buckets[0];
for (unsigned int i = 1; i < block->num_buckets; i++) {
if (block->bucket_virtual_offsets[i] < offset) {
bucket++;
}
}
if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */
return &bucket->entries[0];
}
/* Binary search. */
uint32_t low = 0, high = block->num_entries - 1;
uint32_t low = 0, high = bucket->num_entries - 1;
while (low <= high) {
uint32_t mid = (low + high) / 2;
if (block->entries[mid].virt_offset > offset) { /* Too high. */
if (bucket->entries[mid].virt_offset > offset) { /* Too high. */
high = mid - 1;
} else { /* block->entries[mid].offset <= offset. */
/* Check for success. */
if (mid == block->num_entries - 1 || block->entries[mid+1].virt_offset > offset) {
return &block->entries[mid];
if (mid == bucket->num_entries - 1 || bucket->entries[mid+1].virt_offset > offset) {
return &bucket->entries[mid];
}
low = mid + 1;
}
@ -32,22 +40,31 @@ bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uin
/* Get a subsection entry from offset and subsection block .*/
bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uint64_t offset) {
/* If offset is past the virtual, we're reading from the BKTR_HEADER subsection. */
if (offset >= block->entries[block->num_entries].offset) {
return &block->entries[block->num_entries];
if (offset >= block->buckets[block->num_buckets - 1].entries[block->buckets[block->num_buckets - 1].num_entries].offset) {
return &block->buckets[block->num_buckets - 1].entries[block->buckets[block->num_buckets - 1].num_entries];
}
if (block->num_entries == 1) { /* Check for edge case, short circuit. */
return &block->entries[0];
bktr_subsection_bucket_t *bucket = &block->buckets[0];
for (unsigned int i = 1; i < block->num_buckets; i++) {
if (block->bucket_physical_offsets[i] < offset) {
bucket++;
}
}
if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */
return &bucket->entries[0];
}
/* Binary search. */
uint32_t low = 0, high = block->num_entries - 1;
uint32_t low = 0, high = bucket->num_entries - 1;
while (low <= high) {
uint32_t mid = (low + high) / 2;
if (block->entries[mid].offset > offset) { /* Too high. */
if (bucket->entries[mid].offset > offset) { /* Too high. */
high = mid - 1;
} else { /* block->entries[mid].offset <= offset. */
/* Check for success. */
if (mid == block->num_entries - 1 || block->entries[mid+1].offset > offset) {
return &block->entries[mid];
if (mid == bucket->num_entries - 1 || bucket->entries[mid+1].offset > offset) {
return &bucket->entries[mid];
}
low = mid + 1;
}

33
bktr.h
View file

@ -24,10 +24,21 @@ typedef struct {
#pragma pack(push, 1)
typedef struct {
uint8_t _0x0[0x4004]; /* lol. */
uint32_t _0x0;
uint32_t num_entries;
uint64_t patch_romfs_size;
bktr_relocation_entry_t entries[];
uint64_t virtual_offset_end;
bktr_relocation_entry_t entries[0x3FF0/sizeof(bktr_relocation_entry_t)];
uint8_t padding[0x3FF0 % sizeof(bktr_relocation_entry_t)];
} bktr_relocation_bucket_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct {
uint32_t _0x0;
uint32_t num_buckets;
uint64_t total_size;
uint64_t bucket_virtual_offsets[0x3FF0/sizeof(uint64_t)];
bktr_relocation_bucket_t buckets[];
} bktr_relocation_block_t;
#pragma pack(pop)
@ -41,10 +52,20 @@ typedef struct {
#pragma pack(push, 1)
typedef struct {
uint8_t _0x0[0x4004]; /* lol. */
uint32_t _0x0;
uint32_t num_entries;
uint64_t bktr_entry_offset;
bktr_subsection_entry_t entries[];
uint64_t physical_offset_end;
bktr_subsection_entry_t entries[0x3FF];
} bktr_subsection_bucket_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct {
uint32_t _0x0;
uint32_t num_buckets;
uint64_t total_size;
uint64_t bucket_physical_offsets[0x3FF0/sizeof(uint64_t)];
bktr_subsection_bucket_t buckets[];
} bktr_subsection_block_t;
#pragma pack(pop)

View file

@ -9,6 +9,10 @@
#include "ConvertUTF.h"
#ifdef _WIN32
#include <wchar.h>
#endif
void os_strcpy(oschar_t *dst, const char *src) {
#ifdef _WIN32
if (src == NULL) return;

17
nca.c
View file

@ -947,7 +947,7 @@ void nca_process_bktr_section(nca_section_ctx_t *ctx) {
ctx->bktr_ctx.relocation_block = relocs;
ctx->bktr_ctx.subsection_block = subs;
if (ctx->bktr_ctx.subsection_block->bktr_entry_offset != sb->subsection_header.offset) {
if (ctx->bktr_ctx.subsection_block->total_size != sb->subsection_header.offset) {
free(relocs);
free(subs);
ctx->bktr_ctx.relocation_block = NULL;
@ -957,12 +957,13 @@ void nca_process_bktr_section(nca_section_ctx_t *ctx) {
}
/* This simplifies logic greatly... */
ctx->bktr_ctx.relocation_block->entries[ctx->bktr_ctx.relocation_block->num_entries].virt_offset = ctx->bktr_ctx.relocation_block->patch_romfs_size;
ctx->bktr_ctx.subsection_block->entries[ctx->bktr_ctx.subsection_block->num_entries].offset = sb->relocation_header.offset;
ctx->bktr_ctx.subsection_block->entries[ctx->bktr_ctx.subsection_block->num_entries].ctr_val = ctx->header->section_ctr_low;
ctx->bktr_ctx.subsection_block->entries[ctx->bktr_ctx.subsection_block->num_entries + 1].offset = ctx->size;
ctx->bktr_ctx.subsection_block->entries[ctx->bktr_ctx.subsection_block->num_entries + 1].ctr_val = 0;
bktr_relocation_bucket_t *last_reloc_bucket = &ctx->bktr_ctx.relocation_block->buckets[ctx->bktr_ctx.relocation_block->num_buckets - 1];
bktr_subsection_bucket_t *last_subsec_bucket = &ctx->bktr_ctx.subsection_block->buckets[ctx->bktr_ctx.subsection_block->num_buckets - 1];
last_reloc_bucket->entries[last_reloc_bucket->num_entries].virt_offset = ctx->bktr_ctx.relocation_block->total_size;
last_subsec_bucket->entries[last_subsec_bucket->num_entries].offset = sb->relocation_header.offset;
last_subsec_bucket->entries[last_subsec_bucket->num_entries].ctr_val = ctx->header->section_ctr_low;
last_subsec_bucket->entries[last_subsec_bucket->num_entries + 1].offset = ctx->size;
last_subsec_bucket->entries[last_subsec_bucket->num_entries + 1].ctr_val = 0;
/* Now parse out the romfs stuff. */
for (unsigned int i = 0; i < IVFC_MAX_LEVEL; i++) {
@ -1156,7 +1157,7 @@ void nca_save_section(nca_section_ctx_t *ctx) {
break;
}
} else if (ctx->type == BKTR && ctx->bktr_ctx.subsection_block != NULL && ctx->tool_ctx->base_file != NULL) {
size = ctx->bktr_ctx.relocation_block->patch_romfs_size;
size = ctx->bktr_ctx.relocation_block->total_size;
}
/* Extract to file. */