From c1e24a46e7ad63ce572b581713b48a884bf26409 Mon Sep 17 00:00:00 2001 From: Artie Poole Date: Wed, 12 Nov 2025 10:26:42 +0000 Subject: [PATCH 1/4] libdfx: configfs no longer being remounted, use already existing location Use `/sys/kernel/config/device-tree/overlays/` insted of remounting Signed-off-by: Artie Poole --- src/libdfx.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libdfx.c b/src/libdfx.c index 8e4cf56..4e1b562 100644 --- a/src/libdfx.c +++ b/src/libdfx.c @@ -333,7 +333,7 @@ int dfx_cfg_load(int package_id) } snprintf(command, sizeof(command), - "/configfs/device-tree/overlays/%s_image_%d", + "/sys/kernel/config/device-tree/overlays/%s_image_%lu", package_node->package_name, package_node->package_id); len = strlen(command) + 1; @@ -435,7 +435,7 @@ int dfx_cfg_drivers_load(int package_id) } snprintf(command, sizeof(command), - "/configfs/device-tree/overlays/%s_driver_%d", + "/sys/kernel/config/device-tree/overlays/%s_driver_%lu", package_node->package_name, package_node->package_id); len = strlen(command) + 1; str = (char *) calloc((len), sizeof(char)); @@ -900,12 +900,11 @@ static struct dfx_package_node *create_package() else system("mkdir -p /lib/firmware"); - FD = opendir("/configfs/device-tree/overlays/"); + FD = opendir("/sys/kernel/config/device-tree/overlays/"); if (FD) closedir(FD); else { - system("mkdir -p /configfs"); - system("mount -t configfs configfs /configfs"); + return 0; } temp_node = first_node; From cdfc68e05f98a68856a47254d27dd223692fe8bc Mon Sep 17 00:00:00 2001 From: Artie Poole Date: Wed, 12 Nov 2025 17:35:56 +0000 Subject: [PATCH 2/4] libdfx.c/.h: stops copying files into /lib/firmware the kernel provides a mechanism to set where firmware loads will look to match filenames during probe events. This file is located at `/sys/module/firmware_class/parameters/path`. These changes remove the need for copying firmware files into /lib/firmware. The /lib/firmware location is still probed if the file is not found in the custom location. See https://docs.kernel.org/driver-api/firmware/fw_search_path.html for more information. Signed-off-by: Artie Poole --- src/include/libdfx.h | 1 + src/libdfx.c | 120 +++++++++++++++++++++++++++++-------------- 2 files changed, 82 insertions(+), 39 deletions(-) diff --git a/src/include/libdfx.h b/src/include/libdfx.h index 0eb7238..e7b5f90 100644 --- a/src/include/libdfx.h +++ b/src/include/libdfx.h @@ -84,4 +84,5 @@ int dfx_get_meta_header(char *binfile, int *buffer, int buf_size); int dfx_cfg_init_file(const char *dfx_bin_file, const char *dfx_dtbo_file, const char *dfx_driver_dtbo_file, const char *dfx_aes_key_file, const char *devpath, unsigned long flags, ...); +int dfx_set_firmware_search_path(const char* file_path); #endif diff --git a/src/libdfx.c b/src/libdfx.c index 4e1b562..7eb4758 100644 --- a/src/libdfx.c +++ b/src/libdfx.c @@ -130,7 +130,6 @@ static int read_package_byname(struct dfx_package_node *package_node, const char *dfx_driver_dtbo_file, const char *dfx_aes_key_file); static char *get_file_name_from_path(char *full_path); -static void copy_file_to_firmware(const char *file); static int validate_input_files(const char *dfx_bin_file, const char *dfx_dtbo_file, const char *dfx_driver_dtbo_file, const char *dfx_aes_key_file, unsigned long flags); @@ -336,6 +335,8 @@ int dfx_cfg_load(int package_id) "/sys/kernel/config/device-tree/overlays/%s_image_%lu", package_node->package_name, package_node->package_id); + dfx_set_firmware_search_path(package_node->load_image_path); + len = strlen(command) + 1; str = (char *) calloc((len), sizeof(char)); strncpy(str, command, len); @@ -370,6 +371,7 @@ int dfx_cfg_load(int package_id) zynqmp_print_err_msg(err); system(command); ret = -DFX_IMAGE_CONFIG_ERROR; + dfx_set_firmware_search_path(""); goto END; } } @@ -382,8 +384,8 @@ int dfx_cfg_load(int package_id) package_node->load_image_overlay_pck_path); system(command); printf("%s: Image configuration failed\n", __func__); + dfx_set_firmware_search_path(""); ret = -DFX_IMAGE_CONFIG_ERROR; - goto END; } END: @@ -434,6 +436,10 @@ int dfx_cfg_drivers_load(int package_id) goto END; } + // This may not be neccessary - this approach should use the dma buffer + // TODO(artiepoole): check this is necessary + dfx_set_firmware_search_path(package_node->load_drivers_dtbo_path); + snprintf(command, sizeof(command), "/sys/kernel/config/device-tree/overlays/%s_driver_%lu", package_node->package_name, package_node->package_id); @@ -457,6 +463,7 @@ int dfx_cfg_drivers_load(int package_id) package_node->load_drivers_overlay_pck_path); system(command); printf("%s: Drivers DTBO config failed\n", __func__); + dfx_set_firmware_search_path(""); ret = -DFX_DRIVER_CONFIG_ERROR; } @@ -561,12 +568,6 @@ int dfx_cfg_destroy(int package_id) goto END; } - if (package_node->load_image_overlay_pck_path != NULL) { - snprintf(command, sizeof(command), "rm /lib/firmware/%s", - package_node->load_image_dtbo_name); - system(command); - } - if (!(package_node->flags & DFX_EXTERNAL_CONFIG_EN)) { /* This call will do the following things * unmap the buffer properly @@ -671,14 +672,7 @@ int dfx_get_meta_header(char *binfile, int *buffer, int buf_size) } fclose(fd); - FD = opendir("/lib/firmware"); - if (FD) - closedir(FD); - else - system("mkdir -p /lib/firmware"); - - snprintf(command, sizeof(command), "cp %s /lib/firmware", binfile); - system(command); + dfx_set_firmware_search_path(binfile); tmp = strdup(binfile); while((token = strsep(&tmp, "/"))) tmp1 = token; @@ -715,6 +709,7 @@ int dfx_get_meta_header(char *binfile, int *buffer, int buf_size) time = gettime(t0, t1); printf("%s API Time taken: %f Milli Seconds\n\r", __func__, time); #endif + dfx_set_firmware_search_path(""); return ret; } @@ -871,16 +866,6 @@ static int read_package_folder(struct dfx_package_node *package_node) str = (char *) calloc((len), sizeof(char)); strncpy(str, command, len); package_node->package_name = str; - snprintf(command, sizeof(command), "cp %s /lib/firmware/", - package_node->load_image_dtbo_path); - system(command); - - if (package_node->load_drivers_dtbo_path != NULL) { - snprintf(command, sizeof(command), - "cp %s /lib/firmware/", - package_node->load_drivers_dtbo_path); - system(command); - } } else { printf("%s: Invalid package\n", __func__); return -DFX_READ_PACKAGE_ERROR; @@ -894,12 +879,6 @@ static struct dfx_package_node *create_package() FPGA_NODE *package_node; DIR *FD; - FD = opendir("/lib/firmware"); - if (FD) - closedir(FD); - else - system("mkdir -p /lib/firmware"); - FD = opendir("/sys/kernel/config/device-tree/overlays/"); if (FD) closedir(FD); @@ -1338,7 +1317,7 @@ static int read_package_byname(struct dfx_package_node *package_node, package_node->load_image_path = strdup(dfx_bin_file); str = strdup(get_file_name_from_path(package_node->load_image_path)); package_node->load_image_name = str; - copy_file_to_firmware(dfx_bin_file); + dfx_set_firmware_search_path(dfx_bin_file); } else { return -DFX_READ_PACKAGE_ERROR; } @@ -1351,7 +1330,7 @@ static int read_package_byname(struct dfx_package_node *package_node, str = strndup(package_node->load_image_dtbo_name, slen); str[slen - 1] = '\0'; package_node->package_name = str; - copy_file_to_firmware(dfx_dtbo_file); + dfx_set_firmware_search_path(dfx_dtbo_file); } else { return -DFX_READ_PACKAGE_ERROR; } @@ -1360,7 +1339,7 @@ static int read_package_byname(struct dfx_package_node *package_node, package_node->load_drivers_dtbo_path = strdup(dfx_driver_dtbo_file); str = strdup(get_file_name_from_path(package_node->load_drivers_dtbo_path)); package_node->load_drivers_dtbo_name = str; - copy_file_to_firmware(dfx_driver_dtbo_file); + dfx_set_firmware_search_path(dfx_driver_dtbo_file); } else { package_node->load_drivers_dtbo_path = NULL; package_node->load_drivers_dtbo_name = NULL; @@ -1394,12 +1373,75 @@ static char *get_file_name_from_path(char *full_path) return path; } -static void copy_file_to_firmware(const char *file) +/** + * Extract the parent dir of the target path, and write that location to + * /sys/module/firmware_class/parameters/path so that the kernel can discover + * the firmware within + * + * @param file_path the full path to the file to be loaded + * + * Return: 0 on success + * -1 on failure + */ +int dfx_set_firmware_search_path(const char *file_path) { - char command[MAX_CMD_LEN]; + char path_copy[512]; + char *parent_dir; + int fd = -1; + int rc = -1; + const char *lookup_control = + "/sys/module/firmware_class/parameters/path"; + + if (!file_path) { + printf("%s: ERROR: path provided is NULL\n", __func__); + goto END; + } - snprintf(command, sizeof(command), "cp %s /lib/firmware/", file); - system(command); + if (strlen(file_path) >= sizeof(path_copy)) { + printf("%s: WARN: path provided is too long, truncating\n", __func__); + } + + strlcpy(path_copy, file_path, sizeof(path_copy)); + if (file_path[0]) { + printf("%s: Setting lookup path for `%s`\n", __func__, file_path); + } + + // derive parent directory + parent_dir = dirname(path_copy); + if (!strcmp(".", parent_dir)) { + parent_dir = ""; + } + + fd = open(lookup_control, O_WRONLY); + if (fd < 0) { + printf("%s: ERROR: failed to open firmware path parameter\n", __func__); + goto END; + } + + printf("%s: writing `%s` to %s\n", __func__, parent_dir, lookup_control); + if (write(fd, parent_dir, strlen(parent_dir)) < 0) { + printf("%s: ERROR: failed to write firmware lookup path\n", __func__); + goto END; + } + + rc = 0; + + END: + // always close if opened, not just on fail + if (fd >= 0) { + close(fd); + } + + if (rc <= 0) { + printf("%s: WARN: Failed to set firmware search path. " + "Success only possible if the requested files live in " + "defaults.\nSee " + "https://docs.kernel.org/driver-api/firmware/" + "fw_search_path.html for more information\n", + __func__); + } + + return rc; } static bool file_exists(const char *filename) From 361b434cc8594a91bdf3b9f9b6dbc57d9b61e441 Mon Sep 17 00:00:00 2001 From: Artie Poole Date: Wed, 10 Dec 2025 08:52:00 +0000 Subject: [PATCH 3/4] libdfx.c/.h: remove dependence on state.txt this made it preferable to implement several helper functions which are convenient to export for use in dfx-mgr. define debugging macros Signed-off-by: Artie Poole --- src/include/libdfx.h | 7 + src/libdfx.c | 518 ++++++++++++++++++++++++++++++++----------- 2 files changed, 395 insertions(+), 130 deletions(-) diff --git a/src/include/libdfx.h b/src/include/libdfx.h index e7b5f90..77e486a 100644 --- a/src/include/libdfx.h +++ b/src/include/libdfx.h @@ -85,4 +85,11 @@ int dfx_cfg_init_file(const char *dfx_bin_file, const char *dfx_dtbo_file, const char *dfx_driver_dtbo_file, const char *dfx_aes_key_file, const char *devpath, unsigned long flags, ...); int dfx_set_firmware_search_path(const char* file_path); +int dfx_get_fpga_state(char* buffer, size_t buf_size); +int dfx_set_overlay_path(const char *overlay_dir, const char *requested_path); +int dfx_set_fpga_firmware(const char *requested_binary_name); +int dfx_set_fpga_flags(int flags); +int dfx_set_fpga_key(const char * key); +int dfx_get_overlay_path(const char *overlay_dir, char *buffer, size_t buf_size); +int dfx_get_overlay_status(const char *overlay_dir, char *buffer, size_t buf_size); #endif diff --git a/src/libdfx.c b/src/libdfx.c index 7eb4758..1304762 100644 --- a/src/libdfx.c +++ b/src/libdfx.c @@ -46,6 +46,11 @@ #define ZYNQMP_MAX_ERR 27U +#ifndef DTBO_ROOT_DIR +#define DTBO_ROOT_DIR "/sys/kernel/config/device-tree/overlays" +#endif + + struct dfx_package_node { int flags; int xilplatform; @@ -111,14 +116,13 @@ static struct dfx_package_node *create_package(void); static struct dfx_package_node *get_package(int package_id); static int destroy_package(int package_id); static int read_package_folder(struct dfx_package_node *package_node); -static int dfx_state(char *cmd, char *state); static int dfx_package_load_dmabuf(struct dfx_package_node *package_node, const char *cma_file); static int dfx_getplatform(void); static int find_key(struct dfx_package_node *package_node); static int lengthOfLastWord2(const char *input); static void strlwr(char *destination, const char *source); -static int dfx_get_error(char *cmd); +static int dfx_get_error(const char *state_buf); static void zynqmp_print_err_msg(int err); static int dfx_cfg_init_common(const char *dfx_package_path, const char *cma_file, const char *dfx_bin_file, const char *dfx_dtbo_file, @@ -138,6 +142,309 @@ static bool file_exists(const char *filename); static inline double gettime(struct timeval t0, struct timeval t1); #endif +static void strip_trailing(char *haystack, char needle); +static int read_single_line(const char *path, char *buffer, size_t buf_size); +static int write_string_to_file(const char *path, const char *src); +static void remove_overlay_dir(const char *dir); + +/** + * strip_trailing() - Remove one trailing character from a string + * @haystack: The null-terminated string to modify (in-place). + * @needle: The character to remove from the end of the string. + * + * Strips trailing needle from haystack - e.g. `\n` from file read + * results or `/` from paths before concatenating. + */ +static void strip_trailing(char *haystack, const char needle) +{ + if (!haystack) + return; + + const size_t len = strlen(haystack); + if (len == 0) + return; + + if (haystack[len - 1] == needle) { + haystack[len - 1] = '\0'; + } +} + +/** + * read_single_line() - Read a single line from a file into a buffer. + * + * @path: path of the file to read from + * @buffer: buffer to write the data into + * @buf_size: length of the provided `buffer` in bytes + * + * Reads exactly one line (up to newline or EOF) from @path. + * Trailing newline is removed if present. + * + * Return: 0 on success + * -1 on failure + */ +static int read_single_line(const char *path, + char *buffer, + const size_t buf_size) +{ + FILE *f = fopen(path, "r"); + if (!f) { + printf("%s: Failed to open `%s` for reading\n", __func__, path); + return -1; + } + + if (!fgets(buffer, (int) buf_size, f)) { + printf("%s: Failed to read from `%s`\n", __func__, path); + fclose(f); + return -1; + } + + if (fclose(f) != 0) { + printf("%s: Failed to close `%s`\n", __func__, path); + return -1; + } + + strip_trailing(buffer, '\n'); + return 0; +} + +/** + * write_string_to_file() - Write a string to a file safely + * @path: Path to the file to write + * @src: Null-terminated buffer containing the string to write + * + * This function opens @path for writing, writes the contents of @data, + * and closes the file. All steps are checked for errors. On failure, + * a detailed error message including errno is logged. + * + * Return: 0 on success + * -1 on failure + */ +static int write_string_to_file(const char *path, const char *src) +{ + FILE *f = fopen(path, "w"); + if (!f) { + printf("%s: Failed to open `%s` for writing\n", __func__, path); + return -1; + } + + if (fputs(src, f) == EOF) { + printf("%s: Failed to write to `%s`\n", __func__, path); + fclose(f); // attempt to close anyway + return -1; + } + + if (fclose(f) != 0) { + printf("%s: Failed to close `%s` after writing\n", __func__, path); + return -1; + } + + printf("%s: `%s` written to `%s`\n", __func__, src, path); + return 0; +} + +/** + * remove_overlay_dir() - remove device tree overlay from configfs interface. + * + * @dir: the overlay directory to be removed + * + * This function attempts to remove the directory provided, with additional + * logging. + * + */ +static void remove_overlay_dir(const char *dir) +{ + if (rmdir(dir) != 0) { + printf("%s: Failed to remove directory `%s`\n", __func__, dir); + } else { + printf("%s: Directory `%s` removed\n", __func__, dir); + } +} + +/** + * dfx_get_fpga_state() - read the fpga state into `buffer` + * + * @buffer: buffer to write the state into + * @buf_size: length of the provided `buffer` in bytes + * + * This static function checks the operational state of the FPGA by reading + * the state from the sysfs interface. + * + * Return: number of bytes read on success + * -1 on failure + */ +int dfx_get_fpga_state(char *buffer, const size_t buf_size) +{ + const char *state_file_path = "/sys/class/fpga_manager/fpga0/state"; + return read_single_line(state_file_path, buffer, sizeof(char) * buf_size); +} + +/** + * dfx_set_overlay_path(...) - write a requested overlay path to configfs + * + * @overlay_dir: Path to the overlay directory in configfs. + * @requested_path: The overlay path to write to the `path` attribute. + * + * This function writes the specified overlay path to the overlay's `path` + * attribute in configfs. It attempts to write `requested_path` into the + * `/path` file. + * + * Return: 0 on success, + * -1 on error (e.g., failed to open, write, or close the file) + */ +int dfx_set_overlay_path(const char *overlay_dir, const char *requested_path) +{ + char full_path[256]; + if (sizeof(full_path) < strlen(overlay_dir) + 6) { // '/' + '\0' + "path" + printf("%s: Resulting path `%s` is too long for internal buffer (max: " + "%d)\n", + __func__, overlay_dir, MAX_CMD_LEN); + return -1; + } + + strcpy(full_path, overlay_dir); + strip_trailing(full_path, '/'); + strcat(full_path, "/path"); + + if (write_string_to_file(full_path, requested_path)) { + printf("%s: Failed to apply the overlay - could not write to path file\n", + __func__); + return -1; + } + return 0; +} + +/** + * dfx_set_fpga_firmware(...) - write a firmware binary name to the FPGA + * manager + * + * @requested_binary_name: name of the firmware binary to load + * + * This function writes the specified firmware binary name to the FPGA manager's + * firmware attribute in sysfs (`/sys/class/fpga_manager/fpga0/firmware`). This + * triggers the FPGA manager to load the specified firmware onto the FPGA. All + * file operations (open, write, close) are checked, and detailed error messages + * including errno are reported if any operation fails. + * + * Return: 0 on success (firmware name successfully written), + * -1 on error (e.g., failed to open, write, or close the sysfs file) + */ +int dfx_set_fpga_firmware(const char *requested_binary_name) +{ + if (write_string_to_file("/sys/class/fpga_manager/fpga0/firmware", + requested_binary_name)) { + printf("%s: Failed to write the bitstream ,-" + " could not write to firmware file\n", + __func__); + return -1; + } + + return 0; +} + +/** + * dfx_set_fpga_flags(...) - write a firmware binary name to the FPGA manager + * + * @flags: flag value to write - see user_load for more information. + * + * This function converts `flags` to a hex formatted string before writing + * that string to the fpga flags attribute + * (`/sys/class/fpga_manager/fpga0/flags`) + * + * Return: 0 on success (firmware name successfully written), + * -1 on error (e.g., failed to open, write, or close the sysfs file) + */ +int dfx_set_fpga_flags(const int flags) +{ + char buf[32]; + snprintf(buf, sizeof(buf), "%x", flags); // convert to hex + if (write_string_to_file("/sys/class/fpga_manager/fpga0/flags", buf)) { + printf("%s: Failed to set fpga flags - could not write to flags file\n", + __func__); + return -1; + } + + return 0; +} + +/** + * dfx_set_fpga_key(...) - write a AES key to the FPGA via the sysfs + * interface + * + * @key: AES key string to write + * + * Return: 0 on success (key successfully written), + * -1 on error (e.g., failed to open, write, or close the sysfs file) + */ +int dfx_set_fpga_key(const char *key) +{ + if (write_string_to_file("/sys/class/fpga_manager/fpga0/key", key)) { + printf("%s: Failed to set fpga flags - could not write to flags file\n", + __func__); + return -1; + } + + return 0; +} + + +/** + * dfx_get_overlay_path(...) - read an overlay's path variable into + * `dest_buffer` + * + * @overlay_dir: path to the overlay directory in configfs + * @buffer: buffer to write the path into + * @buf_size: length of the provided `buffer` in bytes + * + * Return: number of bytes read on success + * -1 on failure + */ +int dfx_get_overlay_path(const char *overlay_dir, char *buffer, + const size_t buf_size) +{ + char full_path[MAX_CMD_LEN]; + if (sizeof(full_path) < strlen(overlay_dir) + 6) { // + '/' + '\0' + "path" + printf("%s: Resulting path `%s` is too long for internal buffer (max: " + "%d)\n", + __func__, overlay_dir, MAX_CMD_LEN); + return -1; + } + + strcpy(full_path, overlay_dir); + strip_trailing(full_path, '/'); + strcat(full_path, "/path"); + + return read_single_line(full_path, buffer, buf_size); +} + +/** + * dfx_get_overlay_status(...) - read an overlay's status variable into + * `dest_buffer` + * + * @overlay_dir: path to the overlay directory in configfs + * @buffer: buffer to write the status into + * @buf_size: length of the provided `buffer` in bytes + * + * Return: number of bytes read on success + * -1 on failure + */ +int dfx_get_overlay_status(const char *overlay_dir, char *buffer, + const size_t buf_size) +{ + char full_path[MAX_CMD_LEN]; + if (sizeof(full_path) < strlen(overlay_dir) + 8) { // '/' + '\0' + "status" + printf("%s: Resulting path `%s` is too long for internal buffer (max: " + "%d)\n", + __func__, overlay_dir, MAX_CMD_LEN); + return -1; + } + + strcpy(full_path, overlay_dir); + strip_trailing(full_path, '/'); + strcat(full_path, "/status"); + + return read_single_line(full_path, buffer, buf_size); +} + /* Provide a generic interface to the user to specify the required parameters * for the library.The calling process must call this API before it performs * fpga-load/remove. @@ -283,9 +590,9 @@ int dfx_cfg_load(int package_id) { FPGA_NODE *package_node; int len, fd, buffd, ret = 0, err = 0; - char command[MAX_CMD_LEN]; - char *str; - DIR *FD; + char path_buf[MAX_CMD_LEN]; + char *overlay_dir_path; + char state_buf[128]; #ifdef ENABLE_LIBDFX_TIME struct timeval total_t1, total_t0, load_t1, load_t0; double total_time, load_time; @@ -308,82 +615,70 @@ int dfx_cfg_load(int package_id) if (!(package_node->flags & DFX_EXTERNAL_CONFIG_EN)) { fd = open("/dev/fpga0", O_RDWR); if (fd < 0) { - printf("%s: Cannot open device file...\n", - __func__); + printf("%s: Cannot open device file...\n", __func__); ret = -DFX_FAIL_TO_OPEN_DEV_NODE; goto END; } - - snprintf(command, sizeof(command), - "echo %x > /sys/class/fpga_manager/fpga0/flags", - package_node->flags); - system(command); + dfx_set_fpga_flags(package_node->flags); if (package_node->flags & DFX_ENCRYPTION_USERKEY_EN) { - snprintf(command, sizeof(command), - "echo %s > /sys/class/fpga_manager/fpga0/key", - package_node->aes_key); - system(command); + dfx_set_fpga_key(package_node->aes_key); } - buffd = package_node->dmabuf_info->dma_buffd; - /* Send dmabuf-fd to the FPGA Manager */ - ioctl(fd, DFX_IOCTL_LOAD_DMA_BUFF, &buffd); - close(fd); - } + buffd = package_node->dmabuf_info->dma_buffd; + /* Send dmabuf-fd to the FPGA Manager */ + ioctl(fd, DFX_IOCTL_LOAD_DMA_BUFF, &buffd); + close(fd); + } - snprintf(command, sizeof(command), - "/sys/kernel/config/device-tree/overlays/%s_image_%lu", - package_node->package_name, package_node->package_id); + snprintf(path_buf, sizeof(path_buf), "%s/%s_image_%lu", DTBO_ROOT_DIR, + package_node->package_name, package_node->package_id); dfx_set_firmware_search_path(package_node->load_image_path); - len = strlen(command) + 1; - str = (char *) calloc((len), sizeof(char)); - strncpy(str, command, len); - package_node->load_image_overlay_pck_path = str; - snprintf(command, sizeof(command), "mkdir -p %s", - package_node->load_image_overlay_pck_path); - system(command); + len = strlen(path_buf) + 1; + overlay_dir_path = (char *) calloc(len, sizeof(char)); + strncpy(overlay_dir_path, path_buf, len); + package_node->load_image_overlay_pck_path = overlay_dir_path; + if (mkdir(package_node->load_image_overlay_pck_path, 0755)) { + printf("%s: Failed to create overlay dir `%s`\n", __func__, + package_node->load_image_overlay_pck_path); + return -1; + } + printf("%s: Created overlay at `%s`\n", __func__, + package_node->load_image_overlay_pck_path); + - snprintf(command, sizeof(command), "echo -n %s > %s/path", - package_node->load_image_dtbo_name, - package_node->load_image_overlay_pck_path); #ifdef ENABLE_LIBDFX_TIME gettimeofday(&load_t0, NULL); #endif - system(command); + // Trigger overlay load + dfx_set_overlay_path(package_node->load_image_overlay_pck_path, + package_node->load_image_dtbo_name); #ifdef ENABLE_LIBDFX_TIME gettimeofday(&load_t1, NULL); #endif - + // check FPGA state is operating if (!(package_node->flags & DFX_EXTERNAL_CONFIG_EN)) { - snprintf(command, sizeof(command), - "cat /sys/class/fpga_manager/fpga0/state >> state.txt"); - ret = dfx_state(command, "operating"); - if (ret) { - err = dfx_get_error(command); - snprintf(command, sizeof(command), "rmdir %s", - package_node->load_image_overlay_pck_path); - system(command); - printf("%s: Image configuration failed with error: 0x%x\n", - __func__, err); + dfx_get_fpga_state(state_buf, sizeof(state_buf)); + if (strcmp(state_buf, "operating") != 0) { + err = dfx_get_error(path_buf); + remove_overlay_dir(package_node->load_image_overlay_pck_path); + printf("%s: Image configuration failed with error: 0x%x\n", __func__, + err); if (package_node->xilplatform == ZYNQMP_PLATFORM) zynqmp_print_err_msg(err); - system(command); - ret = -DFX_IMAGE_CONFIG_ERROR; dfx_set_firmware_search_path(""); + ret = -DFX_IMAGE_CONFIG_ERROR; goto END; } } - snprintf(command, sizeof(command), "cat %s/path >> state.txt", - package_node->load_image_overlay_pck_path); - ret = dfx_state(command, package_node->load_image_dtbo_name); - if (ret) { - snprintf(command, sizeof(command), "rmdir %s", - package_node->load_image_overlay_pck_path); - system(command); + // Check that the overlay path is still written + dfx_get_overlay_path(package_node->load_image_overlay_pck_path, state_buf, + sizeof(state_buf)); + if (strcmp(state_buf, package_node->load_image_dtbo_name) != 0) { printf("%s: Image configuration failed\n", __func__); + remove_overlay_dir(package_node->load_image_overlay_pck_path); dfx_set_firmware_search_path(""); ret = -DFX_IMAGE_CONFIG_ERROR; } @@ -409,9 +704,10 @@ int dfx_cfg_load(int package_id) int dfx_cfg_drivers_load(int package_id) { FPGA_NODE *package_node; - char command[MAX_CMD_LEN]; + char path_buf[MAX_CMD_LEN]; int len, ret = 0; - char *str; + char *overlay_dir_path; + char state_buf[128] = {}; #ifdef ENABLE_LIBDFX_TIME struct timeval t1, t0; double time; @@ -436,33 +732,33 @@ int dfx_cfg_drivers_load(int package_id) goto END; } - // This may not be neccessary - this approach should use the dma buffer - // TODO(artiepoole): check this is necessary dfx_set_firmware_search_path(package_node->load_drivers_dtbo_path); - snprintf(command, sizeof(command), - "/sys/kernel/config/device-tree/overlays/%s_driver_%lu", - package_node->package_name, package_node->package_id); - len = strlen(command) + 1; - str = (char *) calloc((len), sizeof(char)); - strncpy(str, command, len); - package_node->load_drivers_overlay_pck_path = str; - snprintf(command, sizeof(command), "mkdir -p %s", - package_node->load_drivers_overlay_pck_path); - system(command); - snprintf(command, sizeof(command), "echo -n %s > %s/path", - package_node->load_drivers_dtbo_name, - package_node->load_drivers_overlay_pck_path); - system(command); + snprintf(path_buf, sizeof(path_buf), + "%s/%s_driver_%lu", + DTBO_ROOT_DIR, + package_node->package_name, + package_node->package_id); + len = (int)strlen(path_buf) + 1; + overlay_dir_path = (char *) calloc((len), sizeof(char)); + strncpy(overlay_dir_path, path_buf, len); + package_node->load_drivers_overlay_pck_path = overlay_dir_path; + + if (mkdir(package_node->load_image_overlay_pck_path, 0755)) { + printf("%s: Failed to create overlay dir `%s`\n", + __func__, package_node->load_image_overlay_pck_path); + return -1; + } - snprintf(command, sizeof(command), "cat %s/path >> state.txt", - package_node->load_drivers_overlay_pck_path); - ret = dfx_state(command, package_node->load_drivers_dtbo_name); - if (ret) { - snprintf(command, sizeof(command), "rmdir %s", - package_node->load_drivers_overlay_pck_path); - system(command); + dfx_set_overlay_path(package_node->load_drivers_overlay_pck_path, + package_node->load_drivers_dtbo_name); + + // Check that the overlay path is still written + dfx_get_overlay_path(package_node->load_image_overlay_pck_path, state_buf, + sizeof(state_buf)); + if (strcmp(state_buf, package_node->load_image_dtbo_name) != 0) { printf("%s: Drivers DTBO config failed\n", __func__); + remove_overlay_dir(package_node->load_image_overlay_pck_path); dfx_set_firmware_search_path(""); ret = -DFX_DRIVER_CONFIG_ERROR; } @@ -511,10 +807,7 @@ int dfx_cfg_remove(int package_id) FD = opendir(package_node->load_drivers_overlay_pck_path); if (FD) { closedir(FD); - snprintf(command, sizeof(command), "rmdir %s", - package_node->load_drivers_overlay_pck_path); - system(command); - + remove_overlay_dir(package_node->load_drivers_overlay_pck_path); } } @@ -522,9 +815,7 @@ int dfx_cfg_remove(int package_id) FD = opendir(package_node->load_image_overlay_pck_path); if (FD) { closedir(FD); - snprintf(command, sizeof(command), "rmdir %s", - package_node->load_image_overlay_pck_path); - system(command); + remove_overlay_dir(package_node->load_image_overlay_pck_path); } } @@ -879,7 +1170,7 @@ static struct dfx_package_node *create_package() FPGA_NODE *package_node; DIR *FD; - FD = opendir("/sys/kernel/config/device-tree/overlays/"); + FD = opendir(DTBO_ROOT_DIR); if (FD) closedir(FD); else { @@ -980,47 +1271,14 @@ static int destroy_package(int package_id) return 0; } -static int dfx_state(char *cmd, char *state) -{ - char buf[PLATFORM_STR_LEN]; - 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; -} - -static int dfx_get_error(char *cmd) +/** + * + * @param state_buf buffer already containing the state string from fpga + * @return the contents of state_buf converted to signed integer + */ +static int dfx_get_error(const char *state_buf) { - char string[PLATFORM_STR_LEN]; - FILE *fp; - int c; - - system(cmd); - fp = fopen("state.txt", "r"); - c = getc(fp); - while(c!=EOF) { - fscanf(fp, "%s", string); - c = getc(fp); - } - - fclose(fp); - - system("rm state.txt"); - - return (int)strtol(string, NULL, 0); + return (int) strtol(state_buf, NULL, 0); } static int dfx_package_load_dmabuf(struct dfx_package_node *package_node, @@ -1418,7 +1676,7 @@ int dfx_set_firmware_search_path(const char *file_path) goto END; } - printf("%s: writing `%s` to %s\n", __func__, parent_dir, lookup_control); + printf("%s: Writing `%s` to %s\n", __func__, parent_dir, lookup_control); if (write(fd, parent_dir, strlen(parent_dir)) < 0) { printf("%s: ERROR: failed to write firmware lookup path\n", __func__); goto END; @@ -1432,7 +1690,7 @@ int dfx_set_firmware_search_path(const char *file_path) close(fd); } - if (rc <= 0) { + if (rc < 0) { printf("%s: WARN: Failed to set firmware search path. " "Success only possible if the requested files live in " "defaults.\nSee " From 8a947a792a12ea7af314633ab2e6bf6dda8554ee Mon Sep 17 00:00:00 2001 From: Artie Poole Date: Wed, 17 Dec 2025 17:46:24 +0000 Subject: [PATCH 4/4] doc/README.txt: update readme with functions for c-style IO helpers Adds docs for functions: - dfx_set_firmware_search_path - dfx_get_fpga_state - dfx_set_overlay_path - dfx_set_fpga_firmware - dfx_set_fpga_flags - dfx_set_fpga_key - dfx_get_overlay_path - dfx_get_overlay_status Signed-off-by: Artie Poole --- doc/README.txt | 218 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/doc/README.txt b/doc/README.txt index 0ea1800..89d4743 100755 --- a/doc/README.txt +++ b/doc/README.txt @@ -511,6 +511,224 @@ Usage example: /* More code */ +================================================================================= +-FPGA state info: dfx_get_fpga_state(char *buffer, size_t buf_size) +================================================================================= + +/* This API populates the user-provided buffer with the current operational +* state of the FPGA as reported by the FPGA manager sysfs interface. +* +* buffer: User buffer address to receive the FPGA state string. +* buf_size: Size of the user-provided buffer in bytes. +* +* Return: Number of bytes read from sysfs in case of success. +* or Negative value on failure. +*/ + +Usage example: +#include "libdfx.h" + +/* More code */ + +char buffer[256]; +ret = dfx_get_fpga_state(buffer, sizeof(buffer)); +if (ret < 0 || strcmp(buffer, "operating") != 0) + return -1; + +/* buffer now contains the FPGA state string */ + +/* More code */ + +================================================================================= +-Overlay path config: dfx_set_overlay_path(const char *overlay_dir, +const char *requested_path) +================================================================================= + +/* This API writes the requested overlay path to the overlay's `path` +* attribute in configfs. +* This function does not check that the path stays set - use +* dfx_get_overlay_path and dfx_get_overlay_status to check that the application +* of an overlay was successful. +* +* overlay_dir: Path to the overlay directory in configfs. +* requested_path: Overlay path string to be written. +* +* Return: 0 on success or Negative value on failure. +*/ + +Usage example: +#include "libdfx.h" + +/* More code */ + +ret = dfx_set_overlay_path("/sys/kernel/config/device-tree/overlays/my_overlay", + "/home/user/firmwares/my_overlay.dtbo"); +if (ret < 0) + return -1; + +/* More code */ + +================================================================================= +-FPGA firmware load: dfx_set_fpga_firmware(const char *requested_binary_name) +================================================================================= + +/* This API triggers the FPGA manager to load the specified firmware +* binary by writing its name to the FPGA manager sysfs interface. +* This function does not check that the firmware application succeeded. +* Use dfx_get_fpga_state to check that the fpga was successful programmed. +* +* requested_binary_name: Name of the firmware binary to load (not full path) +* +* Return: 0 on success or Negative value on failure. + + +*/ + +Usage example: +#include "libdfx.h" + +/* More code */ + +ret = dfx_set_fpga_firmware("my_bitstream.bit.bin"); +if (ret < 0) + return -1; + +/* More code */ + +================================================================================= +-FPGA flags config: dfx_set_fpga_flags(const int flags) +================================================================================= + +/* This API sets FPGA manager flags by writing a hex-formatted flag +* value to the FPGA manager sysfs interface. +* +* flags: Integer flag value to apply. +* +* Return: 0 on success or Negative value on failure. +*/ + +Usage example: +#include "libdfx.h" + +/* More code */ + +ret = dfx_set_fpga_flags(0x20); +if (ret < 0) + return -1; + +/* More code */ + +================================================================================= +-FPGA key config: dfx_set_fpga_key(const char *key) +================================================================================= + +/* This API writes an AES key string to the FPGA manager via the +* sysfs interface. +* +* key: AES key string to be written. +* +* Return: 0 on success or Negative value on failure. +*/ + +Usage example: +#include "libdfx.h" + +/* More code */ + +ret = dfx_set_fpga_key("0123456789abcdef0123456789abcdef"); +if (ret < 0) + return -1; + +/* More code */ + +================================================================================= +-Overlay path info: dfx_get_overlay_path(const char *overlay_dir, +char *buffer, size_t buf_size) +================================================================================= + +/* This API populates the user-provided buffer with the currently +* configured overlay path from configfs. +* +* overlay_dir: Path to the overlay directory in configfs. +* buffer: User buffer address. +* buf_size: Size of the user-provided buffer in bytes. +* +* Return: Number of bytes read from configfs in case of success. +* or Negative value on failure. +*/ + +Usage example: +#include "libdfx.h" + +/* More code */ + +char buffer[256]; +ret = dfx_get_overlay_path("/sys/kernel/config/device-tree/overlays/my_overlay", + buffer, sizeof(buffer)); +if (ret < 0 || strcmp(buffer, "my_overlay.dtbo") != 0) + return -1; + +/* More code */ + +================================================================================= +-Overlay status info: dfx_get_overlay_status(const char *overlay_dir, +char *buffer, size_t buf_size) +================================================================================= + +/* This API populates the user-provided buffer with the current +* status of the specified overlay as reported by configfs. +* +* overlay_dir: Path to the overlay directory in configfs. +* buffer: User buffer address. +* buf_size: Size of the user-provided buffer in bytes. +* +* Return: Number of bytes read from configfs in case of success. +* or Negative value on failure. +*/ + +Usage example: +#include "libdfx.h" + +/* More code */ + +char buffer[256]; +ret = dfx_get_overlay_status("/sys/kernel/config/device-tree/overlays/my_overlay", + buffer, sizeof(buffer)); +if (ret < 0) + return -1; + +/* More code */ + +================================================================================= +-Kernel Firmware Search Path: dfx_set_firmware_search_path(const char *file_path) +================================================================================= + +/* This API tells the kernel where to search for the firmware file +* (i.e. bitstream, dtbo, driver) +* see https://docs.kernel.org/driver-api/firmware/fw_search_path.html +* for more information +* +* The parent dir of the provided file is written to +* /sys/module/firmware_class/parameters/path so that the kernel can discover +* the firmware within the parent directory +* +* @param file_path the full path to the file to be loaded +* +* Return: 0 on success or Negative value on failure. +*/ + +Usage example: + +#include "libdfx.h" + +/* More code */ + +ret = dfx_set_firmware_search_path("/home/user/firmwares/my_firmware.bit.bin"); +if (ret < 0) + return -1; + +/* More code */ + ================ Build procedure: ================