# -*- 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))) def createKernelSFile(target, source, env): with open(target[0].path, 'w') as asmFile: asmFile.write(''' /* * This file is autogenerated. * * This file defines kernel symbols extracted from the * kernel image in their physical address. */ .include "%s" .section .kernel .incbin "%s" ''' % (source[0].path , source[1].path)) for image in source[2:]: asmFile.write(''' .align 4 .section .%s .incbin "%s" ''' % (os.path.splitext(image.name)[0], image.path)) def createMainC(target, source, env): with open(source[0].path) as inFile: with open(target[0].path, 'w') as outFile: externs = '' declarations = '' loads = '' for item in source[1:]: name = os.path.splitext(item.name)[0] if name == 'start' : name = 'kernel' externs += ''' extern char _start_%s[]; extern char _end_%s[]; ''' % (name, name) declarations += ' void *%s_entry = NULL;\n' % (name,) loads += ''' printf("Loading the %s...\\n"); load_image(&%s_entry, _start_%s, _end_%s); ''' %(name, name, name, name) text = inFile.read() text = text.replace('__EXTERNAL_SYMBOLS_EDIT_MARKER__', externs) text = text.replace('__DECLARATIONS_EDIT_MARKER__', declarations) text = text.replace('__LOAD_STATEMENTS_EDIT_MARKER__', loads) outFile.write(text) def createLinkerScript(target, source, env): with open(source[0].path) as inFile: with open(target[0].path, 'w') as outFile: linkerItems = '' for item in source[1:]: name = os.path.splitext(item.name)[0] if name == 'start' : name = 'kernel' linkerItems += ''' _start_%s = .; *(.%s) _end_%s = .; ''' % (name, name, name) outFile.write(inFile.read().replace('__LINKER_ITEMS_EDIT_MARKER__', linkerItems)) 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('kernel.S', [startAxfS] + images, createKernelSFile) mainC = Command('main.c', ['main.c.in'] + images, createMainC) linkerScript = Command('linker.lds', ['linker.lds.in'] + images, createLinkerScript) ## TODO: deal with the situation where there are other .c and .S files in the directory. objects = e.Object(['arch.c' , kernelS, startAxfS, mainC]) Depends(objects, e['configFiles']) Depends(objects, images) program = e.Program('final', objects + [e['baremetal_crt0']]) Depends(program, linkerScript) Return('program')