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

#  Codezero -- a microkernel for embedded systems.
#
#  Copyright © 2009  B Labs Ltd
#
#  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, see
#  <http://www.gnu.org/licenses/>.
#
#  Author: Russel Winder

import os.path
import subprocess
import shutil

Import('environment', 'images')

bootdescTemplate = \
'''
/* 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
        },
};
'''

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

def generateLocationData(image):
    process = subprocess.Popen('tools/pyelf/readelf.py --lma-start-end ' + image.path, shell=True, stdout=subprocess.PIPE)
    assert process.wait() == 0
    return (process.stdout.readline().strip(), process.stdout.readline().strip().split()[1], process.stdout.readline().strip().split()[1])

def generateBootdesc(target, source, env):
    '''
    Extracts name, start, end information from the kernel and each svc task.
    Uses this information to produce bootdesc.c
    '''
    with open(target[0].path, 'w' ) as f:
        imagesString = ''
        numberOfImages = len(source) - 1
        for index in range(1, len(source)):
            imagesString += imageTemplate % ((index - 1,) + generateLocationData(source[index]))
        f.write(bootdescTemplate % (numberOfImages, numberOfImages, imagesString))

def relocateBootdesc(target, source, env):
    name, start, end = generateLocationData(source[1])
    process = subprocess.Popen(executable='arm-none-linux-gnueabi-objcopy', args=(
            '--adjust-section-vma .data=' + end,
            source[0].path))
    assert process.wait() == 0
    shutil.copyfile(source[0].path, target[0].path)

bootdescSource = environment.Command('bootdesc.c', images, generateBootdesc)
objects = environment.Object(bootdescSource)
Depends(objects, environment['configFiles'])
bootdesc = environment.Command('bootdesc.axf', environment.Program('bootdesc_intermediate', objects) + [images[0]] , relocateBootdesc)

Return('bootdesc')
