[U-Boot] [PATCH 5/5] Davinci: Utility for MMC boot
Alagu Sankar
alagusankar at embwise.com
Wed May 12 11:43:46 CEST 2010
This is a Linux command line tool specific to TI's Davinci platforms, for
flashing UBL (User Boot Loader), u-boot and u-boot Environment in the MMC/SD
card. This MMC/SD card can be used for booting Davinci platforms that supports
MMC/SD boot option.
Signed-off-by: Alagu Sankar <alagusankar at embwise.com>
---
Makefile | 2 +-
tools/uflash/Makefile | 13 ++
tools/uflash/README | 125 ++++++++++++++++
tools/uflash/config.txt | 11 ++
tools/uflash/uflash.c | 379 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 529 insertions(+), 1 deletions(-)
create mode 100644 tools/uflash/Makefile
create mode 100644 tools/uflash/README
create mode 100644 tools/uflash/config.txt
create mode 100644 tools/uflash/uflash.c
diff --git a/Makefile b/Makefile
index 82cbbf4..c2b63db 100644
--- a/Makefile
+++ b/Makefile
@@ -3746,7 +3746,7 @@ clean:
@rm -f $(obj)examples/api/demo{,.bin}
@rm -f $(obj)tools/bmp_logo $(obj)tools/easylogo/easylogo \
$(obj)tools/env/{fw_printenv,fw_setenv} \
- $(obj)tools/envcrc \
+ $(obj)tools/envcrc $(obj)tools/uflash/uflash \
$(obj)tools/gdb/{astest,gdbcont,gdbsend} \
$(obj)tools/gen_eth_addr $(obj)tools/img2srec \
$(obj)tools/mkimage $(obj)tools/mpc86x_clk \
diff --git a/tools/uflash/Makefile b/tools/uflash/Makefile
new file mode 100644
index 0000000..ab98441
--- /dev/null
+++ b/tools/uflash/Makefile
@@ -0,0 +1,13 @@
+include $(TOPDIR)/config.mk
+
+all: $(obj)uflash
+
+HOSTCFLAGS_NOPED += -I $(SRCTREE)/include -DUSE_HOSTCC
+
+$(obj)uflash: $(SRCTREE)/tools/uflash/uflash.c $(SRCTREE)/lib/crc32.c
+ $(HOSTCC) $(HOSTCFLAGS_NOPED) $(HOSTLDFLAGS) -o $@ $^
+
+clean:
+ rm -f $(obj)uflash
+
+.PHONY: all clean
diff --git a/tools/uflash/README b/tools/uflash/README
new file mode 100644
index 0000000..cf7dbfb
--- /dev/null
+++ b/tools/uflash/README
@@ -0,0 +1,125 @@
+This is a Linux command line tool specific to TI's Davinci platforms, for
+flashing UBL (User Boot Loader), u-boot and u-boot Environment in the MMC/SD
+card. This MMC/SD card can be used for booting Davinci platforms that supports
+MMC/SD boot option.
+
+For simplicity, MMC is used in the following section to represent both MMC and
+SD cards.
+
+
+Building uflash utility
+=======================
+Set the TOOLSUBDIRS macro in the tools/Makefile to contain uflash directory
+TOOLSUBDIRS = uflash
+
+While building the u-boot binary, the uflash utility is also built and is placed
+under tools/uflash directory.
+
+
+Creating a Davinci bootable MMC card
+=====================================
+This document is based on the assumption that UBL is used the primary boot
+loader for booting u-boot. For more information on Davinci Boot modes, please
+refer the TMS320DM644x DMSoC ARM Subsystem Reference Guide (SPRUE14A).
+
+The embedded ROM boot loader (RBL) in Davinci expects the bootable code
+descriptor to be present in sectors 1 to 25 of the MMC card. Sector 0 is used
+for storing DOS partition information. Hence the UBL descriptor is stored
+from sectors 1 till 24. The descriptor is 512 bytes in size and is replicated
+in each of these sectors. This is followed by the u-boot descriptor,
+environment space, UBL binary and u-boot binary as depicted below:
+
+ _______________________________________
+ | |
+ | Sector 0 - Partition Table |
+ |---------------------------------------|
+ | Sector 1 - UBL descriptor |
+ |---------------------------------------|
+ | Sector 2 - UBL descriptor |
+ |---------------------------------------|
+ | .... |
+ |---------------------------------------|
+ | Sector 24 - UBL descriptor |
+ |---------------------------------------|
+ | Sector 25 - u-boot descriptor |
+ |---------------------------------------|
+ | Sector 26 - u-boot descriptor |
+ |---------------------------------------|
+ | ... |
+ |---------------------------------------|
+ | Sector 51 - u-boot descriptor |
+ |---------------------------------------|
+ | Sectors 52 to 83 - u-boot environment |
+ |---------------------------------------|
+ | Sectors 84 till 116 - empty |
+ |---------------------------------------|
+ | Sector 117 - UBL binary |
+ |---------------------------------------|
+ | ... |
+ |---------------------------------------|
+ | Sector X = u-boot binary |
+ | X = 117 + UBL binary size in blocks |
+ |---------------------------------------|
+ | ... |
+ |---------------------------------------|
+ | Sector Y = Application use |
+ | Y = X + u-boot binary size in blocks |
+ |---------------------------------------|
+ | ... |
+ |_______________________________________|
+
+a. The MMC card shall be re-partitioned and formated to create some room for
+ storing UBL and u-boot. Use fdisk utility (as super user) to delete the
+ existing partition and create a new one.
+ # fdisk /dev/mmcblk0 (device name might change if USB card reader is used)
+ - Delete the existing partitions with 'd' command.
+ - Create a new partition with 'n' command, followed by 'p' command
+ - Mark the first cylinder as 20. Typical cylinder size is 32KBytes. So
+ starting the first cylinder at 20 provides us about 600Kbytes for
+ storing UBL and u-boot. If the fdisk utility displays a different
+ cylinder size, make sure that you are leaving atleast 500K space
+ before the first cylinder.
+ - Leave the last cylinder to default value (or) any other value
+ depending on the partition size requirements.
+ - Save and exit with 'w' command
+
+b. Format the partition for EXT3 file system
+ # mkfs.ext3 /dev/mmcblk0p1
+
+c. Copy the root file system and kernel uImage onto the newly formated
+ partition. Pre-built images for Davinci DM355EVM platform are available at:
+ http://arago-project.org/files/releases/davinci-psp_3.x.0.0/images/dm355-evm/arago-demo-image-dm355-evm.tar.gz (and)
+ http://arago-project.org/files/releases/davinci-psp_3.x.0.0/images/dm355-evm/uImage-dm355-evm.bin
+ # mount /dev/mmcblk0p1 /mnt
+ # cd /mnt
+ # tar xzf /path_to_binaries/arago-demo-image-dm355-evm.tar.gz
+ # cp /path_to_binaries/uImage-dm355-evm.bin boot/uImage
+ # cd /home
+ # umount /mnt
+
+d. Modify the config.txt file to set environment variables for u-boot. These
+ environment variables will be used by default by the u-boot.
+
+e. Using the 'uflash' utility, place the UBL and u-uoot binaries on the MMC
+ card. Copy the u-boot.bin to tools/uflash directory
+ # ./uflash -d /dev/mmcblk0 -u UBL.bin -b u-boot.bin -vv
+ UBL Size 20991
+ u-boot Size 252087
+ First partition starts at 1216(622592)
+ Required Blocks 660, Available Blocks 1215
+ UBL Magic Number : a1aced00
+ UBL Entry Point : 00000100
+ UBL Number of Blocks : 00000028
+ UBL Starting Block : 00000075
+ UBL Load Address : 00000000
+ Writing UBL Signature
+ Writing UBL
+ U-Boot Magic Number : a1aced66
+ U-Boot Entry Point : 81080000
+ U-Boot Number of Blocks : 000001ec
+ U-Boot Starting Block : 000000a7
+ Load U-Boot Address : 81080000
+ Writing U-Boot Signature
+ Writing U-Boot
+ Done...
+
diff --git a/tools/uflash/config.txt b/tools/uflash/config.txt
new file mode 100644
index 0000000..f6acb22
--- /dev/null
+++ b/tools/uflash/config.txt
@@ -0,0 +1,11 @@
+bootargs=console=ttyS0,115200n8 root=/dev/mmcblk0p1 rootwait rootfstype=ext3 rw
+bootcmd=ext2load mmc 0 0x80700000 boot/uImage; bootm 0x80700000
+bootdelay=1
+baudrate=115200
+bootfile="uImage"
+stdin=serial
+stdout=serial
+stderr=serial
+ethact=dm9000
+videostd=ntsc
+
diff --git a/tools/uflash/uflash.c b/tools/uflash/uflash.c
new file mode 100644
index 0000000..3a2260a
--- /dev/null
+++ b/tools/uflash/uflash.c
@@ -0,0 +1,379 @@
+/*
+ * (C) Copyright, Alagu Sankar <alagusankar at embwise.com>
+ *
+ * Utility for flashing the UBL and U-Boot binary onto SD/MMC cards.
+ * Signature as Required by RBL is Added by this utility.
+ * Tested with DM355EVM Platform with UBL v1.65 and Uboot 2009-03
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+typedef unsigned int uint32;
+typedef unsigned char uint8;
+
+struct rbl_header {
+ uint32 magic_num;
+ uint32 entry_point;
+ uint32 num_blocks;
+ uint32 start_block;
+ uint32 load_address;
+ uint32 padding[123];
+};
+
+#define verbose_printf(x...) if (verbose) printf(x)
+#define BLOCK_SIZE 512UL
+
+#define UBL_SIGN_START 1
+#define UBL_SIGN_COUNT 24
+#define UBL_MAGIC_NUM 0xA1ACED00
+#define UBL_ENTRY_POINT 0x00000100
+#define UBL_START_BLOCK 0x00000075
+#define UBL_BLOCK_OFFSET 0x0000000A
+
+#define UBOOT_SIGN_START 25
+#define UBOOT_SIGN_COUNT 26
+#define UBOOT_MAGIC_NUM 0xA1ACED66
+#define UBOOT_LOAD_ADDRESS 0x81080000
+
+#define PART1_LBA_OFFSET 0x000001C6
+#define DEV_NAME "/dev/mmcblk0"
+#define UBL_NAME "UBL.bin"
+#define UBOOT_NAME "u-boot.bin"
+#define ENV_CONFIG_NAME "config.txt"
+#define ENV_OFFSET (51 << 9)
+#define ENV_SIZE (16 << 10) /* 16KiB */
+
+struct env_t {
+ uint32 crc;
+ char data[ENV_SIZE-4];
+};
+
+uint8 ubl_signature[BLOCK_SIZE];
+uint8 uboot_signature[BLOCK_SIZE];
+char readbuf[BLOCK_SIZE];
+
+static void print_hex(uint8 *buf, int len);
+static int get_file_size(char *fname);
+static int write_file(int devfd, char *fname);
+static uint32 get_le32(uint8 *buf);
+static int write_env_file(char *fname, char *data);
+extern uint32 crc32(uint32, const unsigned char *, uint32);
+
+static int verbose;
+static char *dev_name = DEV_NAME;
+static char *ubl_name = UBL_NAME;
+static char *uboot_name = UBOOT_NAME;
+static char *env_name = ENV_CONFIG_NAME;
+static struct env_t default_env;
+
+static void usage(void)
+{
+ printf("Usage : uflash [options]\r\n");
+ printf("\t-d DEVNAME - Block device Name/Node (%s)\r\n", DEV_NAME);
+ printf("\t-u UBL_FILE - UBL File Name (%s)\r\n", UBL_NAME);
+ printf("\t-b UBOOT_FILE - UBoot File Name (%s)\r\n", UBOOT_NAME);
+ printf("\t-c CONFIG_FILE - UBoot File Name (%s)\r\n", ENV_CONFIG_NAME);
+ printf("\t-e UBOOT_ENTRY - UBoot Entry Point (0x%X)\r\n",
+ UBOOT_LOAD_ADDRESS);
+ printf("\t-l UBOOT_LOAD - UBoot Load Address (0x%X)\r\n",
+ UBOOT_LOAD_ADDRESS);
+ printf("\r\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int i, devfd, c, readlen;
+ int req_blocks, part1_offset;
+ int ubl_size, uboot_size;
+ struct rbl_header *rblp;
+ unsigned int uboot_load_address, uboot_entry_point;
+
+ uboot_load_address = uboot_entry_point = UBOOT_LOAD_ADDRESS;
+
+ while ((c = getopt(argc, argv, "?hvd:u:b:l:e:")) >= 0) {
+ switch (c) {
+ case 'd':
+ dev_name = optarg;
+ break;
+ case 'u':
+ ubl_name = optarg;
+ break;
+ case 'c':
+ env_name = optarg;
+ break;
+ case 'l':
+ uboot_load_address = strtoul(optarg, NULL, 16);
+ break;
+ case 'e':
+ uboot_entry_point = strtoul(optarg, NULL, 16);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'b':
+ uboot_name = optarg;
+ break;
+ case 'h':
+ case '?':
+ usage();
+ return 0;
+ }
+ }
+
+ /* Open the SD/MMC Device in Read-Write Mode */
+ devfd = open(dev_name, O_RDWR);
+ if (devfd <= 0) {
+ fprintf(stderr, "Open Device %s : %s\n",
+ dev_name, strerror(errno));
+ usage();
+ exit(-1);
+ }
+
+ /* Read Master Boot Record - MBR */
+ readlen = read(devfd, readbuf, BLOCK_SIZE);
+ if (readlen < 0) {
+ fprintf(stderr, "Read Device %s : %s\n",
+ dev_name, strerror(errno));
+ }
+
+ if (verbose > 2) {
+ printf("====================Master Boot "
+ "Record====================\n");
+ print_hex((uint8 *)readbuf, BLOCK_SIZE);
+ printf("================================"
+ "==========================\n");
+ }
+
+ /* Get UBL file size and round it to upper 512 byte boundary */
+ ubl_size = get_file_size(ubl_name);
+ if (ubl_size < 0) {
+ close(devfd);
+ return -1;
+ }
+ ubl_size = (ubl_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1);
+ verbose_printf("UBL Size %d\n", ubl_size);
+
+ /* Get U-boot file size and round it to upper 512 byte boundary */
+ uboot_size = get_file_size(uboot_name);
+ if (uboot_size <= 0) {
+ fprintf(stderr, "Invalid U-Boot Size %d\n", uboot_size);
+ close(devfd);
+ return -1;
+ }
+ uboot_size = (uboot_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1);
+ verbose_printf("U-Boot Size %d\n", uboot_size);
+
+ /* Get first partition start address offset from Master Boot Record */
+ part1_offset = get_le32((uint8 *)&readbuf[PART1_LBA_OFFSET]);
+ verbose_printf("First partition starts at %d(%ld)\n", part1_offset,
+ (part1_offset * BLOCK_SIZE));
+
+ /* Add MBR + UBL Size + Uboot Size */
+ req_blocks = UBL_START_BLOCK + (ubl_size / BLOCK_SIZE) +
+ UBL_BLOCK_OFFSET + (uboot_size / BLOCK_SIZE) + 1;
+ printf("Required Blocks %d, Available Blocks %d\n", req_blocks,
+ part1_offset - 1);
+
+ /* Return if the card does not have enough space for writing */
+ if (req_blocks > part1_offset) {
+ fprintf(stderr, "Not enough space left for flashing "
+ "UBL and U-boot\n");
+ fprintf(stderr, "Make sure that the First Partition Starts "
+ "after %d sectors\n", req_blocks);
+ close(devfd);
+ return -1;
+ }
+
+ /* Generate UBL Signature */
+ rblp = (struct rbl_header *)ubl_signature;
+ memset(rblp, 0, sizeof(struct rbl_header));
+ rblp->magic_num = UBL_MAGIC_NUM;
+ rblp->entry_point = UBL_ENTRY_POINT;
+ rblp->num_blocks = ubl_size / BLOCK_SIZE;
+ rblp->start_block = UBL_START_BLOCK;
+
+ if (verbose > 1) {
+ printf("UBL Magic Number : %08x\n", rblp->magic_num);
+ printf("UBL Entry Point : %08x\n", rblp->entry_point);
+ printf("UBL Number of Blocks : %08x\n", rblp->num_blocks);
+ printf("UBL Starting Block : %08x\n", rblp->start_block);
+ printf("UBL Load Address : %08x\n", rblp->load_address);
+ }
+
+ /* Write UBL Signature */
+ verbose_printf("Writing UBL Signature\n");
+ lseek(devfd, (BLOCK_SIZE * UBL_SIGN_START), SEEK_SET);
+ for (i = UBL_SIGN_START; i < (UBL_SIGN_COUNT + UBL_SIGN_START); i++) {
+ write(devfd, rblp, BLOCK_SIZE);
+ }
+
+ /* Write UBL Binary */
+ verbose_printf("Writing UBL\n");
+ lseek(devfd, (BLOCK_SIZE * rblp->start_block), SEEK_SET);
+ write_file(devfd, ubl_name);
+
+ /* Generate U-boot signature */
+ rblp = (struct rbl_header *)uboot_signature;
+ memset(rblp, 0, sizeof(struct rbl_header));
+ rblp->magic_num = UBOOT_MAGIC_NUM;
+ rblp->entry_point = uboot_entry_point;
+ rblp->num_blocks = uboot_size / BLOCK_SIZE;
+ rblp->start_block = UBL_START_BLOCK + (ubl_size / BLOCK_SIZE) +
+ UBL_BLOCK_OFFSET;
+ rblp->load_address = uboot_load_address;
+
+ if (verbose > 1) {
+ printf("U-Boot Magic Number : %08x\n", rblp->magic_num);
+ printf("U-Boot Entry Point : %08x\n", rblp->entry_point);
+ printf("U-Boot Number of Blocks : %08x\n", rblp->num_blocks);
+ printf("U-Boot Starting Block : %08x\n", rblp->start_block);
+ printf("Load U-Boot Address : %08x\n", rblp->load_address);
+ }
+
+ /* Write U-Boot Signature */
+ verbose_printf("Writing U-Boot Signature\n");
+ lseek(devfd, (BLOCK_SIZE * UBOOT_SIGN_START), SEEK_SET);
+ for (i = UBOOT_SIGN_START; i < (UBOOT_SIGN_COUNT + UBOOT_SIGN_START);
+ i++) {
+ write(devfd, rblp, BLOCK_SIZE);
+ }
+
+ verbose_printf("Writing Environment Settings\n");
+ memset(&default_env, 0, sizeof(default_env));
+ if (write_env_file(env_name, default_env.data) < 0) {
+ close(devfd);
+ return -1;
+ }
+ default_env.crc = crc32(0, (unsigned char *)default_env.data,
+ sizeof(default_env.data));
+
+ lseek(devfd, ENV_OFFSET, SEEK_SET);
+ write(devfd, &default_env, ENV_SIZE);
+
+ /* Write U-Boot File */
+ lseek(devfd, (BLOCK_SIZE * rblp->start_block), SEEK_SET);
+ verbose_printf("Writing U-Boot\n");
+ write_file(devfd, uboot_name);
+
+ printf("Done...\n");
+ close(devfd);
+ return 0;
+}
+
+static void print_hex(uint8 *buf, int len)
+{
+ int i, j;
+ for (i = 0 ; i < len; i += 16) {
+ printf("%08x : ", i);
+ for (j = i ; (j < (i+16)) && (j < len); j++) {
+ printf("%02x,", buf[j]);
+ }
+ printf(" ");
+ for (j = i ; (j < (i+16)) && (j < len); j++) {
+ if ((buf[j] > 0x20) && (buf[j] < 0x7F)) {
+ printf("%c", buf[j]);
+ } else {
+ printf(".");
+ }
+ }
+ printf("\n");
+ }
+}
+
+static int get_file_size(char *fname)
+{
+ FILE *fp;
+ int size;
+
+ fp = fopen(fname, "rb");
+ if (fp == NULL) {
+ fprintf(stdout, "File %s Open Error : %s\n",
+ fname, strerror(errno));
+ return -1;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+ fclose(fp);
+
+ return size;
+}
+
+static int write_file(int devfd, char *fname)
+{
+ FILE *fp;
+ int readlen;
+
+ fp = fopen(fname, "rb");
+ if (fp == NULL) {
+ fprintf(stderr, "File %s Open Error: %s",
+ fname, strerror(errno));
+ return -1;
+ }
+
+ while ((readlen = fread(readbuf, 1, BLOCK_SIZE, fp)) > 0) {
+ if (readlen < BLOCK_SIZE) {
+ memset(&readbuf[readlen], 0, BLOCK_SIZE-readlen);
+ }
+ write(devfd, readbuf, BLOCK_SIZE);
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
+static uint32 get_le32(uint8 *buf)
+{
+ return (uint32)(((uint32)buf[0]) |
+ ((uint32)buf[1] << 8) |
+ ((uint32)buf[2] << 16) |
+ ((uint32)buf[3] << 24));
+}
+
+static int write_env_file(char *fname, char *data)
+{
+ FILE *fp;
+
+ fp = fopen(fname, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "File %s Open Error: %s",
+ fname, strerror(errno));
+ return -1;
+ }
+
+ while (fgets(readbuf, BLOCK_SIZE, fp) != NULL) {
+ char *str;
+ if ((str = strchr((char *)&readbuf[0], '\r')) != NULL)
+ *str = '\0';
+ if ((str = strchr((char *)&readbuf[0], '\n')) != NULL)
+ *str = '\0';
+ strcpy(data, readbuf);
+ data += (strlen(data)+1);
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
--
1.6.0.6
More information about the U-Boot
mailing list