diff --git a/SConscript b/SConscript index 9444732..3582fb3 100644 --- a/SConscript +++ b/SConscript @@ -35,8 +35,7 @@ import os import GenApps # imports from SConstruct -Import('env libFileName elfFileName binDir coreDir driversDir genDir appBase toolsList chuncksNbits sourcesMap gzipped test') - +Import('env libFileName elfFileName binDir coreDir driversDir genDir appBase toolsList chuncksNbits sourcesMap gzipped test dynApp dynamicAppName') # returns the list of .c and .s files in dir, prefixed by dstDir def getAllSourceFiles(dir, dstDir): sourceFiles = [] @@ -53,9 +52,9 @@ def getAllSourceFiles(dir, dstDir): # used to generate both static and dynamic resources def generateResource(target, source, env): if propsFilesMap.has_key(str(source[0])): - GenApps.generateResource(str(source[0]),str(target[0]),chuncksNbits,gzipped,propsFilesMap[str(source[0])]) + GenApps.generateResource(str(source[0]),str(target[0]), chuncksNbits,gzipped,propsFilesMap[str(source[0])]) else: - GenApps.generateResource(str(source[0]),str(target[0]),chuncksNbits,gzipped,None) + GenApps.generateResource(str(source[0]),str(target[0]), chuncksNbits,gzipped,None) return None # builder used to generate the file index, with the URLs tree @@ -102,10 +101,13 @@ VariantDir(os.path.join(binDir,'drivers'), driversDir, duplicate=0) # applications files index and channel files settings resourcesIndexO = os.path.join(binDir,'gen','resources_index') resourcesIndexC = os.path.join(genDir,'resources_index.c') +elfEnvironmentO = os.path.join(binDir,'gen','elf_environment') +elfEnvironmentC = os.path.join(genDir,'elf_environment.c') channelsH = os.path.join(genDir,'channels.h') appListName = os.path.join(genDir,'appList') definesH = os.path.join(genDir,'defines.h') blobsH = os.path.join(genDir,'blobs.h') + # loop on each web resource in order to generate associated c files # static resources generate pre-computed c files # dynamic resources are enriched with new declarations (from their XML) @@ -156,16 +158,47 @@ env.GenChannelsH(channelsH,propsFilesList) env.Depends(channelsH,toolsList) env.GenDefinesH(definesH,[]) env.GenBlobsH(blobsH,[]) -# engine source code dependencies -coreFiles = getAllSourceFiles(coreDir, os.path.join(binDir,'core')) -# target drivers source code dependencies -targetFiles = getAllSourceFiles(driversDir, os.path.join(binDir,'drivers')) -# create a library from all sources -lib = env.Library(libFileName, targetFiles + coreFiles + genObjects) -# link the library into a elf file -if env['BUILDERS']['Program'] is not None: - final = env.Program(elfFileName, targetFiles + coreFiles + genObjects) +if dynApp : + + installList = [] + removeList = [] + for file in sourcesMap.keys(): + if file.endswith('.h') or file.endswith('.c'): + GenApps.extractXMLElfApplicationLifeCycle(file, installList, removeList) + + # elf application environment generation + GenApps.generateElfApplication(elfEnvironmentC, installList, removeList) + # elf application environment object file + genObjects.append(env.Object(elfEnvironmentO, elfEnvironmentC)) + + linkerCommand = env.subst('$LINK') + linkerCommand += ' -r ' + + pathes = [] + for elt in genObjects : + for inner_elt in elt.data : + pathes.append(inner_elt.path) + linkerCommand += ' '.join(pathes) + linkerCommand += ' -o $TARGET' + + finalDynamicAppName = os.path.join(binDir, dynamicAppName + '.o') + + env.Command(finalDynamicAppName, None, linkerCommand) + + for elt in genObjects : + for inner_elt in elt.data : + env.Depends(finalDynamicAppName, inner_elt.path) else: - final = None -# clean -Clean([lib,final],[binDir,genDir]) + # engine source code dependencies + coreFiles = getAllSourceFiles(coreDir, os.path.join(binDir,'core')) + # target drivers source code dependencies + targetFiles = getAllSourceFiles(driversDir, os.path.join(binDir,'drivers')) + # create a library from all sources + lib = env.Library(libFileName, targetFiles + coreFiles + genObjects) + # link the library into a elf file + if env['BUILDERS']['Program'] is not None: + final = env.Program(elfFileName, targetFiles + coreFiles + genObjects) + else: + final = None + # clean + Clean([lib,final],[binDir,genDir]) diff --git a/SConstruct b/SConstruct index 2040869..1bf6cd1 100644 --- a/SConstruct +++ b/SConstruct @@ -79,6 +79,7 @@ opts.Add(BoolVariable('gzip', 'Set to 1 to gzip (at compile time) static Web res opts.Add(BoolVariable('debug', 'Set to 1 to build for debug', False)) opts.Add(BoolVariable('sdump', 'Set to 1 to include stack dump', False)) opts.Add(BoolVariable('test', 'Set to 1 to test the test apps', False)) +opts.Add(BoolVariable('dynApp', 'Set to 1 to build an uploadable application', False)) opts.Add('ipaddr', 'Set the IP address of Smews', None) # the list of disableable options disabledHash = {} @@ -97,6 +98,7 @@ globalEnv = Environment(tools = ['gcc','as','ar','gnulink'], ENV = os.environ, o Help(opts.GenerateHelpText(globalEnv)) # arguments are stored into variables +dynApp = globalEnv['dynApp'] gzipped = globalEnv['gzip'] debug = globalEnv['debug'] sdump = globalEnv['sdump'] @@ -159,6 +161,7 @@ if len(targets) == 0: # will generate : # / -> smews, myApp/ -> myApplication, test/ -> test appDirs = originalAppDirs.split(',') + dirsMap = {} for appDir in set(appDirs + [httpCodesDir]): if appDir != '': @@ -168,6 +171,18 @@ for appDir in set(appDirs + [httpCodesDir]): else: dirsMap[appDir] = '/' + appDir +dynamicAppName = '' +if dynApp : + appDirNames = [] + for appDir in appDirs: + if appDir != '': + idx = appDir.find(':') + if idx != -1: + appDirNames.append(appDir[idx+1:]) + else: + appDirNames.append(appDir) + dynamicAppName = '_'.join(appDirNames) + # association between web applicative resources and their final URLs # appDir did only contain association of embedded applications # here, we retrieve all the files of each application @@ -185,14 +200,18 @@ for appDir in dirsMap.keys(): globalEnv.Replace(CC = 'gcc') globalEnv.Replace(AS = 'as') globalEnv.Replace(AR = 'ar') +globalEnv.Replace(LINK = 'ld') globalEnv.Append(CCFLAGS = '-Wall') if sdump: globalEnv.Append(CCFLAGS = '-DSTACK_DUMP') if debug: globalEnv.Append(CCFLAGS = '-O0 -g') else: - globalEnv.Append(CCFLAGS = '-Os -ffunction-sections -fdata-sections -fno-strict-aliasing') - globalEnv.Append(LINKFLAGS = '-Wl,--gc-sections -Wl,--print-gc-sections') + if dynApp : + globalEnv.Append(CCFLAGS = '-Os -fno-strict-aliasing') + else : + globalEnv.Append(CCFLAGS = '-Os -ffunction-sections -fdata-sections -fno-strict-aliasing') + globalEnv.Append(LINKFLAGS = '--gc-sections --print-gc-sections') globalEnv.Append(CPPDEFINES = {'CHUNCKS_NBITS' : str(chuncksNbits)}) for func in toDisable: globalEnv.Append(CPPDEFINES = { disabledHash[func] : '1'}) @@ -224,7 +243,7 @@ for target in targets: os.mkdir(dir) # export variables for external SConscript files - Export('env libFileName elfFileName binDir coreDir driversDir genDir appBase toolsList chuncksNbits sourcesMap gzipped test') + Export('env libFileName elfFileName binDir coreDir driversDir genDir appBase toolsList chuncksNbits sourcesMap gzipped test dynApp dynamicAppName') Export('env targetDir binDir projectName elfName') Export('dirsMap sourcesMap target sconsBasePath httpCodesDir tmpBase') # target dependent SConscript call diff --git a/apps/connectionsStats/stats.c b/apps/connectionsStats/stats.c index 938e042..679d3cf 100644 --- a/apps/connectionsStats/stats.c +++ b/apps/connectionsStats/stats.c @@ -65,5 +65,6 @@ static char doGet(struct args_t *args) { out_str("NULL\n"); out_str("\tsomething to send: "); out_uint(something_to_send(conn)); out_str("\n"); }) + return 1; } diff --git a/apps/contactsBook/cb_add.c b/apps/contactsBook/cb_add.c index e788d96..ec129af 100755 --- a/apps/contactsBook/cb_add.c +++ b/apps/contactsBook/cb_add.c @@ -35,7 +35,7 @@ /* - + @@ -47,7 +47,7 @@ #include "cb_shared.h" -static char doGet(struct args_t *args) { +static char doGetAdd(struct args_t *args) { unsigned char id = 0; uint16_t n = CONST_UI16(n_contacts); if(args && args->num < 5) { diff --git a/apps/contactsBook/cb_get.c b/apps/contactsBook/cb_get.c index e82d75c..4f1c00a 100755 --- a/apps/contactsBook/cb_get.c +++ b/apps/contactsBook/cb_get.c @@ -35,7 +35,7 @@ /* - + */ @@ -65,10 +65,9 @@ static void out_const_str(const unsigned char /*CONST_VAR*/ *str) { } } -static char doGet(struct args_t *args) { +static char doGetContacts(struct args_t *args) { uint16_t i = 0; uint16_t n = CONST_UI16(n_contacts); - out_const_str(str0); for(i=0; i + + + + + + +*/ + +#include "elf_allocator.h" + +#include "elfloader-otf.h" +#include "codeprop-otf.h" +#include "RamFileSystem.h" + +#include "application.h" + +struct file_t { + char *filename; + uint16_t size; +}; + +/* elf loader*/ +const char *elf_loader_return_labels[] = { + "ok", "Bad Elf Header", "No Symbol Table", "No String Table", "No Text section", "Symbol not found", "Segment not found", "No StartPoint", + "Unhandled Relocation", "Out Of Range", "Relocation Not Sorted", "Input Error", "Output Error" +}; + + +/* Storage buffer */ +#define STORAGE_BUFFER_SIZE 512 + +static uint8_t storage_buffer[STORAGE_BUFFER_SIZE]; + +void flash_dump() { + int i, index, maxInfosPerLine; + int allocatorSize = 256; + char *flash = (char *)elf_allocator_storage; + + maxInfosPerLine = 16; + + printf("\r\nFlash Dump:\r\n"); + printf("---------\r\n"); + + index = 0; + while(allocatorSize > maxInfosPerLine) { + + printf("%p ", flash + index); + + for(i = 0; i < maxInfosPerLine; i++, index++) + printf("%02X, ", flash[index]); + + printf("\r\n"); + allocatorSize -= maxInfosPerLine; + } + + if(allocatorSize>0) { + printf("%p ", flash + index); + for(i = 0; i < allocatorSize; i++, index++) + printf("%02X, ", flash[index]); + printf("\r\n"); + } + + printf("\r\n"); +} +extern char _text_end; +/*-----------------------------------------------------------------------------*/ +static char initElfLoader() { + + elf_applications_init(elf_allocator_flash_alloc, NULL); + printf("text end %p\r\n", &_text_end); + return 1; +} + +/*-----------------------------------------------------------------------------*/ +static char doPostIn(uint8_t content_type, /*uint16_t content_length,*/ uint8_t call_number, + char *filename, void **post_data) { + uint16_t i = 0; + uint16_t j = 0; + uint16_t k = 0; + short value; + printf("%s IN\r\n", __FUNCTION__); + + if(!filename) return 1; + + // Leave when data is already available.. + if(*post_data) return 1; + + struct file_t *file = mem_alloc(sizeof(struct file_t)); + if(!file) + return 1; + + /* Filename */ + while(filename[i++] != '\0'); + + file->filename = mem_alloc(i * sizeof(char)); + if(!file->filename) { + mem_free(file, sizeof(struct file_t)); + return 1; + } + + i = 0; + do { + file->filename[i] = filename[i]; + }while(filename[i++] != '\0'); + + /* Size + storage */ + i = 0; + while((value = in()) != -1) { + /*printf("%d\r\n", i);*/ + + if(j < STORAGE_BUFFER_SIZE) { + storage_buffer[j] = value; + j++; + } else { + + /* Commit buffer */ + if(APPLICATION_WRITE(((uint8_t *)elf_allocator_storage) + k, storage_buffer, STORAGE_BUFFER_SIZE) != 0) { + printf("An error happened while flashing elf to storage\r\n"); + return 1; + } + + k += STORAGE_BUFFER_SIZE; + printf("%d\r\n", k); + storage_buffer[0] = value; + j = 1; + } + + i++; + } + + if(j > 0) { + if(APPLICATION_WRITE(((uint8_t *)elf_allocator_storage) + k, storage_buffer, j) != 0) { + printf("An error happened while flashing elf to storage\r\n"); + return 1; + } + } + file->size = i; + + //printf("File Size is %d\r\n", file->size); + + + *post_data = file; + printf("%s OUT\r\n", __FUNCTION__); + return 1; +} + +void clean_up(struct file_t *file) { + uint16_t i = 0; + while(file->filename[i++] != '\0'); + + mem_free(file->filename, i * sizeof(char)); + mem_free(file, sizeof(struct file_t)); +} + +/*-----------------------------------------------------------------------------*/ +static char doPostOut(uint8_t content_type, void *data) { + + printf("%s IN\r\n", __FUNCTION__); + if(data) { + + uint16_t i; + struct file_t *file = (struct file_t*)data; + void *storage_handle; + int loading; + + storage_handle = rfs_open((void *)elf_allocator_storage); + + if(storage_handle == NULL) { + out_str("Unable to open elf storage"); + clean_up(file); + return 1; + } + + elfloader_init(); + printf("ElfLoader loading...\r\n"); + loading = elfloader_load(storage_handle, codeprop_output); + + printf("Loading = %d\r\n", loading); + if(loading == ELFLOADER_OK) { + /*flash_dump();*/ + printf("Elf Application Environment is %p\r\n", elf_application_environment); + + printf("Install function is %p\r\n", elf_application_environment->install); + printf("Remove function is %p\r\n", elf_application_environment->remove); + printf("URLS Tree is %p\r\n", elf_application_environment->urls_tree); + printf("Resources index is %p\r\n", elf_application_environment->resources_index); + + printf("Resources index[0] %p\r\n", elf_application_environment->resources_index[0]); + printf("Resources index[1] %p\r\n", elf_application_environment->resources_index[1]); + printf("Resources index[2] %p\r\n", elf_application_environment->resources_index[2]); + printf("Resources index[3] %p\r\n", elf_application_environment->resources_index[3]); + + if(!application_add(file->filename, file->size, data_address, data_size, elf_application_environment)) { + out_str("Failed to add application "); + out_str(file->filename); + out_str("."); + printf("Failed to add application %s.\r\n", file->filename); + clean_up(file); + return 1; + } + + out_str("The file \""); + out_str(file->filename); + out_str("\" has been uploaded successfully ("); + out_uint(file->size); + out_str(" bytes)\n"); + + } else { + + if(loading < 0) { + out_str("An internal error happened\r\n"); + } else { + out_str("An error happened while loading "); + out_str(file->filename); + out_str(" : "); + out_str(elf_loader_return_labels[loading]); + } + + rfs_close(storage_handle); + clean_up(file); + + } + + } else + out_str("Please provide a file"); + + printf("%s OUT\r\n", __FUNCTION__); + return 1; +} diff --git a/apps/elfloader/ElfMonitor.c b/apps/elfloader/ElfMonitor.c new file mode 100644 index 0000000..f82d3ad --- /dev/null +++ b/apps/elfloader/ElfMonitor.c @@ -0,0 +1,52 @@ +/* + + + + +*/ + +#include "../../core/elf_application.h" + +static CONST_VAR(unsigned char, fields_names[5][16]) = { + {"name"}, + {"size"}, +}; + +static CONST_VAR(unsigned char, str0[]) = "["; +static CONST_VAR(unsigned char, str1[]) = "{"; +static CONST_VAR(unsigned char, str2[]) = ":\""; +static CONST_VAR(unsigned char, str3[]) = "\","; +static CONST_VAR(unsigned char, str4[]) = "},"; +static CONST_VAR(unsigned char, str5[]) = "]"; + +static void out_const_str(const unsigned char /*CONST_VAR*/ *str) { + const unsigned char *c = str; + unsigned char tmp; + while((tmp = CONST_READ_UI8(c++))!='\0'){ + out_c(tmp); + } +} + +static char doGetApplis(struct args_t *args) { + out_const_str(str0); + + FOR_EACH_APPLICATION(appli, + + out_const_str(str1); + + out_const_str(fields_names[0]); + out_const_str(str2); + out_const_str(appli->filename); + out_const_str(str3); + + out_const_str(fields_names[1]); + out_const_str(str2); + out_uint(appli->size); + out_const_str(str3); + + out_const_str(str4); + ) + + out_const_str(str5); + return 1; +} diff --git a/apps/elfloader/RamFileSystem.c b/apps/elfloader/RamFileSystem.c new file mode 100644 index 0000000..7fbe9cc --- /dev/null +++ b/apps/elfloader/RamFileSystem.c @@ -0,0 +1,53 @@ + +#ifdef LINUX +#include +#include +#else +#include +#endif + +#include "tinyLibC.h" + +struct RamFileSystem { + const char *base; + const char *current; +}; + +struct RamFileSystem RFS = { + NULL, NULL +}; + +void *rfs_open(const char *aMemoryBank) { + RFS.base = aMemoryBank; + RFS.current = aMemoryBank; + return &RFS; +} + +void rfs_close(void *aHandle) { + RFS.base = 0; + RFS.current = 0; +} + +int rfs_tell(const void *aHandle) { + const struct RamFileSystem *rfs = (struct RamFileSystem *)aHandle; + return (rfs->current - rfs->base); +} + +int rfs_seek(void *aHandle, int anOffset) { + struct RamFileSystem *rfs = (struct RamFileSystem *)aHandle; + rfs->current = rfs->base + anOffset; + + return anOffset; +} + +int rfs_write(const void *aBuffer, int aLength, int aCount, void *aHandle) { + return -1; +} + +int rfs_read(void *aBuffer, int aLength, int aCount, void *aHandle) { + struct RamFileSystem *rfs = (struct RamFileSystem *)aHandle; + + memcpy(aBuffer, rfs->current, aLength * aCount); + rfs->current += aLength * aCount; + return (aLength * aCount); +} diff --git a/apps/elfloader/RamFileSystem.h b/apps/elfloader/RamFileSystem.h new file mode 100644 index 0000000..d9ba0ad --- /dev/null +++ b/apps/elfloader/RamFileSystem.h @@ -0,0 +1,12 @@ +#ifndef __RAM_FILE_SYSTEM_H__ +#define __RAM_FILE_SYSTEM_H__ + +extern void *rfs_open(const char *aMemoryBank); +extern void rfs_close(void *aHandle); + +extern int rfs_tell(const void *aHandle); +extern int rfs_seek(void *handle, int anOffset); +extern int rfs_write(const void *aBuffer, int aLength, int aCount, void *aHandle); +extern int rfs_read(void *aBuffer, int aLength, int aCount, void *aHandle); + +#endif diff --git a/apps/elfloader/application.c b/apps/elfloader/application.c new file mode 100644 index 0000000..79e96eb --- /dev/null +++ b/apps/elfloader/application.c @@ -0,0 +1,88 @@ +#include "application.h" +#include "elf_allocator.h" +#include "tinyLibC.h" + +static struct elf_application_t application_buffer; + +char application_add(const char *filename, uint16_t size, + char *data_address, unsigned int data_size, + struct elf_application_environment_t *environment) { + struct elf_application_t *applicationInFlash; + char res; + int filenameLength; + char *data_source; + + if((filename == NULL) || (size == 0) || (environment == NULL)) + return 0; + + data_source = NULL; + if(data_size > 0) { + data_source = (char *)elf_allocator_flash_alloc(data_size); + if(APPLICATION_WRITE(data_source, data_address, data_size) != 0) { + printf("FAILED to allocate data storage\r\n"); + return 0; + } + } + + if(environment->install) { + int i = 0; + while(environment->install[i] != NULL) { + res = environment->install[i](); + if(res != 0) { + printf("Application %s failed to install (%d).\r\n", filename, res); + return 0; + } + i++; + } + } + + /* Fill the application structure */ + /* +1 to keep the '\0' character */ + filenameLength = strlen(filename) + 1; + application_buffer.filename = elf_allocator_flash_alloc(filenameLength); + if(APPLICATION_WRITE(application_buffer.filename, filename, filenameLength) != 0) { + printf("FAILED TO WRITE application filename\r\n"); + return 0; + } + + printf("Application name is %s\r\n", application_buffer.filename); + + application_buffer.size = size; + application_buffer.environment = environment; + application_buffer.parsing = NULL; + application_buffer.data_destination = data_address; + application_buffer.data_source = data_source; + application_buffer.data_size = data_size; + + applicationInFlash = (struct elf_application_t *)elf_allocator_flash_alloc(sizeof(struct elf_application_t)); + + res = APPLICATION_WRITE(applicationInFlash, &application_buffer, sizeof(struct elf_application_t)); + + printf("Application In Flash : name %s, size %d, environment %p, parsing : %p\r\n", + applicationInFlash->filename, applicationInFlash->size, applicationInFlash->environment, applicationInFlash->parsing); + + return elf_application_add(applicationInFlash); +} + +void application_remove(const char *filename) { + if(all_applications != NULL) { + struct elf_application_t *application = all_applications; + while(application) { + if(strcmp(filename, application->filename) == 0) { + + elf_application_remove(application); + + if(application->environment->remove) { + int i = 0; + while(application->environment->remove[i] != NULL) { + application->environment->remove[i](); + i++; + } + } + // @WARNING We should deallocate memory here but doesn't have any free function in elf_allocator. + return; + } + application = application->next; + } + } +} diff --git a/apps/elfloader/application.h b/apps/elfloader/application.h new file mode 100644 index 0000000..f8b7638 --- /dev/null +++ b/apps/elfloader/application.h @@ -0,0 +1,9 @@ +#ifndef __APPLICATION_H__ +#define __APPLICATION_H__ + +#include "../../core/elf_application.h" + +extern char application_add(const char *filename, uint16_t size,char *data_address, unsigned int data_size, struct elf_application_environment_t *environment); +extern void application_remove(const char *filename); + +#endif diff --git a/apps/elfloader/codeprop-otf.h b/apps/elfloader/codeprop-otf.h new file mode 100644 index 0000000..4fbe14c --- /dev/null +++ b/apps/elfloader/codeprop-otf.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: codeprop-otf.h,v 1.1 2009/07/11 14:18:50 ksb Exp $ + */ +#ifndef __CODEPROP_H__ +#define __CODEPROP_H__ + +/* Segment writing object */ +extern struct elfloader_output *codeprop_output; + +#endif /* __CODEPROP_H__ */ diff --git a/apps/elfloader/elfScript.js b/apps/elfloader/elfScript.js new file mode 100644 index 0000000..60479d8 --- /dev/null +++ b/apps/elfloader/elfScript.js @@ -0,0 +1,57 @@ +var applications = null; +var fields = ["name","size"]; +var table = null; + +function setCellText(cell,cellValue) { + if(cellValue != "") { + var aText = document.createTextNode(cellValue); + cell.appendChild(aText); + } else { + cell.innerHTML = " "; + } +} + +function addTableLine(i) { + var tr = document.createElement("tr"); + tr.id = "application_" + i; + table.appendChild(tr); + for (j in fields) { + var td = document.createElement("td"); + td.id = "td_" + i + "_" + j; + var str = eval("applications[i]." + fields[j]); + str = unescape(str); + setCellText(td,str); + tr.appendChild(td); + } +} + +function updateApplications() { + table = document.getElementById("applicationsTable"); + for(var i in applications) { + addTableLine(i); + } +} + +function initFields(xhr) { + if(xhr.readyState == 4 && xhr.status == 200) { + applications = eval('(' + xhr.responseText + ')'); + updateApplications(); + } +} + +function ajaxGet(url,callBack,arg) { + var xhr; + var chart = this; + var xhrTimer; + try{ xhr = new XMLHttpRequest(); } + catch(e){ xhr = new ActiveXObject('Microsoft.XMLHTTP'); } + xhr.onreadystatechange = function(){ + if(callBack) callBack(xhr,arg); + }; + xhr.open("GET", url, true); + xhr.send(null); +} + +function init() { + ajaxGet('ElfMonitor',initFields); +} diff --git a/apps/elfloader/elf_allocator.c b/apps/elfloader/elf_allocator.c new file mode 100644 index 0000000..7096217 --- /dev/null +++ b/apps/elfloader/elf_allocator.c @@ -0,0 +1,47 @@ +#include "elf_allocator.h" + +/* RAM */ +#ifndef ELF_ALLOCATOR_RAM_SIZE +#define ELF_ALLOCATOR_RAM_SIZE 1024*10 +#endif + +/* FLASH */ +#ifndef ELF_ALLOCATOR_FLASH_ADDRESS +#define ELF_ALLOCATOR_FLASH_ADDRESS ((char *)0x00001000) +#endif + +#ifndef ELF_ALLOCATOR_FLASH_STORAGE_ADDRESS +#define ELF_ALLOCATOR_FLASH_STORAGE_ADDRESS ((char *)0x0000C000) +#endif + + +static char elf_allocator_ram_buffer[ELF_ALLOCATOR_RAM_SIZE]; +static char *elf_allocator_last_ram_used = 0; + +const char *elf_allocator_flash_buffer = ELF_ALLOCATOR_FLASH_ADDRESS; +static char *elf_allocator_last_flash_used = 0; + + +const void * elf_allocator_storage = ELF_ALLOCATOR_FLASH_STORAGE_ADDRESS; + +void *elf_allocator_ram_alloc(unsigned int size) { + char *result; + if(elf_allocator_last_ram_used == 0) + elf_allocator_last_ram_used = elf_allocator_ram_buffer; + + result = elf_allocator_last_ram_used; + elf_allocator_last_ram_used += size; + + return result; +} + +void *elf_allocator_flash_alloc(unsigned int size) { + char *result; + if(elf_allocator_last_flash_used == 0) + elf_allocator_last_flash_used = (char *)elf_allocator_flash_buffer; + + result = elf_allocator_last_flash_used; + elf_allocator_last_flash_used += ((size & 1) == 0) ? size : size + 1; // align on an even address + + return result; +} diff --git a/apps/elfloader/elf_allocator.h b/apps/elfloader/elf_allocator.h new file mode 100644 index 0000000..450f38e --- /dev/null +++ b/apps/elfloader/elf_allocator.h @@ -0,0 +1,10 @@ +#ifndef __ELF_ALLOCATOR_H__ +#define __ELF_ALLOCATOR_H__ + +extern const void * elf_allocator_storage; + +extern void *elf_allocator_ram_alloc(unsigned int size); + +extern void *elf_allocator_flash_alloc(unsigned int size); + +#endif diff --git a/apps/elfloader/elfloader-arch-otf.h b/apps/elfloader/elfloader-arch-otf.h new file mode 100644 index 0000000..f072264 --- /dev/null +++ b/apps/elfloader/elfloader-arch-otf.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * Copyright (c) 2007, Simon Berg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: elfloader-arch-otf.h,v 1.1 2009/07/11 14:18:50 ksb Exp $ + */ +/** + * \addtogroup elfloader + * @{ + */ + +/** + * \defgroup elfloaderarch Architecture specific functionality for the ELF loader. + * + * The architecture specific functionality for the Contiki ELF loader + * has to be implemented for each processor type Contiki runs on. + * + * Since the ELF format is slightly different for different processor + * types, the Contiki ELF loader is divided into two parts: the + * generic ELF loader module (\ref elfloader) and the architecture + * specific part (this module). The architecture specific part deals + * with memory allocation, code and data relocation, and writing the + * relocated ELF code into program memory. + * + * To port the Contiki ELF loader to a new processor type, this module + * has to be implemented for the new processor type. + * + * @{ + */ + +/** + * \file + * Header file for the architecture specific parts of the Contiki ELF loader. + * + * \author + * Adam Dunkels + * + */ + +#ifndef __ELFLOADER_ARCH_H__ +#define __ELFLOADER_ARCH_H__ + +#include "elfloader-otf.h" + + +/** + * \brief Perform a relocation. + * \param output The output object for the segment. + * \param sectionoffset The file offset at which the relocation can be found. + * \param sectionaddr The section start address (absolute runtime). + * \param rela A pointer to an ELF32 rela structure (struct elf32_rela). + * \param addr The relocated address. + * + * This function is called from the Contiki ELF loader to + * perform a relocation on a piece of code or data. The + * relocated address is calculated by the Contiki ELF + * loader, based on information in the ELF file, and it is + * the responsibility of this function to patch the + * executable code. The Contiki ELF loader passes a + * pointer to an ELF32 rela structure (struct elf32_rela) + * that contains information about how to patch the + * code. This information is different from processor to + * processor. + */ +int elfloader_arch_relocate(void *input_fd, + struct elfloader_output *output, + unsigned int sectionoffset, + char *sectionaddr, + struct elf32_rela *rela, char *addr, + struct elf32_sym *symbol); + +#endif /* __ELFLOADER_ARCH_H__ */ + +/** @} */ +/** @} */ diff --git a/apps/elfloader/elfloader-arm.c b/apps/elfloader/elfloader-arm.c new file mode 100644 index 0000000..627bd50 --- /dev/null +++ b/apps/elfloader/elfloader-arm.c @@ -0,0 +1,181 @@ +#include +#include "elfloader-arch-otf.h" + +#include "RamFileSystem.h" + +#if 1 +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) do {} while (0) +#endif + +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + + +/*Elf32_ST_TYPE*/ +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +#define ELF32_ST_TYPE(i) ((i)&0xf) + + +/* Supported relocations */ +#define R_ARM_ABS32 2 +#define R_ARM_THM_CALL 10 +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 + +struct mov_relocation_data { + int offsets[4]; + int mask; +}; + +const struct mov_relocation_data movw_relocation_data = { + {12, 11, 8, 0}, 0xFFFF +}; + +const struct mov_relocation_data movt_relocation_data = { + {28, 27, 24, 16}, 0xFFFF0000 +}; + +/* Adapted from elfloader-avr.c */ +int +elfloader_arch_relocate(void *input_fd, + struct elfloader_output *output, + unsigned int sectionoffset, + char *sectionaddr, + struct elf32_rela *rela, char *addr, + struct elf32_sym *symbol) +{ + unsigned int type; + + type = ELF32_R_TYPE(rela->r_info); + rfs_seek(input_fd, sectionoffset + rela->r_offset); + +/* PRINTF("elfloader_arch_relocate: type %d\n", type); + PRINTF("Addr: %p, Addend: %ld\n", addr, rela->r_addend); */ + switch(type) { + case R_ARM_ABS32: + { + int32_t addend; + rfs_read((char*)&addend, 4, 1, input_fd); + addr += addend; + elfloader_output_write_segment(output,(char*) &addr, 4); + /*printf("%p: addr: %p addend %p\r\n", sectionaddr +rela->r_offset, + addr, addend);*/ + } + break; + + case R_ARM_THM_CALL: { + uint16_t instr[2]; + int32_t offset; + int32_t addend; + + rfs_read((char *)instr, 4, 1, input_fd); + + // Build the addend from the instructions + addend = (instr[0] & 0x7FF) << 12 | (instr[1] & 0x7FF) << 1; + + // Sign extent, when we have a negative number, we preserve it through shifting. + if(addend & (1<<22)) + { + //printf("%x\r\n", addend); + addend |= 0xFF8<<20; + //printf("%x\r\n", addend); + } + + //printf("R_ARM_THM_CALL addend : %x %d\r\n",addend, addend); + // S + A + offset = addend + (uint32_t)addr; + + //printf("R_ARM_THM_CALL S + A : %x\r\n",offset); + + if(ELF32_ST_TYPE(symbol->st_info) == STT_FUNC) { + // (S + A) | T + offset |= 0x1; + //PRINTF("elfloader-arm.c: R_ARM_THM_CALL Symbol is STT_FUNC\r\n"); + } + + //printf("R_ARM_THM_CALL OFFSET (S + A) | T : %x\r\n",offset); + + // ((S+A) | T) - P + offset = offset - ((uint32_t)sectionaddr + (rela->r_offset)); + + //printf("R_ARM_THM_CALL ((S+A) | T) - P: %x\r\n",offset); + + instr[0] = ((offset >> 12) & 0x7FF) | 0xF000; + instr[1] = ((offset >> 1) & 0x7FF) | 0xF800; + + /*printf("R_ARM_THM_CALL after relocation: %04x %04x\r\n",instr[0], instr[1]);*/ + elfloader_output_write_segment(output, (char*)instr, 4); + } + break; + + + case R_ARM_THM_MOVW_ABS_NC : + case R_ARM_THM_MOVT_ABS : { + uint16_t instr[2]; + uint32_t mask; + int16_t addend = 0; + uint32_t val; + const struct mov_relocation_data *mov_relocation_data = + ( type == R_ARM_THM_MOVW_ABS_NC ) ? + &movw_relocation_data : &movt_relocation_data; + + rfs_read((char*)instr, 4, 1, input_fd); + + /*PRINTF("elfloader-arm.c: relocation %d\r\n", type); + PRINTF("elfloader-arm.c: R_ARM_THM_MOV before relocation %x %x\r\n", instr[0], instr[1]);*/ + + // Build the 16 bit addend from the instructions + addend |= (instr[0] & 0xF) << 12; + addend |= ((instr[0] >> 10) & 0x1) << 11; + addend |= ((instr[1] >> 12) & 0x7) << 8; + addend |= instr[1] & 0xF; + + /*printf("A: %x %d\r\n", addend, addend); + printf("S: %x %d\r\n", addr, addr);*/ + + // S + A + val = (uint32_t) addr + addend; + //printf("S+A %d %x\r\n", val, val); + + if(type == R_ARM_THM_MOVW_ABS_NC) { + // We are in thumb mode, we just have to check whether the symbol type is STT_FUNC + if(ELF32_ST_TYPE(symbol->st_info) == STT_FUNC) { + // (S + A) | T + val = val | 0x1; + //PRINTF("elfloader-arm.c: R_ARM_THM_MOVW_ABS_NC Symbol is STT_FUNC\r\n"); + } + } + + // Result_Mask + mask = val & mov_relocation_data->mask; + + instr[0] &= ~0xF; + instr[0] |= (mask >> mov_relocation_data->offsets[0]) & 0xF; + instr[0] &= ~(1<<10); + instr[0] |= ((mask >> mov_relocation_data->offsets[1]) & 0x1)<<10; + + instr[1] &= ~(0x7<<12); + instr[1] |= ((mask >> mov_relocation_data->offsets[2]) & 0x7)<<12; + instr[1] &= ~0xFF; + instr[1] |= (mask >> mov_relocation_data->offsets[3]) & 0xFF; + + //PRINTF("elfloader-arm.c: R_ARM_THM_MOV after relocation %x %x\r\n", instr[0], instr[1]); + elfloader_output_write_segment(output, (char*)instr, 4); + } + break; + + default: + printf("elfloader-arm.c: unsupported relocation type %d\n", type); + return ELFLOADER_UNHANDLED_RELOC; + } + + return ELFLOADER_OK; +} diff --git a/apps/elfloader/elfloader-otf.c b/apps/elfloader/elfloader-otf.c new file mode 100644 index 0000000..40b2128 --- /dev/null +++ b/apps/elfloader/elfloader-otf.c @@ -0,0 +1,848 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * Copyright (c) 2007, Simon Berg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: elfloader-otf.c,v 1.1 2009/07/11 14:18:50 ksb Exp $ + */ + +#ifdef LINUX + +#include +#include +#include +#include + +#else + +#include + +#endif + +#include "elfloader-otf.h" +#include "elfloader-arch-otf.h" + +//#include "cfs/cfs.h" +#include "RamFileSystem.h" +#include "symtab.h" +#include "tinyLibC.h" + +// For rodata linked list. +#include "../../core/memory.h" + +/*#include +#include +#include */ + +#if 0 +#include +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) do {} while (0) +//#define PRINTF(...) printf(__VA_ARGS__) +#endif + + + +#define EI_NIDENT 16 + + +struct elf32_ehdr { + unsigned char e_ident[EI_NIDENT]; /* ident bytes */ + elf32_half e_type; /* file type */ + elf32_half e_machine; /* target machine */ + elf32_word e_version; /* file version */ + elf32_addr e_entry; /* start address */ + elf32_off e_phoff; /* phdr file offset */ + elf32_off e_shoff; /* shdr file offset */ + elf32_word e_flags; /* file flags */ + elf32_half e_ehsize; /* sizeof ehdr */ + elf32_half e_phentsize; /* sizeof phdr */ + elf32_half e_phnum; /* number phdrs */ + elf32_half e_shentsize; /* sizeof shdr */ + elf32_half e_shnum; /* number shdrs */ + elf32_half e_shstrndx; /* shdr string index */ +}; + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ + +struct elf32_shdr { + elf32_word sh_name; /* section name */ + elf32_word sh_type; /* SHT_... */ + elf32_word sh_flags; /* SHF_... */ + elf32_addr sh_addr; /* virtual address */ + elf32_off sh_offset; /* file offset */ + elf32_word sh_size; /* section size */ + elf32_word sh_link; /* misc info */ + elf32_word sh_info; /* misc info */ + elf32_word sh_addralign; /* memory alignment */ + elf32_word sh_entsize; /* entry size if table */ +}; + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends*/ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relation section without addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +struct elf32_rel { + elf32_addr r_offset; /* Location to be relocated. */ + elf32_word r_info; /* Relocation type and symbol index. */ +}; + +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + + +struct relevant_section { + unsigned char number; + unsigned int offset; + char *address; +}; + +struct relevant_rodata_section { + unsigned char number; + unsigned int offset; + char *address; + struct relevant_rodata_section *next; +}; + +char elfloader_unknown[MAX_SYMBOL_SIZE]; /* Name that caused link error. */ + +static struct relevant_section bss, data, rodata, text; + +const static unsigned char elf_magic_header[] = + {0x7f, 0x45, 0x4c, 0x46, /* 0x7f, 'E', 'L', 'F' */ + 0x01, /* Only 32-bit objects. */ + 0x01, /* Only LSB data. */ + 0x01, /* Only ELF version 1. */ + }; + +#define COPY_SEGMENT_DATA_BUFFER_SIZE 128 + +static char copy_segment_data_buffer[COPY_SEGMENT_DATA_BUFFER_SIZE]; +/* Copy data from the elf file to a segment */ +static int +copy_segment_data(void *input_fd, unsigned int offset, + struct elfloader_output *output, unsigned int len) +{ + int res; + + /*printf("Copy Segment Data IN input %p output %p buffer %p, len : %d\r\n", input_fd, output, buffer, len);*/ + + if (rfs_seek(input_fd, offset) != offset) return ELFLOADER_INPUT_ERROR; + while(len > sizeof(copy_segment_data_buffer)) { + + res = rfs_read(copy_segment_data_buffer, sizeof(copy_segment_data_buffer), 1, input_fd); + if (res != sizeof(copy_segment_data_buffer)) return ELFLOADER_INPUT_ERROR; + + res = elfloader_output_write_segment(output, copy_segment_data_buffer, sizeof(copy_segment_data_buffer)); + + if (res != sizeof(copy_segment_data_buffer)) return ELFLOADER_OUTPUT_ERROR; + len -= sizeof(copy_segment_data_buffer); + + } + + if (len) + { + res = rfs_read(copy_segment_data_buffer, len, 1, input_fd); + if (res != len) return ELFLOADER_INPUT_ERROR; + res = elfloader_output_write_segment(output, copy_segment_data_buffer, len); + if (res != len) return ELFLOADER_OUTPUT_ERROR; + } + /*printf("Copy Segment Data OUT input %p output %p\r\n", input_fd, output);*/ + + return ELFLOADER_OK; +} + +static int +seek_read(void *fd, unsigned int offset, char *buf, int len) +{ + if (rfs_seek(fd, offset) != offset) return -1; + return rfs_read(buf, len, 1, fd); +} + +static void * +find_local_symbol(void *input_fd, const char *symbol, + unsigned int symtab, unsigned short symtabsize, + unsigned int strtab, + struct relevant_rodata_section *rodatas) +{ + struct elf32_sym s; + unsigned int a; + char name[MAX_SYMBOL_SIZE]; + struct relevant_section *sect; + int ret; + + //printf("Symbol : %s\r\n", symbol); + + + for(a = symtab; a < symtab + symtabsize; a += sizeof(s)) { + ret = seek_read(input_fd, a, (char *)&s, sizeof(s)); + if (ret < 0) return NULL; + + if(s.st_name != 0) { + ret = seek_read(input_fd, strtab + s.st_name, name, sizeof(name)); + if (ret < 0) return NULL; + + if(strcmp(name, symbol) == 0) { + if(s.st_shndx == bss.number) { + sect = &bss; + } else if(s.st_shndx == data.number) { + sect = &data; + } else if(s.st_shndx == text.number) { + sect = &text; + } else if(s.st_shndx == rodata.number){ + sect = &rodata; + } else { + struct relevant_rodata_section *rodata = rodatas; + while(rodata) { + if(rodata->number == s.st_shndx) { + return &(rodata->address[s.st_value]); + } + + rodata = rodata->next; + } + return NULL; + } + + return &(sect->address[s.st_value]); + } + } + } + return NULL; +} + +/*---------------------------------------------------------------------------*/ +static int +relocate_section(void *input_fd, + struct elfloader_output *output, + unsigned int section, unsigned short size, + unsigned int sectionaddr, + char *sectionbase, + unsigned int strs, + unsigned int strtab, + unsigned int symtab, unsigned short symtabsize, + unsigned char using_relas, + struct relevant_rodata_section *rodatas) +{ + /* sectionbase added; runtime start address of current section */ + struct elf32_rela rela; /* Now used both for rel and rela data! */ + int rel_size = 0; + struct elf32_sym s; + unsigned int a; + char *addr; + struct relevant_section *sect; + int ret; + char name[MAX_SYMBOL_SIZE]; + + /* determine correct relocation entry sizes */ + if(using_relas) { + rel_size = sizeof(struct elf32_rela); + } else { + rel_size = sizeof(struct elf32_rel); + } + + addr = NULL; + +// printf("elfloader : Section %x size :%d relsize %d\r\n", section, size, rel_size); + + for(a = section; a < section + size; a += rel_size) { + ret = seek_read(input_fd, a, (char *)&rela, rel_size); + if (ret < 0) return ELFLOADER_INPUT_ERROR; + + ret = seek_read(input_fd, + (symtab + + sizeof(struct elf32_sym) * ELF32_R_SYM(rela.r_info)), + (char *)&s, sizeof(struct elf32_sym)); + + if (ret < 0) return ELFLOADER_INPUT_ERROR; + + if(s.st_name != 0) { + char c; + int offset = 0; + rfs_seek(input_fd, strtab + s.st_name); + + do { + rfs_read(&c, 1, 1, input_fd); + name[offset++] = c; + } while(c != '\0' && offset < sizeof(name)); + + /*ret = seek_read(input_fd, offset, name, sizeof(name)); + if (ret < 0) return ELFLOADER_INPUT_ERROR;*/ + if (offset >= sizeof(name)) return ELFLOADER_INPUT_ERROR; + + + addr = (char *)symtab_lookup(name); + + /* ADDED */ + if(addr == NULL) { + addr = find_local_symbol(input_fd, name, symtab, symtabsize, strtab, rodatas); + } + + if(addr == NULL) { + if(s.st_shndx == bss.number) { + sect = &bss; + } else if(s.st_shndx == data.number) { + sect = &data; + } else if(s.st_shndx == rodata.number) { + sect = &rodata; + } else if(s.st_shndx == text.number ) { + sect = &text; + } else { + printf("elfloader unknown name: '%s'\n", name); + memcpy(elfloader_unknown, name, sizeof(elfloader_unknown)); + elfloader_unknown[sizeof(elfloader_unknown) - 1] = 0; + return ELFLOADER_SYMBOL_NOT_FOUND; + } + addr = sect->address; + } + } else { + if(s.st_shndx == bss.number) { + addr = bss.address; + } else if(s.st_shndx == data.number) { + addr = data.address; + } else if(s.st_shndx == rodata.number) { + addr = rodata.address; + } else if(s.st_shndx == text.number) { + addr = text.address; + } else { + struct relevant_rodata_section *rodata = rodatas; + while(rodata) { + if(rodata->number == s.st_shndx) { + addr = rodata->address; + break; + } + + rodata = rodata->next; + } + } + + if(addr == NULL) { + return ELFLOADER_SEGMENT_NOT_FOUND; + } + } + +#if 0 /* We don't know how big the relocation is or even if we need to read it. + Let the architecture dependant code decide */ + if (!using_relas) { + /* copy addend to rela structure */ + ret = seek_read(fd, sectionaddr + rela.r_offset, &rela.r_addend, 4); + if (ret < 0) return ELFLOADER_INPUT_ERROR; + } +#endif + { + /* Copy data up to the next relocation */ + unsigned int offset = elfloader_output_segment_offset(output); + if (rela.r_offset < offset) { + PRINTF("elfloader relocation out of offset order\r\n"); + + } + if (rela.r_offset > offset) { + ret = copy_segment_data(input_fd, offset+sectionaddr, output, + rela.r_offset - offset); + + if (ret != ELFLOADER_OK) return ret; + } + } + + ret = elfloader_arch_relocate(input_fd, output, sectionaddr, sectionbase, + &rela, addr, &s); + + + if (ret != ELFLOADER_OK) return ret; + } + + return ELFLOADER_OK; +} + +/*---------------------------------------------------------------------------*/ +void +elfloader_init(void) +{ +} +/*---------------------------------------------------------------------------*/ +#if 0 +static void +print_chars(unsigned char *ptr, int num) +{ + int i; + for(i = 0; i < num; ++i) { + PRINTF("%d", ptr[i]); + if(i == num - 1) { + PRINTF("\n"); + } else { + PRINTF(", "); + } + } +} +#endif /* 0 */ + +static int +copy_segment(void *input_fd, + struct elfloader_output *output, + unsigned int section, unsigned short size, + unsigned int sectionaddr, + char *sectionbase, + unsigned int strs, + unsigned int strtab, + unsigned int symtab, unsigned short symtabsize, + unsigned char using_relas, + unsigned int seg_size, unsigned int seg_type, + struct relevant_rodata_section *rodatas) +{ + unsigned int offset; + int ret; + + ret = elfloader_output_start_segment(output, seg_type,sectionbase, seg_size); + if (ret != ELFLOADER_OK) return ret; + + ret = relocate_section(input_fd, output, + section, size, + sectionaddr, + sectionbase, + strs, + strtab, + symtab, symtabsize, using_relas, rodatas); + + if (ret != ELFLOADER_OK) return ret; + + offset = elfloader_output_segment_offset(output); + ret = copy_segment_data(input_fd, offset+sectionaddr, output,seg_size - offset); + + if (ret != ELFLOADER_OK) return ret; + + return elfloader_output_end_segment(output); +} + +static void cleanup_rodatas(struct relevant_rodata_section *rodatas) { + struct relevant_rodata_section *next_rodata; + struct relevant_rodata_section *temp_rodata; + temp_rodata = rodatas; + while(temp_rodata) { + next_rodata = temp_rodata->next; + mem_free(temp_rodata, sizeof(struct relevant_rodata_section)); + temp_rodata = next_rodata; + } +} + +/*---------------------------------------------------------------------------*/ +struct elf_application_environment_t *elf_application_environment; +char *data_address; +unsigned int data_size; + + +int +elfloader_load(void *input_fd, struct elfloader_output *output) +{ + struct elf32_ehdr ehdr; + struct elf32_shdr shdr; + struct elf32_shdr strtable; + unsigned int strs; + unsigned int shdrptr; + unsigned int nameptr; + char name[12]; + + int i; + unsigned short shdrnum, shdrsize; + + unsigned char using_relas = -1; + unsigned short textoff = 0, textsize, textrelaoff = 0, textrelasize; + unsigned short dataoff = 0, datasize, datarelaoff = 0, datarelasize; + unsigned short rodataoff = 0, rodatasize, rodatarelaoff = 0, rodatarelasize; + unsigned short symtaboff = 0, symtabsize; + unsigned short strtaboff = 0, strtabsize; + unsigned short bsssize = 0; + + struct relevant_rodata_section *rodatas = NULL; + struct relevant_rodata_section *temp_rodata = NULL; + + void *localSymbol; + int ret; + + elfloader_unknown[0] = 0; + + /* The ELF header is located at the start of the buffer. */ + ret = seek_read(input_fd, 0, (char *)&ehdr, sizeof(ehdr)); + if (ret != sizeof(ehdr)) return ELFLOADER_INPUT_ERROR; + + /* print_chars(ehdr.e_ident, sizeof(elf_magic_header)); + print_chars(elf_magic_header, sizeof(elf_magic_header));*/ + /* Make sure that we have a correct and compatible ELF header. */ + if(memcmp(ehdr.e_ident, elf_magic_header, sizeof(elf_magic_header)) != 0) { + PRINTF("ELF header problems\n"); + return ELFLOADER_BAD_ELF_HEADER; + } + + /* Grab the section header. */ + shdrptr = ehdr.e_shoff; + ret = seek_read(input_fd, shdrptr, (char *)&shdr, sizeof(shdr)); + if (ret != sizeof(shdr)) return ELFLOADER_INPUT_ERROR; + + /* Get the size and number of entries of the section header. */ + shdrsize = ehdr.e_shentsize; + shdrnum = ehdr.e_shnum; + + /* The string table section: holds the names of the sections. */ + ret = seek_read(input_fd, ehdr.e_shoff + shdrsize * ehdr.e_shstrndx, + (char *)&strtable, sizeof(strtable)); + if (ret != sizeof(strtable)) return ELFLOADER_INPUT_ERROR; + /* Get a pointer to the actual table of strings. This table holds + the names of the sections, not the names of other symbols in the + file (these are in the sybtam section). */ + strs = strtable.sh_offset; + + /* Go through all sections and pick out the relevant ones. The + ".text" segment holds the actual code from the ELF file, the + ".data" segment contains initialized data, the ".rodata" segment + contains read-only data, the ".bss" segment holds the size of the + unitialized data segment. The ".rel[a].text" and ".rel[a].data" + segments contains relocation information for the contents of the + ".text" and ".data" segments, respectively. The ".symtab" segment + contains the symbol table for this file. The ".strtab" segment + points to the actual string names used by the symbol table. + + In addition to grabbing pointers to the relevant sections, we + also save the section number for resolving addresses in the + relocator code. + */ + + + /* Initialize the segment sizes to zero so that we can check if + their sections was found in the file or not. */ + textsize = textrelasize = datasize = datarelasize = + rodatasize = rodatarelasize = symtabsize = strtabsize = 0; + + bss.number = data.number = rodata.number = text.number = -1; + + bss.address = data.address = rodata.address = text.address = NULL; + bss.offset = data.offset = rodata.offset = text.offset = 0; + + shdrptr = ehdr.e_shoff; + + // first, find all .rodata.* sections + for(i = 0; i < shdrnum; ++i) { + + ret = seek_read(input_fd, shdrptr, (char *)&shdr, sizeof(shdr)); + if (ret != sizeof(shdr)) return ELFLOADER_INPUT_ERROR; + + /* The name of the section is contained in the strings table. */ + nameptr = strs + shdr.sh_name; + ret = seek_read(input_fd, nameptr, name, sizeof(name)); + if (ret != sizeof(name)) return ELFLOADER_INPUT_ERROR; + + if(strncmp(name, ".rodata.str", 11) == 0) { + + temp_rodata = mem_alloc(sizeof(struct relevant_rodata_section)); + if(!temp_rodata) { + PRINTF("Unable to allocate relevant rodata section.\r\n"); + return ELFLOADER_OUTPUT_ERROR; + } + + temp_rodata->number = i; + temp_rodata->offset = shdr.sh_offset; + + temp_rodata->address = (char *) + elfloader_output_alloc_segment(output, ELFLOADER_SEG_RODATA, shdr.sh_size); + if (!temp_rodata->address) { + PRINTF("Unable to allocate relevant rodata section space.\r\n"); + return ELFLOADER_OUTPUT_ERROR; + } + + printf("rodata.str allocated \r\n"); + + ret = elfloader_output_start_segment(output, ELFLOADER_SEG_RODATA, + temp_rodata->address, shdr.sh_size); + if(ret != ELFLOADER_OK) return ret; + + copy_segment_data(input_fd, shdr.sh_offset, output, shdr.sh_size); + + // Head insert + temp_rodata->next = rodatas; + rodatas = temp_rodata; + } + + /* Move on to the next section header. */ + shdrptr += shdrsize; + } + + /*temp_rodata = rodatas; + while(temp_rodata) { + printf("Loaded RODATA %d\r\n", temp_rodata->number); + + temp_rodata = temp_rodata->next; + }*/ + + + // NOW the bss, data, text sections. + shdrptr = ehdr.e_shoff; + + for(i = 0; i < shdrnum; ++i) { + + ret = seek_read(input_fd, shdrptr, (char *)&shdr, sizeof(shdr)); + if (ret != sizeof(shdr)) return ELFLOADER_INPUT_ERROR; + + /* The name of the section is contained in the strings table. */ + nameptr = strs + shdr.sh_name; + ret = seek_read(input_fd, nameptr, name, sizeof(name)); + if (ret != sizeof(name)) return ELFLOADER_INPUT_ERROR; + + /* Match the name of the section with a predefined set of names + (.text, .data, .bss, .rela.text, .rela.data, .symtab, and + .strtab). */ + /* added support for .rodata, .rel.text and .rel.data). */ + + + if(strcmp(name, ".text") == 0) { + textoff = shdr.sh_offset; + textsize = shdr.sh_size; + text.number = i; + text.offset = textoff; + } else if(strcmp(name, ".rel.text") == 0) { + using_relas = 0; + textrelaoff = shdr.sh_offset; + textrelasize = shdr.sh_size; + } else if(strcmp(name, ".rela.text") == 0) { + using_relas = 1; + textrelaoff = shdr.sh_offset; + textrelasize = shdr.sh_size; + } else if(strcmp(name, ".data") == 0) { + dataoff = shdr.sh_offset; + datasize = shdr.sh_size; + data.number = i; + data.offset = dataoff; + } else if(strcmp(name, ".rodata") == 0) { + /* read-only data handled the same way as regular text section */ + rodataoff = shdr.sh_offset; + rodatasize = shdr.sh_size; + rodata.number = i; + rodata.offset = rodataoff; + } else if(strcmp(name, ".rel.rodata") == 0) { + /* using elf32_rel instead of rela */ + using_relas = 0; + rodatarelaoff = shdr.sh_offset; + rodatarelasize = shdr.sh_size; + } else if(strcmp(name, ".rela.rodata") == 0) { + using_relas = 1; + rodatarelaoff = shdr.sh_offset; + rodatarelasize = shdr.sh_size; + } else if(strcmp(name, ".rel.data") == 0) { + /* using elf32_rel instead of rela */ + using_relas = 0; + datarelaoff = shdr.sh_offset; + datarelasize = shdr.sh_size; + } else if(strcmp(name, ".rela.data") == 0) { + using_relas = 1; + datarelaoff = shdr.sh_offset; + datarelasize = shdr.sh_size; + } else if(strcmp(name, ".symtab") == 0) { + symtaboff = shdr.sh_offset; + symtabsize = shdr.sh_size; + } else if(strcmp(name, ".strtab") == 0) { + strtaboff = shdr.sh_offset; + strtabsize = shdr.sh_size; + } else if(strcmp(name, ".bss") == 0) { + bsssize = shdr.sh_size; + bss.number = i; + bss.offset = 0; + } + + /* Move on to the next section header. */ + shdrptr += shdrsize; + } + + if(symtabsize == 0) { + return ELFLOADER_NO_SYMTAB; + } + if(strtabsize == 0) { + return ELFLOADER_NO_STRTAB; + } + if(textsize == 0) { + return ELFLOADER_NO_TEXT; + } + + + if (bsssize) { + bss.address = (char *) + elfloader_output_alloc_segment(output, ELFLOADER_SEG_BSS, bsssize); + if (!bss.address) return ELFLOADER_OUTPUT_ERROR; + } + + + data_address = NULL; + data_size = 0; + if (datasize) { + data.address = (char *) + elfloader_output_alloc_segment(output,ELFLOADER_SEG_DATA,datasize); + if (!data.address) return ELFLOADER_OUTPUT_ERROR; + + data_address = data.address; + data_size = datasize; + } + if (textsize) { + text.address = (char *) + elfloader_output_alloc_segment(output,ELFLOADER_SEG_TEXT,textsize); + if (!text.address) return ELFLOADER_OUTPUT_ERROR; + } + if (rodatasize) { + rodata.address = (char *) + elfloader_output_alloc_segment(output,ELFLOADER_SEG_RODATA,rodatasize); + /*printf("RODATA ADDRESS IS %p\r\n", rodata.address);*/ + if (!rodata.address) return ELFLOADER_OUTPUT_ERROR; + } + +/* If we have text segment relocations, we process them. */ + if(textrelasize > 0) { + PRINTF("elfloader: relocate text\r\n"); + ret = copy_segment(input_fd, output, + textrelaoff, textrelasize, + textoff, + text.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas, + textsize, ELFLOADER_SEG_TEXT, rodatas); + if(ret != ELFLOADER_OK) { + PRINTF("elfloader: text failed\r\n"); + return ret; + } + } + + /* If we have any rodata segment relocations, we process them too. */ + if(rodatarelasize > 0) { + PRINTF("elfloader: relocate rodata %d %d %d\r\n", rodatarelaoff, rodatarelasize, rodataoff); + ret = copy_segment(input_fd, output, + rodatarelaoff, rodatarelasize, + rodataoff, + rodata.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas, + rodatasize, ELFLOADER_SEG_RODATA, rodatas); + if(ret != ELFLOADER_OK) { + PRINTF("elfloader: data failed\r\n"); + return ret; + } + } else { + // When no relocation is performed, we still have to copy the rodata values. + if(rodatasize) { + ret = elfloader_output_start_segment(output, ELFLOADER_SEG_RODATA, + rodata.address, rodatasize); + if(ret != ELFLOADER_OK) return ret; + + copy_segment_data(input_fd, rodataoff, output, rodatasize); + } + } + + /* If we have any data segment relocations, we process them too. */ + if(datarelasize > 0) { + PRINTF("elfloader: relocate data\r\n"); + ret = copy_segment(input_fd, output, + datarelaoff, datarelasize, + dataoff, + data.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas, + datasize, ELFLOADER_SEG_DATA, rodatas); + if(ret != ELFLOADER_OK) { + PRINTF("elfloader: data failed\n"); + return ret; + } + ret = elfloader_output_end_segment(output); + if (ret != ELFLOADER_OK) return ret; + } else { + if(datasize) { + ret = elfloader_output_start_segment(output, ELFLOADER_SEG_DATA, + data.address, datasize); + if(ret != ELFLOADER_OK) return ret; + + copy_segment_data(input_fd, dataoff, output, datasize); + } + } + + /* Write text and rodata segment into flash and data segment into RAM. */ +/* elfloader_arch_write_rom(fd, textoff, textsize, text.address); */ +/* elfloader_arch_write_rom(fd, rodataoff, rodatasize, rodata.address); */ + + { + /* Write zeros to bss segment */ + unsigned int len = bsssize; + static const char zeros[16] = {0}; + ret = elfloader_output_start_segment(output, ELFLOADER_SEG_BSS, + bss.address,bsssize); + if (ret != ELFLOADER_OK) return ret; + while(len > sizeof(zeros)) { + ret = elfloader_output_write_segment(output, zeros, sizeof(zeros)); + if (ret != sizeof(zeros)) return ELFLOADER_OUTPUT_ERROR; + len -= sizeof(zeros); + } + ret = elfloader_output_write_segment(output, zeros, len); + if (ret != len) return ELFLOADER_OUTPUT_ERROR; + } + + PRINTF("elfloader: elf application environment search\r\n"); + + localSymbol = find_local_symbol(input_fd, ELF_APPLICATION_ENVIRONMENT_NAME, symtaboff, symtabsize, strtaboff, rodatas); + + cleanup_rodatas(rodatas); + + if(localSymbol != NULL) { + PRINTF("elfloader: elf application environment %p\r\n", localSymbol); + elf_application_environment = (struct elf_application_environment_t *)localSymbol; + + return ELFLOADER_OK; + } +/* + PRINTF("elfloader: no autostart\n"); + process = (struct process **) find_program_processes(fd, symtaboff, symtabsize, strtaboff); + if(process != NULL) { + PRINTF("elfloader: FOUND PRG\n"); + }*/ + PRINTF("elfloader: elf application environment not found\r\n"); + return ELFLOADER_NO_STARTPOINT; +} +/*---------------------------------------------------------------------------*/ diff --git a/apps/elfloader/elfloader-otf.h b/apps/elfloader/elfloader-otf.h new file mode 100644 index 0000000..1339bdc --- /dev/null +++ b/apps/elfloader/elfloader-otf.h @@ -0,0 +1,339 @@ +/** + * \addtogroup loader + * @{ + */ + +/** + * \defgroup elfloader The Contiki ELF loader + * + * The Contiki ELF loader links, relocates, and loads ELF + * (Executable Linkable Format) object files into a running Contiki + * system. + * + * ELF is a standard format for relocatable object code and executable + * files. ELF is the standard program format for Linux, Solaris, and + * other operating systems. + * + * An ELF file contains either a standalone executable program or a + * program module. The file contains both the program code, the + * program data, as well as information about how to link, relocate, + * and load the program into a running system. + * + * The ELF file is composed of a set of sections. The sections contain + * program code, data, or relocation information, but can also contain + * debugging information. + * + * To link and relocate an ELF file, the Contiki ELF loader first + * parses the ELF file structure to find the appropriate ELF + * sections. It then allocates memory for the program code and data in + * ROM and RAM, respectively. After allocating memory, the Contiki ELF + * loader starts relocating the code found in the ELF file. + * + * @{ + */ + +/** + * \file + * Header file for the Contiki ELF loader. + * \author + * Adam Dunkels + * Simon Berg + * + */ + +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * Copyright (c) 2007, Simon Berg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#ifndef __ELFLOADER_H__ +#define __ELFLOADER_H__ + +#include "../../core/elf_application.h" + +/** + * Return value from elfloader_load() indicating that loading worked. + */ +#define ELFLOADER_OK 0 +/** + * Return value from elfloader_load() indicating that the ELF file had + * a bad header. + */ +#define ELFLOADER_BAD_ELF_HEADER 1 +/** + * Return value from elfloader_load() indicating that no symbol table + * could be find in the ELF file. + */ +#define ELFLOADER_NO_SYMTAB 2 +/** + * Return value from elfloader_load() indicating that no string table + * could be find in the ELF file. + */ +#define ELFLOADER_NO_STRTAB 3 +/** + * Return value from elfloader_load() indicating that the size of the + * .text segment was zero. + */ +#define ELFLOADER_NO_TEXT 4 +/** + * Return value from elfloader_load() indicating that a symbol + * specific symbol could not be found. + * + * If this value is returned from elfloader_load(), the symbol has + * been copied into the elfloader_unknown[] array. + */ +#define ELFLOADER_SYMBOL_NOT_FOUND 5 +/** + * Return value from elfloader_load() indicating that one of the + * required segments (.data, .bss, or .text) could not be found. + */ +#define ELFLOADER_SEGMENT_NOT_FOUND 6 +/** + * Return value from elfloader_load() indicating that no starting + * point could be found in the loaded module. + */ +#define ELFLOADER_NO_STARTPOINT 7 + +/** + * Return value from elfloader_load() indicating that the ELF file contained + * a relocation type that the implementation can't handle. + */ +#define ELFLOADER_UNHANDLED_RELOC 8 + +/** + * Return value from elfloader_load() indicating that the offset for + * a relative addressing mode was too big. + */ +#define ELFLOADER_OUTOF_RANGE 9 + +/** + * Return value from elfloader_load() indicating that the relocations + * where not sorted by offset + */ +#define ELFLOADER_RELOC_NOT_SORTED 10 + +/** + * Return value from elfloader_load() indicating that reading from the + * ELF file failed in some way. + */ +#define ELFLOADER_INPUT_ERROR 11 + +/** + * Return value from elfloader_load() indicating that writing to a segment + * failed. + */ +#define ELFLOADER_OUTPUT_ERROR 12 + + +#define ELFLOADER_SEG_TEXT 1 +#define ELFLOADER_SEG_RODATA 2 +#define ELFLOADER_SEG_DATA 3 +#define ELFLOADER_SEG_BSS 4 + +#define MAX_SYMBOL_SIZE 128 + +/** + * elfloader output object + * + * This object defines methods (callbacks) for writing the segments to memory. + * It can be extended by the user to include any necessary state. + */ + +struct elfloader_output { + const struct elfloader_output_ops *ops; +}; +/** + * \brief Allocate a new segment + * \param input The output object + * \param type Type of segment + * \param size Size of segment in bytes + * \return A pointer to the start of the segment. + * + * The returned address doesn't need to correspond to any real memory, + * since it's only used for calculating the relocations. + */ + +void *elfloader_allocate_segment(struct elfloader_output *output, + unsigned int type, int size); + +/** + * \brief Start writing to a new segment + * \param input The output object + * \param type Type of segment + * \param addr Address of segment from elfloader_allocate_segment + * \param size Size of segment in bytes + * \return Returns ELFLOADER_OK if successful, otherwise an error code + * + */ + +int elfloader_start_segment(struct elfloader_output *output, + unsigned int type, void *addr, int size); +/** + * \brief Mark end of segment + * \param input The output object + * \return Zero if successful + */ + +int elfloader_end_segment(struct elfloader_output *output); + +/** + * \brief Write data to a segment + * \param input The output object + * \param buf Data to be written + * \param len Length of data + * \return The number of bytes actually written, or negative if failed. + */ + +int elfloader_write_segment(struct elfloader_output *output, const char *buf, + unsigned int len); + +/** + * \brief Get the current offset in the file where the next data will + * be written. + * \param input The output object + * \return The current offset. + */ + +unsigned int elfloader_segment_offset(struct elfloader_output *output); + +#define elfloader_output_alloc_segment(output, type, size) \ +((output)->ops->allocate_segment(output, type, size)) + +#define elfloader_output_start_segment(output, type, addr, size) \ +((output)->ops->start_segment(output, type, addr, size)) + +#define elfloader_output_end_segment(output) \ +((output)->ops->end_segment(output)) + +#define elfloader_output_write_segment(output, buf, len) \ +((output)->ops->write_segment(output, buf, len)) + +/* +#define elfloader_output_write_segment(output, buf, len) \ +(printf("%p %p %d\r\n", output, buf, len),((output)->ops->write_segment(output, buf, len))) +*/ + +#define elfloader_output_segment_offset(output) \ +((output)->ops->segment_offset(output)) + + +struct elfloader_output_ops { + void * (*allocate_segment)(struct elfloader_output *output, + unsigned int type, int size); + int (*start_segment)(struct elfloader_output *output, + unsigned int type, void *addr, int size); + int (*end_segment)(struct elfloader_output *output); + int (*write_segment)(struct elfloader_output *output, const char *buf, + unsigned int len); + unsigned int (*segment_offset)(struct elfloader_output *output); +}; + + +/** + * elfloader initialization function. + * + * This function should be called at boot up to initilize the elfloader. + */ +void elfloader_init(void); + +/** + * \brief Load and relocate an ELF file. + * \param input Input object defining how to read from the ELF file + * \param output Output object defining how to create and write to seegments. + * \return ELFLOADER_OK if loading and relocation worked. + * Otherwise an error value. + * + * If the function is able to load the ELF file, a pointer + * to the process structure in the model is stored in the + * elfloader_loaded_process variable. + * + */ +int elfloader_load(void *input_fd, + struct elfloader_output *output); + +/** + * A pointer to the processes loaded with elfloader_load(). + */ +/*extern struct process **elfloader_autostart_processes;*/ +#ifdef ELF_APPLICATION_ENVIRONMENT_NAME +#undef ELF_APPLICATION_ENVIRONMENT_NAME +#endif + +#define ELF_APPLICATION_ENVIRONMENT_NAME "elf_application_environment" + +extern struct elf_application_environment_t *elf_application_environment; +extern char *data_address; +extern unsigned int data_size; + +/** + * If elfloader_load() could not find a specific symbol, it is copied + * into this array. + */ +extern char elfloader_unknown[MAX_SYMBOL_SIZE]; + +#ifdef ELFLOADER_CONF_DATAMEMORY_SIZE +#define ELFLOADER_DATAMEMORY_SIZE ELFLOADER_CONF_DATAMEMORY_SIZE +#else +#define ELFLOADER_DATAMEMORY_SIZE 0x100 +#endif + +#ifdef ELFLOADER_CONF_TEXTMEMORY_SIZE +#define ELFLOADER_TEXTMEMORY_SIZE ELFLOADER_CONF_TEXTMEMORY_SIZE +#else +#define ELFLOADER_TEXTMEMORY_SIZE 0x100 +#endif + +typedef unsigned long elf32_word; +typedef signed long elf32_sword; +typedef unsigned short elf32_half; +typedef unsigned long elf32_off; +typedef unsigned long elf32_addr; + +struct elf32_rela { + elf32_addr r_offset; /* Location to be relocated. */ + elf32_word r_info; /* Relocation type and symbol index. */ + elf32_sword r_addend; /* Addend. */ +}; + +struct elf32_sym { + elf32_word st_name; /* String table index of name. */ + elf32_addr st_value; /* Symbol value. */ + elf32_word st_size; /* Size of associated object. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + elf32_half st_shndx; /* Section index of symbol. */ +}; + + +#endif /* __ELFLOADER_H__ */ + +/** @} */ +/** @} */ diff --git a/apps/elfloader/index.html b/apps/elfloader/index.html new file mode 100644 index 0000000..772ef51 --- /dev/null +++ b/apps/elfloader/index.html @@ -0,0 +1,26 @@ + + + + + Smews Elf Loader + + + + + +

