summaryrefslogtreecommitdiffstats
path: root/utils/ape2elf/main.cpp
diff options
context:
space:
mode:
authorEvan Lojewski <github@meklort.com>2019-03-30 13:39:50 -0600
committerEvan Lojewski <github@meklort.com>2019-03-30 13:39:50 -0600
commitc26cbf8022a71ea67ae351e5ab19a576018d906d (patch)
tree80c55b3406eed83f2d6092e662ca78ab092d2789 /utils/ape2elf/main.cpp
parentb7afce84d48019599724c884f20f2153a7d61f78 (diff)
downloadbcm5719-ortega-c26cbf8022a71ea67ae351e5ab19a576018d906d.tar.gz
bcm5719-ortega-c26cbf8022a71ea67ae351e5ab19a576018d906d.zip
Add ape2elf utility to convert the ape file format into an elf file.
Diffstat (limited to 'utils/ape2elf/main.cpp')
-rw-r--r--utils/ape2elf/main.cpp293
1 files changed, 293 insertions, 0 deletions
diff --git a/utils/ape2elf/main.cpp b/utils/ape2elf/main.cpp
new file mode 100644
index 0000000..79980c4
--- /dev/null
+++ b/utils/ape2elf/main.cpp
@@ -0,0 +1,293 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// @file main.cpp
+///
+/// @project
+///
+/// @brief Main ape tool for parsing BCM5179 APE images.
+///
+////////////////////////////////////////////////////////////////////////////////
+///
+////////////////////////////////////////////////////////////////////////////////
+///
+/// @copyright Copyright (c) 2018, Evan Lojewski
+/// @cond
+///
+/// All rights reserved.
+///
+/// Redistribution and use in source and binary forms, with or without
+/// modification, are permitted provided that the following conditions are met:
+/// 1. Redistributions of source code must retain the above copyright notice,
+/// this list of conditions and the following disclaimer.
+/// 2. Redistributions in binary form must reproduce the above copyright notice,
+/// this list of conditions and the following disclaimer in the documentation
+/// and/or other materials provided with the distribution.
+/// 3. Neither the name of the copyright holder nor the
+/// names of its contributors may be used to endorse or promote products
+/// derived from this software without specific prior written permission.
+///
+////////////////////////////////////////////////////////////////////////////////
+///
+/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+/// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+/// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+/// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+/// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+/// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+/// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+/// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+/// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+/// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+/// POSSIBILITY OF SUCH DAMAGE.
+/// @endcond
+////////////////////////////////////////////////////////////////////////////////
+
+#include <NVRam.h>
+#include <bcm5719_eeprom.h>
+
+#include <OptionParser.h>
+#include <Compress.h>
+
+
+#include <elfio/elfio.hpp>
+
+using namespace std;
+using namespace ELFIO;
+using optparse::OptionParser;
+
+#define MAX_SIZE (1024u * 256u) /* 256KB - max NVRAM */
+int main(int argc, char const *argv[])
+{
+ union {
+ uint8_t bytes[MAX_SIZE];
+ uint32_t words[MAX_SIZE/4];
+ APEHeader_t header;
+ } ape;
+
+ OptionParser parser = OptionParser().description("BCM APE to elf Utility");
+
+ parser.add_option("-i", "--input")
+ .dest("input")
+ .help("Read from the input ape binary")
+ .metavar("FILE");
+
+
+ parser.add_option("-o", "--output")
+ .dest("output")
+ .help("Save to the specified output elf file")
+ .metavar("FILE");
+
+ optparse::Values options = parser.parse_args(argc, argv);
+ vector<string> args = parser.args();
+
+ if(!options.is_set("input"))
+ {
+ cerr << "Please specify an ape binary to use." << endl;
+ parser.print_help();
+ exit(-1);
+ }
+
+ fstream infile;
+ infile.open(options["input"], fstream::in | fstream::binary);
+ if(infile.is_open())
+ {
+ infile.read((char*)ape.bytes, MAX_SIZE);
+
+ // The file is swapped... fix it.
+ for(int i = 0; i < sizeof(ape)/sizeof(ape.words[0]); i++)
+ {
+ ape.words[i] = be32toh(ape.words[i]);
+ }
+
+ infile.close();
+ }
+ else
+ {
+ cerr << " Unable to open file '" << options["filename"] << "'" << endl;
+ exit(-1);
+ }
+
+
+ elfio writer;
+
+ // Setup the elf header
+ writer.create( ELFCLASS32, ELFDATA2LSB );
+ writer.set_os_abi( ELFOSABI_NONE );
+ writer.set_type( ET_EXEC );
+ writer.set_machine( EM_ARM );
+
+ // Create code section
+ section* text_sec = writer.sections.add( ".text" );
+ segment* text_seg = writer.segments.add();
+ text_sec->set_type( SHT_PROGBITS );
+ text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR );
+ text_sec->set_addr_align( 0x4 );
+
+ section* bss_sec = writer.sections.add( ".bss" );
+ segment* bss_seg = writer.segments.add();
+ bss_sec->set_type( SHT_PROGBITS );
+ bss_sec->set_flags( SHF_ALLOC | SHF_WRITE );
+ bss_sec->set_addr_align( 0x4 );
+
+ section* data_sec = writer.sections.add( ".data" );
+ segment* data_seg = writer.segments.add();
+ data_sec->set_type( SHT_PROGBITS );
+ data_sec->set_flags( SHF_ALLOC | SHF_WRITE );
+ data_sec->set_addr_align( 0x4 );
+
+ printf("=== Header ===\n");
+ printf("Magic: 0x%08X\n", ape.header.magic);
+ printf("UNK0: 0x%08X\n", ape.header.unk0);
+
+ char name[sizeof(ape.header.name) + 1] = {0};
+ strncpy(name, (char*)ape.header.name, sizeof(ape.header.name));
+ printf("Name: %s\n", name);
+ printf("Version: 0x%08X\n", ape.header.version);
+ printf("Start: 0x%08X\n", ape.header.entrypoint);
+
+ printf("UNK1: 0x%02X\n", ape.header.unk1);
+ printf("Header Size: %d\n", ape.header.words * 4);
+ printf("UNK2: 0x%02X\n", ape.header.unk2);
+ printf("Sections: %d\n", ape.header.sections);
+
+ printf("CRC: 0x%08X\n", ape.header.crc);
+
+ ape.header.crc = 0;
+ uint32_t calculated_crc = NVRam_crc(ape.bytes, (4 * ape.header.words), 0);
+ printf("Calculated CRC: 0x%08X\n", calculated_crc);
+
+ for(int i = 0; i < ape.header.sections; i++)
+ {
+ uint8_t * inBufferPtr = NULL;
+ uint8_t * outBufferPtr = NULL;
+ ssize_t inBufferSize;
+ ssize_t outBufferSize;
+ size_t out_length;
+
+ APESection_t* section = &ape.header.section[i];
+
+ printf("\n=== Section %i ===\n", i);
+ printf("Load Addr: 0x%08X\n", section->loadAddr);
+
+ printf("Offset: 0x%08X\n", section->offset);
+ printf("Flags: 0x%08X\n", section->flags);
+ if(section->flags & APE_SECTION_FLAG_COMPRESSED)
+ {
+ printf(" compressed\n");
+ }
+ if(section->flags & APE_SECTION_FLAG_CHECKSUM_IS_CRC32)
+ {
+ printf(" crc32\n");
+ }
+ printf(" %s\n", section->flags & APE_SECTION_FLAG_CODE ? "code" : "data");
+ if(section->flags & APE_SECTION_FLAG_UNK0)
+ {
+ printf(" unknown\n");
+ }
+ if(section->flags & APE_SECTION_FLAG_ZERO_ON_FAST_BOOT)
+ {
+ printf(" bss\n");
+ }
+ printf("Decompressed Size: 0x%08X\n", section->decompressedSize);
+ printf("Compressed Size: 0x%08X\n", section->compressedSize);
+ printf("CRC: 0x%08X\n", section->crc);
+
+ inBufferPtr = &ape.bytes[section->offset];
+ inBufferSize = section->compressedSize;
+ outBufferPtr = (uint8_t *)malloc(section->decompressedSize);
+ outBufferSize = section->decompressedSize;
+ out_length = decompress(outBufferPtr, outBufferSize, inBufferPtr, inBufferSize);
+ calculated_crc = NVRam_crc(outBufferPtr, outBufferSize, 0);
+ printf("out_length: 0x%08zX\n", out_length);
+ printf("out CRC: 0x%08X\n", calculated_crc);
+
+ if(i == 0) continue;
+ if(section->flags & APE_SECTION_FLAG_ZERO_ON_FAST_BOOT)
+ {
+ bss_sec->set_data((const char*)outBufferPtr, out_length);
+ bss_seg->set_type( PT_LOAD );
+ bss_seg->set_virtual_address( section->loadAddr );
+ bss_seg->set_physical_address( section->loadAddr );
+ bss_seg->set_flags( PF_W | PF_R );
+ bss_seg->set_align( 0x4 );
+
+ // Add data section into data segment
+ bss_seg->add_section_index( bss_sec->get_index(), bss_sec->get_addr_align() );
+ }
+ else if(!(section->flags & APE_SECTION_FLAG_CODE))
+ {
+ data_sec->set_data((const char*)outBufferPtr, out_length);
+ data_seg->set_type( PT_LOAD );
+ data_seg->set_virtual_address( section->loadAddr );
+ data_seg->set_physical_address( section->loadAddr );
+ data_seg->set_flags( PF_W | PF_R );
+ data_seg->set_align( 0x4 );
+
+ // Add data section into data segment
+ data_seg->add_section_index( data_sec->get_index(), data_sec->get_addr_align() );
+ }
+ else
+ {
+ text_sec->set_data((const char*)outBufferPtr, out_length);
+ text_seg->set_type( PT_LOAD );
+ text_seg->set_virtual_address( section->loadAddr );
+ text_seg->set_physical_address( section->loadAddr );
+ text_seg->set_flags( PF_X | PF_R );
+ text_seg->set_align( 0x4 );
+
+ // Add code section into program segment
+ text_seg->add_section_index( text_sec->get_index(), text_sec->get_addr_align() );
+
+ }
+ }
+
+ if(options.is_set("output"))
+ {
+ // REcord entry-point address
+ writer.set_entry(ape.header.entrypoint);
+
+ // Create string table section
+ section* str_sec = writer.sections.add( ".strtab" );
+ str_sec->set_type ( SHT_STRTAB );
+
+ // Create string table writer
+ string_section_accessor stra( str_sec );
+
+ // Create symbol table section
+ section* sym_sec = writer.sections.add( ".symtab" );
+ sym_sec->set_type ( SHT_SYMTAB );
+ sym_sec->set_info ( 2 );
+ sym_sec->set_addr_align( 0x4 );
+ sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) );
+ sym_sec->set_link ( str_sec->get_index() );
+
+ // Create symbol table writer
+ symbol_section_accessor syma( writer, sym_sec );
+
+
+ // Add label name
+ Elf32_Word _start = stra.add_string( "_start" );
+ Elf32_Word _thumb = stra.add_string( "$t" );
+
+ // Add symbol entry
+ syma.add_symbol( _start, ape.header.entrypoint, 0, STB_GLOBAL,
+ STT_FUNC, 0,
+ text_sec->get_index() );
+
+ syma.add_symbol( _thumb, ape.header.entrypoint & 0xfffffffe, 0, STB_LOCAL,
+ STT_OBJECT, 0,
+ text_sec->get_index() );
+
+ uint32_t* vectors = (uint32_t*)text_sec->get_data();
+ Elf32_Word index = stra.add_string( "_estack" );
+ syma.add_symbol( index, vectors[0], 0, STB_GLOBAL,
+ STT_OBJECT, 0,
+ data_sec->get_index() );
+
+
+ // Create ELF file
+ writer.save(options["output"]);
+ }
+
+ return 0;
+}
OpenPOWER on IntegriCloud