nexmon – Blame information for rev 1
?pathlinks?
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 | } |