# -*- 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 # . # # Author: Russel Winder import os.path import subprocess Import('environment', 'images', 'libsInOrder') e = environment.Clone() e.Append(LINKFLAGS = ['-T' + e['buildDirectory'] + '/loader/linker.lds']) e.Append(LIBS = libsInOrder) e.Append(CPPPATH = ['#libs/elf/include', '#' + e['buildDirectory'] + '/loader']) def convertAddress(address): '''Convert the string representation of the address given as parameter to a string representation of the address without the top four bits set. The issue here is that Python has a penchant for adding L to the end to create a Python literal. This is not wanted here.''' value = hex(int(address, 16) - 0xf0000000) if value[-1] in ['l', 'L']: value = value[:-1] return value def ksymToLds(target, source, env): symbols = ['break_virtual'] with open(target[0].path, 'w') as asmFile: asmFile.write(''' /* * %s autogenerated from %s. * * This file is included by the loader sources so that any * kernel symbol address can be known in advance and stopped * at by debuggers before virtual memory is enabled. */ ''' % (target[0].name, source[0].name)) for symbol in symbols: process = subprocess.Popen('arm-none-eabi-objdump -d ' + source[0].path + ' | grep "<' + symbol + '>"', shell=True, stdout=subprocess.PIPE) assert process.wait() == 0 address, name = process.stdout.read().split() assert '<' + symbol + '>:' == name asmFile.write( ''' .section .text .align 4 .global %s .type %s, function .equ %s, %s ''' % (symbol, symbol, symbol, convertAddress(address))) container_assembler_start = \ ''' .align 4 .section .kernel .incbin "%s" ''' container_assembler_body = \ ''' .align 4 .section .cont.%d .incbin "%s" ''' container_lds_start = \ '''/* * Autogenerated linker script that embeds each container image. * * Copyright (C) 2009 B Labs */ SECTIONS {''' container_lds_body = \ ''' .cont.%d : { *(.cont.%d) }''' container_lds_end = \ ''' } ''' def generate_container_assembler(source, target, env): with open(target[0].path, "w+") as f: file_body = container_assembler_start % (str(source[0])) img_i = 0 for img in source[1:]: file_body += container_assembler_body % (img_i, img) img_i += 1 f.write(file_body) f.close() def generate_container_lds(source, target, env): with open(target[0].path, "w+") as f: img_i = 0 file_body = container_lds_start for img in source[1:]: file_body += container_lds_body % (img_i, img_i) img_i += 1 file_body += container_lds_end f.write(file_body) f.close() startAxfS = Command('start.axf.S', images[0], ksymToLds) # In the following, it is crucially important that the order of the sources is as it is -- assumptions are # made in the functions doing the processing. kernelS = Command('containers.S', images, generate_container_assembler) linkerScript = Command('linker.lds', images, generate_container_lds) ## TODO: deal with the situation where there are other .c and .S files in the directory. objects = e.Object(['arch.c' , 'main.c', kernelS, startAxfS]) Depends(objects, e['configFiles']) Depends(objects, images) program = e.Program('final', objects + [e['baremetal_crt0']]) Depends(program, linkerScript) Return('program')