From 1658d6b42c75708017d195f9bc255c84631c9e58 Mon Sep 17 00:00:00 2001 From: ksb Date: Sat, 11 Jul 2009 14:18:50 +0000 Subject: [PATCH] Older ELF-loader code, may not work any longer --- cpu/arm/at91sam7s/loader/codeprop-otf.c | 523 ++++++++++++++ cpu/arm/at91sam7s/loader/codeprop-otf.h | 52 ++ cpu/arm/at91sam7s/loader/elfloader-arch-otf.h | 101 +++ cpu/arm/at91sam7s/loader/elfloader-otf.c | 680 ++++++++++++++++++ cpu/arm/at91sam7s/loader/elfloader-otf.h | 314 ++++++++ cpu/arm/at91sam7s/loader/empty-symbols.c | 3 + cpu/arm/at91sam7s/loader/ram-segments.c | 139 ++++ cpu/arm/at91sam7s/loader/ram-segments.h | 6 + 8 files changed, 1818 insertions(+) create mode 100644 cpu/arm/at91sam7s/loader/codeprop-otf.c create mode 100644 cpu/arm/at91sam7s/loader/codeprop-otf.h create mode 100644 cpu/arm/at91sam7s/loader/elfloader-arch-otf.h create mode 100644 cpu/arm/at91sam7s/loader/elfloader-otf.c create mode 100644 cpu/arm/at91sam7s/loader/elfloader-otf.h create mode 100644 cpu/arm/at91sam7s/loader/empty-symbols.c create mode 100644 cpu/arm/at91sam7s/loader/ram-segments.c create mode 100644 cpu/arm/at91sam7s/loader/ram-segments.h diff --git a/cpu/arm/at91sam7s/loader/codeprop-otf.c b/cpu/arm/at91sam7s/loader/codeprop-otf.c new file mode 100644 index 000000000..fa739d38b --- /dev/null +++ b/cpu/arm/at91sam7s/loader/codeprop-otf.c @@ -0,0 +1,523 @@ +/* + * 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.c,v 1.1 2009/07/11 14:18:50 ksb Exp $ + */ + +/** \addtogroup esb + * @{ */ + +/** + * + * \file + * Code propagation and storage. + * \author + * Adam Dunkels + * + * This file implements a simple form of code propagation, which + * allows a binary program to be downloaded and propagated throughout + * a network of devices. + * + * Features: + * + * Commands: load code, start code + * Point-to-point download over TCP + * Point-to-multipoint delivery over UDP broadcasts + * Versioning of code modules + * + * Procedure: + * + * 1. Receive code over TCP + * 2. Send code packets over UDP + * + * When a code packet is deemed to be missed, a NACK is sent. If a + * NACK is received, the sending restarts at the point in the + * binary where the NACK pointed to. (This is *not* very efficient, + * but simple to implement...) + * + * States: + * + * Receiving code header -> receiving code -> sending code + * + */ + +#include + +#include "contiki-net.h" +#include "cfs/cfs.h" +#include "codeprop-otf.h" +#include "loader/elfloader-otf.h" +#include + +static const char *err_msgs[] = + {"OK\r\n", "Bad ELF header\r\n", "No symtab\r\n", "No strtab\r\n", + "No text\r\n", "Symbol not found\r\n", "Segment not found\r\n", + "No startpoint\r\n", "Unhandled relocation\r\n", + "Relocation out of range\r\n", "Relocations not sorted\r\n", + "Input error\r\n" , "Ouput error\r\n" }; + +#define CODEPROP_DATA_PORT 6510 + +/*static int random_rand(void) { return 1; }*/ + +#if 0 +#define PRINTF(x) printf x +#else +#define PRINTF(x) +#endif + +#define START_TIMEOUT 12 * CLOCK_SECOND +#define MISS_NACK_TIMEOUT (CLOCK_SECOND / 8) * (random_rand() % 8) +#define HIT_NACK_TIMEOUT (CLOCK_SECOND / 8) * (8 + random_rand() % 16) +#define NACK_REXMIT_TIMEOUT CLOCK_SECOND * (4 + random_rand() % 4) + +#define WAITING_TIME CLOCK_SECOND * 10 + +#define NUM_SEND_DUPLICATES 2 + +#define UDPHEADERSIZE 8 +#define UDPDATASIZE 32 + +struct codeprop_udphdr { + u16_t id; + u16_t type; +#define TYPE_DATA 0x0001 +#define TYPE_NACK 0x0002 + u16_t addr; + u16_t len; + u8_t data[UDPDATASIZE]; +}; + +struct codeprop_tcphdr { + u16_t len; + u16_t pad; +}; + +static void uipcall(void *state); + +PROCESS(codeprop_process, "Code propagator"); + +struct codeprop_state { + u8_t state; +#define STATE_NONE 0 +#define STATE_RECEIVING_TCPDATA 1 +#define STATE_RECEIVING_UDPDATA 2 +#define STATE_SENDING_UDPDATA 3 + u16_t count; + u16_t addr; + u16_t len; + u16_t id; + struct etimer sendtimer; + struct timer nacktimer, timer, starttimer; + u8_t received; + u8_t send_counter; + struct pt tcpthread_pt; + struct pt udpthread_pt; + struct pt recv_udpthread_pt; +}; + +static int fd; + +static struct uip_udp_conn *udp_conn; + +static struct codeprop_state s; + +void system_log(char *msg); + +static clock_time_t send_time; + +#define CONNECTION_TIMEOUT (30 * CLOCK_SECOND) + +/*---------------------------------------------------------------------*/ +void +codeprop_set_rate(clock_time_t time) +{ + send_time = time; +} +/*---------------------------------------------------------------------*/ +PROCESS_THREAD(codeprop_process, ev, data) +{ + PROCESS_BEGIN(); + + elfloader_init(); + + s.id = 0/*random_rand()*/; + + send_time = CLOCK_SECOND/4; + + PT_INIT(&s.udpthread_pt); + PT_INIT(&s.recv_udpthread_pt); + + tcp_listen(HTONS(CODEPROP_DATA_PORT)); + + udp_conn = udp_broadcast_new(HTONS(CODEPROP_DATA_PORT), NULL); + + s.state = STATE_NONE; + s.received = 0; + s.addr = 0; + s.len = 0; + + fd = cfs_open("codeprop-image", CFS_READ | CFS_WRITE); + + while(1) { + + PROCESS_YIELD(); + + if(ev == tcpip_event) { + uipcall(data); + } else if(ev == PROCESS_EVENT_TIMER) { + tcpip_poll_udp(udp_conn); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------*/ +static u16_t +send_udpdata(struct codeprop_udphdr *uh) +{ + u16_t len; + + uh->type = HTONS(TYPE_DATA); + uh->addr = htons(s.addr); + uh->id = htons(s.id); + + if(s.len - s.addr > UDPDATASIZE) { + len = UDPDATASIZE; + } else { + len = s.len - s.addr; + } + + cfs_seek(fd, s.addr, CFS_SEEK_SET); + cfs_read(fd, (char*)&uh->data[0], len); + /* eeprom_read(EEPROMFS_ADDR_CODEPROP + s.addr, + &uh->data[0], len);*/ + + uh->len = htons(s.len); + + PRINTF(("codeprop: sending packet from address 0x%04x\n", s.addr)); + uip_udp_send(len + UDPHEADERSIZE); + + return len; +} +/*---------------------------------------------------------------------*/ +static +PT_THREAD(send_udpthread(struct pt *pt)) +{ + int len; + struct codeprop_udphdr *uh = (struct codeprop_udphdr *)uip_appdata; + + + PT_BEGIN(pt); + + while(1) { + PT_WAIT_UNTIL(pt, s.state == STATE_SENDING_UDPDATA); + + for(s.addr = 0; s.addr < s.len; ) { + len = send_udpdata(uh); + s.addr += len; + + etimer_set(&s.sendtimer, CLOCK_SECOND/4); + do { + PT_WAIT_UNTIL(pt, uip_newdata() || etimer_expired(&s.sendtimer)); + + if(uip_newdata()) { + if(uh->type == HTONS(TYPE_NACK)) { + PRINTF(("send_udpthread: got NACK for address 0x%x (now 0x%x)\n", + htons(uh->addr), s.addr)); + /* Only accept a NACK if it points to a lower byte. */ + if(htons(uh->addr) <= s.addr) { + /* beep();*/ + s.addr = htons(uh->addr); + } + } + PT_YIELD(pt); + } + } while(!etimer_expired(&s.sendtimer)); + } + + s.state = STATE_NONE; + +/* process_post(PROCESS_BROADCAST, codeprop_event_quit, (process_data_t)NULL); */ + } + PT_END(pt); +} +/*---------------------------------------------------------------------*/ +static void +send_nack(struct codeprop_udphdr *uh, unsigned short addr) +{ + uh->type = HTONS(TYPE_NACK); + uh->addr = htons(addr); + uip_udp_send(UDPHEADERSIZE); +} +/*---------------------------------------------------------------------*/ +static +PT_THREAD(recv_udpthread(struct pt *pt)) +{ + int len; + struct codeprop_udphdr *uh = (struct codeprop_udphdr *)uip_appdata; + + /* if(uip_newdata()) { + PRINTF(("recv_udpthread: id %d uh->id %d\n", s.id, htons(uh->id))); + }*/ + + PT_BEGIN(pt); + + while(1) { + + do { + PT_WAIT_UNTIL(pt, uip_newdata() && + uh->type == HTONS(TYPE_DATA) && + htons(uh->id) > s.id); + + if(htons(uh->addr) != 0) { + s.addr = 0; + send_nack(uh, 0); + } + + } while(htons(uh->addr) != 0); + + /* leds_on(LEDS_YELLOW); + beep_down(10000);*/ + + s.addr = 0; + s.id = htons(uh->id); + s.len = htons(uh->len); + + timer_set(&s.timer, CONNECTION_TIMEOUT); +/* process_post(PROCESS_BROADCAST, codeprop_event_quit, (process_data_t)NULL); */ + + while(s.addr < s.len) { + + if(htons(uh->addr) == s.addr) { + /* leds_blink();*/ + len = uip_datalen() - UDPHEADERSIZE; + if(len > 0) { + /* eeprom_write(EEPROMFS_ADDR_CODEPROP + s.addr, + &uh->data[0], len);*/ + cfs_seek(fd, s.addr, CFS_SEEK_SET); + cfs_write(fd, (char*)&uh->data[0], len); + + /* beep();*/ + PRINTF(("Saved %d bytes at address %d, %d bytes left\n", + uip_datalen() - UDPHEADERSIZE, s.addr, + s.len - s.addr)); + + s.addr += len; + } + + } else if(htons(uh->addr) > s.addr) { + PRINTF(("sending nack since 0x%x != 0x%x\n", htons(uh->addr), s.addr)); + send_nack(uh, s.addr); + } + + if(s.addr < s.len) { + + /* timer_set(&s.nacktimer, NACK_TIMEOUT);*/ + + do { + timer_set(&s.nacktimer, HIT_NACK_TIMEOUT); + PT_YIELD_UNTIL(pt, timer_expired(&s.nacktimer) || + (uip_newdata() && + uh->type == HTONS(TYPE_DATA) && + htons(uh->id) == s.id)); + if(timer_expired(&s.nacktimer)) { + send_nack(uh, s.addr); + } + } while(timer_expired(&s.nacktimer)); + } + + } + + /* leds_off(LEDS_YELLOW); + beep_quick(2);*/ + /* printf("Received entire bunary over udr\n");*/ + codeprop_start_program(); + PT_EXIT(pt); + } + + PT_END(pt); +} +/*---------------------------------------------------------------------*/ + +#define CODEPROP_TCPHDR_SIZE sizeof(struct codeprop_tcphdr) + +static +PT_THREAD(recv_tcpthread(struct pt *pt)) +{ + struct codeprop_tcphdr *th; + int datalen = uip_datalen(); + PT_BEGIN(pt); + + while(1) { + + PT_WAIT_UNTIL(pt, uip_connected()); + + codeprop_exit_program(); + + s.state = STATE_RECEIVING_TCPDATA; + + s.addr = 0; + s.count = 0; + + /* Read the header. */ + PT_WAIT_UNTIL(pt, uip_newdata() && uip_datalen() > 0); + + if(uip_datalen() < CODEPROP_TCPHDR_SIZE) { + PRINTF(("codeprop: header not found in first tcp segment\n")); + uip_abort(); + } + th = (struct codeprop_tcphdr *)uip_appdata; + s.len = htons(th->len); + s.addr = 0; + uip_appdata += CODEPROP_TCPHDR_SIZE; + datalen -= CODEPROP_TCPHDR_SIZE; + + /* Read the rest of the data. */ + do { + if(datalen > 0) { + /* printf("Got %d bytes\n", datalen); */ + + if (cfs_seek(fd, s.addr, CFS_SEEK_SET) != s.addr) { + PRINTF(("codeprop: seek in buffer file failed\n")); + uip_abort(); + } + + if (cfs_write(fd, uip_appdata, datalen) != datalen) { + PRINTF(("codeprop: write to buffer file failed\n")); + uip_abort(); + } + s.addr += datalen; + } + if(s.addr < s.len) { + PT_YIELD_UNTIL(pt, uip_newdata()); + } + } while(s.addr < s.len); +#if 1 + + { + static int err; + + err = codeprop_start_program(); + + /* Print out the "OK"/error message. */ + do { + if (err >= 0 && err < sizeof(err_msgs)/sizeof(char*)) { + uip_send(err_msgs[err], strlen(err_msgs[err])); + } else { + uip_send("Unknown error\r\n", 15); + } + PT_WAIT_UNTIL(pt, uip_acked() || uip_rexmit() || uip_closed()); + } while(uip_rexmit()); + + /* Close the connection. */ + uip_close(); + } +#endif + ++s.id; + s.state = STATE_SENDING_UDPDATA; + tcpip_poll_udp(udp_conn); + + PT_WAIT_UNTIL(pt, s.state != STATE_SENDING_UDPDATA); + /* printf("recv_tcpthread: unblocked\n");*/ + } + + PT_END(pt); +} +/*---------------------------------------------------------------------*/ +void +codeprop_start_broadcast(unsigned int len) +{ + s.addr = 0; + s.len = len; + ++s.id; + s.state = STATE_SENDING_UDPDATA; + tcpip_poll_udp(udp_conn); +} +/*---------------------------------------------------------------------*/ +void +codeprop_exit_program(void) +{ + if(elfloader_autostart_processes != NULL) { + autostart_exit(elfloader_autostart_processes); + } +} +/*---------------------------------------------------------------------*/ +int +codeprop_start_program(void) +{ + int err; + + codeprop_exit_program(); + + err = elfloader_load(fd, codeprop_output); + if(err == ELFLOADER_OK) { + PRINTF(("codeprop: starting %s\n", + elfloader_autostart_processes[0]->name)); + autostart_start(elfloader_autostart_processes); + } + return err; +} +/*---------------------------------------------------------------------*/ +static void +uipcall(void *state) +{ + if(uip_udpconnection()) { + recv_udpthread(&s.recv_udpthread_pt); + send_udpthread(&s.udpthread_pt); + } else { + if(uip_conn->lport == HTONS(CODEPROP_DATA_PORT)) { + if(uip_connected()) { + + if(state == NULL) { + s.addr = 0; + s.count = 0; + PT_INIT(&s.tcpthread_pt); + process_poll(&codeprop_process); + tcp_markconn(uip_conn, &s); +/* process_post(PROCESS_BROADCAST, codeprop_event_quit, */ +/* (process_data_t)NULL); */ + } else { + PRINTF(("codeprop: uip_connected() and state != NULL\n")); + uip_abort(); + } + } + recv_tcpthread(&s.tcpthread_pt); + + + if(uip_closed() || uip_aborted() || uip_timedout()) { + PRINTF(("codeprop: connection down\n")); + tcp_markconn(uip_conn, NULL); + } + } + } +} +/*---------------------------------------------------------------------*/ +/** @} */ diff --git a/cpu/arm/at91sam7s/loader/codeprop-otf.h b/cpu/arm/at91sam7s/loader/codeprop-otf.h new file mode 100644 index 000000000..546e7dd1b --- /dev/null +++ b/cpu/arm/at91sam7s/loader/codeprop-otf.h @@ -0,0 +1,52 @@ +/* + * 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__ + +#include "contiki.h" + +#define CODEPROP_DATA_PORT 6510 + +PROCESS_NAME(codeprop_process); + +void codeprop_set_rate(clock_time_t time); +void codeprop_start_broadcast(unsigned int len); +void codeprop_exit_program(void); +int codeprop_start_program(void); + +/* Segment writing object */ +extern struct elfloader_output *codeprop_output; + +extern char *codeprop_filesystem; + +#endif /* __CODEPROP_H__ */ diff --git a/cpu/arm/at91sam7s/loader/elfloader-arch-otf.h b/cpu/arm/at91sam7s/loader/elfloader-arch-otf.h new file mode 100644 index 000000000..d67c280a4 --- /dev/null +++ b/cpu/arm/at91sam7s/loader/elfloader-arch-otf.h @@ -0,0 +1,101 @@ +/* + * 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(int input_fd, + struct elfloader_output *output, + unsigned int sectionoffset, + char *sectionaddr, + struct elf32_rela *rela, char *addr); + +#endif /* __ELFLOADER_ARCH_H__ */ + +/** @} */ +/** @} */ diff --git a/cpu/arm/at91sam7s/loader/elfloader-otf.c b/cpu/arm/at91sam7s/loader/elfloader-otf.c new file mode 100644 index 000000000..b39749f15 --- /dev/null +++ b/cpu/arm/at91sam7s/loader/elfloader-otf.c @@ -0,0 +1,680 @@ +/* + * 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 $ + */ + +#include "contiki.h" + +#include "loader/elfloader-otf.h" +#include "loader/elfloader-arch-otf.h" + +#include "cfs/cfs.h" +#include "loader/symtab.h" + +#include +#include +#include + +#if 0 +#include +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) do {} while (0) +#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. */ +}; + +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. */ +}; + +#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; +}; + +char elfloader_unknown[30]; /* Name that caused link error. */ + +struct process **elfloader_autostart_processes; + +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. */ + }; + +/* Copy data from the elf file to a segment */ +static int +copy_segment_data(int input_fd, unsigned int offset, + struct elfloader_output *output, unsigned int len) +{ + char buffer[16]; + int res; + if (cfs_seek(input_fd, offset, CFS_SEEK_SET) != offset) return ELFLOADER_INPUT_ERROR; + while(len > sizeof(buffer)) { + res = cfs_read(input_fd, buffer, sizeof(buffer)); + if (res != sizeof(buffer)) return ELFLOADER_INPUT_ERROR; + res = elfloader_output_write_segment(output, buffer, sizeof(buffer)); + if (res != sizeof(buffer)) return ELFLOADER_OUTPUT_ERROR; + len -= sizeof(buffer); + } + res = cfs_read(input_fd, buffer, len); + if (res != len) return ELFLOADER_INPUT_ERROR; + res = elfloader_output_write_segment(output, buffer, len); + if (res != len) return ELFLOADER_OUTPUT_ERROR; + return ELFLOADER_OK; +} + +static int +seek_read(int fd, unsigned int offset, char *buf, int len) +{ + if (cfs_seek(fd, offset, CFS_SEEK_SET) != offset) return -1; + return cfs_read(fd, buf, len); +} + +static void * +find_local_symbol(int input_fd, const char *symbol, + unsigned int symtab, unsigned short symtabsize, + unsigned int strtab) +{ + struct elf32_sym s; + unsigned int a; + char name[30]; + struct relevant_section *sect; + int ret; + + 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 { + return NULL; + } + return &(sect->address[s.st_value]); + } + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +static int +relocate_section(int 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) +{ + /* 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 name[30]; + char *addr; + struct relevant_section *sect; + int ret; + + /* determine correct relocation entry sizes */ + if(using_relas) { + rel_size = sizeof(struct elf32_rela); + } else { + rel_size = sizeof(struct elf32_rel); + } + + 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(s)); + if (ret < 0) return ELFLOADER_INPUT_ERROR; + if(s.st_name != 0) { + ret = seek_read(input_fd, strtab + s.st_name, name, sizeof(name)); + if (ret < 0) return ELFLOADER_INPUT_ERROR; + PRINTF("name: %s\n", name); + addr = (char *)symtab_lookup(name); + /* ADDED */ + if(addr == NULL) { + PRINTF("name not found in global: %s\n", name); + addr = find_local_symbol(input_fd, name, symtab, symtabsize, strtab); + PRINTF("found address %p\n", addr); + } + 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: '%30s'\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) { + 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 { + return ELFLOADER_SEGMENT_NOT_FOUND; + } + + addr = sect->address; + } + +#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\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); + if (ret != ELFLOADER_OK) return ret; + } + return ELFLOADER_OK; +} +/*---------------------------------------------------------------------------*/ +static void * +find_program_processes(int input_fd, + unsigned int symtab, unsigned short size, + unsigned int strtab) +{ + struct elf32_sym s; + unsigned int a; + char name[30]; + + for(a = symtab; a < symtab + size; a += sizeof(s)) { + seek_read(input_fd, a, (char *)&s, sizeof(s)); + + if(s.st_name != 0) { + seek_read(input_fd, strtab + s.st_name, name, sizeof(name)); + if(strcmp(name, "autostart_processes") == 0) { + return &data.address[s.st_value]; + } + } + } + return NULL; +/* return find_local_symbol(fd, "autostart_processes", symtab, size, strtab); */ +} +/*---------------------------------------------------------------------------*/ +void +elfloader_init(void) +{ + elfloader_autostart_processes = NULL; +} +/*---------------------------------------------------------------------------*/ +#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(int 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) +{ + 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); + 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); +} + +/*---------------------------------------------------------------------------*/ +int +elfloader_load(int 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 process **process; + 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; + + 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(strncmp(name, ".text", 5) == 0) { + textoff = shdr.sh_offset; + textsize = shdr.sh_size; + text.number = i; + text.offset = textoff; + } else if(strncmp(name, ".rel.text", 9) == 0) { + using_relas = 0; + textrelaoff = shdr.sh_offset; + textrelasize = shdr.sh_size; + } else if(strncmp(name, ".rela.text", 10) == 0) { + using_relas = 1; + textrelaoff = shdr.sh_offset; + textrelasize = shdr.sh_size; + } else if(strncmp(name, ".data", 5) == 0) { + dataoff = shdr.sh_offset; + datasize = shdr.sh_size; + data.number = i; + data.offset = dataoff; + } else if(strncmp(name, ".rodata", 7) == 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(strncmp(name, ".rel.rodata", 11) == 0) { + /* using elf32_rel instead of rela */ + using_relas = 0; + rodatarelaoff = shdr.sh_offset; + rodatarelasize = shdr.sh_size; + } else if(strncmp(name, ".rela.rodata", 12) == 0) { + using_relas = 1; + rodatarelaoff = shdr.sh_offset; + rodatarelasize = shdr.sh_size; + } else if(strncmp(name, ".rel.data", 9) == 0) { + /* using elf32_rel instead of rela */ + using_relas = 0; + datarelaoff = shdr.sh_offset; + datarelasize = shdr.sh_size; + } else if(strncmp(name, ".rela.data", 10) == 0) { + using_relas = 1; + datarelaoff = shdr.sh_offset; + datarelasize = shdr.sh_size; + } else if(strncmp(name, ".symtab", 7) == 0) { + symtaboff = shdr.sh_offset; + symtabsize = shdr.sh_size; + } else if(strncmp(name, ".strtab", 7) == 0) { + strtaboff = shdr.sh_offset; + strtabsize = shdr.sh_size; + } else if(strncmp(name, ".bss", 4) == 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; + } + if (datasize) { + data.address = (char *) + elfloader_output_alloc_segment(output,ELFLOADER_SEG_DATA,datasize); + if (!data.address) return ELFLOADER_OUTPUT_ERROR; + } + 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); + if (!rodata.address) return ELFLOADER_OUTPUT_ERROR; + } + +/* printf("bss base address: bss.address = 0x%08x\n", bss.address); + printf("data base address: data.address = 0x%08x\n", data.address); + printf("text base address: text.address = 0x%08x\n", text.address); + printf("rodata base address: rodata.address = 0x%08x\n", rodata.address); */ + + + /* If we have text segment relocations, we process them. */ + PRINTF("elfloader: relocate text\n"); + if(textrelasize > 0) { + ret = copy_segment(input_fd, output, + textrelaoff, textrelasize, + textoff, + text.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas, + textsize, ELFLOADER_SEG_TEXT); + if(ret != ELFLOADER_OK) { + return ret; + } + } + + /* If we have any rodata segment relocations, we process them too. */ + PRINTF("elfloader: relocate rodata\n"); + if(rodatarelasize > 0) { + ret = copy_segment(input_fd, output, + rodatarelaoff, rodatarelasize, + rodataoff, + rodata.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas, + rodatasize, ELFLOADER_SEG_RODATA); + if(ret != ELFLOADER_OK) { + PRINTF("elfloader: data failed\n"); + return ret; + } + } + + /* If we have any data segment relocations, we process them too. */ + PRINTF("elfloader: relocate data\n"); + if(datarelasize > 0) { + ret = copy_segment(input_fd, output, + datarelaoff, datarelasize, + dataoff, + data.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas, + datasize, ELFLOADER_SEG_DATA); + if(ret != ELFLOADER_OK) { + PRINTF("elfloader: data failed\n"); + return ret; + } + ret = elfloader_output_end_segment(output); + if (ret != ELFLOADER_OK) return ret; + } + + /* 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); */ + +/* memset(bss.address, 0, bsssize); */ +/* seek_read(fd, dataoff, data.address, datasize); */ + + { + /* 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: autostart search\n"); + process = find_local_symbol(input_fd, "autostart_processes", symtaboff, symtabsize, strtaboff); + if(process != NULL) { + PRINTF("elfloader: autostart found\n"); + elfloader_autostart_processes = process; + return ELFLOADER_OK; + } else { + PRINTF("elfloader: no autostart\n"); + process = find_program_processes(input_fd, symtaboff, symtabsize, strtaboff); + if(process != NULL) { + PRINTF("elfloader: FOUND PRG\n"); + } + return ELFLOADER_NO_STARTPOINT; + } +} +/*---------------------------------------------------------------------------*/ diff --git a/cpu/arm/at91sam7s/loader/elfloader-otf.h b/cpu/arm/at91sam7s/loader/elfloader-otf.h new file mode 100644 index 000000000..91dc94b9b --- /dev/null +++ b/cpu/arm/at91sam7s/loader/elfloader-otf.h @@ -0,0 +1,314 @@ +/** + * \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 "cfs/cfs.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 + +/** + * 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_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(int input_fd, + struct elfloader_output *output); + +/** + * A pointer to the processes loaded with elfloader_load(). + */ +extern struct process **elfloader_autostart_processes; + +/** + * If elfloader_load() could not find a specific symbol, it is copied + * into this array. + */ +extern char elfloader_unknown[30]; + +#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. */ +}; + + +#endif /* __ELFLOADER_H__ */ + +/** @} */ +/** @} */ diff --git a/cpu/arm/at91sam7s/loader/empty-symbols.c b/cpu/arm/at91sam7s/loader/empty-symbols.c new file mode 100644 index 000000000..e2f43ffdb --- /dev/null +++ b/cpu/arm/at91sam7s/loader/empty-symbols.c @@ -0,0 +1,3 @@ +#include "symbols.h" +const int symbols_nelts = 0; +const struct symbols symbols[] = {{0,0}}; diff --git a/cpu/arm/at91sam7s/loader/ram-segments.c b/cpu/arm/at91sam7s/loader/ram-segments.c new file mode 100644 index 000000000..2fceb3bf8 --- /dev/null +++ b/cpu/arm/at91sam7s/loader/ram-segments.c @@ -0,0 +1,139 @@ +#ifndef __RAM_SEGMENTS_C__1POIF5E8U4__ +#define __RAM_SEGMENTS_C__1POIF5E8U4__ + +#include +#include +#include +#include +#include + +struct ram_output +{ + struct elfloader_output output; + char *base; + unsigned int offset; + void *text; + void *rodata; + void *data; + void *bss; +}; + +static void * +allocate_segment(struct elfloader_output * const output, + unsigned int type, int size) +{ + struct ram_output * const ram = (struct ram_output *)output; + void *block = malloc(size); + if (!block) return NULL; + switch(type) { + case ELFLOADER_SEG_TEXT: + if (ram->text) free(ram->text); + ram->text = block; + break; + case ELFLOADER_SEG_RODATA: + if (ram->rodata) free(ram->rodata); + ram->rodata = block; + break; + case ELFLOADER_SEG_DATA: + if (ram->data) free(ram->data); + ram->data = block; + break; + case ELFLOADER_SEG_BSS: + if (ram->bss) free(ram->bss); + ram->bss = block; + break; + default: + free(block); + return NULL; + } + return block; +} + +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; + 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 ram = (struct ram_output *)output; + memcpy(ram->base + ram->offset, buf, len); + ram->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}, + NULL, + 0, + NULL, + NULL, + NULL, + NULL +}; + +PROCESS(ram_segments_cleanup_process, "RAM segments cleanup process"); + +PROCESS_THREAD(ram_segments_cleanup_process, ev, data) +{ + PROCESS_BEGIN(); + while(1) { + PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_EXITED + || ev == PROCESS_EVENT_EXIT); + if (ev == PROCESS_EVENT_EXIT) break; + if (elfloader_autostart_processes || + elfloader_autostart_processes[0] == data) { + PROCESS_PAUSE(); /* Let the process exit */ + if (seg_output.text) { + free(seg_output.text); + seg_output.text = NULL; + } + if (seg_output.rodata) { + free(seg_output.rodata); + seg_output.rodata = NULL; + } + if (seg_output.data) { + free(seg_output.data); + seg_output.data = NULL; + } + + if (seg_output.bss) { + free(seg_output.bss); + seg_output.bss = NULL; + } + elfloader_autostart_processes = NULL; + } + } + PROCESS_END(); +} +struct elfloader_output *codeprop_output = &seg_output.output; + +#endif /* __RAM_SEGMENTS_C__1POIF5E8U4__ */ diff --git a/cpu/arm/at91sam7s/loader/ram-segments.h b/cpu/arm/at91sam7s/loader/ram-segments.h new file mode 100644 index 000000000..6f3936dfa --- /dev/null +++ b/cpu/arm/at91sam7s/loader/ram-segments.h @@ -0,0 +1,6 @@ +#ifndef __RAM_SEGMENTS_H__8EDB9N09UD__ +#define __RAM_SEGMENTS_H__8EDB9N09UD__ + +PROCESS_NAME(ram_segments_cleanup_process); + +#endif /* __RAM_SEGMENTS_H__8EDB9N09UD__ */