# -*- mode: python; coding: utf-8; -*-

#  Codezero -- a microkernel for embedded systems.
#
#  Copyright © 2009  B Labs Ltd

import os.path
import sys, subprocess, shutil
from os.path import *

Import('config', 'environment', 'images')

e = environment.Clone()
e.Replace(PROGSUFFIX = '')
e.Append(LINKFLAGS = ['-T' + e['bootdesc_dir'] + '/linker.lds'])
#e.Append(LINKFLAGS = ['-T' + '/linker.lds'])

PROJRELROOT = '../../../../'

sys.path.append(os.path.abspath(PROJRELROOT))

from config.projpaths import *
from config.configuration import *
from tools.pyelf import elf

config = configuration_retrieve()

bootdesc_template = \
'''
/* This file is autogenerated, do not edit by hand. */

/* Supervisor task at load time. */
struct svc_image {
        char name[16];
        unsigned int phys_start;
        unsigned int phys_end;
} __attribute__((__packed__));

/* Supervisor task descriptor at load time */
struct bootdesc {
        int desc_size;
        int total_images;
        struct svc_image images[];
} __attribute__((__packed__));

struct bootdesc bootdesc = {
        .desc_size = sizeof(struct bootdesc) + sizeof(struct svc_image) * %s,
        .total_images = %s,
        .images = {
%s
        },
};
'''

image_template = \
'''             [%s] = {
                        .name = "%s",
                        .phys_start = %s,
                        .phys_end = %s,
                },
'''

def conv_hex(val):
    hexval = hex(val)
    if hexval[-1:] == 'L':
        hexval = hexval[:-1]
    return hexval

def image_lma_start_end(img):
    elffile = elf.ElfFile.from_file(img)
    paddr_first = 0
    paddr_start = 0
    paddr_end = 0
    for pheader in elffile.pheaders:
        x = pheader.ai
        if str(x.p_type) != "LOAD":
            continue
        if paddr_first == 0:
            paddr_first = 1
            paddr_start = x.p_paddr.value
        if paddr_start > x.p_paddr.value:
            paddr_start = x.p_paddr.value
        if paddr_end < x.p_paddr + x.p_memsz:
            paddr_end = x.p_paddr + x.p_memsz
    return paddr_start, paddr_end

def generate_bootdesc(target, source, env):
    with open(target[0].path, 'w+' ) as f:
        images_string = ''
        for index in range(len(source)):
            start, end = image_lma_start_end(source[index].path)
            images_string += image_template % (str(index), basename(source[index].path), conv_hex(start), conv_hex(end))
        f.write(bootdesc_template % (len(source), len(source), images_string))

def relocate_bootdesc(target, source, env):
    bootdesc_raw = source[0]
    images = source[1:]
    mm0 = images[0]
    start, end = image_lma_start_end(mm0.path)
    print config.user_toolchain + "objcopy --adjust-section-vma .data=" + conv_hex(end) + " " + bootdesc_raw.path
    os.system(config.user_toolchain + "objcopy --adjust-section-vma .data=" + conv_hex(end) + " " + bootdesc_raw.path)
    shutil.copyfile(bootdesc_raw.path, target[0].path)

bootdesc_c = e.Command('bootdesc.c', images, generate_bootdesc)
bootdesc_raw = e.Program('bootdesc_raw', bootdesc_c)
bootdesc = e.Command('bootdesc.elf', [bootdesc_raw, images], relocate_bootdesc)

Return('bootdesc')
