From db4df3036615f94819c39c5a204809ffb63a1626 Mon Sep 17 00:00:00 2001 From: Sumankumar Panchal Date: Thu, 7 May 2015 22:47:41 +0530 Subject: [PATCH] Added MSP430X ELFLOADER support to load image with large memory model. --- apps/codeprop/Makefile.codeprop-tmp | 10 + core/loader/elfloader-msp430x.c | 810 ++++++++++++++++++++++++++++ cpu/msp430/Makefile.msp430 | 12 +- 3 files changed, 831 insertions(+), 1 deletion(-) create mode 100644 apps/codeprop/Makefile.codeprop-tmp create mode 100644 core/loader/elfloader-msp430x.c diff --git a/apps/codeprop/Makefile.codeprop-tmp b/apps/codeprop/Makefile.codeprop-tmp new file mode 100644 index 000000000..e725df070 --- /dev/null +++ b/apps/codeprop/Makefile.codeprop-tmp @@ -0,0 +1,10 @@ +codeprop-tmp_src = codeprop-tmp.c + +# Enable LARGE MEMORY MODEL supports for WISMOTE and EXP5438 platform +ifeq ($(TARGET),wismote) + TARGET_MEMORY_MODEL = large +endif + +ifeq ($(TARGET),exp5438) + TARGET_MEMORY_MODEL = large +endif diff --git a/core/loader/elfloader-msp430x.c b/core/loader/elfloader-msp430x.c new file mode 100644 index 000000000..32e1126f3 --- /dev/null +++ b/core/loader/elfloader-msp430x.c @@ -0,0 +1,810 @@ +/* + * Copyright (c) 2015, Indian Institute of 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. + * + */ + +/** + * \file + * MSP430x elfloader. + * \author + * Sumankumar Panchal + * + */ + +#include "contiki.h" +#include "loader/elfloader.h" +#include "loader/elfloader-arch.h" +#include "cfs/cfs.h" +#include "loader/symtab.h" +#include +#include +#include +#include "dev/flash.h" + +#define DEBUG 0 +#if DEBUG +#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) + +struct relevant_section { + unsigned char number; + unsigned int offset; + char *address; +}; + +char elfloader_unknown[30]; /* Name that caused link error. */ + +struct process *const *elfloader_autostart_processes; + +static struct relevant_section bss, data, rodata, rodatafar, text, textfar; + +static const 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. */ +}; + +/* relocation type */ +#define R_MSP430_NONE 0 +#define R_MSP430_32 1 +#define R_MSP430_10_PCREL 2 +#define R_MSP430_16 3 +#define R_MSP430_16_PCREL 4 +#define R_MSP430_16_BYTE 5 +#define R_MSP430_16_PCREL_BYTE 6 +#define R_MSP430_2X_PCREL 7 +#define R_MSP430_RL_PCREL 8 +#define R_MSP430X_SRC_BYTE 9 +#define R_MSP430X_SRC 10 +#define R_MSP430X_DST_BYTE 11 +#define R_MSP430X_DST 12 +#define R_MSP430X_DST_2ND_BYTE 13 +#define R_MSP430X_DST_2ND 14 +#define R_MSP430X_PCREL_SRC_BYTE 15 +#define R_MSP430X_PCREL_SRC 16 +#define R_MSP430X_PCREL_DST_BYTE 17 +#define R_MSP430X_PCREL_DST 18 +#define R_MSP430X_PCREL_DST_2ND 19 +#define R_MSP430X_PCREL_DST_2ND_BYTE 20 +#define R_MSP430X_S_BYTE 21 +#define R_MSP430X_S 22 +#define R_MSP430X_D_BYTE 23 +#define R_MSP430X_D 24 +#define R_MSP430X_PCREL_D 25 +#define R_MSP430X_INDXD 26 +#define R_MSP430X_PCREL_INDXD 27 +#define R_MSP430_10 28 + +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +static uint16_t datamemory_aligned[ELFLOADER_DATAMEMORY_SIZE / 2 + 1]; +static uint8_t *datamemory = (uint8_t *)datamemory_aligned; +#if ELFLOADER_CONF_TEXT_IN_ROM +static const char textmemory[ELFLOADER_TEXTMEMORY_SIZE] = { 0 }; +#else /* ELFLOADER_CONF_TEXT_IN_ROM */ +static char textmemory[ELFLOADER_TEXTMEMORY_SIZE]; +#endif /* ELFLOADER_CONF_TEXT_IN_ROM */ + +/*---------------------------------------------------------------------------*/ +static void +seek_read(int fd, unsigned int offset, char *buf, int len) +{ + cfs_seek(fd, offset, CFS_SEEK_SET); + cfs_read(fd, buf, len); +#if DEBUG + { + int i; + PRINTF("seek_read: Read len %d from offset %d\n", + len, offset); + for(i = 0; i < len; ++i) { + PRINTF("%02x ", buf[i]); + } + printf("\n"); + } +#endif /* DEBUG */ +} +/*---------------------------------------------------------------------------*/ +static void * +find_local_symbol(int 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; + + for(a = symtab; a < symtab + symtabsize; a += sizeof(s)) { + seek_read(fd, a, (char *)&s, sizeof(s)); + if(s.st_name != 0) { + seek_read(fd, strtab + s.st_name, name, sizeof(name)); + 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 == rodatafar.number) { + sect = &rodatafar; + } else if(s.st_shndx == textfar.number) { + sect = &textfar; + } else { + return NULL; + } + return &(sect->address[s.st_value]); + } + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +static int +relocate_section(int fd, + 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; + + /* 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) { + seek_read(fd, a, (char *)&rela, rel_size); + seek_read(fd, + symtab + sizeof(struct elf32_sym) * ELF32_R_SYM(rela.r_info), + (char *)&s, sizeof(s)); + if(s.st_name != 0) { + seek_read(fd, strtab + s.st_name, name, sizeof(name)); + PRINTF("name: %s\n", name); + addr = (char *)symtab_lookup(name); + if(addr == NULL) { + PRINTF("name not found in global: %s\n", name); + addr = find_local_symbol(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 == rodatafar.number) { + sect = &rodatafar; + } else if(s.st_shndx == textfar.number) { + sect = &textfar; + } 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 == rodatafar.number) { + sect = &rodatafar; + } else if(s.st_shndx == textfar.number) { + sect = &textfar; + } else { + return ELFLOADER_SEGMENT_NOT_FOUND; + } + + addr = sect->address; + } + + if(!using_relas) { + /* copy addend to rela structure */ + seek_read(fd, sectionaddr + rela.r_offset, (char *)&rela.r_addend, 4); + } + + elfloader_arch_relocate(fd, sectionaddr, sectionbase, &rela, addr); + } + + return ELFLOADER_OK; +} +/*---------------------------------------------------------------------------*/ +static void * +find_program_processes(int 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(fd, a, (char *)&s, sizeof(s)); + + if(s.st_name != 0) { + seek_read(fd, strtab + s.st_name, name, sizeof(name)); + if(strcmp(name, "autostart_processes") == 0) { + return &data.address[s.st_value]; + } + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +void +elfloader_init(void) +{ + elfloader_autostart_processes = NULL; +} +/*---------------------------------------------------------------------------*/ +int +elfloader_load(int fd) +{ + struct elf32_ehdr ehdr; + struct elf32_shdr shdr; + struct elf32_shdr strtable; + unsigned int strs; + unsigned int shdrptr; + unsigned int nameptr; + char name[17]; + + int i; + unsigned short shdrnum, shdrsize; + + unsigned char using_relas = -1; + unsigned short textoff = 0, textfaroff = 0, textsize, textfarsize, + textrelaoff = 0, textrelasize, textfarrelaoff = 0, textfarrelasize; + unsigned short dataoff = 0, datasize, datarelaoff = 0, datarelasize; + unsigned short rodataoff = 0, rodatafaroff = 0, rodatasize, rodatafarsize, + rodatarelaoff = 0, rodatarelasize, rodatafarrelaoff = 0, + rodatafarrelasize; + 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. */ + seek_read(fd, 0, (char *)&ehdr, sizeof(ehdr)); + + /* 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; + seek_read(fd, shdrptr, (char *)&shdr, sizeof(shdr)); + + /* Get the size and number of entries of the section header. */ + shdrsize = ehdr.e_shentsize; + shdrnum = ehdr.e_shnum; + + PRINTF("Section header: size %d num %d\n", shdrsize, shdrnum); + + /* The string table section: holds the names of the sections. */ + seek_read(fd, ehdr.e_shoff + shdrsize * ehdr.e_shstrndx, + (char *)&strtable, sizeof(strtable)); + + /* + * 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; + + PRINTF("Strtable offset %d\n", strs); + + /* + * Go through all sections and pick out the relevant ones. The + * ".text" and ".far.text" segments holds the actual code from + * the ELF file. The ".data" segment contains initialized data. + * The ".bss" segment holds the size of the unitialized data segment. + * The ".rodata" and ".far.rodata" segments contains constant data. + * The ".rela[a].text" and ".rela[a].far.text" segments contains + * relocation information for the contents of the ".text" and + * ".far.text" segments, respectively. The ".rela[a].rodata" and + * ".rela[a].far.rodata" segments contains relocation information + * for the contents of the ".rodata" and ".far.rodata" segments, + * respectively. The ".rela[a].data" segment contains relocation + * information for the contents of the ".data" segment. 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 = textfarsize = textrelasize = textfarrelasize = + datasize = datarelasize = rodatasize = rodatafarsize = + rodatarelasize = rodatafarrelasize = symtabsize = strtabsize = 0; + + bss.number = data.number = rodata.number = rodatafar.number = + text.number = textfar.number = -1; + + shdrptr = ehdr.e_shoff; + for(i = 0; i < shdrnum; ++i) { + seek_read(fd, shdrptr, (char *)&shdr, sizeof(shdr)); + + /* The name of the section is contained in the strings table. */ + nameptr = strs + shdr.sh_name; + seek_read(fd, nameptr, name, sizeof(name)); + PRINTF("Section shdrptr 0x%x, %d + %d type %d\n", + shdrptr, + strs, shdr.sh_name, + (int)shdr.sh_type); + /* + * Match the name of the section with a predefined set of names + * (.text, .far.text, .data, .bss, .rodata, .far.rodata, .rela.text, .rela.far.text, + * .rela.data, .rela.rodata, .rela.far.rodata, .symtab, and .strtab). + */ + + if(shdr.sh_type == SHT_SYMTAB) { + PRINTF("symtab\n"); + symtaboff = shdr.sh_offset; + symtabsize = shdr.sh_size; + } else if(shdr.sh_type == SHT_STRTAB) { + PRINTF("strtab\n"); + strtaboff = shdr.sh_offset; + strtabsize = shdr.sh_size; + } else if(strncmp(name, ".text", 5) == 0) { + textoff = shdr.sh_offset; + textsize = shdr.sh_size; + text.number = i; + text.offset = textoff; + } else if(strncmp(name, ".far.text", 9) == 0) { + textfaroff = shdr.sh_offset; + textfarsize = shdr.sh_size; + textfar.number = i; + textfar.offset = textfaroff; + } 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, ".rela.far.text", 14) == 0) { + using_relas = 1; + textfarrelaoff = shdr.sh_offset; + textfarrelasize = 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, ".far.rodata", 11) == 0) { + rodatafaroff = shdr.sh_offset; + rodatafarsize = shdr.sh_size; + rodatafar.number = i; + rodatafar.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, ".rela.far.rodata", 16) == 0) { + using_relas = 1; + rodatafarrelaoff = shdr.sh_offset; + rodatafarrelasize = 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, ".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(textfarsize == 0) { + return ELFLOADER_NO_TEXT; + } + + PRINTF("before allocate ram\n"); + bss.address = (char *)elfloader_arch_allocate_ram(bsssize + datasize); + data.address = (char *)bss.address + bsssize; + PRINTF("before allocate rom\n"); + textfar.address = (char *)elfloader_arch_allocate_rom(textfarsize + rodatafarsize); + rodatafar.address = (char *)textfar.address + textfarsize; + + PRINTF("bss base address: bss.address = 0x%08x\n", bss.address); + PRINTF("data base address: data.address = 0x%08x\n", data.address); + PRINTF("textfar base address: textfar.address = 0x%08x\n", textfar.address); + PRINTF("rodatafar base address: rodatafar.address = 0x%08x\n", rodatafar.address); + + /* If we have text segment relocations, we process them. */ + PRINTF("elfloader: relocate textfar\n"); + if(textfarrelasize > 0) { + ret = relocate_section(fd, + textfarrelaoff, textfarrelasize, + textfaroff, + textfar.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas); + if(ret != ELFLOADER_OK) { + return ret; + } + } + + /* If we have any rodata segment relocations, we process them too. */ + PRINTF("elfloader: relocate rodata\n"); + if(rodatafarrelasize > 0) { + ret = relocate_section(fd, + rodatafarrelaoff, rodatafarrelasize, + rodatafaroff, + rodatafar.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas); + 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 = relocate_section(fd, + datarelaoff, datarelasize, + dataoff, + data.address, + strs, + strtaboff, + symtaboff, symtabsize, using_relas); + if(ret != ELFLOADER_OK) { + PRINTF("elfloader: data failed\n"); + return ret; + } + } + + /* Write text and rodata segment into flash and data segment into RAM. */ + elfloader_arch_write_rom(fd, textfaroff, textfarsize, textfar.address); + elfloader_arch_write_rom(fd, rodatafaroff, rodatafarsize, rodatafar.address); + + memset(bss.address, 0, bsssize); + seek_read(fd, dataoff, data.address, datasize); + + PRINTF("elfloader: autostart search\n"); + process = (struct process **)find_local_symbol(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 = (struct process **)find_program_processes(fd, symtaboff, + symtabsize, strtaboff); + if(process != NULL) { + PRINTF("elfloader: FOUND PRG\n"); + } + return ELFLOADER_NO_STARTPOINT; + } +} +/*---------------------------------------------------------------------------*/ +void * +elfloader_arch_allocate_ram(int size) +{ + return datamemory; +} +/*---------------------------------------------------------------------------*/ +void * +elfloader_arch_allocate_rom(int size) +{ +#if ELFLOADER_CONF_TEXT_IN_ROM + /* Return an 512-byte aligned pointer. */ + return (char *) + ((unsigned long)&textmemory[0] & 0xfffffe00) + + (((unsigned long)&textmemory[0] & 0x1ff) == 0 ? 0 : 0x200); +#else /* ELFLOADER_CONF_TEXT_IN_ROM */ + return textmemory; +#endif /* ELFLOADER_CONF_TEXT_IN_ROM */ +} +/*---------------------------------------------------------------------------*/ +#define READSIZE 32 +void +elfloader_arch_write_rom(int fd, unsigned short textoff, unsigned int size, char *mem) +{ +#if ELFLOADER_CONF_TEXT_IN_ROM + int i; + unsigned int ptr; + unsigned short *flashptr; + + flash_setup(); + + flashptr = (unsigned short *)mem; + + cfs_seek(fd, textoff, CFS_SEEK_SET); + for(ptr = 0; ptr < size; ptr += READSIZE) { + + /* Read data from file into RAM. */ + cfs_read(fd, (unsigned char *)datamemory, READSIZE); + + /* Clear flash page on 512 byte boundary. */ + if((((unsigned short)flashptr) & 0x01ff) == 0) { + flash_clear(flashptr); + } + + /* + * Burn data from RAM into flash ROM. Flash is burned one 16-bit + * word at a time, so we need to be careful when incrementing + * pointers. The flashptr is already a short pointer, so + * incrementing it by one will actually increment the address by + * two. + */ + for(i = 0; i < READSIZE / 2; ++i) { + flash_write(flashptr, ((unsigned short *)datamemory)[i]); + ++flashptr; + } + } + + flash_done(); +#else /* ELFLOADER_CONF_TEXT_IN_ROM */ + cfs_seek(fd, textoff, CFS_SEEK_SET); + cfs_read(fd, (unsigned char *)mem, size); +#endif /* ELFLOADER_CONF_TEXT_IN_ROM */ +} +/*---------------------------------------------------------------------------*/ +/* Relocate an MSP430X ELF section. */ +void +elfloader_arch_relocate(int fd, unsigned int sectionoffset, + char *sectionaddr, + struct elf32_rela *rela, char *addr) +{ + unsigned int type; + unsigned char instr[2]; + + type = ELF32_R_TYPE(rela->r_info); + addr += rela->r_addend; + + switch(type) { + case R_MSP430_16: + case R_MSP430_16_PCREL: + case R_MSP430_16_BYTE: + case R_MSP430_16_PCREL_BYTE: + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_write(fd, (char *)&addr, 2); + break; + case R_MSP430_32: + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_write(fd, (char *)&addr, 2); + break; + case R_MSP430X_S: + case R_MSP430X_S_BYTE: + /* src(19:16) located at positions 11:8 of opcode */ + /* src(15:0) located just after opcode */ + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_read(fd, instr, 2); + instr[1] = (int)(instr[1]) & 0xf0 | (((long int)addr >> 8) & 0x0f00); + instr[0] = (int)(instr[0]) & 0xff; + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_write(fd, instr, 2); + cfs_write(fd, (char *)&addr, 2); + break; + case R_MSP430X_D: + case R_MSP430X_PCREL_D: + case R_MSP430X_D_BYTE: + /* dst(19:16) located at positions 3:0 of opcode */ + /* dst(15:0) located just after opcode */ + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_read(fd, instr, 2); + instr[1] = (int)(instr[1]) & 0xff; + instr[0] = (int)(instr[0]) & 0xf0 | (((long int)addr >> 16) & 0x000f); + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_write(fd, instr, 2); + cfs_write(fd, (char *)&addr, 2); + break; + case R_MSP430X_PCREL_SRC_BYTE: + case R_MSP430X_SRC_BYTE: + case R_MSP430X_PCREL_SRC: + case R_MSP430X_SRC: + /* src(19:16) located at positions 10:7 of extension word */ + /* src(15:0) located just after opcode */ + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_read(fd, instr, 2); + /* 4 most-significant bits */ + instr[1] = (int)(instr[1]) & 0xf8 | (((long int)addr >> 9) & 0x0780); + instr[0] = (int)(instr[0]) & 0x7f | (((long int)addr >> 9) & 0x0780); + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_write(fd, instr, 2); + /* 16 least-significant bits */ + cfs_seek(fd, sectionoffset + rela->r_offset + 0x04, CFS_SEEK_SET); + cfs_write(fd, (char *)&addr, 2); + break; + case R_MSP430X_DST_BYTE: + case R_MSP430X_PCREL_DST_BYTE: + case R_MSP430X_DST: + case R_MSP430X_PCREL_DST: + /* dst(19:16) located at positions 3:0 of extension word */ + /* dst(15:0) located just after opcode */ + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_read(fd, instr, 2); + instr[1] = (int)(instr[1]) & 0xff; + instr[0] = (int)(instr[0]) & 0xf0 | (((long int)addr >> 16) & 0x000f); + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_write(fd, instr, 2); + cfs_seek(fd, sectionoffset + rela->r_offset + 0x04, CFS_SEEK_SET); + cfs_write(fd, (char *)&addr, 2); + break; + case R_MSP430X_DST_2ND: + case R_MSP430X_PCREL_DST_2ND: + case R_MSP430X_DST_2ND_BYTE: + case R_MSP430X_PCREL_DST_2ND_BYTE: + /* dst(19:16) located at positions 3:0 of extension word */ + /* dst(15:0) located after src(15:0) */ + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_read(fd, instr, 2); + instr[1] = (int)(instr[1]) & 0xff; + instr[0] = (int)(instr[0]) & 0xf0 | (((long int)addr >> 16) & 0x000f); + cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); + cfs_write(fd, instr, 2); + cfs_seek(fd, sectionoffset + rela->r_offset + 0x06, CFS_SEEK_SET); + cfs_write(fd, (char *)&addr, 2); + break; + case R_MSP430X_INDXD: + case R_MSP430X_PCREL_INDXD: + cfs_seek(fd, sectionoffset + rela->r_offset + 0x02, CFS_SEEK_SET); + cfs_write(fd, (char *)&addr, 2); + break; + default: + PRINTF("Unknown relocation type!\n"); + break; + } +} +/*---------------------------------------------------------------------------*/ diff --git a/cpu/msp430/Makefile.msp430 b/cpu/msp430/Makefile.msp430 index 264538611..1a75e6068 100644 --- a/cpu/msp430/Makefile.msp430 +++ b/cpu/msp430/Makefile.msp430 @@ -37,6 +37,10 @@ MSP430 = msp430.c flash.c clock.c leds.c leds-arch.c \ UIPDRIVERS = me.c me_tabs.c slip.c crc16.c ELFLOADER = elfloader.c elfloader-msp430.c symtab.c +ifeq ($(TARGET_MEMORY_MODEL),large) +ELFLOADER = elfloader-msp430x.c symtab.c +endif + CONTIKI_TARGET_SOURCEFILES += $(MSP430) \ $(SYSAPPS) $(ELFLOADER) \ $(UIPDRIVERS) @@ -149,10 +153,16 @@ endif ifndef IAR ifneq (,$(findstring 4.7.,$(shell msp430-gcc -dumpversion))) ifdef CPU_HAS_MSP430X - TARGET_MEMORY_MODEL ?= medium + ifeq ($(TARGET_MEMORY_MODEL),large) + CFLAGS += -mmemory-model=$(TARGET_MEMORY_MODEL) + CFLAGS += -mcode-region=far -mdata-region=far -msr20 -mc20 -md20 + LDFLAGS += -mmemory-model=$(TARGET_MEMORY_MODEL) -mcode-region=far -mdata-region=far -msr20 -mc20 -md20 + else + TARGET_MEMORY_MODEL = medium CFLAGS += -mmemory-model=$(TARGET_MEMORY_MODEL) CFLAGS += -ffunction-sections -fdata-sections -mcode-region=any LDFLAGS += -mmemory-model=$(TARGET_MEMORY_MODEL) -Wl,-gc-sections + endif endif endif endif