Skip to content

Commit

Permalink
Add NDS overlays sections and updated nds header. (#4570)
Browse files Browse the repository at this point in the history
  • Loading branch information
wargio committed Jul 17, 2024
1 parent e878181 commit 2b4aa53
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 27 deletions.
37 changes: 27 additions & 10 deletions librz/bin/format/nin/nds.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
// SPDX-FileCopyrightText: 2022-2024 deroad <[email protected]>
// SPDX-FileCopyrightText: 2014 Alberto Ortega
// SPDX-License-Identifier: LGPL-3.0-only

/*
http://dsibrew.org/wiki/NDS_Format
http://sourceforge.net/p/devkitpro/ndstool/ci/master/tree/source/header.h
https://dsibrew.org/wiki/DSi_cartridge_header
*/

#ifndef NIN_NDS_H
#define NIN_NDS_H

#include <rz_types_base.h>

typedef struct nds_overlay_table_entry_t {
ut32 id;
ut32 load_address;
ut32 ram_size;
ut32 bss_size;
ut32 static_initializer_start_address;
ut32 static_initializer_end_address;
ut32 file_id;
ut32 reserved;
} NDSOverlayTblEntry;

typedef struct nds_file_alloc_table_entry_t {
ut32 file_start_offset;
ut32 file_end_offset;
} NDSFatEntry;

typedef struct nds_header_t {
st8 title[0xC];
st8 gamecode[0x4];
Expand All @@ -29,10 +47,10 @@ typedef struct nds_header_t {
ut32 arm7_entry_address;
ut32 arm7_ram_address;
ut32 arm7_size;
ut32 fnt_offset;
ut32 fnt_size;
ut32 fat_offset;
ut32 fat_size;
ut32 fnt_offset; ///< Filename Table Offset
ut32 fnt_size; ///< Filename Table Size
ut32 fat_offset; ///< File Allocaton Table Offset
ut32 fat_size; ///< File Allocaton Table Size
ut32 arm9_overlay_offset;
ut32 arm9_overlay_size;
ut32 arm7_overlay_offset;
Expand All @@ -41,12 +59,11 @@ typedef struct nds_header_t {
ut32 rom_control_info2;
ut32 banner_offset;
ut16 secure_area_crc;
ut16 rom_control_info3;
ut32 offset_0x70;
ut32 offset_0x74;
ut32 offset_0x78;
ut32 offset_0x7C;
ut32 application_end_offset;
ut16 secure_transfer_timeout;
ut32 arm9_autoload;
ut32 arm7_autoload;
ut64 secure_disable;
ut32 ntr_region_rom_size;
ut32 rom_header_size;
ut32 offset_0x88;
ut32 offset_0x8C;
Expand Down
166 changes: 149 additions & 17 deletions librz/bin/p/bin_ninds.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 deroad <[email protected]>
// SPDX-FileCopyrightText: 2022-2024 deroad <[email protected]>
// SPDX-FileCopyrightText: 2015-2019 a0rtega
// SPDX-License-Identifier: LGPL-3.0-only

Expand All @@ -10,7 +10,75 @@

#include "../format/nin/nds.h"

#define nds_get_hdr(bf) ((NDSHeader *)bf->o->bin_obj)
typedef struct nds_rom_t {
NDSHeader header;
RzPVector /*<NDSFatEntry *>*/ *fat_table;
RzPVector /*<NDSOverlayTblEntry *>*/ *arm9_overlays;
RzPVector /*<NDSOverlayTblEntry *>*/ *arm7_overlays;
} NDSRom;

#define nds_get_rom(bf) ((NDSRom *)bf->o->bin_obj)
#define nds_get_hdr(bf) (&nds_get_rom(bf)->header)

static bool nds_read_overlay_entry(RzBuffer *buf, NDSOverlayTblEntry *entry, ut64 *offset) {
return rz_buf_read_le32_offset(buf, offset, &entry->id) &&
rz_buf_read_le32_offset(buf, offset, &entry->load_address) &&
rz_buf_read_le32_offset(buf, offset, &entry->ram_size) &&
rz_buf_read_le32_offset(buf, offset, &entry->bss_size) &&
rz_buf_read_le32_offset(buf, offset, &entry->static_initializer_start_address) &&
rz_buf_read_le32_offset(buf, offset, &entry->static_initializer_end_address) &&
rz_buf_read_le32_offset(buf, offset, &entry->file_id) &&
rz_buf_read_le32_offset(buf, offset, &entry->reserved);
}

static bool nds_read_overlay_table(RzBuffer *buf, RzPVector /*<NDSOverlayTblEntry *>*/ *table, ut32 offset_begin, ut32 size) {
if (!buf || !table) {
rz_warn_if_reached();
return false;
} else if (offset_begin < 1 || size < 1) {
return true;
}
ut64 offset_end = offset_begin + size;
for (ut64 offset = offset_begin; offset < offset_end;) {
NDSOverlayTblEntry *entry = RZ_NEW0(NDSOverlayTblEntry);
if (!entry || !nds_read_overlay_entry(buf, entry, &offset)) {
free(entry);
rz_warn_if_reached();
return false;
}
rz_pvector_push(table, entry);
}

return true;
}

static bool nds_read_file_alloc_entry(RzBuffer *buf, NDSFatEntry *entry, ut64 *offset) {
// these addresses are relative to the beginning of the file.
// https://problemkaputt.de/gbatek-ds-cartridge-nitrorom-and-nitroarc-file-systems.htm
return rz_buf_read_le32_offset(buf, offset, &entry->file_start_offset) &&
rz_buf_read_le32_offset(buf, offset, &entry->file_end_offset);
}

static bool nds_read_file_alloc_table(RzBuffer *buf, RzPVector /*<NDSFatEntry *>*/ *table, NDSHeader *header) {
if (!buf || !table) {
rz_warn_if_reached();
return false;
} else if (header->fat_offset < 1 || header->fat_size < 1) {
return true;
}
ut64 offset_end = header->fat_offset + header->fat_size;
for (ut64 offset = header->fat_offset; offset < offset_end;) {
NDSFatEntry *entry = RZ_NEW0(NDSFatEntry);
if (!entry || !nds_read_file_alloc_entry(buf, entry, &offset)) {
free(entry);
rz_warn_if_reached();
return false;
}
rz_pvector_push(table, entry);
}

return true;
}

static bool nds_read_header(RzBuffer *buf, NDSHeader *hdr) {
ut64 offset = 0;
Expand Down Expand Up @@ -43,12 +111,11 @@ static bool nds_read_header(RzBuffer *buf, NDSHeader *hdr) {
rz_buf_read_le32_offset(buf, &offset, &hdr->rom_control_info2) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->banner_offset) &&
rz_buf_read_le16_offset(buf, &offset, &hdr->secure_area_crc) &&
rz_buf_read_le16_offset(buf, &offset, &hdr->rom_control_info3) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->offset_0x70) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->offset_0x74) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->offset_0x78) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->offset_0x7C) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->application_end_offset) &&
rz_buf_read_le16_offset(buf, &offset, &hdr->secure_transfer_timeout) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->arm9_autoload) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->arm7_autoload) &&
rz_buf_read_le64_offset(buf, &offset, &hdr->secure_disable) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->ntr_region_rom_size) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->rom_header_size) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->offset_0x88) &&
rz_buf_read_le32_offset(buf, &offset, &hdr->offset_0x8C) &&
Expand Down Expand Up @@ -84,13 +151,31 @@ static bool nds_check_buffer(RzBuffer *b) {
return false;
}

