summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJimmy Zhang <jimmzhang@nvidia.com>2016-03-14 19:42:46 -0700
committerStephen Warren <swarren@nvidia.com>2016-03-15 10:36:51 -0600
commit918e0fd8fce2b4450686e2bd0effceb73b33f2ae (patch)
treea9328f1dd39ff9d70037eea3a9cc7d1ffc50aa98
parent5303a312754391e5d104550ef29a5a0fe56d3942 (diff)
downloadtegrarcm-918e0fd8fce2b4450686e2bd0effceb73b33f2ae.tar.gz
Add option --download-signed-msgs to download signed blobs
This feature allows user to download signed messages to devices secured with PKC. Example: tegrarcm --download-signed-msgs --signed-msgs-file rel_1001.bin \ --bct=jetson-tk1-bct.bct --bootloader=u-boot.bin --loadaddr=0x83d88000 Where the following blob files are downloaded to device sequentially: a) rel_1001.bin.qry b) rel_1001.bin.ml c) rel_1001.bin.bl Signed-off-by: Jimmy Zhang <jimmzhang@nvidia.com> Signed-off-by: Stephen Warren <swarren@nvidia.com>
-rw-r--r--src/main.c261
-rw-r--r--src/tegrarcm.1.in118
2 files changed, 305 insertions, 74 deletions
diff --git a/src/main.c b/src/main.c
index 93daef4..57cd2d8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -62,20 +62,23 @@
#include "miniloader/tegra124-miniloader.h"
static int initialize_rcm(uint16_t devid, usb_device_t *usb,
- const char *pkc_keyfile, const char *signed_msgs_file);
+ const char *pkc_keyfile, const char *signed_msgs_file,
+ bool download_signed_msgs);
static int initialize_miniloader(uint16_t devid, usb_device_t *usb,
- char *mlfile, uint32_t mlentry, const char *signed_msgs_file);
+ char *mlfile, uint32_t mlentry, const char *signed_msgs_file,
+ bool download_signed_msgs);
static int wait_status(nv3p_handle_t h3p);
static int send_file(nv3p_handle_t h3p, const char *filename);
static int create_miniloader_rcm(uint8_t *miniloader, uint32_t size,
uint32_t entry, const char *signed_msgs_file);
static int download_miniloader(usb_device_t *usb, uint8_t *miniloader,
- uint32_t size, uint32_t entry);
+ uint32_t size, uint32_t entry,
+ bool download_signed_msgs);
static void dump_platform_info(nv3p_platform_info_t *info);
static int download_bct(nv3p_handle_t h3p, char *filename);
static int download_bootloader(nv3p_handle_t h3p, char *filename,
- uint32_t entry, uint32_t loadaddr,
- const char *pkc_keyfile);
+ uint32_t entry, uint32_t loadaddr,
+ const char *pkc_keyfile, const char *signed_msgs_file);
static int read_bct(nv3p_handle_t h3p, char *filename);
static int sign_blob(const char *blob_filename, const char *pkc_keyfile,
const char *signed_msgs_file);
@@ -101,6 +104,7 @@ enum cmdline_opts {
OPT_SIGN_MSGS,
OPT_SIGNED_MSGS_FILE,
OPT_SOC,
+ OPT_DOWNLOAD_SIGNED_MSGS,
OPT_END,
};
@@ -149,6 +153,8 @@ static void usage(char *progname)
fprintf(stderr, "\t\tSpecify message files prefix\n");
fprintf(stderr, "\t--soc=<tegra soc #>\n");
fprintf(stderr, "\t\tSpecify Tegra SoC chip model number, ie, 124.\n");
+ fprintf(stderr, "\t--download-signed-msgs\n");
+ fprintf(stderr, "\t\tDownload signed messages\n");
fprintf(stderr, "\n");
}
@@ -234,6 +240,7 @@ int main(int argc, char **argv)
bool sign_msgs = false;
char *signed_msgs_file = NULL;
uint32_t soc = 0;
+ bool download_signed_msgs = false;
static struct option long_options[] = {
[OPT_BCT] = {"bct", 1, 0, 0},
@@ -251,6 +258,7 @@ int main(int argc, char **argv)
[OPT_SIGN_MSGS] = {"gen-signed-msgs", 0, 0, 0},
[OPT_SIGNED_MSGS_FILE] = {"signed-msgs-file", 1, 0, 0},
[OPT_SOC] = {"soc", 1, 0, 0},
+ [OPT_DOWNLOAD_SIGNED_MSGS] = {"download-signed-msgs", 0, 0, 0},
[OPT_END] = {0, 0, 0, 0}
};
// parse command line args
@@ -305,6 +313,9 @@ int main(int argc, char **argv)
case OPT_SOC:
soc = strtoul(optarg, NULL, 0);
break;
+ case OPT_DOWNLOAD_SIGNED_MSGS:
+ download_signed_msgs = true;
+ break;
case OPT_HELP:
default:
usage(argv[0]);
@@ -353,12 +364,36 @@ int main(int argc, char **argv)
}
}
+ /* error check */
+ if (download_signed_msgs == true) {
+ /* must have signed_msgs_file option */
+ if (signed_msgs_file == NULL) {
+ fprintf(stderr, "signed msgs filename must be"
+ " specified\n");
+ goto usage_exit;
+ }
+
+ /* can not have pkc keyfile */
+ if (pkc_keyfile) {
+ fprintf(stderr, "No pkc keyfile is needed\n");
+ goto usage_exit;
+ }
+
+ /* can not load in unsigned ml */
+ if (mlfile) {
+ fprintf(stderr, "can not have option --miniloader\n");
+ goto usage_exit;
+ }
+ }
+
/*
* option --signed-msgs-file needs to work with option
- * --gen-signed-msgs
+ * either --gen-signed-msgs or --download-signed-msgs
*/
- if (signed_msgs_file && (sign_msgs == false)) {
- fprintf(stderr, "missing option --gen-signed-msgs\n");
+ if (signed_msgs_file && (sign_msgs == false) &&
+ (download_signed_msgs == false)) {
+ fprintf(stderr, "missing option either --gen-signed-msgs or"
+ " --download-signed-msgs\n");
goto usage_exit;
}
@@ -403,12 +438,13 @@ int main(int argc, char **argv)
}
// init and create signed query version rcm
- if (initialize_rcm(devid, NULL, pkc_keyfile, signed_msgs_file))
+ if (initialize_rcm(devid, NULL, pkc_keyfile, signed_msgs_file,
+ download_signed_msgs))
error(1, errno, "error initializing RCM protocol");
// create signed download miniloader rcm
if (initialize_miniloader(devid, NULL, mlfile, mlentry,
- signed_msgs_file))
+ signed_msgs_file, download_signed_msgs))
error(1, errno, "error initializing miniloader");
// create bl signature
@@ -439,13 +475,13 @@ int main(int argc, char **argv)
// initialize rcm
ret2 = initialize_rcm(devid, usb, pkc_keyfile,
- signed_msgs_file);
+ signed_msgs_file, download_signed_msgs);
if (ret2)
error(1, errno, "error initializing RCM protocol");
// download the miniloader to start nv3p or create ml rcm file
ret2 = initialize_miniloader(devid, usb, mlfile, mlentry,
- signed_msgs_file);
+ signed_msgs_file, download_signed_msgs);
if (ret2)
error(1, errno, "error initializing miniloader");
@@ -501,7 +537,8 @@ int main(int argc, char **argv)
}
// download the bootloader
- ret = download_bootloader(h3p, blfile, entryaddr, loadaddr, pkc_keyfile);
+ ret = download_bootloader(h3p, blfile, entryaddr, loadaddr,
+ pkc_keyfile, signed_msgs_file);
if (ret)
error(1, ret, "error downloading bootloader: %s", blfile);
@@ -546,7 +583,8 @@ static int save_to_file(const char *filename, const uint8_t *msg_buff,
}
static int initialize_rcm(uint16_t devid, usb_device_t *usb,
- const char *pkc_keyfile, const char *signed_msgs_file)
+ const char *pkc_keyfile, const char *signed_msgs_file,
+ bool download_signed_msgs)
{
int ret = 0;
uint8_t *msg_buff;
@@ -578,16 +616,55 @@ static int initialize_rcm(uint16_t devid, usb_device_t *usb,
// create query version message
rcm_create_msg(RCM_CMD_QUERY_RCM_VERSION, NULL, 0, NULL, 0, &msg_buff);
- /* save query version rcm blob */
+ /* if signed_msgs_file is given */
if (signed_msgs_file) {
+ int fd;
+ struct stat sb;
+
ret = create_name_string(query_version_rcm_filename,
signed_msgs_file, ".qry");
if (ret)
goto done;
- ret = save_to_file(query_version_rcm_filename, msg_buff,
+ /* either save query version rcm blob */
+ if (download_signed_msgs == false) {
+ ret = save_to_file(query_version_rcm_filename, msg_buff,
rcm_get_msg_len(msg_buff));
- goto done;
+ goto done;
+ }
+
+ /* or download signed query version rcm blob */
+ printf("download signed query version rcm from file %s\n",
+ query_version_rcm_filename);
+
+ free(msg_buff); // release memory allocated by rcm_create_msg
+ msg_buff = NULL;
+
+ fd = open(query_version_rcm_filename, O_RDONLY, 0);
+ if (fd < 0) {
+ fprintf(stderr, "error opening %s\n",
+ query_version_rcm_filename);
+ return errno;
+ }
+
+ ret = fstat(fd, &sb);
+ if (ret) {
+ fprintf(stderr, "error on fstat of %s\n",
+ query_version_rcm_filename);
+ return ret;
+ }
+ msg_buff = (uint8_t *)malloc(sb.st_size);
+ if (!msg_buff) {
+ fprintf(stderr, "error allocating %zd bytes for query"
+ " rcm\n", sb.st_size);
+ return errno;
+ }
+ if (read(fd, msg_buff, sb.st_size) != sb.st_size) {
+ fprintf(stderr,"error reading from %s\n",
+ query_version_rcm_filename);
+ free(msg_buff);
+ return errno;
+ }
}
// write query version message to device
@@ -623,25 +700,68 @@ done:
}
static int initialize_miniloader(uint16_t devid, usb_device_t *usb,
- char *mlfile, uint32_t mlentry, const char *signed_msgs_file)
+ char *mlfile, uint32_t mlentry, const char *signed_msgs_file,
+ bool download_signed_msgs)
{
int fd;
struct stat sb;
int ret;
- uint8_t *miniloader;
+ uint8_t *miniloader = NULL;
+ bool ml_buffer_alloc = false;
uint32_t miniloader_size;
uint32_t miniloader_entry;
+ char ml_rcm_filename[PATH_MAX];
+ char *filename = NULL;
+
+ // use prebuilt miniloader if not loading from a file
+ if ((devid & 0xff) == USB_DEVID_NVIDIA_TEGRA20) {
+ miniloader = miniloader_tegra20;
+ miniloader_size = sizeof(miniloader_tegra20);
+ miniloader_entry = TEGRA20_MINILOADER_ENTRY;
+ } else if ((devid & 0xff) == USB_DEVID_NVIDIA_TEGRA30) {
+ miniloader = miniloader_tegra30;
+ miniloader_size = sizeof(miniloader_tegra30);
+ miniloader_entry = TEGRA30_MINILOADER_ENTRY;
+ } else if ((devid & 0xff) == USB_DEVID_NVIDIA_TEGRA114) {
+ miniloader = miniloader_tegra114;
+ miniloader_size = sizeof(miniloader_tegra114);
+ miniloader_entry = TEGRA114_MINILOADER_ENTRY;
+ } else if ((devid & 0xff) == USB_DEVID_NVIDIA_TEGRA124) {
+ miniloader = miniloader_tegra124;
+ miniloader_size = sizeof(miniloader_tegra124);
+ miniloader_entry = TEGRA124_MINILOADER_ENTRY;
+ } else {
+ fprintf(stderr, "unknown tegra device: 0x%x\n", devid);
+ return ENODEV;
+ }
+
+ // if loading unsigned ml from a file
+ if (mlfile)
+ filename = mlfile;
+
+ // if loading signed ml rcm file
+ if (signed_msgs_file && (download_signed_msgs == true)) {
+ filename = ml_rcm_filename;
+ ret = create_name_string(ml_rcm_filename, signed_msgs_file,
+ ".ml");
+ if (ret)
+ goto done;
- // if using miniloader from an external file
- if (mlfile) {
- fd = open(mlfile, O_RDONLY, 0);
+ /* download signed ml rcm blob */
+ printf("download signed miniloader rcm from file %s\n",
+ ml_rcm_filename);
+ }
+
+ // loading ml or signed ml rcm from a file
+ if (filename) {
+ fd = open(filename, O_RDONLY, 0);
if (fd < 0) {
- dprintf("error opening %s for reading\n", mlfile);
+ dprintf("error opening %s\n", filename);
return errno;
}
ret = fstat(fd, &sb);
if (ret) {
- dprintf("error on fstat of %s\n", mlfile);
+ dprintf("error on fstat of %s\n", filename);
return ret;
}
miniloader_size = sb.st_size;
@@ -650,50 +770,37 @@ static int initialize_miniloader(uint16_t devid, usb_device_t *usb,
dprintf("error allocating %d bytes for miniloader\n", miniloader_size);
return errno;
}
+ ml_buffer_alloc = true;
if (read(fd, miniloader, miniloader_size) != miniloader_size) {
dprintf("error reading from miniloader file");
return errno;
}
- miniloader_entry = mlentry;
- } else {
- if ((devid & 0xff) == USB_DEVID_NVIDIA_TEGRA20) {
- miniloader = miniloader_tegra20;
- miniloader_size = sizeof(miniloader_tegra20);
- miniloader_entry = TEGRA20_MINILOADER_ENTRY;
- } else if ((devid & 0xff) == USB_DEVID_NVIDIA_TEGRA30) {
- miniloader = miniloader_tegra30;
- miniloader_size = sizeof(miniloader_tegra30);
- miniloader_entry = TEGRA30_MINILOADER_ENTRY;
- } else if ((devid & 0xff) == USB_DEVID_NVIDIA_TEGRA114) {
- miniloader = miniloader_tegra114;
- miniloader_size = sizeof(miniloader_tegra114);
- miniloader_entry = TEGRA114_MINILOADER_ENTRY;
- } else if ((devid & 0xff) == USB_DEVID_NVIDIA_TEGRA124) {
- miniloader = miniloader_tegra124;
- miniloader_size = sizeof(miniloader_tegra124);
- miniloader_entry = TEGRA124_MINILOADER_ENTRY;
- } else {
- fprintf(stderr, "unknown tegra device: 0x%x\n", devid);
- return ENODEV;
- }
}
- if (signed_msgs_file) {
- return create_miniloader_rcm(miniloader, miniloader_size,
+ // if entry is specified
+ if (mlentry)
+ miniloader_entry = mlentry;
+
+ // if generating ml rcm file
+ if (signed_msgs_file && (download_signed_msgs == false)) {
+ ret = create_miniloader_rcm(miniloader, miniloader_size,
miniloader_entry, signed_msgs_file);
+ goto done;
}
printf("downloading miniloader to target at address 0x%x (%d bytes)...\n",
miniloader_entry, miniloader_size);
ret = download_miniloader(usb, miniloader, miniloader_size,
- miniloader_entry);
+ miniloader_entry, download_signed_msgs);
if (ret) {
fprintf(stderr, "Error downloading miniloader\n");
return ret;
}
printf("miniloader downloaded successfully\n");
-
- return 0;
+done:
+ if ((ml_buffer_alloc == true) && miniloader)
+ free(miniloader);
+ return ret;
}
static int wait_status(nv3p_handle_t h3p)
@@ -834,17 +941,24 @@ done:
}
static int download_miniloader(usb_device_t *usb, uint8_t *miniloader,
- uint32_t size, uint32_t entry)
+ uint32_t size, uint32_t entry,
+ bool download_signed_msgs)
{
- uint8_t *msg_buff;
+ uint8_t *msg_buff = NULL;
+ bool msg_buff_alloc = false;
int ret;
uint32_t status;
int actual_len;
// download the miniloader to the bootrom
- rcm_create_msg(RCM_CMD_DL_MINILOADER,
- (uint8_t *)&entry, sizeof(entry), miniloader, size,
- &msg_buff);
+ if (download_signed_msgs == true) /* signed ml with rcm header */
+ msg_buff = miniloader;
+ else {
+ rcm_create_msg(RCM_CMD_DL_MINILOADER, (uint8_t *)&entry,
+ sizeof(entry), miniloader, size, &msg_buff);
+ msg_buff_alloc = true;
+ }
+
ret = usb_write(usb, msg_buff, rcm_get_msg_len(msg_buff));
if (ret)
goto fail;
@@ -862,7 +976,8 @@ static int download_miniloader(usb_device_t *usb, uint8_t *miniloader,
ret = 0;
fail:
- free(msg_buff);
+ if ((msg_buff_alloc == true) && msg_buff)
+ free(msg_buff);
return ret;
}
@@ -1030,8 +1145,8 @@ out:
}
static int download_bootloader(nv3p_handle_t h3p, char *filename,
- uint32_t entry, uint32_t loadaddr,
- const char *pkc_keyfile)
+ uint32_t entry, uint32_t loadaddr,
+ const char *pkc_keyfile, const char *signed_msgs_file)
{
int ret;
nv3p_cmd_dl_bl_t arg;
@@ -1069,8 +1184,8 @@ static int download_bootloader(nv3p_handle_t h3p, char *filename,
// For fused board, the bootloader hash must be sent first
if (get_op_mode() == RCM_OP_MODE_ODM_SECURE_PKC) {
- /* sign and download */
if (pkc_keyfile) {
+ /* sign and download with --pkc option */
uint8_t rsa_pss_sig[RCM_RSA_SIG_SIZE];
ret = rsa_pss_sign_file(pkc_keyfile, filename, rsa_pss_sig);
@@ -1081,15 +1196,31 @@ static int download_bootloader(nv3p_handle_t h3p, char *filename,
}
ret = nv3p_data_send(h3p, rsa_pss_sig, sizeof(rsa_pss_sig));
- if (ret) {
- dprintf("error sending bootloader signature\n");
+
+ } else if (signed_msgs_file) {
+ /* download bl's signature */
+ char signature_filename[PATH_MAX];
+
+ ret = create_name_string(signature_filename,
+ signed_msgs_file, ".bl");
+ if (ret)
return ret;
- }
+
+ // send the bootloader's signature file
+ ret = send_file(h3p, signature_filename);
+
} else {
- fprintf(stderr, "Error: missing pkc keyfile to sign"
- " bootloader\n");
+ /* missing both options */
+ dprintf("error: missing both pkc keyfile and"
+ " bootloader's signature file\n");
return -1;
}
+
+ // check transfer status
+ if (ret) {
+ dprintf("error sending bootloader signature\n");
+ return ret;
+ }
}
// send the bootloader file
diff --git a/src/tegrarcm.1.in b/src/tegrarcm.1.in
index f8009b9..b7cba7f 100644
--- a/src/tegrarcm.1.in
+++ b/src/tegrarcm.1.in
@@ -9,13 +9,12 @@ tegrarcm \- tegra firmware download utility
]
.SH DESCRIPTION
This program is used to send code to a Tegra device in recovery mode.
-It does not supported locked devices with an encrypted boot key, only
-open devices such as the ventana or cardhu reference boards. It is
-not capable of flashing firmware to a device, but can be used to
-download firmware that is then capable of flashing. For example in
-ChromeOS tegrarcm is used to download a special build of u-boot to the
-target Tegra device with a payload that it then flashes to the boot
-device.
+It also supports locked devices with pkc private key, such as Jetson
+tk1 board. It is not capable of flashing firmware to a device, but can
+be used to download firmware that is then capable of flashing. For
+example in ChromeOS tegrarcm is used to download a special build of
+u-boot to the target Tegra device with a payload that it then flashes
+to the boot device.
.SS Platforms supported
.IP \(bu
@@ -82,6 +81,24 @@ Specify the entry address of the miniloader.
.TP
.B \-\-usb\-port\-path \fIpath\fP
Specify the physical USB port path of the Tegra device to control.
+.TP
+.B \-\-pkc \fIkey.der\fP
+Specify the key file for secured devices. The private key should be in DER format.
+.TP
+.B \-\-gen\-signed\-msgs
+Generate signed messages for pkc secured devices.
+.TP
+.B \-\-signed\-msgs\-file \fImsg_file_prefix\fP
+Specify messages file name prefix.
+.TP
+.B \-\-download\-signed\-msgs
+Download signed messages.
+.TP
+.B \-\-soc \fItegra_soc_#\fP
+Specify Tegra SoC chip model number, ie, 124.
+.TP
+.B \-\-usb\-timeout \fItimeout_ms\fP
+Specify usb transfer timeout value in ms, 0 for unlimited timeout.
.SH USB PORT PATH
@@ -155,7 +172,7 @@ connections are physically changed, so you can use it over and over
without repeating the steps above.
.SH EXAMPLES
-To download u-boot firmware to a Tegra20 seaboard:
+1) To download unsigned u-boot firmware to a Tegra20 seaboard:
.nf
$ sudo tegrarcm --bct seaboard.bct --bootloader u-boot.bin --loadaddr 0x108000
@@ -187,7 +204,7 @@ sending file: u-boot.bin
u-boot.bin sent successfully
.fi
-To read the BCT from a system:
+2) To read the BCT from a system:
.nf
$ sudo tegrarcm --bct ventana.bct readbct
@@ -196,6 +213,89 @@ device id: 0x7820
reading BCT from system, writing to ventana.bct...done!
.fi
+3) To download with auto-signing u-boot.bin to jetson-tk1 target:
+
+.nf
+$ sudo tegrarcm --bct=jetson-tk1.bct --bootloader=u-boot.bin --loadaddr=0x83d88000 --pkc=rsa_priv.der
+bct file: jetson-tk1-bct.bct
+booloader file: u-boot.bin
+load addr 0x83d88000
+entry addr 0x83d88000
+device id: 0x7140
+uid: 0x640010017410b1000000000016020540
+RCM version: 64.1
+downloading miniloader to target at address 0x4000e000 (136920 bytes)...
+miniloader downloaded successfully
+Chip UID: 0x000000017410b1000000000016020540
+Chip ID: 0x40
+Chip ID Major Version: 0x1
+Chip ID Minor Version: 0x1
+Chip SKU: 0x81 (t124)
+Boot ROM Version: 0x1
+Boot Device: 0x2 (EMMC)
+Operating Mode: 0x6 (odm secure mode with PKC)
+Device Config Strap: 0x0
+Device Config Fuse: 0x0
+SDRAM Config Strap: 0x3
+sending file: jetson-tk1-bct.bct
+- 8192/8192 bytes sent
+jetson-tk1-bct.bct sent successfully
+sending file: u-boot.bin
+| 440004/440004 bytes sent
+u-boot.bin sent successfully
+.fi
+
+4) To generate signed messages for jetson-tk1 target:
+
+.nf
+$ sudo tegrarcm --gen-signed-msgs --signed-msgs-file rel_1001.bin --bootloader=u-boot.bin --loadaddr 0x83d88000 --soc 124 --pkc rsa_priv.der
+booloader file: u-boot.bin
+load addr 0x83d88000
+entry addr 0x83d88000
+Create file rel_1001.bin.qry...
+Create file rel_1001.bin.ml...
+Create file rel_1001.bin.bl...
+.fi
+
+
+5) To download signed messages to jetson-tk1 target:
+
+.nf
+$ sudo tegrarcm --download-signed-msgs --signed-msgs-file rel_1001.bin --bct=jetson-tk1-bct.bct --bootloader=u-boot.bin --loadaddr 0x83d88000
+bct file: jetson-tk1-bct.bct
+booloader file: u-boot.bin
+load addr 0x83d88000
+entry addr 0x83d88000
+device id: 0x7140
+uid: 0x640010017410b1000000000016020540
+download signed query version rcm from file rel_1001.bin.qry
+RCM version: 64.1
+download signed miniloader rcm from file rel_1001.bin.ml
+downloading miniloader to target at address 0x4000e000 (137572 bytes)...
+miniloader downloaded successfully
+Chip UID: 0x000000017410b1000000000016020540
+Chip ID: 0x40
+Chip ID Major Version: 0x1
+Chip ID Minor Version: 0x1
+Chip SKU: 0x81 (t124)
+Boot ROM Version: 0x1
+Boot Device: 0x2 (EMMC)
+Operating Mode: 0x6 (odm secure mode with PKC)
+Device Config Strap: 0x0
+Device Config Fuse: 0x0
+SDRAM Config Strap: 0x3
+sending file: jetson-tk1-bct.bct
+- 8192/8192 bytes sent
+jetson-tk1-bct.bct sent successfully
+sending file: rel_1001.bin.bl
+- 256/256 bytes sent
+rel_1001.bin.bl sent successfully
+sending file: u-boot.bin
+| 440004/440004 bytes sent
+u-boot.bin sent successfully
+.fi
+
+
.SH RETURN VALUE
If any error occurs a non zero exit status is returned.