nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 #define _XOPEN_SOURCE 700
2  
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <argp.h>
6 #include <string.h>
7 #include "darm/darm.h"
8  
9 #include <arpa/inet.h>
10 #include <netinet/in.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <unistd.h>
14  
15 #define AS_STR2(TEXT) #TEXT
16 #define AS_STR(TEXT) AS_STR2(TEXT)
17  
18 char *ram_array = NULL;
19 long ram_len = 0;
20  
21 char *rom_array = NULL;
22 long rom_len = 0;
23  
24 char *ram_file_name = AS_STR(RAM_FILE_NAME);
25 char *rom_file_in_name = NULL;
26 char *rom_file_out_name = NULL;
27 int fp_config_base = 0;
28 int fp_config_end = 0;
29 int ram_start = 0x180000;
30 int rom_start = 0x0;
31 char bcm43596 = 0;
32 char bcm4366 = 0;
33  
34 const char *argp_program_version = "fpext";
35 const char *argp_program_bug_address = "<mschulz@seemoo.tu-darmstadt.de>";
36  
37 static char doc[] = "fpext -- a program to extract flash patches form a firmware rom.";
38  
39 static struct argp_option options[] = {
40 {"ramfile", 'r', "FILE", 0, "Read ram from FILE"},
41 {"ramstart", 's', "ADDR", 0, "RAM start address"},
42 {"fpconfigbase", 'b', "ADDR", 0, "Use ADDR as base address of the flash patch config block"},
43 {"fpconfigend", 'e', "ADDR", 0, "Use ADDR as end address of the flash patch config block"},
44 {"romfilein", 'i', "FILE", 0, "Apply patches to this ROM FILE"},
45 {"romfileout", 'o', "FILE", 0, "Save the patched ROM file as FILE"},
46 {"romstart", 't', "ADDR", 0, "ROM start address"},
47 {"bcm43596", 'x', 0, 0, "Select whether target chip has a flash patching unit similar to the bcm43596"},
48 {"bcm4366", 'y', 0, 0, "Select whether target chip has a flash patching unit similar to the bcm4366"},
49 { 0 }
50 };
51  
52 static error_t
53 parse_opt(int key, char *arg, struct argp_state *state)
54 {
55 switch (key) {
56  
57 case 'r':
58 ram_file_name = arg;
59 break;
60  
61 case 'b':
62 fp_config_base = strtol(arg, NULL, 0);
63 break;
64  
65 case 'e':
66 fp_config_end = strtol(arg, NULL, 0);
67 break;
68  
69 case 's':
70 ram_start = strtol(arg, NULL, 0);
71 break;
72  
73 case 'i':
74 rom_file_in_name = arg;
75 break;
76  
77 case 'o':
78 rom_file_out_name = arg;
79 break;
80  
81 case 't':
82 rom_start = strtol(arg, NULL, 0);
83 break;
84  
85 case 'x':
86 bcm43596 = 1;
87 break;
88  
89 case 'y':
90 bcm4366 = 1;
91 break;
92  
93 default:
94 return ARGP_ERR_UNKNOWN;
95 }
96  
97 return 0;
98 }
99  
100 static struct argp argp = { options, parse_opt, 0, doc };
101  
102 int
103 write_array_to_file(char *filename, char *buffer, long filelen)
104 {
105 FILE *fileptr;
106  
107 if ((fileptr = fopen(filename, "wb"))) {
108 fwrite(buffer, 1, filelen, fileptr);
109 fclose(fileptr);
110 return 0;
111 }
112  
113 return -1;
114 }
115  
116 int
117 read_file_to_array(char *filename, char **buffer, long *filelen)
118 {
119 FILE *fileptr;
120  
121 if ((fileptr = fopen(filename, "rb"))) {
122 fseek(fileptr, 0, SEEK_END);
123 *filelen = ftell(fileptr);
124 rewind(fileptr);
125  
126 *buffer = (char *) malloc(*filelen + 1);
127 fread(*buffer, *filelen, 1, fileptr);
128 fclose(fileptr);
129  
130 return *filelen;
131 }
132  
133 return 0;
134 }
135  
136 int
137 get_words(unsigned int addr, unsigned short *low, unsigned short *high)
138 {
139 if (addr > ram_start && addr < ram_start + ram_len - 4) {
140 *low = *((unsigned short *) (ram_array + addr - ram_start));
141 *high = *((unsigned short *) (ram_array + addr - ram_start + 2));
142 return 2;
143 }
144  
145 return 0;
146 }
147  
148 struct fp_config {
149 unsigned int target_addr;
150 unsigned int size;
151 unsigned int data_ptr;
152 };
153  
154 void
155 analyse_ram()
156 {
157 darm_t d;
158 darm_t *dd = &d;
159 unsigned short low, high;
160  
161 struct fp_config *fpc = (struct fp_config *) (ram_array + fp_config_base - ram_start);
162  
163 darm_init(&d);
164  
165 for (int i = 0; i < (fp_config_end - fp_config_base) / sizeof(struct fp_config); i++) {
166 get_words(fpc[i].data_ptr, &low, &high);
167 darm_disasm(dd, low, high, 1);
168  
169 printf("__attribute__((at(0x%08x, \"flashpatch\")))\n", fpc[i].target_addr);
170 printf("BPatch(flash_patch_%d, 0x%08x);\n\n", i, fpc[i].target_addr + dd->imm + 4);
171  
172 if (rom_array != NULL && (fpc[i].target_addr - rom_start) < rom_len) {
173 memcpy(&rom_array[fpc[i].target_addr - rom_start], &ram_array[fpc[i].data_ptr - ram_start], fpc[i].size);
174 }
175 }
176 }
177  
178 struct fp_config_bcm43596 {
179 unsigned int target_addr;
180 unsigned int data_ptr;
181 };
182  
183 void
184 analyse_ram_bcm43596()
185 {
186 darm_t d;
187 darm_t *dd = &d;
188 unsigned short low, high;
189  
190 struct fp_config_bcm43596 *fpc = (struct fp_config_bcm43596 *) (ram_array + fp_config_base - ram_start);
191  
192 darm_init(&d);
193  
194 for (int i = 0; i < (fp_config_end - fp_config_base) / sizeof(struct fp_config_bcm43596); i++) {
195 get_words(fpc[i].data_ptr, &low, &high);
196 darm_disasm(dd, low, high, 1);
197  
198 printf("__attribute__((at(0x%08x, \"flashpatch\")))\n", fpc[i].target_addr);
199 printf("unsigned int flash_patch_%d[2] = {0x%08x, 0x%08x};\n\n", i,
200 *((unsigned int *) (ram_array + fpc[i].data_ptr - ram_start)),
201 *((unsigned int *) (ram_array + fpc[i].data_ptr + 4 - ram_start)));
202  
203 if (rom_array != NULL && (fpc[i].target_addr - rom_start) < rom_len) {
204 memcpy(&rom_array[fpc[i].target_addr - rom_start], &ram_array[fpc[i].data_ptr - ram_start], 8);
205 }
206 }
207 }
208  
209 void
210 analyse_ram_bcm4366()
211 {
212 darm_t d;
213 darm_t *dd = &d;
214 unsigned short low, high;
215  
216 struct fp_config_bcm43596 *fpc = (struct fp_config_bcm43596 *) (ram_array + fp_config_base - ram_start);
217  
218 darm_init(&d);
219  
220 for (int i = 0; i < (fp_config_end - fp_config_base) / sizeof(struct fp_config_bcm43596); i++) {
221 get_words(fpc[i].data_ptr, &low, &high);
222 darm_disasm(dd, low, high, 1);
223  
224 printf("__attribute__((at(0x%08x, \"flashpatch\")))\n", fpc[i].target_addr);
225 printf("unsigned int flash_patch_%d[4] = {0x%08x, 0x%08x, 0x%08x, 0x%08x};\n\n", i,
226 *((unsigned int *) (ram_array + fpc[i].data_ptr - ram_start)),
227 *((unsigned int *) (ram_array + fpc[i].data_ptr + 4 - ram_start)),
228 *((unsigned int *) (ram_array + fpc[i].data_ptr + 8 - ram_start)),
229 *((unsigned int *) (ram_array + fpc[i].data_ptr + 12 - ram_start)));
230  
231 if (rom_array != NULL && (fpc[i].target_addr - rom_start) < rom_len) {
232 memcpy(&rom_array[fpc[i].target_addr - rom_start], &ram_array[fpc[i].data_ptr - ram_start], 16);
233 }
234 }
235 }
236  
237 int
238 main(int argc, char **argv)
239 {
240 argp_parse(&argp, argc, argv, 0, 0, 0);
241  
242 if (!read_file_to_array(ram_file_name, &ram_array, &ram_len)) {
243 fprintf(stderr, "ERR: RAM file empty or unavailable.\n");
244 exit(EXIT_FAILURE);
245 }
246  
247 if (rom_file_in_name != NULL && rom_file_out_name != NULL) {
248 if (!read_file_to_array(rom_file_in_name, &rom_array, &rom_len)) {
249 fprintf(stderr, "ERR: ROM file empty or unavailable.\n");
250 exit(EXIT_FAILURE);
251 }
252 }
253  
254 if (bcm43596 == 1)
255 analyse_ram_bcm43596();
256 if (bcm4366 == 1)
257 analyse_ram_bcm4366();
258 else
259 analyse_ram();
260  
261 if (rom_file_in_name != NULL && rom_file_out_name != NULL) {
262 write_array_to_file(rom_file_out_name, rom_array, rom_len);
263 }
264  
265 exit(EXIT_SUCCESS);
266 }