#!/usr/bin/env python3
#
# SPDX-License-Identifier: BSD-3-Clause

import os
import struct
import sys

PROG_NAME = os.path.basename(sys.argv[0])

def create_header(base, size):
    """Returns a packed MBN header image with the specified base and size.

    @arg base: integer, specifies the image load address in RAM
    @arg size: integer, specifies the size of the image
    @returns: string, the MBN header
    """

    # SBLs require size to be 4 bytes aligned.
    size = (size + 3) & 0xfffffffc

    # We currently do not support appending certificates. Signing GPL
    # code might violate the GPL. So U-Boot will never be signed. So
    # this is not required for U-Boot.

    header = [
        0x5,         # Type: APPSBL
        0x3,         # Version: 3
        0x0,         # Image source pointer
        base,        # Image destination pointer
        size,        # Code Size + Cert Size + Signature Size
        size,        # Code Size
        base + size, # Destination + Code Size
        0x0,         # Signature Size
        base + size, # Destination + Code Size + Signature Size
        0x0,         # Cert Size
    ]

    header_packed = struct.pack('<10I', *header)
    return header_packed

def mkheader(base_addr, infname, outfname):
    """Prepends the image with the MBN header.

    @arg base_addr: integer, specifies the image load address in RAM
    @arg infname: string, image filename
    @arg outfname: string, output image with header prepended
    @raises IOError: if reading/writing input/output file fails
    """
    with open(infname, "rb") as infp:
        image = infp.read()
        insize = len(image)

    if base_addr > 0xFFFFFFFF:
        raise ValueError("invalid base address")

    if base_addr + insize > 0xFFFFFFFF:
        raise ValueError("invalid destination range")

    header = create_header(base_addr, insize)
    with open(outfname, "wb") as outfp:
        outfp.write(header)
        outfp.write(image)

def usage(msg=None):
    """Print command usage.

    @arg msg: string, error message if any (default: None)
    """
    if msg != None:
        sys.stderr.write("%s: %s\n" % (PROG_NAME, msg))

    print("Usage: %s <base-addr> <input-file> <output-file>" % PROG_NAME)

    if msg != None:
        exit(1)

def main():
    """Main entry function"""

    if len(sys.argv) != 4:
        usage("incorrect number of arguments")

    try:
        base_addr = int(sys.argv[1], 0)
        infname = sys.argv[2]
        outfname = sys.argv[3]
    except ValueError as e:
        sys.stderr.write("mkheader: invalid base address '%s'\n" % sys.argv[1])
        exit(1)

    try:
        mkheader(base_addr, infname, outfname)
    except IOError as e:
        sys.stderr.write("%s: %s\n" % (PROG_NAME, e))
        exit(1)
    except ValueError as e:
        sys.stderr.write("%s: %s\n" % (PROG_NAME, e))
        exit(1)

if __name__ == "__main__":
    main()
