#
# Build script to autogenerate a bootdesc image
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import sys
import shutil
from os.path import join

# The root directory of the repository where this file resides:
project_root = "../.."
tools_root = "../../tools"

kernel = join(project_root, "build/start.axf")
mm0 = join(project_root, "tasks/mm0/mm0.axf")
fs0 = join(project_root, "tasks/fs0/fs0.axf")
test0 = join(project_root, "tasks/test0/test0.axf")
#test1 = join(project_root, "tasks/test1/test1.axf")
#blkdev0 = join(project_root, "tasks/fsbin/blkdev0.axf")

images = [kernel, mm0, fs0, test0]
autogen_templ = "bootdesc.c.append"

def get_image_name_start_end(image, target):
	'''
	Using readelf.py utility, extracts name, start, end triplet from an arm-elf image.
	'''
	rest, name = os.path.split(image)
	if name[-4] == ".":
		name = name[:-4]
	os.system(join(tools_root, "pyelf/readelf.py --lma-start-end " + \
		  image + " > " + target))

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

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

images_template_end = \
'''
	},
'''

def generate_bootdesc(source, target, env):
	'''
	Extracts name, start, end information from the kernel and each svc task.
	Uses this information to produce bootdesc.c
	'''
	source.sort()
	images = []
	images_string = ""
	for node in source:
		if str(node)[-4:] == ".axf":
			rest, imgname = os.path.split(str(node))
			images.append((str(node), imgname[:-4]))
		elif str(node) [-6:] == ".templ":
			# Static template that has type definitions.
			#rest, original_template = os.path.split(str(node))
			original_template = str(node)
	index = 0
	for imgpath, imgname in images:
		get_image_name_start_end(imgpath, imgname + ".txt")
		if imgname != "start":
			f = open(imgname + ".txt", "r")
			svc_name = f.readline()[:-1]
			[start, startval] = str.split(f.readline()[:-1])
			[end, endval] = str.split(f.readline()[:-1])
			f.close()
			images_string += images_template % (str(index), svc_name, \
			hex(int(startval, 16)), hex(int(endval, 16)))
			index += 1

	# Autogenerated template with actual data.
	autogen_template = open(autogen_templ, "w+")
	autogen_template.write(bootdesc_template % (str(index), str(index), images_string))
	autogen_template.close()

	os.system("cat " + original_template + " > " + str(target[0]))
	os.system("cat " + autogen_templ + " >> " + str(target[0]))

def relocate_bootdesc(source, target, env):
	f = open("start.txt", "r")
	kernel_name = f.readline()[:-1]
	[start, startval] = str.split(f.readline()[:-1])
	[end, endval] = str.split(f.readline()[:-1])
	os.system("arm-none-linux-gnueabi-objcopy --adjust-section-vma .data=" + \
		  hex(int(endval,16)) + " " + str(source[0]))
	os.system("mv " + str(source[0]) + " " + str(target[0]))
# The kernel build environment:
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
		  # We don't use -nostdinc because sometimes we need standard headers,
		  # such as stdarg.h e.g. for variable args, as in printk().
		  CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', '-Werror'],
		  LINKFLAGS = ['-nostdlib','-Tlinker.lds'],
		  ASFLAGS = ['-D__ASSEMBLY__'],
		  PROGSUFFIX = '.axf',			# The suffix to use for final executable
		  ENV = {'PATH' : os.environ['PATH']},	# Inherit shell path
		  LIBS = 'gcc',				# libgcc.a - This is required for division routines.
		  CPPPATH = '#include')			# `hash' ('#') is a shorthand meaning `relative to
							# the root directory'. But this only works for
							# well-defined variables, not all paths, and only
							# if we use a relative build directory for sources.

bootdesc_src = env.Command("bootdesc.c", ["bootdesc.c.templ"] + images, generate_bootdesc)
objs = env.Object('bootdesc.c')
bootdesc = env.Program('bootdesc_data', objs)
bootdesc_relocated = env.Command("bootdesc.axf", "bootdesc_data.axf", relocate_bootdesc)
env.Depends(bootdesc_relocated, bootdesc)