static void nds_rom_free(NDSRom *rom) {
if (!rom) {
return;
}
rz_pvector_free(rom->fat_table);
rz_pvector_free(rom->arm7_overlays);
rz_pvector_free(rom->arm9_overlays);
free(rom);
}

static bool nds_load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *b, Sdb *sdb) {
NDSHeader *hdr = RZ_NEW0(NDSHeader);
if (!hdr || !nds_read_header(b, hdr)) {
free(hdr);
NDSRom *rom = RZ_NEW0(NDSRom);
rom->fat_table = rz_pvector_new((RzPVectorFree)free);
rom->arm9_overlays = rz_pvector_new((RzPVectorFree)free);
rom->arm7_overlays = rz_pvector_new((RzPVectorFree)free);
if (!rom ||
!nds_read_header(b, &rom->header) ||
!nds_read_file_alloc_table(b, rom->fat_table, &rom->header) ||
!nds_read_overlay_table(b, rom->arm9_overlays, rom->header.arm9_overlay_offset, rom->header.arm9_overlay_size) ||
!nds_read_overlay_table(b, rom->arm7_overlays, rom->header.arm7_overlay_offset, rom->header.arm7_overlay_size)) {
nds_rom_free(rom);
rz_warn_if_reached();
return false;
}
obj->bin_obj = hdr;
obj->bin_obj = rom;
return true;
}

Expand All @@ -99,8 +184,8 @@ static void nds_destroy(RzBinFile *bf) {
return;
}

NDSHeader *hdr = nds_get_hdr(bf);
free(hdr);
NDSRom *rom = nds_get_rom(bf);
nds_rom_free(rom);
}

