Contiki 2.5
elfloader-avr.c
1 /*
2  * Copyright (c) 2005, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  * @(#)$Id: elfloader-avr.c,v 1.10 2009/07/16 18:02:34 dak664 Exp $
32  */
33 
34 #include <stdio.h>
35 #include <avr/boot.h>
36 #include <avr/pgmspace.h>
37 #include <avr/interrupt.h>
38 #include "dev/rs232.h"
39 #include "elfloader-arch.h"
40 #include "lib/mmem.h"
41 #include <string.h> //memset
42 
43 #define R_AVR_NONE 0
44 #define R_AVR_32 1
45 #define R_AVR_7_PCREL 2
46 #define R_AVR_13_PCREL 3
47 #define R_AVR_16 4
48 #define R_AVR_16_PM 5
49 #define R_AVR_LO8_LDI 6
50 #define R_AVR_HI8_LDI 7
51 #define R_AVR_HH8_LDI 8
52 #define R_AVR_LO8_LDI_NEG 9
53 #define R_AVR_HI8_LDI_NEG 10
54 #define R_AVR_HH8_LDI_NEG 11
55 #define R_AVR_LO8_LDI_PM 12
56 #define R_AVR_HI8_LDI_PM 13
57 #define R_AVR_HH8_LDI_PM 14
58 #define R_AVR_LO8_LDI_PM_NEG 15
59 #define R_AVR_HI8_LDI_PM_NEG 16
60 #define R_AVR_HH8_LDI_PM_NEG 17
61 #define R_AVR_CALL 18
62 
63 #define ELF32_R_TYPE(info) ((unsigned char)(info))
64 
65 #define DEBUG 0
66 #if DEBUG
67 /*#define PRINTF(...) rs232_print_p(RS232_PORT_1, __VA_ARGS__)*/
68 #define PRINTF(...) printf(__VA_ARGS__)
69 #else
70 #define PRINTF(...)
71 #endif
72 
73 static struct mmem module_heap;
74 /*---------------------------------------------------------------------------*/
75 void*
77 {
78  /* Free previously allocated memory */
79  /* TODO Assumes memory address 0 can't be allocated, use flag instead? */
80  if (MMEM_PTR(&module_heap) != 0) {
81  mmem_free(&module_heap);
82  }
83 
84  /* Allocate RAM for module */
85  if (mmem_alloc (&module_heap, size) == 0) {
86  return NULL;
87  }
88 
89  return (char*)MMEM_PTR(&module_heap);
90 }
91 
92 /*---------------------------------------------------------------------------*/
93 /* TODO: Currently, modules are written to the fixed address 0x10000. Since
94  * flash rom uses word addresses on the AVR, we return 0x8000 here
95  */
96 void*
98 {
99  return (void *)0x8000;
100 }
101 
102 /*---------------------------------------------------------------------------*/
103 /* Eliminate compiler warnings for (non-functional) code when flash requires 32 bit addresses and pointers are 16 bit */
104 #define INCLUDE_APPLICATE_SOURCE 1
105 #ifdef __GNUC__
106 #if (FLASHEND > USHRT_MAX) && (__SIZEOF_POINTER__ <= 2)
107 #undef INCLUDE_APPLICATE_SOURCE
108 #define INCLUDE_APPLICATE_SOURCE 0
109 #endif
110 #if (__SIZEOF_POINTER__ > 2)
111 #define INCLUDE_32BIT_CODE 1
112 #endif
113 #endif
114 #if INCLUDE_APPLICATE_SOURCE
115 
116 BOOTLOADER_SECTION void
117 elfloader_arch_write_rom(int fd, unsigned short textoff, unsigned int size, char *mem)
118 {
119  unsigned char buf[SPM_PAGESIZE];
120  unsigned short* flashptr = (unsigned short *) mem;
121 
122 
123  // Sanity-check size of loadable module
124  if (size <= 0)
125  return;
126 
127 
128  // Seek to patched module and burn it to flash (in chunks of
129  // size SPM_PAGESIZE, i.e. 256 bytes on the ATmega128)
130  cfs_seek(fd, textoff, CFS_SEEK_SET);
131  for (flashptr=(unsigned short *)mem; flashptr < (unsigned short *) mem + size; flashptr += SPM_PAGESIZE) {
132  memset (buf, 0, SPM_PAGESIZE);
133  cfs_read(fd, buf, SPM_PAGESIZE);
134 
135  // Disable interrupts
136  uint8_t sreg;
137  sreg = SREG;
138  cli ();
139 
140  // Erase flash page
141  boot_page_erase (flashptr);
142  boot_spm_busy_wait ();
143 
144  unsigned short *origptr = flashptr;
145 
146  int i;
147  // Store data into page buffer
148  for(i = 0; i < SPM_PAGESIZE; i+=2) {
149  boot_page_fill (flashptr, (uint16_t)((buf[i+1] << 8) | buf[i]));
150  PORTB = 0xff - 7;
151  ++flashptr;
152  }
153 
154  // Burn page
155  boot_page_write (origptr);
156  boot_spm_busy_wait();
157 
158  // Reenable RWW sectin
159  boot_rww_enable ();
160  boot_spm_busy_wait ();
161 
162  // Restore original interrupt settings
163  SREG = sreg;
164  }
165 }
166 #endif /* INCLUDE_APPLICATE_SOURCE */
167 
168 /*---------------------------------------------------------------------------*/
169 static void
170 write_ldi(int fd, unsigned char *instr, unsigned char byte)
171 {
172  instr[0] = (instr[0] & 0xf0) | (byte & 0x0f);
173  instr[1] = (instr[1] & 0xf0) | (byte >> 4);
174  cfs_write (fd, instr, 2);
175 }
176 /*---------------------------------------------------------------------------*/
177 void
178 elfloader_arch_relocate(int fd, unsigned int sectionoffset,
179  // struct elf32_rela *rela, elf32_addr addr)
180  char *sectionaddr,
181  struct elf32_rela *rela, char *addr)
182 {
183  unsigned int type;
184  unsigned char instr[4];
185 
186  cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET);
187  cfs_read(fd, instr, 4);
188  cfs_seek(fd, sectionoffset + rela->r_offset, CFS_SEEK_SET);
189 
190  type = ELF32_R_TYPE(rela->r_info);
191 
192  addr += rela->r_addend;
193 
194  switch(type) {
195  case R_AVR_NONE:
196  case R_AVR_32:
197  PRINTF(PSTR ("elfloader-avr.c: unsupported relocation type: "));
198  PRINTF("%d\n", type);
199  break;
200 
201  case R_AVR_7_PCREL: { /* 4 */
202  /*
203  * Relocation is relative to PC. -2: branch instructions add 2 to PC.
204  * Do not use >> 1 for division because branch instructions use
205  * signed offsets.
206  */
207  int16_t a = (((int)addr - rela->r_offset -2) / 2);
208  instr[0] |= (a << 3) & 0xf8;
209  instr[1] |= (a >> 5) & 0x03;
210  cfs_write(fd, instr, 2);
211  }
212  break;
213  case R_AVR_13_PCREL: { /* 3 */
214  /*
215  * Relocation is relative to PC. -2: RJMP adds 2 to PC.
216  * Do not use >> 1 for division because RJMP uses signed offsets.
217  */
218  int16_t a = (int)addr / 2;
219  a -= rela->r_offset / 2;
220  a--;
221  instr[0] |= a & 0xff;
222  instr[1] |= (a >> 8) & 0x0f;
223  cfs_write(fd, instr, 2);
224  }
225  break;
226 
227  case R_AVR_16: /* 4 */
228  instr[0] = (int)addr & 0xff;
229  instr[1] = ((int)addr >> 8) & 0xff;
230 
231  cfs_write(fd, instr, 2);
232  break;
233 
234  case R_AVR_16_PM: /* 5 */
235  addr = (char *)((int)addr >> 1);
236  instr[0] = (int)addr & 0xff;
237  instr[1] = ((int)addr >> 8) & 0xff;
238 
239  cfs_write(fd, instr, 2);
240  break;
241 
242  case R_AVR_LO8_LDI: /* 6 */
243  write_ldi(fd, instr, (int)addr);
244  break;
245  case R_AVR_HI8_LDI: /* 7 */
246  write_ldi(fd, instr, (int)addr >> 8);
247  break;
248 
249 #if INCLUDE_32BIT_CODE /* 32 bit AVRs */
250  case R_AVR_HH8_LDI: /* 8 */
251  write_ldi(fd, instr, (int)addr >> 16);
252  break;
253 #endif
254 
255  case R_AVR_LO8_LDI_NEG: /* 9 */
256  addr = (char *) (0 - (int)addr);
257  write_ldi(fd, instr, (int)addr);
258  break;
259  case R_AVR_HI8_LDI_NEG: /* 10 */
260  addr = (char *) (0 - (int)addr);
261  write_ldi(fd, instr, (int)addr >> 8);
262  break;
263 
264 #if INCLUDE_32BIT_CODE /* 32 bit AVRs */
265  case R_AVR_HH8_LDI_NEG: /* 11 */
266  addr = (char *)(0 - (int)addr);
267  write_ldi(fd, instr, (int)addr >> 16);
268  break;
269 #endif
270 
271  case R_AVR_LO8_LDI_PM: /* 12 */
272  write_ldi(fd, instr, (int)addr >> 1);
273  break;
274  case R_AVR_HI8_LDI_PM: /* 13 */
275  write_ldi(fd, instr, (int)addr >> 9);
276  break;
277 
278 #if INCLUDE_32BIT_CODE /* 32 bit AVRs */
279  case R_AVR_HH8_LDI_PM: /* 14 */
280  write_ldi(fd, instr, (int)addr >> 17);
281  break;
282 #endif
283 
284  case R_AVR_LO8_LDI_PM_NEG: /* 15 */
285  addr = (char *) (0 - (int)addr);
286  write_ldi(fd, instr, (int)addr >> 1);
287  break;
288  case R_AVR_HI8_LDI_PM_NEG: /* 16 */
289  addr = (char *) (0 - (int)addr);
290  write_ldi(fd, instr, (int)addr >> 9);
291  break;
292 
293 #if INCLUDE_32BIT_CODE /* 32 bit AVRs */
294  case R_AVR_HH8_LDI_PM_NEG: /* 17 */
295  addr = (char *) (0 - (int)addr);
296  write_ldi(fd, instr, (int)addr >> 17);
297  break;
298 #endif
299 
300  case R_AVR_CALL: /* 18 */
301  /* old solution:
302  addr = ((int16_t)addr >> 1);
303  instr[2] = (int16_t)addr & 0xff;
304  instr[3] = (int16_t)addr >> 8;
305  */
306 
307  /* new solution */
308  instr[2] = (u8_t) ((int)addr) & 0xff;
309  instr[3] = ((int)addr) >> 8;
310  cfs_write(fd, instr, 4);
311  break;
312 
313  default:
314  PRINTF(PSTR ("Unknown relocation type!\n"));
315  break;
316  }
317 }
318 /*---------------------------------------------------------------------------*/
319 void
320 elfloader_unload(void) {
321 }