/*
 * src/misc/bin2h.c
 * https://gitlab.com/bztsrc/easyboot
 *
 * Copyright (C) 2023 bzt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * @brief Simple helper utility for embedding binary data into C source ("ld -b" isn't portable)
 */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HOSTED
#include "../loader.h"  /* elf headers */

int main(int argc, char **argv)
{
    FILE *f, *h, *b;
    int size, i, j, k;
    unsigned char *buff = NULL;
    char name[256];

    if(argc < 2) {
        printf("Easyboot bin2h, Copyright (c) 2023 bzt, GPLv3+\r\nhttps://gitlab.com/bztsrc/easyboot\r\n\r\n");
        printf(" bin2h <bin file> [bin file2...]\r\n");
        return 1;
    }
    h = fopen("data.h", "w"); if(!h) { fprintf(stderr, "bin2h: unable to open data.h\r\n"); return 1; }
    fprintf(h, "/*\n"
        " * src/data.h\n"
        " * https://codeberg.org/bzt/easyboot\n"
        " *\n"
        " * Copyright (C) 2023 bzt\n"
        " *\n"
        " * This program is free software; you can redistribute it and/or modify\n"
        " * it under the terms of the GNU General Public License as published by\n"
        " * the Free Software Foundation; either version 3 of the License, or\n"
        " * (at your option) any later version.\n"
        " *\n"
        " * This program is distributed in the hope that it will be useful,\n"
        " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
        " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
        " * GNU General Public License for more details.\n"
        " *\n"
        " * You should have received a copy of the GNU General Public License\n"
        " * along with this program; if not, write to the Free Software\n"
        " * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
        " *\n"
        " * @brief Embedded loader binary data, used by the image creator\n"
        " */\n\n/* generated by bin2h, do not edit */\n\n");
    for(i = 1; i < argc; i++){
        f = fopen(argv[i],"rb");
        if(f) {
            fseek(f, 0, SEEK_END);
            size = (int)ftell(f);
            fseek(f, 0, SEEK_SET);
            buff = (unsigned char*)malloc(size + 512);
            if(!buff) { fprintf(stderr, "bin2h: memory allocation error\r\n"); return 2; }
            fread(buff, 1, size, f);
            fclose(f);
            for(j = 0; argv[i][j]; j++) { name[j] = argv[i][j] == '.' || argv[i][j] <= ' ' ? '_' : argv[i][j]; } name[j] = 0;
            /* ehhh LLVM lld accepts -stub flag, but then does nothing with it, lld/COFF/Writer.cpp always writes dosProgram */
            if(!strcmp(name, "loader_x86_efi")) {
                memset(buff + size, 0, 512);
                size = (size + 511) & ~511;
                memset(buff + 0x40, 0, 0x38); memcpy(buff + 0x40, "Easyboot https://codeberg.org/bzt/easyboot\0x86_64", 49);
                b = fopen("loader_x86.efi", "wb"); if(b) { fwrite(buff, 1, size, b); fclose(b); }
            }
            /* objcopy can't interpret program headers from another platform's elf... plus we need to store bss size */
            if(!strcmp(name, "loader_rpi_o")) {
                k = (int)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_offset;
                size = (int)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_filesz;
                /* patch _bss_start and _bss_end values, must be right after the default names */
                for(j = 0; j < size - 128; j += 16)
                    if(!memcmp(buff + j + k, "kernel\0\0\0\0\0\0\0\0\0", 16)) {
                        *((uint32_t*)(buff + j + k + 128)) =
                            (uint32_t)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_vaddr +
                            (uint32_t)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_filesz;
                        *((uint32_t*)(buff + j + k + 128 + 4)) =
                            ((uint32_t)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_vaddr +
                            (uint32_t)((Elf64_Phdr*)(buff + ((Elf64_Ehdr*)buff)->e_phoff))->p_memsz + 4095) & ~4095;
                        break;
                    }
                /* make sure we write out multiple of 512 bytes */
                memset(buff + k + size, 0, 512);
                size = (size + 511) & ~511;
                /* it would be enough just to include in data.h, but also write out as bin file for debugging */
                b = fopen("loader_rpi.bin", "wb");
                if(!b) { fclose(h); free(buff); fprintf(stderr, "bin2h: unable to open loader_rpi.bin\r\n"); return 1; }
                fwrite(buff + k, 1, size, b);
                fclose(b);
                strcpy(name, "loader_rpi_bin");
            } else k = 0;
            fprintf(h, "unsigned char %s[%u] = { ", name, size);
            for(j = 0; j < size; j++) fprintf(h, "%s%d", j?",":"", buff[j + k]);
            fprintf(h, " };\n");
            free(buff);
        }
    }
    fclose(h);
    return 0;
}