static ut64 nds_baddr(RzBinFile *bf) {
Expand All @@ -121,6 +206,7 @@ static RzPVector /*<RzBinSection *>*/ *nds_sections(RzBinFile *bf) {
}
RzPVector *ret = NULL;
RzBinSection *ptr9 = NULL, *ptr7 = NULL;
int perm_rwx = rz_str_rwx("rwx");

if (!(ret = rz_pvector_new((RzPVectorFree)rz_bin_section_free)) ||
!(ptr9 = RZ_NEW0(RzBinSection)) ||
Expand All @@ -129,24 +215,70 @@ static RzPVector /*<RzBinSection *>*/ *nds_sections(RzBinFile *bf) {
free(ptr9);
return NULL;
}
NDSHeader *hdr = nds_get_hdr(bf);
NDSRom *rom = nds_get_rom(bf);
NDSHeader *hdr = &rom->header;

ptr9->name = strdup("arm9");
ptr9->size = hdr->arm9_size;
ptr9->vsize = hdr->arm9_size;
ptr9->paddr = hdr->arm9_rom_offset;
ptr9->vaddr = hdr->arm9_ram_address;
ptr9->perm = rz_str_rwx("rwx");
ptr9->perm = perm_rwx;
rz_pvector_push(ret, ptr9);

ptr7->name = strdup("arm7");
ptr7->size = hdr->arm7_size;
ptr7->vsize = hdr->arm7_size;
ptr7->paddr = hdr->arm7_rom_offset;
ptr7->vaddr = hdr->arm7_ram_address;
ptr7->perm = rz_str_rwx("rwx");
ptr7->perm = perm_rwx;
rz_pvector_push(ret, ptr7);

void **it;

rz_pvector_foreach (rom->arm7_overlays, it) {
NDSOverlayTblEntry *ovl_entry = *it;
NDSFatEntry *fat_entry = rz_pvector_at(rom->fat_table, ovl_entry->file_id);
if (!fat_entry) {
rz_warn_if_reached();
continue;
}

RzBinSection *overlay = RZ_NEW0(RzBinSection);
if (!overlay) {
return ret;
}

overlay->name = rz_str_newf("arm7_overlay_%" PFMT32u, ovl_entry->id);
overlay->size = fat_entry->file_end_offset - fat_entry->file_start_offset;
overlay->vsize = ovl_entry->ram_size;
overlay->paddr = fat_entry->file_start_offset;
overlay->vaddr = ovl_entry->load_address;
overlay->perm = perm_rwx;
rz_pvector_push(ret, overlay);
}

rz_pvector_foreach (rom->arm9_overlays, it) {
NDSOverlayTblEntry *ovl_entry = *it;
NDSFatEntry *fat_entry = rz_pvector_at(rom->fat_table, ovl_entry->file_id);
if (!fat_entry) {
rz_warn_if_reached();
continue;
}

RzBinSection *overlay = RZ_NEW0(RzBinSection);
if (!overlay) {
return ret;
}

overlay->name = rz_str_newf("arm9_overlay_%" PFMT32u, ovl_entry->id);
overlay->size = fat_entry->file_end_offset - fat_entry->file_start_offset;
overlay->vsize = ovl_entry->ram_size;
overlay->paddr = fat_entry->file_start_offset;
overlay->vaddr = ovl_entry->load_address;
overlay->perm = perm_rwx;
rz_pvector_push(ret, overlay);
}
return ret;
}

Expand Down

0 comments on commit 2b4aa53

Please sign in to comment.