Welcome to the elf applications manager

+

Uploaded applications

+ + + + +
NameSize
+

Upload a file

+
+ + +
+ + + diff --git a/apps/elfloader/ram-segments.c b/apps/elfloader/ram-segments.c new file mode 100644 index 0000000..40aa0e0 --- /dev/null +++ b/apps/elfloader/ram-segments.c @@ -0,0 +1,139 @@ +#ifndef __RAM_SEGMENTS_C__1POIF5E8U4__ +#define __RAM_SEGMENTS_C__1POIF5E8U4__ + +#include "elfloader-otf.h" +#include "codeprop-otf.h" + + +#include "elf_allocator.h" + +#include "tinyLibC.h" + +struct ram_output +{ + struct elfloader_output output; + char *base; + unsigned int offset, type; + void *text; + void *rodata; + void *data; + void *bss; + void *flashLimit; +}; + +static void * +allocate_segment(struct elfloader_output * const output, + unsigned int type, int size) +{ + struct ram_output * const ram = (struct ram_output *)output; + + switch(type) { + case ELFLOADER_SEG_TEXT: + /*if (ram->text) mem_free(ram->text, ram->textSize);*/ + ram->text = elf_allocator_flash_alloc(size); + return ram->text; + + case ELFLOADER_SEG_RODATA: + /*if (ram->rodata) free(ram->rodata, ram->rodataSize);*/ + ram->rodata = elf_allocator_flash_alloc(size); + return ram->rodata; + + case ELFLOADER_SEG_DATA: + /*if (ram->data) free(ram->data, ram->dataSize);*/ + ram->data = elf_allocator_ram_alloc(size); + return ram->data; + + case ELFLOADER_SEG_BSS: + /*if (ram->bss) free(ram->bss, ram->bssSize);*/ + ram->bss = elf_allocator_ram_alloc(size); + return ram->bss; + } + return 0; +} + +static int +start_segment(struct elfloader_output *output, + unsigned int type, void *addr, int size) +{ + ((struct ram_output*)output)->base = addr; + ((struct ram_output*)output)->offset = 0; + ((struct ram_output*)output)->type = type; + return ELFLOADER_OK; +} + +static int +end_segment(struct elfloader_output *output) +{ + return ELFLOADER_OK; +} + +static int +write_segment(struct elfloader_output *output, const char *buf, + unsigned int len) +{ + struct ram_output * const memory = (struct ram_output *)output; + printf("ram-segments.write Base %p + Ram Offset %x = %p (%d bytes)\r\n", memory->base, memory->offset, memory->base + memory->offset,len); + printf("Output->ops %p 0\r\n", output->ops); + switch(memory->type) { + case ELFLOADER_SEG_TEXT : + case ELFLOADER_SEG_RODATA : { + int ret; + + if(memory->flashLimit) { + if( ((memory->base + memory->offset) <= (char *)memory->flashLimit) && + ((memory->base + memory->offset + len) >= (char *)memory->flashLimit)) { + printf("No more available flash memory\r\n"); + return -2; + } + } + + printf("Output->ops %p 1 Memory %p\r\n", output->ops, memory->base + memory->offset); + ret = APPLICATION_WRITE(memory->base + memory->offset, buf, len); + printf("Output->ops %p 2\r\n", output->ops); + if(ret != 0) { + printf("An error happened while writing to flash %d\r\n", ret); + return ret; + } + } + + break; + default : + fake_memcpy(memory->base + memory->offset, buf, len); + break; + + } + + memory->offset += len; + + return len; +} + +static unsigned int +segment_offset(struct elfloader_output *output) +{ + return ((struct ram_output*)output)->offset; +} + +static const struct elfloader_output_ops elf_output_ops = + { + allocate_segment, + start_segment, + end_segment, + write_segment, + segment_offset + }; + +static struct ram_output seg_output = { + {&elf_output_ops}, + 0, 0, + 0, + 0, 0, 0, 0, 0 +}; + +struct elfloader_output *codeprop_output = &seg_output.output; + +void ram_segments_set_flash_limit(void *aLimit) { + seg_output.flashLimit = aLimit; +} + +#endif /* __RAM_SEGMENTS_C__1POIF5E8U4__ */ diff --git a/apps/elfloader/ram-segments.h b/apps/elfloader/ram-segments.h new file mode 100644 index 0000000..ef7f342 --- /dev/null +++ b/apps/elfloader/ram-segments.h @@ -0,0 +1,6 @@ +#ifndef __RAM_SEGMENTS_H__ +#define __RAM_SEGMENTS_H__ + +extern void ram_segments_set_flash_limit(void *aLimit); + +#endif diff --git a/apps/elfloader/style.css b/apps/elfloader/style.css new file mode 100755 index 0000000..6ddb865 --- /dev/null +++ b/apps/elfloader/style.css @@ -0,0 +1,19 @@ +body {fill: #333333; color: #333333; font-family: sans-serif; font-size: 12pt; } +h1 {text-align: center; font-weight: normal; font-size: 2em; } + +img { border: 0px; } +a { color: #000000; text-decoration: none; } +a:hover { color: #444466; text-decoration: underline; } + +#smewsLogo { display: block; text-align: center; } +#contactsTable { position: relative; margin: 0 auto; border: 3px solid #444466; border-collapse: collapse; } +#contactsTable td, #contactsTable th { padding: 5px; text-align: center; font-size: 0.9em; } +#contactsTable th { border: 3px solid #444466; } +#contactsTable td { border: 1px solid #666688; width: 10em; } +#contactsTable tr { height: 2.4em; } +#googleFrame { width: 450px; height: 250px; } +#googleLink { font-size: 0.8em; float: right; } +#smewsContact { position: absolute; background-color: #dddddd; padding: 6px; border: 2px solid black; } +.fieldInput { width: 97%; } +.busyCell { background-color: #bbffbb; } +#adddel { color: #444466; font-weight: bold; font-size: 18px; text-align: center; } diff --git a/apps/elfloader/symbols.c b/apps/elfloader/symbols.c new file mode 100644 index 0000000..d897657 --- /dev/null +++ b/apps/elfloader/symbols.c @@ -0,0 +1,52 @@ +#include +#include "symbols.h" +#include "../../core/generators.h" +#include "../../core/connections.h" +#include "../../core/timers.h" +#include "../../core/memory.h" + + +const struct symbols symbols[] = { + {"get_all_connections", get_all_connections }, + {"get_current_remote_ip", get_current_remote_ip }, + {"get_local_ip", get_local_ip }, +#ifndef DISABLE_GP_IP_HANDLER + {"get_payload_size", get_payload_size }, + {"get_protocol", get_protocol }, +#endif + {"get_remote_ip", get_remote_ip }, + +#ifndef DISABLE_GP_IP_HANDLER + {"get_send_code", get_send_code }, +#endif + +#if !defined(DISABLE_POST) || !defined(DISABLE_GP_IP_HANDLER) + {"in", in }, +#endif + {"mem_alloc", mem_alloc }, + {"mem_free", mem_free }, + {"out_c", out_c }, + {"out_str", out_str }, + {"out_uint", out_uint }, + {"printf", printf}, + + {"rand", rand }, + +#ifndef DISABLE_GP_IP_HANDLER + {"request_packet_out_call", request_packet_out_call }, +#endif + + {"rflpc_timer_get_counter", rflpc_timer_get_counter }, + +#ifndef DISABLE_COMET + {"server_push", server_push}, +#endif +#ifndef DISABLE_TIMERS + {"set_timer", set_timer}, +#endif + {"something_to_send", something_to_send }, + + {"srand", srand } +}; + +const int symbols_nelts = sizeof(symbols)/sizeof(struct symbols); diff --git a/apps/elfloader/symbols.h b/apps/elfloader/symbols.h new file mode 100644 index 0000000..e1e811e --- /dev/null +++ b/apps/elfloader/symbols.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: symbols.h,v 1.5 2007/01/30 18:04:59 bg- Exp $ + */ +#ifndef __SYMBOLS_H__ +#define __SYMBOLS_H__ + +struct symbols { + const char *name; + void *value; +}; + +extern const int symbols_nelts; + +extern const struct symbols symbols[/* symbols_nelts */]; + +#endif /* __SYMBOLS_H__ */ diff --git a/apps/elfloader/symtab.c b/apps/elfloader/symtab.c new file mode 100644 index 0000000..ce06a6c --- /dev/null +++ b/apps/elfloader/symtab.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: symtab.c,v 1.7 2007/01/24 16:13:50 adamdunkels Exp $ + */ + +#include "symtab.h" + +#include "symbols.h" + +#include "tinyLibC.h" + +/* Binary search is twice as large but still small. */ +#ifndef SYMTAB_CONF_BINARY_SEARCH +#define SYMTAB_CONF_BINARY_SEARCH 1 +#endif + +/*---------------------------------------------------------------------------*/ +#if SYMTAB_CONF_BINARY_SEARCH +void * +symtab_lookup(const char *name) +{ + int start, middle, end; + int r; + + start = 0; + end = symbols_nelts - 1; /* Last entry is { 0, 0 }. */ + while(start <= end) { + /* Check middle, divide */ + middle = (start + end) / 2; + r = strcmp(name, symbols[middle].name); + if(r < 0) { + end = middle - 1; + } else if(r > 0) { + start = middle + 1; + } else { + return symbols[middle].value; + } + } + return 0; +} +#else * SYMTAB_CONF_BINARY_SEARCH */ +void * +symtab_lookup(const char *name) +{ + const struct symbols *s; + + for(s = symbols; s->name != NULL; ++s) { + if(strcmp(name, s->name) == 0) { + return s->value; + } + } + return 0; +} +#endif /* SYMTAB_CONF_BINARY_SEARCH */ +/*---------------------------------------------------------------------------*/ diff --git a/apps/elfloader/symtab.h b/apps/elfloader/symtab.h new file mode 100644 index 0000000..f01eb6b --- /dev/null +++ b/apps/elfloader/symtab.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: symtab.h,v 1.4 2007/01/12 13:55:05 bg- Exp $ + */ +#ifndef __SYMTAB_H__ +#define __SYMTAB_H__ + +void *symtab_lookup(const char *name); + +#endif /* __SYMTAB_H__ */ diff --git a/apps/elfloader/tinyLibC.c b/apps/elfloader/tinyLibC.c new file mode 100644 index 0000000..9f77f68 --- /dev/null +++ b/apps/elfloader/tinyLibC.c @@ -0,0 +1,63 @@ +#include "tinyLibC.h" + +/* not written for speed*/ +int memcmp(const void *aPointer, const void *anotherPointer, int aSize) { + const char *pointer = (const char *) aPointer; + const char *nother = (const char *) aPointer; + int i = 0; + for(i = 0; i < aSize; i++) { + if(pointer[i] != nother[i]) + return pointer[i] - nother[i]; + } + return 0; +} + +int strlen(const char *aString) { + int i = 0; + while(aString[i] != '\0') + i++; + return i; +} + +int strcmp(const char *aString, const char *anotherString) { + while (*aString == *anotherString && *aString != '\0') + { + aString++;anotherString++; + } + return *aString - *anotherString; +/* + + int length = strlen(aString); + int diff = length - strlen(anotherString); + if(diff == 0) + return memcmp(aString, anotherString, length); + return diff;*/ +} + +char toLower(char aChar) { + if(aChar>= 'a' && (aChar <= 'z')) + return aChar; + return (aChar>= 'A' && (aChar <= 'Z')) ? aChar - 'A' + 'a' : aChar; +} + +int strncmp(const char *aString, const char *anotherString, int aSize) { + while (*aString == *anotherString && *aString != '\0' && --aSize) { + aString++;anotherString++; + } + return *aString - *anotherString; +/* int diff, i; + for(i = 0; i < aSize; i++) { + diff = toLower(aString[i]) - toLower(anotherString[i]); + if(diff != 0) + return diff; + } + return 0;*/ +} + +void fake_memcpy(void *dest, const void *source, int len) { + int i; + char * dst = (char *)dest; + const char *src = (const char *)source; + for(i = 0; i < len; i++) + dst[i] = src[i]; +} diff --git a/apps/elfloader/tinyLibC.h b/apps/elfloader/tinyLibC.h new file mode 100644 index 0000000..4d95840 --- /dev/null +++ b/apps/elfloader/tinyLibC.h @@ -0,0 +1,13 @@ +#ifndef __TINY_LIB_C_H__ +#define __TINY_LIB_C_H__ + +#ifndef LINUX +extern int memcmp(const void *aPointer, const void *anotherPointer, int aSize); +extern int strlen(const char *aString); +extern int strcmp(const char *aString, const char *anotherString); +extern int strncmp(const char *aString, const char *anotherString, int aSize); +extern char toLower(char aChar); +extern void fake_memcpy(void *dest, const void *source, int len); +#endif + +#endif diff --git a/apps/kernel_console/kernel_console.c b/apps/kernel_console/kernel_console.c index f8e571b..ff3ac0e 100644 --- a/apps/kernel_console/kernel_console.c +++ b/apps/kernel_console/kernel_console.c @@ -99,7 +99,8 @@ static char kernel_console_init() } -extern CONST_VAR(const struct output_handler_t *, resources_index[]); +extern struct output_handler_t * resources_index[]; +/*extern CONST_VAR(const struct output_handler_t *, resources_index[]);*/ extern CONST_VAR(unsigned char, urls_tree[]); void kernel_console_ressource_index(const char *args) { diff --git a/core/connections.c b/core/connections.c index e4b937d..afdf516 100644 --- a/core/connections.c +++ b/core/connections.c @@ -36,6 +36,8 @@ #include "connections.h" #include "memory.h" +#include "elf_application.h" + /* Local IP address */ #ifdef IPV6 @@ -57,6 +59,10 @@ unsigned char local_ip_addr[4] = { IP_ADDR }; struct connection *all_connections; struct http_rst_connection rst_connection; +struct connection *get_all_connections() { + return all_connections; +} + #ifdef IPV6 /*-----------------------------------------------------------------------------------*/ @@ -158,12 +164,15 @@ struct connection *add_connection(const struct connection *from #else connection = mem_alloc(sizeof(struct connection)); /* test NULL: done */ #endif + if (connection == NULL) return NULL; /* copy the connection */ - if (from != NULL) + if (from != NULL) { *connection = *from; + } + /* insert the new connection */ if(all_connections == NULL) { connection->next = connection; @@ -175,6 +184,11 @@ struct connection *add_connection(const struct connection *from connection->next = all_connections; all_connections->prev = connection; } + +#ifndef DISABLE_ELF + elf_application_add_connection(connection); +#endif + return connection; } @@ -198,8 +212,15 @@ void free_connection(const struct connection *connection) { #endif if(connection->protocol.http.generator_service) { clean_service(connection->protocol.http.generator_service, NULL); +#ifndef DISABLE_COROUTINES + cr_clean(&connection->protocol.http.generator_service->coroutine); +#endif mem_free(connection->protocol.http.generator_service, sizeof(struct generator_service_t)); } +#ifndef DISABLE_ELF + elf_application_remove_connection(connection); +#endif + } #ifdef IPV6 diff --git a/core/connections.h b/core/connections.h index ef09b51..2a49a49 100644 --- a/core/connections.h +++ b/core/connections.h @@ -178,12 +178,12 @@ struct connection { /* Loop on each connection */ #define FOR_EACH_CONN(item, code) \ - if(all_connections) { \ - struct connection *(item) = all_connections; \ + if(get_all_connections()) { \ + struct connection *(item) = get_all_connections(); \ do { \ {code} \ (item) = (item)->next; \ - } while((item) != all_connections); \ + } while((item) != get_all_connections()); \ } \ #define NEXT_CONN(item) (item) = (item)->next @@ -204,6 +204,7 @@ struct http_rst_connection { extern struct connection *all_connections; extern struct http_rst_connection rst_connection; +extern struct connection *get_all_connections(); diff --git a/core/coroutines.c b/core/coroutines.c index ec453f4..a285d0e 100644 --- a/core/coroutines.c +++ b/core/coroutines.c @@ -53,6 +53,15 @@ static struct coroutine_t *cr_in_stack = NULL; /* Currently running coroutine. Null when the main program is running. */ static volatile struct coroutine_t *current_cr = NULL; +void dumpCRInStack() { + if(cr_in_stack == NULL) { + printf("No cr in stack\r\n"); + return; + } + + printf("CR in stack %p, sp %p\r\n", cr_in_stack, cr_in_stack->curr_context.sp[0]); +} + /* initialize a coroutine structure */ void cr_init(struct coroutine_t *coroutine) { coroutine->curr_context.status = cr_ready; @@ -73,31 +82,38 @@ void cr_run(struct coroutine_t *coroutine ) { /* push all working registers */ PUSHREGS; + /* backup current context stack pointer(s) */ if(current_cr) { BACKUP_CTX(current_cr->curr_context.sp); } else { BACKUP_CTX(main_sp); } + /* set new current context */ current_cr = coroutine; + if(current_cr) { RESTORE_CTX(current_cr->curr_context.sp); /* test if this is the first time we run this context */ if(current_cr->curr_context.status == cr_ready) { current_cr->curr_context.status = cr_active; + + #ifndef DISABLE_POST if(type == cor_type_post_out) current_cr->func.func_post_out(current_cr->params.out.content_type,current_cr->params.out.post_data); else if(type == cor_type_post_in) - current_cr->func.func_post_in(current_cr->params.in.content_type,current_cr->params.in.part_number,current_cr->params.in.filename,(void**)¤t_cr->params.in.post_data); + current_cr->func.func_post_in(current_cr->params.in.content_type,/* current_cr->params.in.content_length,*/ current_cr->params.in.part_number,current_cr->params.in.filename,(void**)¤t_cr->params.in.post_data); else #endif current_cr->func.func_get(current_cr->params.args); + current_cr->curr_context.status = cr_terminated; current_cr = NULL; } } + if(current_cr == NULL) { /* restore the main program stack pointer if needed */ RESTORE_CTX(main_sp); @@ -112,16 +128,23 @@ void cr_run(struct coroutine_t *coroutine struct coroutine_t *cr_prepare(struct coroutine_t *coroutine) { if(cr_in_stack != coroutine) { if(cr_in_stack != NULL) { /* is there a coroutine currently using the shared stack? */ + /* backup its context in a freshly allocated buffer of the exact needed size */ char *sp = cr_in_stack->curr_context.sp[0]; uint16_t stack_size = shared_stack + STACK_SIZE - sp; - cr_in_stack->curr_context.stack = mem_alloc(stack_size); /* test NULL: done */ - if(cr_in_stack->curr_context.stack == NULL) { - return NULL; + + if(stack_size>0) { + + cr_in_stack->curr_context.stack = mem_alloc(stack_size); /* test NULL: done */ + + if(cr_in_stack->curr_context.stack == NULL) { + return NULL; + } + + cr_in_stack->curr_context.stack_size = stack_size; + /* process the copy from (big) shared stack to the new (small) buffer */ + memcpy(cr_in_stack->curr_context.stack, sp, stack_size); } - cr_in_stack->curr_context.stack_size = stack_size; - /* process the copy from (big) shared stack to the new (small) buffer */ - memcpy(cr_in_stack->curr_context.stack, sp, stack_size); } if(coroutine->curr_context.stack != NULL) { /* does the new coroutine already has an allocated stack? */ /* restore its context to the (big) shared stack */ @@ -133,6 +156,7 @@ struct coroutine_t *cr_prepare(struct coroutine_t *coroutine) { /* update the cr_in_stack pointer */ cr_in_stack = coroutine; } + return cr_in_stack; } diff --git a/core/coroutines.h b/core/coroutines.h index 4346d05..ac9dfa3 100644 --- a/core/coroutines.h +++ b/core/coroutines.h @@ -53,7 +53,7 @@ typedef char (cr_func_get)(struct args_t *args); #ifndef DISABLE_POST typedef char (cr_func_post_out)(uint8_t content_type,void *post_data); -typedef char (cr_func_post_in)(uint8_t content_type, uint8_t part_number, char *filename, void **post_data); +typedef char (cr_func_post_in)(uint8_t content_type, /*uint16_t content_length,*/ uint8_t part_number, char *filename, void **post_data); #endif /* A context (possibly several per coroutine) */ @@ -82,6 +82,7 @@ struct coroutine_t { #ifndef DISABLE_POST struct in_t { /* used with dopostin function */ uint8_t content_type; + /*uint16_t content_length;*/ uint8_t part_number; /* number of part with multipart data (0 if one part) */ char *filename; /* filename of current file */ void *post_data; /* data flowing between dopostin and dopostout functions */ @@ -116,6 +117,8 @@ enum coroutine_type_e { cor_type_get, cor_type_post_in, cor_type_post_out } coro /* Functions and variables for coroutines */ +extern void dumpCRInStack(); + /* initialize a coroutine structure */ extern void cr_init(struct coroutine_t *coroutine); /* prepare a coroutine for usage: the context is copied in the shared stack diff --git a/core/elf_application.c b/core/elf_application.c new file mode 100644 index 0000000..cd8ed01 --- /dev/null +++ b/core/elf_application.c @@ -0,0 +1,389 @@ +#ifndef DISABLE_ELF + +#include "elf_application.h" +#include "memory.h" + +unsigned int elf_applications_count __attribute__ ((section(".persistent_data"))) = 0; + +struct elf_application_t *all_applications __attribute__ ((section(".persistent_data"))) = 0; + +/* Post Url termination character */ +#define URL_POST_END 255 + +/* "404 Not found" handler */ +#define http_404_handler apps_httpCodes_404_html_handler +extern CONST_VAR(struct output_handler_t, apps_httpCodes_404_html_handler); + +static elf_application_allocate_t elf_application_allocate; +static elf_application_free_t elf_application_free; + +void elf_applications_init(elf_application_allocate_t allocate, elf_application_free_t free) { + elf_application_allocate = allocate; + elf_application_free = free; +} + +int elf_application_get_count() { return elf_applications_count; } + + +char elf_application_add(struct elf_application_t *application) { + struct elf_application_parsing_t *parsing; + /* Head insert */ + struct elf_application_t *buf[1]; + unsigned int i; + const struct output_handler_t * /*CONST_VAR*/ output_handler; + + /*application->previous = NULL; */ + buf[0] = NULL; + APPLICATION_WRITE(&application->previous, buf, sizeof(struct elf_application_t *)); + + if(all_applications == NULL) { + /* application->next = NULL; */ + APPLICATION_WRITE(&application->next, buf, sizeof(struct elf_application_t *)); + } else { + /* application->next = all_applications; */ + APPLICATION_WRITE(&application->next, &all_applications, sizeof(struct elf_application_t *)); + /* all_applications->previous = application; */ + APPLICATION_WRITE(&all_applications->previous, application, sizeof(struct elf_application_t *)); + } + + /* all_applications = application; */ + APPLICATION_WRITE(&all_applications, &application, sizeof(struct elf_application_t *)); + + { + unsigned int elfApplicationsCount = elf_applications_count + 1; + APPLICATION_WRITE((void *)&elf_applications_count, &elfApplicationsCount, sizeof(unsigned int)); + } + + i = 0; + while((output_handler = CONST_ADDR(application->environment->resources_index[i])) != NULL) { + + if(CONST_UI8(output_handler->handler_type) == type_generator + #ifndef DISABLE_GP_IP_HANDLER + || CONST_UI8(output_handler->handler_type) == type_general_ip_handler + #endif + ) { + generator_init_func_t * init_handler = CONST_ADDR(GET_GENERATOR(output_handler).init); + if(init_handler) + init_handler(); + } + + i++; + } + + /* Add all existing connections to the application's parsing */ + FOR_EACH_CONN(conn, { + if(!IS_HTTP(conn)) { + NEXT_CONN(conn); + continue; + } + + parsing = (struct elf_application_parsing_t *)mem_alloc(sizeof(struct elf_application_parsing_t)); + parsing->connection = conn; + parsing->blob = application->environment->urls_tree; + parsing->previous = NULL; + parsing->next = application->parsing; + + if(application->parsing != NULL) { + application->parsing->previous = parsing; + } + + APPLICATION_WRITE(&application->parsing, &parsing, sizeof(struct elf_application_parsing_t *)); + }) + + return 1; +} + +void elf_application_remove(const struct elf_application_t *application) { + if(elf_application_get_count() > 0 ) { + struct elf_application_t *appli = all_applications; + + while(appli) { + if(application == appli) { + + /* remove the parsing data */ + { + struct elf_application_parsing_t *parsing = appli->parsing; + struct elf_application_parsing_t *parsingNext; + while(parsing) { + parsingNext = parsing->next; + mem_free(parsing, sizeof(struct elf_application_parsing_t)); + parsing = parsingNext; + } + } + + /* Now remove the application by itself */ + if(application == all_applications) { + + /* all_applications = application->next; */ + APPLICATION_WRITE(all_applications, application->next, sizeof(struct elf_application_t *)); + + if(all_applications != NULL) { + /* all_applications->previous = NULL; */ + struct elf_application_t *buf[1]; + buf[0] = NULL; + APPLICATION_WRITE(all_applications->previous, buf, sizeof(struct elf_application_t *)); + } + + } else { + /* application->previous->next = application->next; */ + APPLICATION_WRITE(application->previous->next, application->next, sizeof(struct elf_application_t *)); + + /* application->next->previous = application->previous; */ + APPLICATION_WRITE(application->next->previous, application->previous, sizeof(struct elf_application_t *)); + } + + { + unsigned int elfApplicationsCount = elf_applications_count - 1; + APPLICATION_WRITE((void *)&elf_applications_count, &elfApplicationsCount, sizeof(unsigned int)); + } + return; + } + appli = appli->next; + } + } +} + +/* When the device resets, init all dynamic applications*/ +void elf_application_init() { + + if(elf_application_get_count() > 0) { + struct elf_application_t *appli = all_applications; + const struct output_handler_t * /*CONST_VAR*/ output_handler; + int i; + + while(appli) { + + + if(appli->data_size>0) { + memcpy(appli->data_destination, appli->data_source, appli->data_size); + } + + + i = 0; + while((output_handler = CONST_ADDR(appli->environment->resources_index[i])) != NULL) { + + if(CONST_UI8(output_handler->handler_type) == type_generator +#ifndef DISABLE_GP_IP_HANDLER + || CONST_UI8(output_handler->handler_type) == type_general_ip_handler +#endif + ) { + generator_init_func_t * init_handler = CONST_ADDR(GET_GENERATOR(output_handler).init); + if(init_handler) + init_handler(); + } + + i++; + } + + appli = appli->next; + } + + } +} + +/* When a connection has been created */ +void elf_application_add_connection(struct connection *connection) { + if(connection) { + + if(!IS_HTTP(connection)) + return; + + if(elf_application_get_count() > 0 ) { + struct elf_application_parsing_t *parsing; + struct elf_application_t * appli = all_applications; + + + while(appli) { + + parsing = (struct elf_application_parsing_t *)mem_alloc(sizeof(struct elf_application_parsing_t)); + /* Head insert */ + parsing->connection = connection; + parsing->blob = appli->environment->urls_tree; + parsing->previous = NULL; + parsing->next = appli->parsing; + + if(appli->parsing != NULL) + appli->parsing->previous = parsing; + + APPLICATION_WRITE(&appli->parsing, &parsing, sizeof(struct elf_application_parsing_t *)); + + appli = appli->next; + } + } + } +} +/* When a connection has been terminated */ +void elf_application_remove_connection(const struct connection *connection) { + if(connection) { + if(elf_application_get_count() > 0 ) { + struct elf_application_parsing_t *parsing; + struct elf_application_t * appli = all_applications; + + while(appli) { + parsing = appli->parsing; + + while(parsing) { + + if(parsing->connection == connection) { + if(parsing->previous) + parsing->previous->next = parsing->next; + + if(parsing->next) + parsing->next->previous = parsing->previous; + + if(parsing == appli->parsing) { + APPLICATION_WRITE(&appli->parsing, &parsing->next, sizeof(struct elf_application_parsing_t *)); + } + + mem_free(parsing, sizeof(struct elf_application_parsing_t)); + break; + } + + parsing = parsing->next; + } + + appli = appli->next; + } + } + } +} + +struct output_handler_t *url_parse_step(uint8_t byte, unsigned char **url_blob, const struct output_handler_t **resources_index) { + unsigned char *blob; + unsigned char blob_curr; + + blob = *url_blob; + blob_curr = CONST_READ_UI8(blob); + + if(blob_curr == URL_POST_END) { + blob++; + blob_curr = CONST_READ_UI8(blob); + } + + if(blob_curr >= 128) { + if (byte == ' ') { + printf("======> OUTPUT HANDLER FOUND %p %d<=====\r\n", CONST_ADDR(resources_index[blob_curr - 128]), blob_curr - 128); + return (struct output_handler_t*)CONST_ADDR(resources_index[blob_curr - 128]); + } + + blob++; + blob_curr = CONST_READ_UI8(blob); + } + + do { + unsigned char offsetInf = 0; + unsigned char offsetEq = 0; + unsigned char blob_next; + + blob_curr = CONST_READ_UI8(blob); + blob_next = CONST_READ_UI8(++blob); + if (byte != blob_curr && blob_next >= 128) { + blob_next = CONST_READ_UI8(++blob); + } + + if (blob_next < 32) { + offsetInf += + ((blob_next>>2) & 1) + ((blob_next>>1) & 1) + (blob_next & 1); + + offsetEq = offsetInf + ((blob_next & 2)?CONST_READ_UI8(blob+1):0); + } + if (byte == blob_curr) { + if (blob_next < 32) { + if (blob_next & 2) + blob += offsetEq; + else { + *url_blob = blob; + return &http_404_handler; + } + } + + *url_blob = blob; + return NULL; + } + else if (byte < blob_curr) { + if (blob_next < 32 && blob_next & 1) { + blob += offsetInf; + } + else { + *url_blob = blob; + return &http_404_handler; + } + } + else { + if (blob_next < 32 && blob_next & 4) { + unsigned char offsetSup = offsetEq + ((blob_next & 3) ? CONST_READ_UI8(blob + (offsetInf - 1)) : 0); + + blob += offsetSup; + } + else { + *url_blob = blob; + return &http_404_handler; + } + } + } while(1); + + return NULL; +} + +void elf_application_parsing_start(const struct connection *connection) { + if(elf_application_get_count() > 0) { + struct elf_application_parsing_t *parsing; + struct elf_application_t *appli = all_applications; + while(appli) { + + parsing = appli->parsing; + + while(parsing) { + + if(parsing->connection == connection) { + parsing->blob = appli->environment->urls_tree; + break; + } + + parsing = parsing->next; + } + + appli = appli->next; + } + } +} + +struct output_handler_t *elf_application_parse_step(const struct connection *connection, uint8_t byte) { + if(elf_application_get_count() > 0) { + struct elf_application_parsing_t *parsing; + struct output_handler_t *output_handler = NULL; + struct elf_application_t *appli = all_applications; + char still_parsing = 0; + + while(appli) { + + parsing = appli->parsing; + + while(parsing) { + + if(parsing->connection == connection) { + output_handler = url_parse_step(byte, &parsing->blob, appli->environment->resources_index); + + if(output_handler == NULL) + still_parsing = 1; + else { + if(output_handler != &http_404_handler) + return output_handler; + } + + break; + } + + parsing = parsing->next; + } + + appli = appli->next; + } + + if(still_parsing == 1) + return NULL; + } + return &http_404_handler; +} + +#endif diff --git a/core/elf_application.h b/core/elf_application.h new file mode 100644 index 0000000..7a18992 --- /dev/null +++ b/core/elf_application.h @@ -0,0 +1,115 @@ +/* +* Copyright or © or Copr. 2008, Simon Duquennoy +* +* Author e-mail: simon.duquennoy@lifl.fr +* +* This software is a computer program whose purpose is to design an +* efficient Web server for very-constrained embedded system. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +*/ + +#ifndef DISABLE_ELF + +#ifndef __ELF_APPLICATION_H__ +#define __ELF_APPLICATION_H__ + +#include "handlers.h" +#include "connections.h" + +typedef void *(*elf_application_allocate_t)(unsigned int size); +typedef void (*elf_application_free_t)(void *memory); + +/* Callbacks */ +typedef char (*elf_application_install_t)(); +typedef void (*elf_application_remove_t)(); + +struct elf_application_environment_t { + elf_application_install_t *install; + elf_application_remove_t *remove; + unsigned char * urls_tree; + struct output_handler_t ** resources_index; +}; + +/* Stores parsing information per connection*/ +struct elf_application_parsing_t { + struct connection *connection; + unsigned char * blob; + + struct elf_application_parsing_t *previous; + struct elf_application_parsing_t *next; +}; + +struct elf_application_t { + char * filename; + uint16_t size; + + char * data_source; + char * data_destination; + unsigned int data_size; + + struct elf_application_parsing_t * parsing; + + struct elf_application_environment_t *environment; + + struct elf_application_t * previous; + struct elf_application_t * next; +}; + + +#define FOR_EACH_APPLICATION(item, code) \ + if(elf_application_get_count() > 0) { \ + struct elf_application_t *(item) = all_applications; \ + do { \ + {code} \ + (item) = (item)->next; \ + } while(item); \ + } + +extern struct elf_application_t * all_applications; + +extern void elf_applications_init(elf_application_allocate_t allocate, elf_application_free_t free); + +extern int elf_application_get_count(); +extern char elf_application_add(struct elf_application_t *application); +extern void elf_application_remove(const struct elf_application_t *application); + +/* When the device resets, init all dynamic applications*/ +extern void elf_application_init(); + +/* When a connection has been created */ +extern void elf_application_add_connection(struct connection *connection); +/* When a connection has been terminated */ +extern void elf_application_remove_connection(const struct connection *connection); + +/* Resets the parsing internals*/ +extern void elf_application_parsing_start(const struct connection *connection); +extern struct output_handler_t *elf_application_parse_step(const struct connection *connection, uint8_t byte); + +#endif + +#endif diff --git a/core/handlers.h b/core/handlers.h index 91140c4..6b3b18c 100644 --- a/core/handlers.h +++ b/core/handlers.h @@ -53,7 +53,7 @@ typedef char (generator_dopacket_out_func_t)(const void *connection_info); #endif #ifndef DISABLE_POST -typedef char (generator_dopost_in_func_t)(uint8_t,uint8_t,char *,void **); +typedef char (generator_dopost_in_func_t)(uint8_t, /*uint16_t,*/ uint8_t,char *,void **); typedef char (generator_dopost_out_func_t)(uint8_t,void *); #endif @@ -164,7 +164,7 @@ struct output_handler_t { #define GET_FLAGS(r) (CONST_UI8((r)->handler_type) == type_control ? CONST_UI8(GET_CONTROL(r).flags) : (TCP_ACK | TCP_PSH)) /* Global output_handler table */ -extern CONST_VAR(const struct output_handler_t *, resources_index[]); +extern CONST_VAR(struct output_handler_t * const, resources_index[]); /* URL tree: parsing an URL to retrieve an output_handler */ extern CONST_VAR(unsigned char, urls_tree[]); diff --git a/core/input.c b/core/input.c index b718c54..dabad39 100644 --- a/core/input.c +++ b/core/input.c @@ -42,6 +42,9 @@ #include "coroutines.h" #include "blobs.h" #include "defines.h" +#include "elf_application.h" + +#include /* Used to dump the runtime stack */ #ifdef STACK_DUMP @@ -192,7 +195,7 @@ short in() #ifndef DISABLE_POST /* called from dopostin or dopacketin */ short in(){ - unsigned char tmp; + unsigned char tmp, last_position_in_boundary; #ifndef DISABLE_GP_IP_HANDLER /* If post AND general purpose ip, then check if the connection is null @@ -206,12 +209,16 @@ short in(){ if(coroutine_state.state == cor_out) return -1; + if(!curr_input.connection->protocol.http.post_data->content_length) return -1; + if(curr_input.connection->protocol.http.post_data->boundary && (curr_input.connection->protocol.http.post_data->boundary->index == (uint8_t)-1)) /* index = -1 => boundary found */ return -1; + if(!curr_input.length) cr_run(NULL,cor_type_get); /* input buffer is empty, changing context */ + if(curr_input.connection->protocol.http.post_data->boundary){ /* getting next value in input buffer */ tmp = curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index]; @@ -221,7 +228,12 @@ short in(){ if(curr_input.connection->protocol.http.post_data->boundary->index == curr_input.connection->protocol.http.post_data->boundary->boundary_size) curr_input.connection->protocol.http.post_data->boundary->index = 0; /* comparing first and last characters of buffer with boundary, then all characters */ - if(curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[(unsigned char)(curr_input.connection->protocol.http.post_data->boundary->index - 1) % curr_input.connection->protocol.http.post_data->boundary->boundary_size] + if(curr_input.connection->protocol.http.post_data->boundary->index == 0) + last_position_in_boundary = curr_input.connection->protocol.http.post_data->boundary->boundary_size - 1; + else + last_position_in_boundary = (unsigned char)(curr_input.connection->protocol.http.post_data->boundary->index - 1); + + if(curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[last_position_in_boundary] == curr_input.connection->protocol.http.post_data->boundary->boundary_ref[curr_input.connection->protocol.http.post_data->boundary->boundary_size-1] && curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index] == curr_input.connection->protocol.http.post_data->boundary->boundary_ref[0]){ @@ -230,6 +242,7 @@ short in(){ for(i = 1 ; i < curr_input.connection->protocol.http.post_data->boundary->boundary_size-1 ; i++){ if(index == curr_input.connection->protocol.http.post_data->boundary->boundary_size) index = 0; + if(curr_input.connection->protocol.http.post_data->boundary->boundary_ref[i] != curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[index]) break; index++; @@ -240,6 +253,7 @@ short in(){ } else DEV_GETC(tmp); + /* updating counters */ if(curr_input.connection->protocol.http.post_data->content_length != (uint16_t)-1) curr_input.connection->protocol.http.post_data->content_length--; @@ -316,7 +330,7 @@ char smews_receive(void) { /* tmp connection used to store the current state until checksums are checked */ struct connection tmp_connection; - if(!DEV_DATA_TO_READ) + if(!DEV_DATA_TO_READ) return 0; #ifdef IPV6 @@ -329,7 +343,6 @@ char smews_receive(void) { DEV_GETC(tmp_char); #endif - #ifdef SMEWS_RECEIVING SMEWS_RECEIVING; #endif @@ -361,7 +374,6 @@ char smews_receive(void) { return 1; #endif - /* We don't care about the Hop Limit (TTL) */ DEV_GET(tmp_char); @@ -422,6 +434,7 @@ char smews_receive(void) { if(UI16(current_checksum) != 0xffff) return 1; + #endif #ifndef DISABLE_GP_IP_HANDLER @@ -467,6 +480,7 @@ char smews_receive(void) { return 1; } #endif + /* End of IP, starting TCP */ checksum_init(); @@ -541,7 +555,6 @@ char smews_receive(void) { /* get TCP ack */ DEV_GETC32(current_inack); - /* duplicate ACK: set nextoutseqno for retransmission */ if(UI32(tmp_connection.protocol.http.next_outseqno) - UI16(tmp_connection.protocol.http.inflight) == UI32(current_inack)) { UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack); @@ -663,7 +676,7 @@ char smews_receive(void) { x = 0; if(segment_length && tmp_connection.protocol.http.tcp_state == tcp_established && (new_tcp_data || tmp_connection.output_handler == NULL)) { const struct output_handler_t * /*CONST_VAR*/ output_handler = NULL; - + struct output_handler_t * elf_application_output_handler = NULL; /* parse the eventual GET request */ unsigned const char * /*CONST_VAR*/ blob; unsigned char blob_curr; @@ -705,6 +718,7 @@ char smews_receive(void) { && output_handler != &http_505_handler #endif ) { + blob_curr = CONST_READ_UI8(blob); #ifndef DISABLE_POST /* testing end multipart */ @@ -720,6 +734,7 @@ char smews_receive(void) { #endif x++; DEV_GETC(tmp_char); + #ifndef DISABLE_POST /* updating content length */ if((tmp_connection.protocol.http.parsing_state == parsing_init_buffer @@ -727,8 +742,11 @@ char smews_receive(void) { ||(tmp_connection.protocol.http.post_data && tmp_connection.protocol.http.post_data->boundary && tmp_connection.protocol.http.post_data->boundary->ready_to_count)) - && tmp_connection.protocol.http.post_data->content_length != (uint16_t)-1) + && tmp_connection.protocol.http.post_data->content_length != (uint16_t)-1) { + tmp_connection.protocol.http.post_data->content_length--; + + } } /* initializing buffer before parsing data */ if(tmp_connection.protocol.http.parsing_state == parsing_init_buffer){ @@ -857,6 +875,9 @@ char smews_receive(void) { cr_init(&(tmp_connection.protocol.http.post_data->coroutine)); tmp_connection.protocol.http.post_data->coroutine.func.func_post_in = CONST_ADDR(GET_GENERATOR(output_handler).handlers.post.dopostin); tmp_connection.protocol.http.post_data->coroutine.params.in.content_type = tmp_connection.protocol.http.post_data->content_type; + + /*tmp_connection.protocol.http.post_data->coroutine.params.in.content_length = tmp_connection.protocol.http.post_data->content_length;*/ + tmp_connection.protocol.http.post_data->coroutine.params.in.filename = tmp_connection.protocol.http.post_data->filename; tmp_connection.protocol.http.post_data->coroutine.params.in.post_data = tmp_connection.protocol.http.post_data->post_data; if(tmp_connection.protocol.http.post_data->boundary){ @@ -914,6 +935,7 @@ char smews_receive(void) { continue; break; } + /* searching end character of post url detection */ if(tmp_connection.protocol.http.parsing_state == parsing_url && blob_curr == URL_POST_END){ if(tmp_connection.protocol.http.post_data){ @@ -998,24 +1020,25 @@ char smews_receive(void) { else{ /* final reallocation */ uint8_t i = 0; - char *new_tab = mem_alloc((tmp_connection.protocol.http.post_data->boundary->index+5)*sizeof(char)); + char *new_tab = mem_alloc((tmp_connection.protocol.http.post_data->boundary->index+4)*sizeof(char)); if(!new_tab){ output_handler = &http_404_handler; break; } - new_tab[0] = '\n'; - new_tab[1] = '\r'; - new_tab[2] = '\n'; + + new_tab[0] = '\r'; + new_tab[1] = '\n'; + new_tab[2] = '-'; new_tab[3] = '-'; - new_tab[4] = '-'; /* copying boundary */ for(i = 0 ; i < tmp_connection.protocol.http.post_data->boundary->index ; i++) - new_tab[i+5] = tmp_connection.protocol.http.post_data->boundary->boundary_ref[i]; + new_tab[i+4] = tmp_connection.protocol.http.post_data->boundary->boundary_ref[i]; mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_ref,(tmp_connection.protocol.http.post_data->boundary->boundary_size)*sizeof(char)); - tmp_connection.protocol.http.post_data->boundary->boundary_size = tmp_connection.protocol.http.post_data->boundary->index + 5; + tmp_connection.protocol.http.post_data->boundary->boundary_size = tmp_connection.protocol.http.post_data->boundary->index + 4; tmp_connection.protocol.http.post_data->boundary->boundary_ref = new_tab; tmp_connection.protocol.http.post_data->boundary->index = -1; tmp_connection.protocol.http.post_data->boundary->boundary_buffer = mem_alloc(tmp_connection.protocol.http.post_data->boundary->boundary_size*sizeof(char)); + if(!tmp_connection.protocol.http.post_data->boundary->boundary_buffer){ /* If no space for boundary_ref, free boundary */ mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t)); @@ -1025,6 +1048,7 @@ char smews_receive(void) { } } } + /* parsing content-type */ else if(tmp_connection.protocol.http.parsing_state == parsing_post_content_type){ if(blob_curr - 128 == CONTENT_TYPE_MULTIPART_47_FORM_45_DATA){ /* multipart */ @@ -1086,6 +1110,7 @@ char smews_receive(void) { #endif tmp_connection.protocol.http.parsing_state = parsing_url; blob = urls_tree; + elf_application_parsing_start(connection); } else { if(tmp_char == ' ') { #ifndef DISABLE_POST @@ -1095,8 +1120,14 @@ char smews_receive(void) { } else{ #endif - if(!output_handler) + + elf_application_output_handler = elf_application_parse_step(connection, tmp_char); + if((elf_application_output_handler != NULL) && (elf_application_output_handler != &http_404_handler)) + output_handler = elf_application_output_handler; + + if(!output_handler) { output_handler = (struct output_handler_t*)CONST_ADDR(resources_index[blob_curr - 128]); + } #ifndef DISABLE_POST if(tmp_connection.protocol.http.post_data){ tmp_connection.protocol.http.parsing_state = parsing_post_attributes; @@ -1160,6 +1191,7 @@ char smews_receive(void) { } blob_curr = CONST_READ_UI8(blob); } + #ifndef DISABLE_POST /* end header detection */ if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && tmp_char == 13){ @@ -1231,6 +1263,7 @@ char smews_receive(void) { if (tmp_char != blob_curr && blob_next >= 128) { blob_next = CONST_READ_UI8(++blob); } + if (blob_next < 32) { offsetInf += ((blob_next>>2) & 1) + ((blob_next>>1) & 1) + (blob_next & 1); offsetEq = offsetInf + ((blob_next & 2)?CONST_READ_UI8(blob+1):0); @@ -1277,8 +1310,19 @@ char smews_receive(void) { } } } while(1); + + elf_application_output_handler = elf_application_parse_step(connection, tmp_char); + if(output_handler == &http_404_handler) { + output_handler = elf_application_output_handler; + + if((tmp_char == ' ') && (output_handler != &http_404_handler) && (output_handler != NULL)){ + tmp_connection.protocol.http.parsing_state = parsing_end; + break; + } + } } } + /* detecting parsing_end */ if( #ifndef DISABLE_POST @@ -1289,9 +1333,11 @@ char smews_receive(void) { || output_handler == &http_505_handler #endif ) && tmp_connection.protocol.http.parsing_state != parsing_cmd)){ + tmp_connection.protocol.http.parsing_state = parsing_end; tmp_connection.protocol.http.ready_to_send = 1; } + if(!output_handler) tmp_connection.protocol.http.blob = blob; else { @@ -1357,6 +1403,7 @@ char smews_receive(void) { tmp_connection.protocol.http.blob = blob; } } + /* drop remaining TCP data */ while(x++ < segment_length) DEV_GETC(tmp_char); @@ -1397,13 +1444,14 @@ char smews_receive(void) { #endif } } - + if(!connection && tmp_connection.protocol.http.tcp_state == tcp_syn_rcvd) { connection = add_connection(&tmp_connection #ifdef IPV6 , compressed_ip_size(comp_ipv6_addr) #endif ); + /* update the pointer in the tmp_connection because * it will be copied later so if the pointers do not have the right value, the list * will be screwed */ @@ -1413,7 +1461,7 @@ char smews_receive(void) { tmp_connection.next = connection->next; } } - + if(!connection) { /* no valid connection has been found for this packet, send a reset */ UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack); @@ -1449,5 +1497,6 @@ char smews_receive(void) { } } } + return 1; } diff --git a/core/memory.c b/core/memory.c index 8b31ee4..82983ab 100644 --- a/core/memory.c +++ b/core/memory.c @@ -110,6 +110,7 @@ void *mem_alloc(uint16_t size) { return NULL; } + return curr_free; } diff --git a/core/output.c b/core/output.c index 74b064c..4b01d48 100644 --- a/core/output.c +++ b/core/output.c @@ -309,6 +309,7 @@ void smews_send_packet (struct connection *connection) { uint16_t max_out_size; uint32_t file_remaining_bytes; + max_out_size = MAX_OUT_SIZE (connection->protocol.http.tcp_mss); file_remaining_bytes = UI32 (connection->protocol.http.final_outseqno) - UI32 (next_outseqno); segment_length = file_remaining_bytes > max_out_size ? max_out_size : file_remaining_bytes; @@ -316,6 +317,7 @@ void smews_send_packet (struct connection *connection) break; } case type_generator: + segment_length = curr_output.content_length; segment_length += _service_headers_size (curr_output.service_header); break; @@ -680,7 +682,6 @@ char smews_send (void) struct connection *active_connection = NULL; const struct output_handler_t * /*CONST_VAR */ old_output_handler = NULL; - /* sending reset has the highest priority */ if (UI16 (rst_connection.port)) { @@ -730,7 +731,7 @@ char smews_send (void) } #endif - if (!active_connection->protocol.http.ready_to_send) + if(!active_connection->protocol.http.ready_to_send) { old_output_handler = active_connection->output_handler; active_connection->output_handler = &ref_ack; @@ -743,13 +744,21 @@ char smews_send (void) active_connection->output_handler = &ref_ack; } #endif - + /* get the type of web applicative resource */ switch (CONST_UI8 (active_connection->output_handler->handler_type)) { case type_control: /* preparing to send TCP control data */ - smews_send_packet (active_connection); +#ifndef DISABLE_POST + /* Added to prevent from duplicate ack generation while dealing with post requests + * When dealing with post requests, it happens that smews has to handle packets acknowlegment while the post data + * are still not fully received : + * in the meantime, smews acknowledges multiple times (read dozens) the same packet, till post data reception completes. + */ + //if(!active_connection->protocol.http.post_data) +#endif + smews_send_packet (active_connection); active_connection->output_handler = NULL; if (active_connection->protocol.http.tcp_state == tcp_closing) { @@ -798,6 +807,7 @@ char smews_send (void) { return 1; } + curr_output.service = active_connection->protocol.http.generator_service; /* if we create the service, it is the first segment of the answer stream, we need * to reduce its size to fit the mss if the segment is not the last. @@ -808,6 +818,7 @@ char smews_send (void) curr_output.service->in_flight_infos = NULL; curr_output.service->is_persistent = CONST_UI8 (GET_GENERATOR (active_connection->output_handler).prop) == prop_persistent; UI32 (curr_output.service->curr_outseqno) = UI32 (active_connection->protocol.http.next_outseqno); + #ifndef DISABLE_COROUTINES /* init coroutine */ cr_init (&curr_output.service->coroutine); @@ -827,6 +838,7 @@ char smews_send (void) else { #endif + #ifndef DISABLE_COROUTINES curr_output.service->coroutine.func.func_get = CONST_ADDR(GET_GENERATOR(active_connection->output_handler).handlers.get.doget); #ifndef DISABLE_ARGS @@ -837,9 +849,11 @@ char smews_send (void) #ifndef DISABLE_POST } #endif + /* we don't know yet the final output sequence number for this service */ UI32 (active_connection->protocol.http.final_outseqno) = UI32 (active_connection->protocol.http.next_outseqno) - 1; #ifndef DISABLE_COMET + /* if this is a comet generator, manage all listenning clients */ if (CONST_UI8 (active_connection->output_handler->handler_comet)) { @@ -854,6 +868,7 @@ char smews_send (void) } ) } + /* manage streamed comet data */ if (CONST_UI8 (active_connection->output_handler->handler_stream)) { @@ -923,7 +938,6 @@ char smews_send (void) { curr_output.service_header = curr_output.service->service_header; } - /* initializations before generating the segment */ curr_output.content_length = 0; checksum_init (); diff --git a/core/smews.c b/core/smews.c index 91856d2..09c516c 100644 --- a/core/smews.c +++ b/core/smews.c @@ -42,7 +42,6 @@ /*-----------------------------------------------------------------------------------*/ void smews_retransmit(void) { last_transmission_time++; - FOR_EACH_CONN(conn, { if(conn->output_handler && IS_HTTP(conn) diff --git a/core/smews.h b/core/smews.h index d58cef9..018c2a8 100644 --- a/core/smews.h +++ b/core/smews.h @@ -42,6 +42,7 @@ #include "coroutines.h" #include "timers.h" #include "memory.h" +#include "elf_application.h" extern void smews_retransmit(void); @@ -99,6 +100,9 @@ static inline void smews_init(void) { } x++; } + + elf_application_init(); + #ifndef DISABLE_TIMERS set_timer(&smews_retransmit,1000); #endif diff --git a/doc/elf_screenshot.png b/doc/elf_screenshot.png new file mode 100644 index 0000000..6ab181b Binary files /dev/null and b/doc/elf_screenshot.png differ diff --git a/doc/userguide.pdf b/doc/userguide.pdf index 8e8ff28..a1a5875 100644 Binary files a/doc/userguide.pdf and b/doc/userguide.pdf differ diff --git a/doc/userguide.tex b/doc/userguide.tex index a66056c..70c9968 100755 --- a/doc/userguide.tex +++ b/doc/userguide.tex @@ -1269,6 +1269,72 @@ \section{Synthesis of the features} \label{tab:gpip-appssyscalls} \end{table} +\chapter{Uploading new applications into an embedded Smews} +\label{ch:uploadingapp} + +In a standard behaviour, only applications crafted with Smews are accessible, but there's another way to deploy applications for the MBED device, without having to modify the embedded server, called post-issuance. + +\section{Preparing Smews for post-issuance.} +Post-issuance in Smews is available thanks to an application called ElfLoader, shipped with the server, that will handle the file upload through a POST request and relocation of elf files onto the device. To build such a configuration : + +\begin{verbatim} +$ scons target=mbed_ethernet apps=:elfloader ipaddr=192.168.100.2 +\end{verbatim} + +Then, flash the resulting image onto the MBED : +\begin{verbatim} +$ cp ./bin/mbed_ethernet/smews.bin /media/MBED/ && sync +\end{verbatim} + +From now on, Smews is able to deploy new applications with no need to rebuild the Smews image. + +\section{Building your own elf application} + +Building an elf application uploadable to Smews is nothing more complicated than the regular process. +For example, to build the connections stats application : +\begin{verbatim} +$ scons target=mbed_ethernet apps=constat:connectionsStats dynApp=1 +\end{verbatim} + +The \verb+dynApp+ option tells SCons to build an uploadable elf file, and the result will be outputted into \verb+bin/mbed_ethernet+ directory. + +Though not used here, programmers can handle several application lifecycle steps by declaring XML metadata either in a separate C file and/or directly into their applications. +\begin{itemize} +\item \verb+install+ -- function executed during application installation; +\item \verb+remove+ -- function executed when an application is removed; +\end{itemize} + +The XML metadata should look as the following, and be declared into one single file, or as many times needed into applications' files : +\begin{lstlisting} +/* + + + + */ +\end{lstlisting} + +\section{Uploading elf applications.} +Open up your browser and enter the Smews' ip; a Post form should appear. Then, select the \verb+*.o+ file into \verb+bin/mbed_ethernet+ folder and press the submit button. +\begin{center} +\includegraphics[width=15cm]{elf_screenshot} +\end{center} + + + +Wait until the process completion, then finally, to access to the newly deployed application, open a new tab and enter the application URL as in the application SCons command line, here \url{http://192.168.100.2/constat/} + +\section{Summary} + To deploy applications onto Smews for an MBED device : +\begin{itemize} +\item 1) Prepare a Smews image : \begin{verbatim} $ scons target=mbed_ethernet apps=:elfloader ipaddr=192.168.100.2\end{verbatim} +\item 2) Flash it down to the device : \begin{verbatim}$ cp ./bin/mbed_ethernet/smews.bin /media/MBED/ && sync\end{verbatim} +\item 3) Build your elf application : \begin{verbatim}$ scons target=mbed_ethernet apps=constat:connectionsStats dynApp=1\end{verbatim} +\item 4) Open your browser and enter the Smews' ip address, here \url{http://192.168.100.2}. +\item 5) Choose the \verb+*.o+ file into \verb+bin/mbed_ethernet+ directory, then press the Submit button. Wait until the process completes. +\item 6) Enter in a new tab the application's url. Here, \url{http://192.168.100.2/constat/} +\end{itemize} + + To add a new application, start again at step 3). \chapter{Credits} diff --git a/targets/linux/drivers/target.h b/targets/linux/drivers/target.h index 34fe141..90cc181 100644 --- a/targets/linux/drivers/target.h +++ b/targets/linux/drivers/target.h @@ -107,6 +107,14 @@ extern fd_set fdset; #define CONST_WRITE_NBYTES(dst,src,len) memcpy(dst,src,len) +/* Application */ +#define APPLICATION_READ_UI8(x) CONST_READ_UI8(x) +#define APPLICATION_READ_UI16(x) CONST_READ_UI16(x) +#define APPLICATION_READ_UI32(x) CONST_READ_UI32(x) +#define APPLICATION_READ_ADDR(x) CONST_READ_ADDR(x) + +#define APPLICATION_WRITE(dst, src, len) CONST_WRITE_NBYTES(dst,src,len) + /* Endianness */ #define ENDIANNESS LITTLE_ENDIAN diff --git a/targets/mbed_ethernet/SConscript b/targets/mbed_ethernet/SConscript index 4f6592a..d176ce8 100644 --- a/targets/mbed_ethernet/SConscript +++ b/targets/mbed_ethernet/SConscript @@ -35,7 +35,6 @@ import os import sys,subprocess - def check_output(args): str = "" try: @@ -58,7 +57,7 @@ def execute(args): except OSError as e: sys.stderr.write("failed to execute process: {}\n".format(args)) -Import('env binDir projectName elfName targetDir') +Import('env binDir projectName elfName targetDir dynApp') # Clone rflpc if needed @@ -71,6 +70,7 @@ cflags = check_output(args) args[1] = '--ldflags' ldflags = check_output(args) +ldflags = ("-L" + os.path.join(targetDir) + " " + ldflags).replace("rflpc17xx.ld", "smews.ld") args[1] = '--lib' lib = check_output(args) @@ -79,11 +79,13 @@ env.Replace(CC = 'arm-none-eabi-gcc') env.Replace(AS = 'arm-none-eabi-as') env.Replace(AR = 'arm-none-eabi-ar') env.Replace(RANLIB = 'arm-none-eabi-ranlib') +env.Replace(LINK = 'arm-none-eabi-ld') env.Append(CCFLAGS = cflags) env.Append(CCFLAGS = '-DENABLE_LL_CACHE') env.Append(CCFLAGS = '-DMBED_USE_LCD_DISPLAY') env.Append(LIBS = lib) env.Append(LINKFLAGS = ldflags) -binaryName = projectName + '.bin' -env.Command(binaryName, elfName, ['arm-none-eabi-objcopy -O binary -j .text -j .data $SOURCE $TARGET']) +if not dynApp : + binaryName = projectName + '.bin' + env.Command(binaryName, elfName, ['arm-none-eabi-objcopy -O binary -j .text -j .data $SOURCE $TARGET']) diff --git a/targets/mbed_ethernet/drivers/hardware.c b/targets/mbed_ethernet/drivers/hardware.c index bab92e8..16eacc6 100644 --- a/targets/mbed_ethernet/drivers/hardware.c +++ b/targets/mbed_ethernet/drivers/hardware.c @@ -261,6 +261,8 @@ void mbed_print_configuration(void) printf("\r\n"); } +extern char _stack_end; + void mbed_print_motd(void) { printf("\r\n ______\r\n"); diff --git a/targets/mbed_ethernet/drivers/target.h b/targets/mbed_ethernet/drivers/target.h index 0379851..89e046e 100644 --- a/targets/mbed_ethernet/drivers/target.h +++ b/targets/mbed_ethernet/drivers/target.h @@ -120,6 +120,18 @@ /* Writes len bytes from src to dst, where dst targets a persistent variable */ #define CONST_WRITE_NBYTES(dst,src,len) +/* Application */ +/* Gets a byte from address x */ +#define APPLICATION_READ_UI8(x) CONST_READ_UI8(x) +/* Gets two bytes from address x */ +#define APPLICATION_READ_UI16(x) CONST_READ_UI16(x) +/* Gets four bytes from address x */ +#define APPLICATION_READ_UI32(x) CONST_READ_UI32(x) +/* Gets an address from address x */ +#define APPLICATION_READ_ADDR(x) CONST_READ_ADDR(x) + +#define APPLICATION_WRITE(dst, src, len) rflpc_iap_write_buffer(dst, src, len) + /* Endianness: define ENDIANNESS as LITTLE_ENDIAN or BIG_ENDIAN */ #ifndef ENDIANNESS #define ENDIANNESS LITTLE_ENDIAN diff --git a/targets/mbed_ethernet/smews.ld b/targets/mbed_ethernet/smews.ld new file mode 100644 index 0000000..82456c2 --- /dev/null +++ b/targets/mbed_ethernet/smews.ld @@ -0,0 +1,121 @@ +/* This file is part of rflpc. Copyright 2010-2011 Michael Hauspie + * + * rflpc 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. + * + * rflpc 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 rflpc. If not, see . + */ + +/* + Linker script for lpc1768 mbed platform (http://www.mbed.org). + + Author: Michael Hauspie + Created: Nov. 12 2010 + Time-stamp: <2011-09-28 10:11:51 (mickey)> +*/ + +/* output format of the file. + default, big endian, little endian + Arm cortex M3 is little endian so use that as default +*/ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +/* Architecture, obviously arm */ +OUTPUT_ARCH(arm) +ENTRY(_start) + +/* Memory map, give names and properties to the mbed different memories */ +MEMORY +{ + /* Flash: starting at 0x00000000 512kB available. + rx stands for read only executable. + Writing to flash must use algorithms included in boot rom so read + only from ld point of view + */ + flash(rx) : ORIGIN = 0, LENGTH = 512K +/* on chip sram: starting at 0x10000000, 32kB available */ + ram(rwx): ORIGIN = 0x10000000, LENGTH = 32K +/* outside chip sram (accessible via AHB matrix: starting at 0x2007C000, 32kB available */ + out_ram(rwx): ORIGIN = 0x2007C000, LENGTH = 32K +} + + +SECTIONS +{ + /* .text sections starts at address 0 */ + . = 0x0; + /* output .text section is the concatenation of all .text section of all object files + However, the special sections defined in init.c which contains interrupt vector + need to be put first + */ + .text : { + /* The interrupt vector will be remapped in RAM so that it can be easily modified + and the one in flash will be copied at startup before performing the actual remap + by modifying the VTOR register (p. 75, user manual) + */ + _interrupt_start = .; + *(.interrupt_vector) ; + _interrupt_end = .; + + . = 0x10000; + + *(.text*) ; + /* Constant data is also put in flash */ + *(.rodata*) ; + _persistent_data_start = .; + *(.persistent_data); + _persistent_data_end = .; + } + /* this declares a global constant which contains the address of the end of section text. + This will be used by the startup code to copy data from flash to ram */ + _text_end = .; + + /* This will enforce the relocated interrupt vector to be located at the start of the RAM */ + .relocated_interrupt_vector(NOLOAD) : { + *(.ram_int_vector); + } > ram + + /* bss has to be located in ram */ + .bss (NOLOAD): { + /* stores the start address of the bss so that the startup code can 0 it */ + _bss_start = .; + _ram_start = .; + *(.bss*); + } > ram + /* stores the end address of the bss so that the startup code can 0 it */ + _bss_end = .; + + + /* Data section is put in flash and will be copied in ram by startup script */ + + /* the > ram makes all the symbol referencing section .data to be relocated in + ram (i.e. addresses used in code are in ram) the AT>flash makes the section + to be located in flash. Thus, the startup script will just have to copy + the data section from flash to ram */ + + /* this declares a global constant _data_start which contains the address of + the section in ram */ + .data : { + _data_start = .; + *(.data*) ; +} > ram AT>flash + _data_end = .; + /* declares a global constant _data_end which contains the address of the end of the section in ram */ + + + + /* Stack must be located in ram*/ + .stack(NOLOAD) : { *(.stack) } > ram + + + + /* outram section must be located in out_ram */ + .out_ram(NOLOAD) : { *(.out_ram) } > out_ram +} diff --git a/tools/GenApps.py b/tools/GenApps.py index 83ca98b..138b323 100755 --- a/tools/GenApps.py +++ b/tools/GenApps.py @@ -192,6 +192,91 @@ def getAppFilesRec(appPath,path): def getAppFiles(path): return getAppFilesRec(path,path) +def extractXMLElfApplicationLifeCycle(sourceFile, installList, removeList) : + # open the source file in order to parse the XML and return the file data + file = open(sourceFile,'r') + lines = file.readlines() + if len(lines) > 1: + fileData = reduce(lambda x,y: x + y,lines) + else: + fileData = '' + def start_element(name, attrs): + global elfInfos + if name == 'lifeCycle': + elfInfos = attrs + def end_element(name): + return + def char_data(data): + return + + # select the XML part of the c file + xmlRoot = 'elf' + xmlData = fileData[fileData.rfind('<' + xmlRoot + '>'):] + xmlData = xmlData[:xmlData.rfind('') + len(xmlRoot) + 3] + if len(xmlData) > 1: + global elfInfos + # init globals used for parsing + elfInfos = {} + + # parse the XML + p = xml.parsers.expat.ParserCreate() + p.StartElementHandler = start_element + p.EndElementHandler = end_element + p.CharacterDataHandler = char_data + p.Parse(xmlData, 0) + + if elfInfos.has_key('onInstall'): + installList.append(elfInfos['onInstall']) + if elfInfos.has_key('onRemove'): + removeList.append(elfInfos['onRemove']) + +def generateElfApplication(dstFile, installList, removeList) : + generatedHeader = '#include "elf_application.h"\n\n' + forwardDeclarations = '' + generatedDynApp = '' + + #install + if(len(installList)>0): + for install in installList : + forwardDeclarations += 'extern elf_application_install_t ' + install + ';\n' + generatedDynApp += 'static elf_application_install_t elf_application_installs[] = {' + generatedDynApp += '&' + ',&'.join(installList) + ", NULL};\n\n" + + #remove + if(len(removeList)>0): + for remove in removeList : + forwardDeclarations += 'extern elf_application_remove_t ' + remove + ';\n' + generatedDynApp += 'static elf_application_remove_t elf_application_removes[] = {' + generatedDynApp += '&' + ',&'.join(removeList) + ", NULL};\n\n" + + # elf application environment + + generatedDynApp += 'CONST_VAR(struct elf_application_environment_t const, elf_application_environment) = {\n' + + forwardDeclarations += 'extern CONST_VAR(struct output_handler_t * const, resources_index[]);\n' + forwardDeclarations += 'extern CONST_VAR(unsigned char, urls_tree[]);\n' + + if(len(installList)>0): + generatedDynApp += '\t.install = elf_application_installs,\n' + else : + generatedDynApp += '\t.install = NULL,\n' + + if(len(removeList)>0): + generatedDynApp += '\t.remove = elf_application_removes,\n' + else : + generatedDynApp += '\t.remove = NULL,\n' + + generatedDynApp += '\t.urls_tree = urls_tree,\n'; + generatedDynApp += '\t.resources_index = resources_index,\n' + generatedDynApp = generatedHeader + forwardDeclarations + '\n' + generatedDynApp + '};\n' + + cOut = open(dstFile,'w') + writeHeader(cOut, 0) + cOut.write(generatedDynApp) + cOut.close() + + + # Web resource type from original applicative file def getResourceType(path): if path.endswith('.c') or path.endswith('.h'): @@ -310,7 +395,7 @@ def char_data(data): if (controlByte == 128): exit('Error: the file ' + srcFile + ' only defines a doPacketOut without a doPacketIn handler') - exit('Error: the file ' + srcFile + 'has an incompatible decription (' + + exit('Error: the file ' + srcFile + 'has an incompatible description (' + ((controlByte & 1 == 1 and 'doGet,') or '') + ((controlByte & 2 == 2 and 'doPost,') or '') + ((controlByte & 4 == 4 and 'doPostIn,') or '') + @@ -327,6 +412,13 @@ def char_data(data): # initGet handler if handlerInfos.has_key('initGet'): dstFileInfos['initGet'] = handlerInfos['initGet'] + # install handler + if handlerInfos.has_key('install'): + dstFileInfos['install'] = handlerInfos['install'] + # shutdown handler + if handlerInfos.has_key('shutdown'): + dstFileInfos['shutdown'] = handlerInfos['shutdown'] + # generator arguments dstFileInfos['argsList'] = argsList dstFileInfos['contentTypeList'] = contentTypeList @@ -367,7 +459,7 @@ def generateResourceProps(srcFile,dstFileInfos): pOut.close() # launches a Web applicative resource file generation -def generateResource(srcFile,dstFile,chuncksNbits,gzipped,dstFileInfos): +def generateResource(srcFile,dstFile, chuncksNbits,gzipped,dstFileInfos): if getResourceType(srcFile) == DynamicResource: generateDynamicResource(srcFile,dstFile,dstFileInfos) else: @@ -415,6 +507,7 @@ def generateDynamicResource(srcFile,dstFile,dstFileInfos): generatedOutputHandler += '#endif\n' # output_handler structure creation +# generatedOutputHandler += 'struct output_handler_t ' + cFuncName + ' = {\n' generatedOutputHandler += 'CONST_VAR(struct output_handler_t, ' + cFuncName + ') = {\n' # handler type if dstFileInfos.has_key('doPacketIn'): @@ -663,6 +756,7 @@ def generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped): # we fill the output handler structure cOut.write('\n/********** File handler **********/\n') +# cOut.write('struct output_handler_t ' + cName + '_handler = {\n') cOut.write('CONST_VAR(struct output_handler_t, ' + cName + '_handler) = {\n') cOut.write('\t.handler_type = type_file,\n' + '\t.handler_data = {\n' @@ -703,6 +797,7 @@ def generateChannelsH(dstFile,propsFilesMap): # for each channel: external structure declaration, macro for the channel name if propsFilesMap[fileName]['channel'] != '': cStructName = getCName(fileName[:fileName.rfind('.c')]) +# hOut.write('extern struct output_handler_t ' + cStructName + ';\n') hOut.write('extern CONST_VAR(struct output_handler_t, ' + cStructName + ');\n') hOut.write('#define ' + propsFilesMap[fileName]['channel'] + ' ' + cStructName + '\n') hOut.write('\n#endif\n') @@ -733,9 +828,11 @@ def generateIndex(dstDir,sourcesMap,target,chuncksNbits,appBase,propsFilesMap): cOut.write('\n/********** External references **********/\n') for fileName in staticFilesNames: cName = getCName(fileName) +# cOut.write('extern struct output_handler_t ' + cName + '_handler;\n') cOut.write('extern CONST_VAR(struct output_handler_t, ' + cName + '_handler);\n') for fileName in generatorFilesNames: cFuncName = getCName(fileName[:fileName.rfind('.c')]) +# cOut.write('extern struct output_handler_t ' + cFuncName + ';\n') cOut.write('extern CONST_VAR(struct output_handler_t, ' + cFuncName + ');\n') # filesRef is a map used to associate URLs to output_handlers @@ -788,7 +885,7 @@ def generateIndex(dstDir,sourcesMap,target,chuncksNbits,appBase,propsFilesMap): # files index creation (table of ordered output_handlers) cOut.write('\n/********** Files index **********/\n') - cOut.write('CONST_VAR(const struct output_handler_t /*CONST_VAR*/ *, resources_index[]) = {\n') + cOut.write('CONST_VAR(struct output_handler_t /*CONST_VAR*/ * const, resources_index[]) = {\n') # insert each handler for file in filesList: cOut.write('\t&' + filesRefs[file] + ',\n') diff --git a/tools/mimeListPost b/tools/mimeListPost index 7e39761..8f8b900 100644 --- a/tools/mimeListPost +++ b/tools/mimeListPost @@ -15,7 +15,7 @@ #application/mspowerpoint #application/msword #application/mswordf -#application/octet-stream +application/octet-stream #application/oda #application/pdf #application/postscript @@ -41,6 +41,7 @@ application/x-latex #application/x-mif #application/x-netcdf #application/x-nschat +application/x-object application/x-sh #application/x-shar #application/x-shockwave-flash