Contiki 2.6
|
00001 /* 00002 * Copyright (c) 2005, Swedish Institute of Computer Science 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the Institute nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 * 00029 * This file is part of the Contiki operating system. 00030 * 00031 */ 00032 00033 #include <stdio.h> 00034 #include <avr/boot.h> 00035 #include <avr/pgmspace.h> 00036 #include <avr/interrupt.h> 00037 #include "elfloader-arch.h" 00038 #include "lib/mmem.h" 00039 #include <string.h> //memset 00040 00041 #define R_AVR_NONE 0 00042 #define R_AVR_32 1 00043 #define R_AVR_7_PCREL 2 00044 #define R_AVR_13_PCREL 3 00045 #define R_AVR_16 4 00046 #define R_AVR_16_PM 5 00047 #define R_AVR_LO8_LDI 6 00048 #define R_AVR_HI8_LDI 7 00049 #define R_AVR_HH8_LDI 8 00050 #define R_AVR_LO8_LDI_NEG 9 00051 #define R_AVR_HI8_LDI_NEG 10 00052 #define R_AVR_HH8_LDI_NEG 11 00053 #define R_AVR_LO8_LDI_PM 12 00054 #define R_AVR_HI8_LDI_PM 13 00055 #define R_AVR_HH8_LDI_PM 14 00056 #define R_AVR_LO8_LDI_PM_NEG 15 00057 #define R_AVR_HI8_LDI_PM_NEG 16 00058 #define R_AVR_HH8_LDI_PM_NEG 17 00059 #define R_AVR_CALL 18 00060 00061 #define ELF32_R_TYPE(info) ((unsigned char)(info)) 00062 00063 #define DEBUG 0 00064 #if DEBUG 00065 #include <avr/pgmspace.h> 00066 #define PRINTF(FORMAT,args...) printf_P(PSTR(FORMAT),##args) 00067 #else 00068 #define PRINTF(...) 00069 #endif 00070 00071 static struct mmem module_heap; 00072 /*---------------------------------------------------------------------------*/ 00073 void* 00074 elfloader_arch_allocate_ram(int size) 00075 { 00076 /* Free previously allocated memory */ 00077 /* TODO Assumes memory address 0 can't be allocated, use flag instead? */ 00078 if (MMEM_PTR(&module_heap) != 0) { 00079 mmem_free(&module_heap); 00080 } 00081 00082 /* Allocate RAM for module */ 00083 if (mmem_alloc (&module_heap, size) == 0) { 00084 return NULL; 00085 } 00086 00087 return (char*)MMEM_PTR(&module_heap); 00088 } 00089 00090 /*---------------------------------------------------------------------------*/ 00091 /* TODO: Currently, modules are written to the fixed address 0x10000. Since 00092 * flash rom uses word addresses on the AVR, we return 0x8000 here 00093 */ 00094 void* 00095 elfloader_arch_allocate_rom(int size) 00096 { 00097 return (void *)0x8000; 00098 } 00099 00100 /*---------------------------------------------------------------------------*/ 00101 /* Eliminate compiler warnings for (non-functional) code when flash requires 32 bit addresses and pointers are 16 bit */ 00102 #define INCLUDE_APPLICATE_SOURCE 1 00103 #ifdef __GNUC__ 00104 #if (FLASHEND > USHRT_MAX) && (__SIZEOF_POINTER__ <= 2) 00105 #undef INCLUDE_APPLICATE_SOURCE 00106 #define INCLUDE_APPLICATE_SOURCE 0 00107 #endif 00108 #if (__SIZEOF_POINTER__ > 2) 00109 #define INCLUDE_32BIT_CODE 1 00110 #endif 00111 #endif 00112 #if INCLUDE_APPLICATE_SOURCE 00113 00114 BOOTLOADER_SECTION void 00115 elfloader_arch_write_rom(int fd, unsigned short textoff, unsigned int size, char *mem) 00116 { 00117 unsigned char buf[SPM_PAGESIZE]; 00118 unsigned short* flashptr = (unsigned short *) mem; 00119 00120 00121 // Sanity-check size of loadable module 00122 if (size <= 0) 00123 return; 00124 00125 00126 // Seek to patched module and burn it to flash (in chunks of 00127 // size SPM_PAGESIZE, i.e. 256 bytes on the ATmega128) 00128 cfs_seek(fd, textoff, CFS_SEEK_SET); 00129 for (flashptr=(unsigned short *)mem; flashptr < (unsigned short *) mem + size; flashptr += SPM_PAGESIZE) { 00130 memset (buf, 0, SPM_PAGESIZE); 00131 cfs_read(fd, buf, SPM_PAGESIZE); 00132 00133 // Disable interrupts 00134 uint8_t sreg; 00135 sreg = SREG; 00136 cli (); 00137 00138 // Erase flash page 00139 boot_page_erase (flashptr); 00140 boot_spm_busy_wait (); 00141 00142 unsigned short *origptr = flashptr; 00143 00144 int i; 00145 // Store data into page buffer 00146 for(i = 0; i < SPM_PAGESIZE; i+=2) { 00147 boot_page_fill (flashptr, (uint16_t)((buf[i+1] << 8) | buf[i])); 00148 PORTB = 0xff - 7; 00149 ++flashptr; 00150 } 00151 00152 // Burn page 00153 boot_page_write (origptr); 00154 boot_spm_busy_wait(); 00155 00156 // Reenable RWW sectin 00157 boot_rww_enable (); 00158 boot_spm_busy_wait (); 00159 00160 // Restore original interrupt settings 00161 SREG = sreg; 00162 } 00163 } 00164 #endif /* INCLUDE_APPLICATE_SOURCE */ 00165 00166 /*---------------------------------------------------------------------------*/ 00167 static void 00168 write_ldi(int fd, unsigned char *instr, unsigned char byte) 00169 { 00170 instr[0] = (instr[0] & 0xf0) | (byte & 0x0f); 00171 instr[1] = (instr[1] & 0xf0) | (byte >> 4); 00172 cfs_write (fd, instr, 2); 00173 } 00174 /*---------------------------------------------------------------------------*/ 00175 void 00176 elfloader_arch_relocate(int fd, unsigned int sectionoffset, 00177 // struct elf32_rela *rela, elf32_addr addr) 00178 char *sectionaddr, 00179 struct elf32_rela *rela, char *addr) 00180 { 00181 unsigned int type; 00182 unsigned char instr[4]; 00183 00184 cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); 00185 cfs_read(fd, instr, 4); 00186 cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); 00187 00188 type = ELF32_R_TYPE(rela->r_info); 00189 00190 addr += rela->r_addend; 00191 00192 switch(type) { 00193 case R_AVR_NONE: 00194 case R_AVR_32: 00195 PRINTF(PSTR ("elfloader-avr.c: unsupported relocation type: ")); 00196 PRINTF("%d\n", type); 00197 break; 00198 00199 case R_AVR_7_PCREL: { /* 4 */ 00200 /* 00201 * Relocation is relative to PC. -2: branch instructions add 2 to PC. 00202 * Do not use >> 1 for division because branch instructions use 00203 * signed offsets. 00204 */ 00205 int16_t a = (((int)addr - rela->r_offset -2) / 2); 00206 instr[0] |= (a << 3) & 0xf8; 00207 instr[1] |= (a >> 5) & 0x03; 00208 cfs_write(fd, instr, 2); 00209 } 00210 break; 00211 case R_AVR_13_PCREL: { /* 3 */ 00212 /* 00213 * Relocation is relative to PC. -2: RJMP adds 2 to PC. 00214 * Do not use >> 1 for division because RJMP uses signed offsets. 00215 */ 00216 int16_t a = (int)addr / 2; 00217 a -= rela->r_offset / 2; 00218 a--; 00219 instr[0] |= a & 0xff; 00220 instr[1] |= (a >> 8) & 0x0f; 00221 cfs_write(fd, instr, 2); 00222 } 00223 break; 00224 00225 case R_AVR_16: /* 4 */ 00226 instr[0] = (int)addr & 0xff; 00227 instr[1] = ((int)addr >> 8) & 0xff; 00228 00229 cfs_write(fd, instr, 2); 00230 break; 00231 00232 case R_AVR_16_PM: /* 5 */ 00233 addr = (char *)((int)addr >> 1); 00234 instr[0] = (int)addr & 0xff; 00235 instr[1] = ((int)addr >> 8) & 0xff; 00236 00237 cfs_write(fd, instr, 2); 00238 break; 00239 00240 case R_AVR_LO8_LDI: /* 6 */ 00241 write_ldi(fd, instr, (int)addr); 00242 break; 00243 case R_AVR_HI8_LDI: /* 7 */ 00244 write_ldi(fd, instr, (int)addr >> 8); 00245 break; 00246 00247 #if INCLUDE_32BIT_CODE /* 32 bit AVRs */ 00248 case R_AVR_HH8_LDI: /* 8 */ 00249 write_ldi(fd, instr, (int)addr >> 16); 00250 break; 00251 #endif 00252 00253 case R_AVR_LO8_LDI_NEG: /* 9 */ 00254 addr = (char *) (0 - (int)addr); 00255 write_ldi(fd, instr, (int)addr); 00256 break; 00257 case R_AVR_HI8_LDI_NEG: /* 10 */ 00258 addr = (char *) (0 - (int)addr); 00259 write_ldi(fd, instr, (int)addr >> 8); 00260 break; 00261 00262 #if INCLUDE_32BIT_CODE /* 32 bit AVRs */ 00263 case R_AVR_HH8_LDI_NEG: /* 11 */ 00264 addr = (char *)(0 - (int)addr); 00265 write_ldi(fd, instr, (int)addr >> 16); 00266 break; 00267 #endif 00268 00269 case R_AVR_LO8_LDI_PM: /* 12 */ 00270 write_ldi(fd, instr, (int)addr >> 1); 00271 break; 00272 case R_AVR_HI8_LDI_PM: /* 13 */ 00273 write_ldi(fd, instr, (int)addr >> 9); 00274 break; 00275 00276 #if INCLUDE_32BIT_CODE /* 32 bit AVRs */ 00277 case R_AVR_HH8_LDI_PM: /* 14 */ 00278 write_ldi(fd, instr, (int)addr >> 17); 00279 break; 00280 #endif 00281 00282 case R_AVR_LO8_LDI_PM_NEG: /* 15 */ 00283 addr = (char *) (0 - (int)addr); 00284 write_ldi(fd, instr, (int)addr >> 1); 00285 break; 00286 case R_AVR_HI8_LDI_PM_NEG: /* 16 */ 00287 addr = (char *) (0 - (int)addr); 00288 write_ldi(fd, instr, (int)addr >> 9); 00289 break; 00290 00291 #if INCLUDE_32BIT_CODE /* 32 bit AVRs */ 00292 case R_AVR_HH8_LDI_PM_NEG: /* 17 */ 00293 addr = (char *) (0 - (int)addr); 00294 write_ldi(fd, instr, (int)addr >> 17); 00295 break; 00296 #endif 00297 00298 case R_AVR_CALL: /* 18 */ 00299 /* old solution: 00300 addr = ((int16_t)addr >> 1); 00301 instr[2] = (int16_t)addr & 0xff; 00302 instr[3] = (int16_t)addr >> 8; 00303 */ 00304 00305 /* new solution */ 00306 instr[2] = (uint8_t) ((int)addr) & 0xff; 00307 instr[3] = ((int)addr) >> 8; 00308 cfs_write(fd, instr, 4); 00309 break; 00310 00311 default: 00312 PRINTF(PSTR ("Unknown relocation type!\n")); 00313 break; 00314 } 00315 } 00316 /*---------------------------------------------------------------------------*/ 00317 void 00318 elfloader_unload(void) { 00319 }