diff options
Diffstat (limited to 'meta-xilinx-core/recipes-bsp/fpga-manager-script/files/fpgautil.c')
-rw-r--r-- | meta-xilinx-core/recipes-bsp/fpga-manager-script/files/fpgautil.c | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/meta-xilinx-core/recipes-bsp/fpga-manager-script/files/fpgautil.c b/meta-xilinx-core/recipes-bsp/fpga-manager-script/files/fpgautil.c new file mode 100644 index 00000000..0b77569d --- /dev/null +++ b/meta-xilinx-core/recipes-bsp/fpga-manager-script/files/fpgautil.c | |||
@@ -0,0 +1,464 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright (C) 2019-2020 Xilinx, Inc. All rights reserved. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
6 | * this software and associated documentation files (the "Software"), to deal in | ||
7 | * the Software without restriction, including without limitation the rights to | ||
8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
9 | * of the Software, and to permit persons to whom the Software is furnished to do | ||
10 | * so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice shall be included in all | ||
13 | * copies or substantial portions of the Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
21 | * SOFTWARE. | ||
22 | * | ||
23 | ******************************************************************************/ | ||
24 | /*****************************************************************************/ | ||
25 | /** | ||
26 | * @file: fpgautil.c | ||
27 | * Simple command line tool to load fpga via overlay or through sysfs interface | ||
28 | * and read fpga configuration using Xilinx Zynq/ZynqMP fpga manager | ||
29 | * Author: Appana Durga Kedareswara Rao <appanad@xilinx.com> | ||
30 | * Author: Nava kishore Manne <navam@xilinx.com> | ||
31 | */ | ||
32 | #include <stdbool.h> | ||
33 | #include <stdio.h> | ||
34 | #include <stdlib.h> | ||
35 | #include <string.h> | ||
36 | #include <unistd.h> | ||
37 | #include <string.h> | ||
38 | #include <signal.h> | ||
39 | #include <getopt.h> | ||
40 | #include <poll.h> | ||
41 | #include <ctype.h> | ||
42 | #include <libgen.h> | ||
43 | #include <time.h> | ||
44 | #include <errno.h> | ||
45 | #include <sys/time.h> | ||
46 | #include <sys/stat.h> | ||
47 | |||
48 | #define OVERLAY 1 | ||
49 | #define FPGA_SYSFS 2 | ||
50 | #define READBACK 3 | ||
51 | #define ENCRYPTION_USERKEY_EN (0x20U) | ||
52 | |||
53 | int fpga_getplatform() | ||
54 | { | ||
55 | char fpstr[100]; | ||
56 | FILE *fptr; | ||
57 | char *zynqmpstr = "Xilinx ZynqMP FPGA Manager"; | ||
58 | |||
59 | if ((fptr = fopen("/sys/class/fpga_manager/fpga0/name", "r")) == NULL) | ||
60 | { | ||
61 | printf("Error! opening file"); | ||
62 | // Program exits if file pointer returns NULL. | ||
63 | exit(1); | ||
64 | } | ||
65 | |||
66 | // reads text until newline | ||
67 | fscanf(fptr,"%[^\n]", fpstr); | ||
68 | fclose(fptr); | ||
69 | |||
70 | if (!strcmp(zynqmpstr, fpstr)) | ||
71 | return 1; | ||
72 | else | ||
73 | return 0; | ||
74 | |||
75 | } | ||
76 | |||
77 | void print_usage(char *prg) | ||
78 | { | ||
79 | int iszynqmp = fpga_getplatform(); | ||
80 | |||
81 | fprintf(stderr, "\n%s: FPGA Utility for Loading/reading PL Configuration\n\n", prg); | ||
82 | fprintf(stderr, "Usage: %s -b <bin file path> -o <dtbo file path>\n\r", prg); | ||
83 | fprintf(stderr, "\n"); | ||
84 | fprintf(stderr, "Options: -b <binfile> (Bin file path)\n"); | ||
85 | fprintf(stderr, " -o <dtbofile> (DTBO file path)\n"); | ||
86 | fprintf(stderr, " -f <flags> Optional: <Bitstream type flags>\n"); | ||
87 | fprintf(stderr, " f := <Full | Partial > \n"); | ||
88 | fprintf(stderr, " -n <Fpga region info> FPGA Regions represent FPGA's\n"); | ||
89 | fprintf(stderr, " and partial reconfiguration\n"); | ||
90 | fprintf(stderr, " regions of FPGA's in the\n"); | ||
91 | fprintf(stderr, " Device Tree\n"); | ||
92 | if (iszynqmp) | ||
93 | { | ||
94 | fprintf(stderr, " Default: <Full>\n"); | ||
95 | fprintf(stderr, " -s <secure flags> Optional: <Secure flags>\n"); | ||
96 | fprintf(stderr, " s := <AuthDDR | AuthOCM | EnUsrKey | EnDevKey | AuthEnUsrKeyDDR | AuthEnUsrKeyOCM | AuthEnDevKeyDDR | AuthEnDevKeyOCM>\n"); | ||
97 | fprintf(stderr, " -k <AesKey> Optional: <AES User Key>\n"); | ||
98 | fprintf(stderr, " -r <Readback> Optional: <file name>\n"); | ||
99 | fprintf(stderr, " Default: By default Read back contents will be stored in readback.bin file\n"); | ||
100 | fprintf(stderr, " -t Optional: <Readback Type>\n"); | ||
101 | fprintf(stderr, " 0 - Configuration Register readback\n"); | ||
102 | fprintf(stderr, " 1 - Configuration Data Frames readback\n"); | ||
103 | fprintf(stderr, " Default: 0 (Configuration register readback)\n"); | ||
104 | fprintf(stderr, " -R Optional: Remove overlay from a live tree\n"); | ||
105 | } | ||
106 | |||
107 | fprintf(stderr, " \n"); | ||
108 | fprintf(stderr, "Examples:\n"); | ||
109 | fprintf(stderr, "(Load Full bitstream using Overlay)\n"); | ||
110 | fprintf(stderr, "%s -b top.bit.bin -o can.dtbo -f Full -n Full \n", prg); | ||
111 | fprintf(stderr, "(Load Partial bitstream using Overlay)\n"); | ||
112 | fprintf(stderr, "%s -b rm0.bit.bin -o rm0.dtbo -f Partial -n PR0\n", prg); | ||
113 | fprintf(stderr, "(Load Full bitstream using sysfs interface)\n"); | ||
114 | fprintf(stderr, "%s -b top.bit.bin -f Full\n", prg); | ||
115 | fprintf(stderr, "(Load Partial bitstream using sysfs interface)\n"); | ||
116 | fprintf(stderr, "%s -b rm0.bit.bin -f Partial\n", prg); | ||
117 | if (iszynqmp) | ||
118 | { | ||
119 | fprintf(stderr, "(Load Authenticated bitstream through the sysfs interface)\n"); | ||
120 | fprintf(stderr, "%s -b top.bit.bin -f Full -s AuthDDR \n", prg); | ||
121 | fprintf(stderr, "(Load Parital Encrypted Userkey bitstream using Overlay)\n"); | ||
122 | fprintf(stderr, "%s -b top.bit.bin -o pl.dtbo -f Partial -s EnUsrKey -k <32byte key value>\n", prg); | ||
123 | fprintf(stderr, "(Read PL Configuration Registers)\n"); | ||
124 | fprintf(stderr, "%s -b top.bit.bin -r\n", prg); | ||
125 | } | ||
126 | fprintf(stderr, " \n"); | ||
127 | } | ||
128 | |||
129 | int gettime(struct timeval t0, struct timeval t1) | ||
130 | { | ||
131 | return ((t1.tv_sec - t0.tv_sec) * 1000.0f + (t1.tv_usec -t0.tv_usec) / 1000.0f); | ||
132 | } | ||
133 | |||
134 | int fpga_state() | ||
135 | { | ||
136 | FILE *fptr; | ||
137 | char buf[10]; | ||
138 | char *state_operating = "operating"; | ||
139 | char *state_unknown = "unknown"; | ||
140 | |||
141 | system("cat /sys/class/fpga_manager/fpga0/state >> state.txt"); | ||
142 | fptr = fopen("state.txt", "r"); | ||
143 | if (fptr) { | ||
144 | fgets(buf, 10, fptr); | ||
145 | fclose(fptr); | ||
146 | system("rm state.txt"); | ||
147 | if ((strncmp(buf, state_operating, 9) == 0) || (strncmp(buf, state_unknown, 7) == 0)) | ||
148 | return 0; | ||
149 | else | ||
150 | return 1; | ||
151 | } | ||
152 | |||
153 | return 1; | ||
154 | } | ||
155 | |||
156 | static int fpga_overlay_check(char *cmd, char *state) | ||
157 | { | ||
158 | char buf[512]; | ||
159 | FILE *fptr; | ||
160 | int len; | ||
161 | |||
162 | system(cmd); | ||
163 | len = strlen(state) + 1; | ||
164 | fptr = fopen("state.txt", "r"); | ||
165 | if (fptr) { | ||
166 | fgets(buf, len, fptr); | ||
167 | fclose(fptr); | ||
168 | system("rm state.txt"); | ||
169 | if (!strcmp(buf, state)) | ||
170 | return 0; | ||
171 | else | ||
172 | return 1; | ||
173 | } | ||
174 | |||
175 | return 1; | ||
176 | } | ||
177 | |||
178 | struct fpgaflag { | ||
179 | char *flag; | ||
180 | unsigned int value; | ||
181 | }; | ||
182 | |||
183 | static struct fpgaflag flagdump[] = { | ||
184 | {.flag = "Full", .value = 0x0}, | ||
185 | {.flag = "Partial", .value = 0x1}, | ||
186 | {.flag = "AuthDDR", .value = 0x40}, | ||
187 | {.flag = "AuthOCM", .value = 0x80}, | ||
188 | {.flag = "EnUsrKey", .value = 0x20}, | ||
189 | {.flag = "EnDevKey", .value = 0x4}, | ||
190 | {.flag = "AuthEnUsrKeyDDR", .value = 0x60}, | ||
191 | {.flag = "AuthEnUsrKeyOCM", .value = 0xA0}, | ||
192 | {.flag = "AuthEnDevKeyDDR", .value = 0x44}, | ||
193 | {.flag = "AuthEnDevKeyOCM", .value = 0x84}, | ||
194 | {} | ||
195 | }; | ||
196 | |||
197 | static int cmd_flags(int argc, const char *name) | ||
198 | { | ||
199 | int valid_flag = 0; | ||
200 | int flag = 0; | ||
201 | struct fpgaflag *p = flagdump; | ||
202 | |||
203 | while (p->flag) { | ||
204 | if (!strcmp(name, p->flag)) { | ||
205 | flag = p->value; | ||
206 | break; | ||
207 | } | ||
208 | p++; | ||
209 | } | ||
210 | |||
211 | return flag; | ||
212 | } | ||
213 | |||
214 | static int isvalid_flags(int argc, const char *name, bool is_secure) | ||
215 | { | ||
216 | int valid_flag = 0; | ||
217 | int count = 0; | ||
218 | struct fpgaflag *p; | ||
219 | |||
220 | if (!is_secure) | ||
221 | p = flagdump; | ||
222 | else | ||
223 | p = &flagdump[2]; | ||
224 | |||
225 | while (p->flag) { | ||
226 | if (!strcmp(name, p->flag)) | ||
227 | return 0; | ||
228 | else if ((!is_secure) && (++count == 2)) | ||
229 | return 1; | ||
230 | p++; | ||
231 | } | ||
232 | |||
233 | return 1; | ||
234 | } | ||
235 | |||
236 | int main(int argc, char **argv) | ||
237 | { | ||
238 | int ret; | ||
239 | int iszynqmp = fpga_getplatform(); | ||
240 | char *binfile = NULL, *overlay = NULL, *AesKey = NULL, *flag = NULL, *partial_overlay = NULL; | ||
241 | char *region = NULL, *Module[100] = {0}; | ||
242 | int opt, flags = 0, flow = 0,rm_overlay = 0, readback_type = 0, sflags = 0; | ||
243 | char command[2048], folder[512], *token, *tmp, *tmp1, *tmp2 , *tmp3; | ||
244 | const char *filename = "readback", *name; | ||
245 | struct stat sb; | ||
246 | double time; | ||
247 | struct timeval t1, t0; | ||
248 | |||
249 | if (argc == 1) { | ||
250 | print_usage(basename(argv[0])); | ||
251 | return 1; | ||
252 | } | ||
253 | |||
254 | while ((opt = getopt(argc, argv, "o:b:n:f:s:p:k:rt::Rh?:")) != -1) { | ||
255 | switch (opt) { | ||
256 | case 'o': | ||
257 | overlay = optarg; | ||
258 | flow = OVERLAY; | ||
259 | break; | ||
260 | case 'b': | ||
261 | binfile = optarg; | ||
262 | if (!(flow == OVERLAY)) | ||
263 | flow = FPGA_SYSFS; | ||
264 | break; | ||
265 | case 'n': | ||
266 | region = optarg; | ||
267 | break; | ||
268 | case 'f': | ||
269 | if (flow == OVERLAY) { | ||
270 | name = argv[6]; | ||
271 | flags = cmd_flags(argc, name); | ||
272 | } else if (flow == FPGA_SYSFS) { | ||
273 | name = argv[4]; | ||
274 | flags = cmd_flags(argc, name); | ||
275 | } | ||
276 | |||
277 | ret = isvalid_flags(argc, name, false); | ||
278 | if (ret) { | ||
279 | printf("Error: Invalid arugments :%s\n", strerror(1)); | ||
280 | print_usage(basename(argv[0])); | ||
281 | return -EINVAL; | ||
282 | } | ||
283 | |||
284 | flags += sflags; | ||
285 | break; | ||
286 | case 's': | ||
287 | if (flow == OVERLAY) { | ||
288 | name = argv[8]; | ||
289 | sflags = cmd_flags(argc, name); | ||
290 | } else if (flow == FPGA_SYSFS) { | ||
291 | name = argv[6]; | ||
292 | sflags = cmd_flags(argc, name); | ||
293 | } | ||
294 | |||
295 | ret = isvalid_flags(argc, name, true); | ||
296 | if (ret) { | ||
297 | printf("Error: Invalid arugments :%s\n", strerror(1)); | ||
298 | print_usage(basename(argv[0])); | ||
299 | return -EINVAL; | ||
300 | } | ||
301 | |||
302 | flags += sflags; | ||
303 | break; | ||
304 | case 'p': | ||
305 | partial_overlay = optarg; | ||
306 | break; | ||
307 | case 'k': | ||
308 | AesKey = optarg; | ||
309 | break; | ||
310 | case 't': | ||
311 | if (optarg == NULL && argv[4] != NULL) | ||
312 | readback_type = atoi(argv[4]); | ||
313 | break; | ||
314 | case 'r': | ||
315 | if (optarg == NULL && argv[2] != NULL) | ||
316 | filename = argv[2]; | ||
317 | flow = READBACK; | ||
318 | break; | ||
319 | case 'R': | ||
320 | rm_overlay = 1; | ||
321 | break; | ||
322 | case '?': | ||
323 | case 'h': | ||
324 | default: | ||
325 | print_usage(basename(argv[0])); | ||
326 | return 1; | ||
327 | break; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | if(region != NULL) | ||
332 | snprintf(folder, sizeof(folder), "/configfs/device-tree/overlays/%s", region); | ||
333 | else if (!(flags & 1)) | ||
334 | snprintf(folder, sizeof(folder), "/configfs/device-tree/overlays/full"); | ||
335 | else if (overlay != NULL) { | ||
336 | printf("Error: Provide valid Overlay region info\n\r"); | ||
337 | return 1; | ||
338 | } | ||
339 | system("mkdir -p /lib/firmware"); | ||
340 | if (rm_overlay) { | ||
341 | if (((stat(folder, &sb) == 0) && S_ISDIR(sb.st_mode))) { | ||
342 | snprintf(command, sizeof(command), "rmdir %s", folder); | ||
343 | system(command); | ||
344 | } | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | if (flow == OVERLAY) { | ||
349 | if (((stat(folder, &sb) == 0) && S_ISDIR(sb.st_mode))) { | ||
350 | printf("Error: Overlay already exists in the live tree\n\r"); | ||
351 | return 1; | ||
352 | } | ||
353 | |||
354 | if (((stat("/configfs/device-tree/", &sb) == 0) && S_ISDIR(sb.st_mode))) { | ||
355 | } else { | ||
356 | system("mkdir /configfs"); | ||
357 | system("mount -t configfs configfs /configfs"); | ||
358 | } | ||
359 | |||
360 | if (binfile != NULL) { | ||
361 | snprintf(command, sizeof(command), "cp %s /lib/firmware", binfile); | ||
362 | system(command); | ||
363 | } | ||
364 | |||
365 | snprintf(command, sizeof(command), "cp %s /lib/firmware", overlay); | ||
366 | system(command); | ||
367 | tmp = strdup(overlay); | ||
368 | while((token = strsep(&tmp, "/"))) { | ||
369 | tmp1 = token; | ||
370 | } | ||
371 | |||
372 | if (binfile != NULL) { | ||
373 | snprintf(command, sizeof(command), "echo %x > /sys/class/fpga_manager/fpga0/flags", flags); | ||
374 | system(command); | ||
375 | if (ENCRYPTION_USERKEY_EN & flags) { | ||
376 | snprintf(command, sizeof(command), "echo %s > /sys/class/fpga_manager/fpga0/key", AesKey); | ||
377 | system(command); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | snprintf(command, sizeof(command), "mkdir %s", folder); | ||
382 | system(command); | ||
383 | snprintf(command, sizeof(command), "echo -n %s > %s/path", tmp1, folder); | ||
384 | gettimeofday(&t0, NULL); | ||
385 | system(command); | ||
386 | gettimeofday(&t1, NULL); | ||
387 | time = gettime(t0, t1); | ||
388 | |||
389 | snprintf(command, sizeof(command), "cat %s/path >> state.txt", folder); | ||
390 | ret = fpga_overlay_check(command, tmp1); | ||
391 | if (ret) { | ||
392 | printf("Failed to apply Overlay\n\r"); | ||
393 | } | ||
394 | |||
395 | /* Delete Bin file and DTBO file*/ | ||
396 | snprintf(command, sizeof(command), "rm /lib/firmware/%s", tmp1); | ||
397 | system(command); | ||
398 | if (binfile != NULL) { | ||
399 | tmp = strdup(binfile); | ||
400 | while((token = strsep(&tmp, "/"))) { | ||
401 | tmp1 = token; | ||
402 | } | ||
403 | snprintf(command, sizeof(command), "rm /lib/firmware/%s", tmp1); | ||
404 | system(command); | ||
405 | } | ||
406 | |||
407 | /* FPGA state check */ | ||
408 | if (binfile != NULL) { | ||
409 | if (!fpga_state()) { | ||
410 | printf("Time taken to load BIN is %f Milli Seconds\n\r", time); | ||
411 | printf("BIN FILE loaded through FPGA manager successfully\n\r"); | ||
412 | } else { | ||
413 | printf("BIN FILE loading through FPGA manager failed\n\r"); | ||
414 | } | ||
415 | } | ||
416 | } else if (flow == FPGA_SYSFS) { | ||
417 | if (argc < 3) { | ||
418 | printf("%s: For more information run %s -h\n", strerror(22), basename(argv[0])); | ||
419 | return 1; | ||
420 | } | ||
421 | snprintf(command, sizeof(command), "cp %s /lib/firmware", binfile); | ||
422 | system(command); | ||
423 | snprintf(command, sizeof(command), "echo %x > /sys/class/fpga_manager/fpga0/flags", flags); | ||
424 | system(command); | ||
425 | if (ENCRYPTION_USERKEY_EN & flags) { | ||
426 | snprintf(command, sizeof(command), "echo %s > /sys/class/fpga_manager/fpga0/key", AesKey); | ||
427 | system(command); | ||
428 | } | ||
429 | tmp = strdup(binfile); | ||
430 | while((token = strsep(&tmp, "/"))) { | ||
431 | tmp1 = token; | ||
432 | } | ||
433 | snprintf(command, sizeof(command), "echo %s > /sys/class/fpga_manager/fpga0/firmware", tmp1); | ||
434 | gettimeofday(&t0, NULL); | ||
435 | system(command); | ||
436 | gettimeofday(&t1, NULL); | ||
437 | time = gettime(t0, t1); | ||
438 | |||
439 | /* Delete Bin file and DTBO file*/ | ||
440 | snprintf(command, sizeof(command), "rm /lib/firmware/%s", tmp1); | ||
441 | system(command); | ||
442 | |||
443 | /* FPGA state check */ | ||
444 | if (!fpga_state()) { | ||
445 | printf("Time taken to load BIN is %f Milli Seconds\n\r", time); | ||
446 | printf("BIN FILE loaded through FPGA manager successfully\n\r"); | ||
447 | } else { | ||
448 | printf("BIN FILE loading through FPGA manager failed\n\r"); | ||
449 | } | ||
450 | } else if (flow == READBACK) { | ||
451 | if (readback_type > 1) { | ||
452 | printf("Invalid arugments :%s\n", strerror(1)); | ||
453 | printf("For more information run %s -h\n", basename(argv[0])); | ||
454 | return -EINVAL; | ||
455 | } | ||
456 | snprintf(command, sizeof(command), "echo %x > /sys/module/zynqmp_fpga/parameters/readback_type", readback_type); | ||
457 | system(command); | ||
458 | snprintf(command, sizeof(command), "cat /sys/kernel/debug/fpga/fpga0/image >> %s.bin", filename); | ||
459 | system(command); | ||
460 | printf("Readback contents are stored in the file %s.bin\n\r", filename); | ||
461 | } | ||
462 | |||
463 | return 0; | ||
464 | } | ||