aboutsummaryrefslogtreecommitdiffstats
path: root/meta-xilinx-core/recipes-bsp/fpga-manager-script/files/fpgautil.c
diff options
context:
space:
mode:
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.c471
1 files changed, 471 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..04777a91
--- /dev/null
+++ b/meta-xilinx-core/recipes-bsp/fpga-manager-script/files/fpgautil.c
@@ -0,0 +1,471 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2019-2022 Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ ******************************************************************************/
+/*****************************************************************************/
+/**
+ * @file: fpgautil.c
+ * Simple command line tool to load fpga via overlay or through sysfs interface
+ * and read fpga configuration using Xilinx Zynq/ZynqMP fpga manager
+ * Author: Appana Durga Kedareswara Rao <appanad@xilinx.com>
+ * Author: Nava kishore Manne <navam@xilinx.com>
+ */
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <getopt.h>
+#include <poll.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#define OVERLAY 1
+#define FPGA_SYSFS 2
+#define READBACK 3
+#define ENCRYPTION_USERKEY_EN (0x20U)
+
+int fpga_getplatform()
+{
+ char fpstr[100];
+ FILE *fptr;
+ char *zynqmpstr = "Xilinx ZynqMP FPGA Manager";
+
+ if ((fptr = fopen("/sys/class/fpga_manager/fpga0/name", "r")) == NULL)
+ {
+ printf("Error! opening file");
+ // Program exits if file pointer returns NULL.
+ exit(1);
+ }
+
+ // reads text until newline
+ fscanf(fptr,"%[^\n]", fpstr);
+ fclose(fptr);
+
+ if (!strcmp(zynqmpstr, fpstr))
+ return 1;
+ else
+ return 0;
+
+}
+
+void print_usage(char *prg)
+{
+ int iszynqmp = fpga_getplatform();
+
+ fprintf(stderr, "\n%s: FPGA Utility for Loading/reading PL Configuration\n\n", prg);
+ fprintf(stderr, "Usage: %s -b <bin file path> -o <dtbo file path>\n\r", prg);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Options: -b <binfile> (Bin file path)\n");
+ fprintf(stderr, " -o <dtbofile> (DTBO file path)\n");
+ fprintf(stderr, " -f <flags> Optional: <Bitstream type flags>\n");
+ fprintf(stderr, " f := <Full | Partial > \n");
+ fprintf(stderr, " -n <Fpga region info> FPGA Regions represent FPGA's\n");
+ fprintf(stderr, " and partial reconfiguration\n");
+ fprintf(stderr, " regions of FPGA's in the\n");
+ fprintf(stderr, " Device Tree\n");
+ if (iszynqmp)
+ {
+ fprintf(stderr, " Default: <full>\n");
+ fprintf(stderr, " -s <secure flags> Optional: <Secure flags>\n");
+ fprintf(stderr, " s := <AuthDDR | AuthOCM | EnUsrKey | EnDevKey | AuthEnUsrKeyDDR | AuthEnUsrKeyOCM | AuthEnDevKeyDDR | AuthEnDevKeyOCM>\n");
+ fprintf(stderr, " -k <AesKey> Optional: <AES User Key>\n");
+ fprintf(stderr, " -r <Readback> Optional: <file name>\n");
+ fprintf(stderr, " Default: By default Read back contents will be stored in readback.bin file\n");
+ fprintf(stderr, " -t Optional: <Readback Type>\n");
+ fprintf(stderr, " 0 - Configuration Register readback\n");
+ fprintf(stderr, " 1 - Configuration Data Frames readback\n");
+ fprintf(stderr, " Default: 0 (Configuration register readback)\n");
+ fprintf(stderr, " -R Optional: Remove overlay from a live tree\n");
+ }
+
+ fprintf(stderr, " \n");
+ fprintf(stderr, "Examples:\n");
+ fprintf(stderr, "(Load Full bitstream using Overlay)\n");
+ fprintf(stderr, "%s -b top.bit.bin -o can.dtbo -f Full -n full \n", prg);
+ fprintf(stderr, "(Load Partial bitstream using Overlay)\n");
+ fprintf(stderr, "%s -b rm0.bit.bin -o rm0.dtbo -f Partial -n PR0\n", prg);
+ fprintf(stderr, "(Load Full bitstream using sysfs interface)\n");
+ fprintf(stderr, "%s -b top.bit.bin -f Full\n", prg);
+ fprintf(stderr, "(Load Partial bitstream using sysfs interface)\n");
+ fprintf(stderr, "%s -b rm0.bit.bin -f Partial\n", prg);
+ if (iszynqmp)
+ {
+ fprintf(stderr, "(Load Authenticated bitstream through the sysfs interface)\n");
+ fprintf(stderr, "%s -b top.bit.bin -f Full -s AuthDDR \n", prg);
+ fprintf(stderr, "(Load Parital Encrypted Userkey bitstream using Overlay)\n");
+ fprintf(stderr, "%s -b top.bit.bin -o pl.dtbo -f Partial -s EnUsrKey -k <32byte key value>\n", prg);
+ fprintf(stderr, "(Read PL Configuration Registers)\n");
+ fprintf(stderr, "%s -b top.bit.bin -r\n", prg);
+ }
+
+ fprintf(stderr, "(Remove Partial Overlay)\n");
+ fprintf(stderr, "%s -R -n PR0\n", prg);
+ fprintf(stderr, "(Remove Full Overlay)\n");
+ fprintf(stderr, "%s -R -n full\n", prg);
+ fprintf(stderr, "Note: %s -R is responsible for only removing the dtbo file from the livetree. it will not remove the PL logic from the FPGA region.\n", prg);
+ fprintf(stderr, " \n");
+}
+
+int gettime(struct timeval t0, struct timeval t1)
+{
+ return ((t1.tv_sec - t0.tv_sec) * 1000.0f + (t1.tv_usec -t0.tv_usec) / 1000.0f);
+}
+
+int fpga_state()
+{
+ FILE *fptr;
+ char buf[10];
+ char *state_operating = "operating";
+ char *state_unknown = "unknown";
+
+ system("cat /sys/class/fpga_manager/fpga0/state >> state.txt");
+ fptr = fopen("state.txt", "r");
+ if (fptr) {
+ fgets(buf, 10, fptr);
+ fclose(fptr);
+ system("rm state.txt");
+ if ((strncmp(buf, state_operating, 9) == 0) || (strncmp(buf, state_unknown, 7) == 0))
+ return 0;
+ else
+ return 1;
+ }
+
+ return 1;
+}
+
+static int fpga_overlay_check(char *cmd, char *state)
+{
+ char buf[512];
+ FILE *fptr;
+ int len;
+
+ system(cmd);
+ len = strlen(state) + 1;
+ fptr = fopen("state.txt", "r");
+ if (fptr) {
+ fgets(buf, len, fptr);
+ fclose(fptr);
+ system("rm state.txt");
+ if (!strcmp(buf, state))
+ return 0;
+ else
+ return 1;
+ }
+
+ return 1;
+}
+
+struct fpgaflag {
+ char *flag;
+ unsigned int value;
+};
+
+static struct fpgaflag flagdump[] = {
+ {.flag = "Full", .value = 0x0},
+ {.flag = "Partial", .value = 0x1},
+ {.flag = "AuthDDR", .value = 0x40},
+ {.flag = "AuthOCM", .value = 0x80},
+ {.flag = "EnUsrKey", .value = 0x20},
+ {.flag = "EnDevKey", .value = 0x4},
+ {.flag = "AuthEnUsrKeyDDR", .value = 0x60},
+ {.flag = "AuthEnUsrKeyOCM", .value = 0xA0},
+ {.flag = "AuthEnDevKeyDDR", .value = 0x44},
+ {.flag = "AuthEnDevKeyOCM", .value = 0x84},
+ {}
+};
+
+static int cmd_flags(int argc, const char *name)
+{
+ int valid_flag = 0;
+ int flag = 0;
+ struct fpgaflag *p = flagdump;
+
+ while (p->flag) {
+ if (!strcmp(name, p->flag)) {
+ flag = p->value;
+ break;
+ }
+ p++;
+ }
+
+ return flag;
+}
+
+static int isvalid_flags(int argc, const char *name, bool is_secure)
+{
+ int valid_flag = 0;
+ int count = 0;
+ struct fpgaflag *p;
+
+ if (!is_secure)
+ p = flagdump;
+ else
+ p = &flagdump[2];
+
+ while (p->flag) {
+ if (!strcmp(name, p->flag))
+ return 0;
+ else if ((!is_secure) && (++count == 2))
+ return 1;
+ p++;
+ }
+
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ int iszynqmp = fpga_getplatform();
+ char *binfile = NULL, *overlay = NULL, *AesKey = NULL, *flag = NULL, *partial_overlay = NULL;
+ char *region = NULL, *Module[100] = {0};
+ int opt, flags = 0, flow = 0,rm_overlay = 0, readback_type = 0, sflags = 0;
+ char command[2048], folder[512], *token, *tmp, *tmp1, *tmp2 , *tmp3;
+ const char *filename = "readback", *name;
+ struct stat sb;
+ double time;
+ struct timeval t1, t0;
+
+ if (argc == 1) {
+ print_usage(basename(argv[0]));
+ return 1;
+ }
+
+ while ((opt = getopt(argc, argv, "o:b:n:f:s:p:k:rt::Rh?:")) != -1) {
+ switch (opt) {
+ case 'o':
+ overlay = optarg;
+ flow = OVERLAY;
+ break;
+ case 'b':
+ binfile = optarg;
+ if (!(flow == OVERLAY))
+ flow = FPGA_SYSFS;
+ break;
+ case 'n':
+ region = optarg;
+ break;
+ case 'f':
+ if (flow == OVERLAY) {
+ name = argv[6];
+ flags = cmd_flags(argc, name);
+ } else if (flow == FPGA_SYSFS) {
+ name = argv[4];
+ flags = cmd_flags(argc, name);
+ }
+
+ ret = isvalid_flags(argc, name, false);
+ if (ret) {
+ printf("Error: Invalid arugments :%s\n", strerror(1));
+ print_usage(basename(argv[0]));
+ return -EINVAL;
+ }
+
+ flags += sflags;
+ break;
+ case 's':
+ if (flow == OVERLAY) {
+ name = argv[8];
+ sflags = cmd_flags(argc, name);
+ } else if (flow == FPGA_SYSFS) {
+ name = argv[6];
+ sflags = cmd_flags(argc, name);
+ }
+
+ ret = isvalid_flags(argc, name, true);
+ if (ret) {
+ printf("Error: Invalid arugments :%s\n", strerror(1));
+ print_usage(basename(argv[0]));
+ return -EINVAL;
+ }
+
+ flags += sflags;
+ break;
+ case 'p':
+ partial_overlay = optarg;
+ break;
+ case 'k':
+ AesKey = optarg;
+ break;
+ case 't':
+ if (optarg == NULL && argv[4] != NULL)
+ readback_type = atoi(argv[4]);
+ break;
+ case 'r':
+ if (optarg == NULL && argv[2] != NULL)
+ filename = argv[2];
+ flow = READBACK;
+ break;
+ case 'R':
+ rm_overlay = 1;
+ break;
+ case '?':
+ case 'h':
+ default:
+ print_usage(basename(argv[0]));
+ return 1;
+ break;
+ }
+ }
+
+ if(region != NULL)
+ snprintf(folder, sizeof(folder), "/configfs/device-tree/overlays/%s", region);
+ else if (!(flags & 1))
+ snprintf(folder, sizeof(folder), "/configfs/device-tree/overlays/full");
+ else if (overlay != NULL) {
+ printf("Error: Provide valid Overlay region info\n\r");
+ return 1;
+ }
+ system("mkdir -p /lib/firmware");
+ if (rm_overlay) {
+ if (((stat(folder, &sb) == 0) && S_ISDIR(sb.st_mode))) {
+ snprintf(command, sizeof(command), "rmdir %s", folder);
+ system(command);
+ }
+ return 0;
+ }
+
+ if (flow == OVERLAY) {
+ if (((stat(folder, &sb) == 0) && S_ISDIR(sb.st_mode))) {
+ printf("Error: Overlay already exists in the live tree\n\r");
+ return 1;
+ }
+
+ if (((stat("/configfs/device-tree/", &sb) == 0) && S_ISDIR(sb.st_mode))) {
+ } else {
+ system("mkdir /configfs");
+ system("mount -t configfs configfs /configfs");
+ }
+
+ if (binfile != NULL) {
+ snprintf(command, sizeof(command), "cp %s /lib/firmware", binfile);
+ system(command);
+ }
+
+ snprintf(command, sizeof(command), "cp %s /lib/firmware", overlay);
+ system(command);
+ tmp = strdup(overlay);
+ while((token = strsep(&tmp, "/"))) {
+ tmp1 = token;
+ }
+
+ if (binfile != NULL) {
+ snprintf(command, sizeof(command), "echo %x > /sys/class/fpga_manager/fpga0/flags", flags);
+ system(command);
+ if (ENCRYPTION_USERKEY_EN & flags) {
+ snprintf(command, sizeof(command), "echo %s > /sys/class/fpga_manager/fpga0/key", AesKey);
+ system(command);
+ }
+ }
+
+ snprintf(command, sizeof(command), "mkdir %s", folder);
+ system(command);
+ snprintf(command, sizeof(command), "echo -n %s > %s/path", tmp1, folder);
+ gettimeofday(&t0, NULL);
+ system(command);
+ gettimeofday(&t1, NULL);
+ time = gettime(t0, t1);
+
+ snprintf(command, sizeof(command), "cat %s/path >> state.txt", folder);
+ ret = fpga_overlay_check(command, tmp1);
+ if (ret) {
+ printf("Failed to apply Overlay\n\r");
+ }
+
+ /* Delete Bin file and DTBO file*/
+ snprintf(command, sizeof(command), "rm /lib/firmware/%s", tmp1);
+ system(command);
+ if (binfile != NULL) {
+ tmp = strdup(binfile);
+ while((token = strsep(&tmp, "/"))) {
+ tmp1 = token;
+ }
+ snprintf(command, sizeof(command), "rm /lib/firmware/%s", tmp1);
+ system(command);
+ }
+
+ /* FPGA state check */
+ if (binfile != NULL) {
+ if (!fpga_state()) {
+ printf("Time taken to load BIN is %f Milli Seconds\n\r", time);
+ printf("BIN FILE loaded through FPGA manager successfully\n\r");
+ } else {
+ printf("BIN FILE loading through FPGA manager failed\n\r");
+ }
+ }
+ } else if (flow == FPGA_SYSFS) {
+ if (argc < 3) {
+ printf("%s: For more information run %s -h\n", strerror(22), basename(argv[0]));
+ return 1;
+ }
+ snprintf(command, sizeof(command), "cp %s /lib/firmware", binfile);
+ system(command);
+ snprintf(command, sizeof(command), "echo %x > /sys/class/fpga_manager/fpga0/flags", flags);
+ system(command);
+ if (ENCRYPTION_USERKEY_EN & flags) {
+ snprintf(command, sizeof(command), "echo %s > /sys/class/fpga_manager/fpga0/key", AesKey);
+ system(command);
+ }
+ tmp = strdup(binfile);
+ while((token = strsep(&tmp, "/"))) {
+ tmp1 = token;
+ }
+ snprintf(command, sizeof(command), "echo %s > /sys/class/fpga_manager/fpga0/firmware", tmp1);
+ gettimeofday(&t0, NULL);
+ system(command);
+ gettimeofday(&t1, NULL);
+ time = gettime(t0, t1);
+
+ /* Delete Bin file and DTBO file*/
+ snprintf(command, sizeof(command), "rm /lib/firmware/%s", tmp1);
+ system(command);
+
+ /* FPGA state check */
+ if (!fpga_state()) {
+ printf("Time taken to load BIN is %f Milli Seconds\n\r", time);
+ printf("BIN FILE loaded through FPGA manager successfully\n\r");
+ } else {
+ printf("BIN FILE loading through FPGA manager failed\n\r");
+ }
+ } else if (flow == READBACK) {
+ if (readback_type > 1) {
+ printf("Invalid arugments :%s\n", strerror(1));
+ printf("For more information run %s -h\n", basename(argv[0]));
+ return -EINVAL;
+ }
+ snprintf(command, sizeof(command), "echo %x > /sys/module/zynqmp_fpga/parameters/readback_type", readback_type);
+ system(command);
+ snprintf(command, sizeof(command), "cat /sys/kernel/debug/fpga/fpga0/image >> %s.bin", filename);
+ system(command);
+ printf("Readback contents are stored in the file %s.bin\n\r", filename);
+ }
+
+ return 0;
+}