From d1893e1116fee67db54962dba7417508b3128b9e Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Fri, 7 Aug 2015 19:40:34 +0200 Subject: Created a tool for building multiboot images --- Makefile | 4 + icemulti/.gitignore | 3 + icemulti/Makefile | 24 +++++ icemulti/icemulti.cc | 263 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 294 insertions(+) create mode 100644 icemulti/.gitignore create mode 100644 icemulti/Makefile create mode 100644 icemulti/icemulti.cc diff --git a/Makefile b/Makefile index be631e7..8704427 100644 --- a/Makefile +++ b/Makefile @@ -3,21 +3,25 @@ all: $(MAKE) -C icebox $(MAKE) -C icepack $(MAKE) -C iceprog + $(MAKE) -C icemulti clean: $(MAKE) -C icebox clean $(MAKE) -C icepack clean $(MAKE) -C iceprog clean + $(MAKE) -C icemulti clean install: $(MAKE) -C icebox install $(MAKE) -C icepack install $(MAKE) -C iceprog install + $(MAKE) -C icemulti install uninstall: $(MAKE) -C icebox uninstall $(MAKE) -C icepack uninstall $(MAKE) -C iceprog uninstall + $(MAKE) -C icemulti uninstall .PHONY: all clean install uninstall diff --git a/icemulti/.gitignore b/icemulti/.gitignore new file mode 100644 index 0000000..51ac8f9 --- /dev/null +++ b/icemulti/.gitignore @@ -0,0 +1,3 @@ +icemulti +icemulti.o +icemulti.d diff --git a/icemulti/Makefile b/icemulti/Makefile new file mode 100644 index 0000000..0b4e0aa --- /dev/null +++ b/icemulti/Makefile @@ -0,0 +1,24 @@ +# CXX = clang +LDLIBS = -lm -lstdc++ +CXXFLAGS = -MD -O0 -ggdb -Wall -std=c++11 +CC = $(CXX) +DESTDIR = /usr/local + +all: icemulti + +icemulti: icemulti.o + +install: all + cp icemulti $(DESTDIR)/bin/icemulti + +uninstall: + rm -f $(DESTDIR)/bin/icemulti + +clean: + rm -f icemulti + rm -f *.o *.d + +-include *.d + +.PHONY: all install uninstall clean + diff --git a/icemulti/icemulti.cc b/icemulti/icemulti.cc new file mode 100644 index 0000000..5911550 --- /dev/null +++ b/icemulti/icemulti.cc @@ -0,0 +1,263 @@ +// +// Copyright (C) 2015 Marcus Comstedt +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +#include +#include +#include +#include + +#include + +#define log(...) fprintf(stderr, __VA_ARGS__); +#define info(...) do { if (log_level > 0) fprintf(stderr, __VA_ARGS__); } while (0) +#define error(...) do { fprintf(stderr, "Error: " __VA_ARGS__); exit(1); } while (0) + +int log_level = 0; + +static const int NUM_IMAGES = 4; +static const int NUM_HEADERS = NUM_IMAGES + 1; +static const int HEADER_SIZE = 32; +static const int HEADERS_SIZE = NUM_HEADERS * HEADER_SIZE; + +static void write_byte(std::ostream &ofs, uint32_t &file_offset, uint8_t byte) +{ + ofs << byte; + file_offset++; +} + +static void write_bytes(std::ostream &ofs, uint32_t &file_offset, + const uint8_t *buf, size_t n) +{ + if (n > 0) { + ofs.write(reinterpret_cast(buf), n); + file_offset += n; + } +} + +static void write_file(std::ostream &ofs, uint32_t &file_offset, + std::istream &ifs) +{ + const size_t bufsize = 8192; + uint8_t *buffer = new uint8_t[bufsize]; + + while(!ifs.eof()) { + ifs.read(reinterpret_cast(buffer), bufsize); + if (ifs.bad()) + error("Read error on input image"); + write_bytes(ofs, file_offset, buffer, ifs.gcount()); + } + + delete[] buffer; +} + +static void pad_to(std::ostream &ofs, uint32_t &file_offset, uint32_t target) +{ + if (target < file_offset) + error("Trying to pad backwards!\n"); + while(file_offset < target) + write_byte(ofs, file_offset, 0xff); +} + +class Image { + std::ifstream ifs; + uint32_t offs; + +public: + Image(const char *filename) : ifs(filename, std::ifstream::binary) {} + + size_t size(); + void write(std::ostream &ofs, uint32_t &file_offset); + void place(uint32_t o) { offs = o; } + uint32_t offset() const { return offs; } +}; + +size_t Image::size() +{ + ifs.seekg (0, ifs.end); + size_t length = ifs.tellg(); + ifs.seekg (0, ifs.beg); + return length; +} + +void Image::write(std::ostream &ofs, uint32_t &file_offset) +{ + write_file(ofs, file_offset, ifs); +} + +class Header { + uint32_t image_offs; + bool coldboot_flag; + bool empty; +public: + Header() : empty(true) {} + Header(const Image &i) : + image_offs(i.offset()), coldboot_flag(false), empty(false) {} + void set_coldboot_flag() { coldboot_flag = true; } + void write(std::ostream &ofs, uint32_t &file_offset); +}; + +void Header::write(std::ostream &ofs, uint32_t &file_offset) +{ + if (empty) + return; + + // Preamble + write_byte(ofs, file_offset, 0x7e); + write_byte(ofs, file_offset, 0xaa); + write_byte(ofs, file_offset, 0x99); + write_byte(ofs, file_offset, 0x7e); + + // Boot mode + write_byte(ofs, file_offset, 0x92); + write_byte(ofs, file_offset, 0x00); + write_byte(ofs, file_offset, (coldboot_flag? 0x10: 0x00)); + + // Boot address + write_byte(ofs, file_offset, 0x44); + write_byte(ofs, file_offset, 0x03); + write_byte(ofs, file_offset, (image_offs >> 16) & 0xff); + write_byte(ofs, file_offset, (image_offs >> 8) & 0xff); + write_byte(ofs, file_offset, image_offs & 0xff); + + // Bank offset + write_byte(ofs, file_offset, 0x82); + write_byte(ofs, file_offset, 0x00); + write_byte(ofs, file_offset, 0x00); + + // Reboot + write_byte(ofs, file_offset, 0x01); + write_byte(ofs, file_offset, 0x08); + + // Zero out any unused bytes + while (file_offset & (HEADER_SIZE - 1)) + write_byte(ofs, file_offset, 0x00); +} + +void usage() +{ + log("\n"); + log("Usage: icemulti [options] input-files\n"); + log("\n"); + log(" -c\n"); + log(" coldboot mode, power on reset image is selected by CBSEL0/CBSEL1\n"); + log("\n"); + log(" -p0, -p1, -p2, -p3\n"); + log(" select power on reset image when not using coldboot mode\n"); + log("\n"); + log(" -o filename\n"); + log(" write output image to file instead of stdout\n"); + log("\n"); + log(" -v\n"); + log(" verbose (repeat to increase verbosity)\n"); + log("\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + bool coldboot = false; + int por_image = 0; + int image_count = 0; + Header headers[NUM_HEADERS]; + std::unique_ptr images[NUM_IMAGES]; + const char *outfile_name = NULL; + + for (int i = 1; i < argc; i++) + { + if (argv[i][0] == '-' && argv[i][1]) { + for (int j = 1; argv[i][j]; j++) + if (argv[i][j] == 'c') { + coldboot = true; + } else if (argv[i][j] == 'p' && argv[i][j+1]) { + por_image = argv[i][++j] - '0'; + } else if (argv[i][j] == 'o') { + if (argv[i][j+1]) + outfile_name = &argv[i][j+1]; + else if(i+1 < argc) + outfile_name = argv[++i]; + else + usage(); + break; + } else if (argv[i][j] == 'v') { + log_level++; + } else + usage(); + continue; + } + + if (image_count >= NUM_IMAGES) + error("Too many images supplied\n"); + images[image_count++].reset(new Image(argv[i])); + } + + if (!image_count) + usage(); + + if (coldboot && por_image != 0) + error("Can't select power on reset boot image in cold boot mode\n"); + + if (por_image >= image_count) + error("Specified non-existing image for power on reset\n"); + + // Place images + uint32_t offs = 0x100; + for (int i=0; iplace(offs); + offs += images[i]->size(); + + // Align to 4K + if (offs & 0xfff) { + offs |= 0xfff; + offs++; + } + } + + // Populate headers + for (int i=0; ioffset()); + images[i]->write(*osp, file_offset); + } + + info("Done.\n"); + return 0; +} -- cgit v1.2.3