diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2007-07-05 18:02:13 +0200 |
---|---|---|
committer | Sascha Hauer <sha@octopus.labnet.pengutronix.de> | 2007-07-05 18:02:13 +0200 |
commit | 4b07af6730d2811363f158f5175138116038f7b9 (patch) | |
tree | 206044270884f80204a2da69e02ca3b6f5803185 /commands | |
parent | d08c60e9d77dc0f83946cd702d383451865e66dd (diff) | |
download | barebox-4b07af6730d2811363f158f5175138116038f7b9.tar.gz barebox-4b07af6730d2811363f158f5175138116038f7b9.tar.xz |
svn_rev_643
structure cleanup
Diffstat (limited to 'commands')
-rw-r--r-- | commands/Kconfig | 152 | ||||
-rw-r--r-- | commands/Makefile | 18 | ||||
-rw-r--r-- | commands/bootm.c | 1043 | ||||
-rw-r--r-- | commands/clear.c | 15 | ||||
-rw-r--r-- | commands/echo.c | 82 | ||||
-rw-r--r-- | commands/edit.c | 486 | ||||
-rw-r--r-- | commands/environment.c | 236 | ||||
-rw-r--r-- | commands/exec.c | 44 | ||||
-rw-r--r-- | commands/fs.c | 391 | ||||
-rw-r--r-- | commands/go.c | 79 | ||||
-rw-r--r-- | commands/loadb.c | 651 | ||||
-rw-r--r-- | commands/loads.c | 423 | ||||
-rw-r--r-- | commands/mem.c | 705 | ||||
-rw-r--r-- | commands/meminfo.c | 15 | ||||
-rw-r--r-- | commands/memtest.c | 348 | ||||
-rw-r--r-- | commands/reset.c | 16 | ||||
-rw-r--r-- | commands/sleep.c | 30 |
17 files changed, 4734 insertions, 0 deletions
diff --git a/commands/Kconfig b/commands/Kconfig new file mode 100644 index 0000000000..00127932be --- /dev/null +++ b/commands/Kconfig @@ -0,0 +1,152 @@ +menu "Commands " + +menu "scripting " + +config CMD_EDIT + bool + prompt "edit" + +config CMD_EXEC + bool + prompt "exec" + +config CMD_SLEEP + bool + prompt "sleep" + +config CMD_ENVIRONMENT + bool + prompt "saveenv / loadenv" + +config CMD_HELP + bool + default y + prompt "help" + +endmenu + + +menu "console " + +config CMD_CLEAR + bool + prompt "clear" + +config CMD_CONSOLE + bool + prompt "coninfo" + +config CMD_ECHO + bool + prompt "echo" + +config CMD_SPLASH + bool + prompt "splash" + +endmenu + + +menu "i2c " + +config CMD_I2C + bool + prompt "i2c" + +endmenu + + +menu "memory " + +config CMD_LOADB + select CRC16 + bool + prompt "loadb" + +config CMD_LOADS + bool + prompt "loads" + +config CMD_SAVES + bool + depends on CMD_LOADS + prompt "saves" + +config CMD_MEMINFO + bool + prompt "meminfo" + +config CMD_MEMORY + bool + prompt "md, mm, mw and several others" + +config CMD_MTEST + bool + prompt "mtest" + +config CMD_MTEST_ALTERNATIVE + bool + depends on CMD_MTEST + prompt "alternative mtest implementation" + +config CMD_MTEST_START + hex + depends on CMD_MTEST + prompt "mtest start address" + +config CMD_MTEST_END + hex + depends on CMD_MTEST + prompt "mtest end address" + +endmenu + + +menu "network " + +config CMD_MII + bool + prompt "mii" + +endmenu + + +menu "flash " + +config CMD_FLASH + bool + prompt "protect/erase/flinfo" + +endmenu + + +menu "booting " + +config CMD_BOOTM + bool + select CRC32 + prompt "bootm" + +config CMD_BOOTM_ZLIB + bool + depends on CMD_BOOTM + select ZLIB + prompt "bootm with zlib support" + +config CMD_BOOTM_BZLIB + bool + depends on CMD_BOOTM + select BZLIB + prompt "bootm with bzlib support" + +config CMD_RESET + bool + prompt "reset" + +config CMD_GO + bool + prompt "go" + +endmenu + +endmenu diff --git a/commands/Makefile b/commands/Makefile new file mode 100644 index 0000000000..9a60914103 --- /dev/null +++ b/commands/Makefile @@ -0,0 +1,18 @@ +obj-$(CONFIG_CMD_BOOTM) += bootm.o +obj-$(CONFIG_CMD_LOADB) += loadb.o xyzModem.o +obj-$(CONFIG_CMD_LOADS) += loads.o +obj-$(CONFIG_CMD_ECHO) += echo.o +#obj-$(CONFIG_CMD_FLASH) += flash.o +obj-$(CONFIG_CMD_MEMORY) += mem.o +obj-$(CONFIG_CMD_MII) += mii.o +obj-$(CONFIG_CMD_I2C) += i2c.o +obj-$(CONFIG_CMD_LOADS) += s_record.o +obj-$(CONFIG_CMD_SPLASH) += splash.o +obj-$(CONFIG_CMD_MTEST) += memtest.o +obj-$(CONFIG_CMD_EDIT) += edit.o +obj-$(CONFIG_CMD_EXEC) += exec.o +obj-$(CONFIG_CMD_SLEEP) += sleep.o +obj-$(CONFIG_CMD_RESET) += reset.o +obj-$(CONFIG_CMD_GO) += go.o +obj-$(CONFIG_CMD_ENVIRONMENT) += environment.o +obj-y += fs.o diff --git a/commands/bootm.c b/commands/bootm.c new file mode 100644 index 0000000000..02ddf20fdb --- /dev/null +++ b/commands/bootm.c @@ -0,0 +1,1043 @@ +/* + * (C) Copyright 2000-2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Boot support + */ +#include <common.h> +#include <watchdog.h> +#include <driver.h> +#include <command.h> +#include <image.h> +#include <malloc.h> +#include <zlib.h> +#include <bzlib.h> +#include <environment.h> +#include <asm/byteorder.h> +#include <xfuncs.h> +#include <getopt.h> +#include <fcntl.h> +#include <fs.h> +#include <errno.h> +#include <boot.h> + + /*cmd_boot.c*/ + +#if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP) +#include <rtc.h> +#endif + +#ifdef CONFIG_HUSH_PARSER +#include <hush.h> +#endif + +#ifdef CONFIG_SHOW_BOOT_PROGRESS +# include <status_led.h> +# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg) +#else +# define SHOW_BOOT_PROGRESS(arg) +#endif + +#ifdef CFG_INIT_RAM_LOCK +#include <asm/cache.h> +#endif + +#ifdef CONFIG_LOGBUFFER +#include <logbuff.h> +#endif + +/* + * Some systems (for example LWMON) have very short watchdog periods; + * we must make sure to split long operations like memmove() or + * crc32() into reasonable chunks. + */ +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +# define CHUNKSZ (64 * 1024) +#endif + +#ifdef CONFIG_CMD_BOOTM_ZLIB +int gunzip (void *, int, unsigned char *, unsigned long *); + +static void *zalloc(void *, unsigned, unsigned); +static void zfree(void *, void *, unsigned); +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_IMI) +static int image_info (unsigned long addr); +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_IMLS) +#include <flash.h> +static int do_imls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +#endif + +static void print_type (image_header_t *hdr); + +#ifdef __I386__ +image_header_t *fake_header(image_header_t *hdr, void *ptr, int size); +#endif + +/* + * Continue booting an OS image; caller already has: + * - copied image header to global variable `header' + * - checked header magic number, checksums (both header & image), + * - verified image architecture (PPC) and type (KERNEL or MULTI), + * - loaded (first part of) image to header load address, + * - disabled interrupts. + */ +typedef void boot_os_Fcn (cmd_tbl_t *cmdtp, int flag, + int argc, char *argv[], + ulong addr, /* of image to boot */ + ulong *len_ptr, /* multi-file image length table */ + int verify); /* getenv("verify")[0] != 'n' */ + +#ifdef DEBUG +extern int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +#endif + +#ifdef CONFIG_SILENT_CONSOLE +static void fixup_silent_linux (void); +#endif +#if (CONFIG_COMMANDS & CFG_CMD_ELF) +int do_bootvx ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[] ); +int do_bootelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[] ); +#endif /* CFG_CMD_ELF */ +#ifdef CONFIG_LYNXKDI +extern void lynxkdi_boot( image_header_t * ); +#endif + +#ifndef CFG_BOOTM_LEN +#define CFG_BOOTM_LEN 0x800000 /* use 8MByte as default max gunzip size */ +#endif + +#ifdef CONFIG_OF_FLAT_TREE +#define OPT_OFTREE "o:" +#else +#define OPT_OFTREE +#endif + +int relocate_image(image_header_t *hdr, void *load_address) +{ + unsigned long data = (unsigned long)(hdr + 1); + unsigned long len = ntohl(hdr->ih_size); + int ret; + +#if defined CONFIG_CMD_BOOTM_ZLIB || defined CONFIG_CMD_BOOTM_BZLIB + uint unc_len = CFG_BOOTM_LEN; +#endif + + switch (hdr->ih_comp) { + case IH_COMP_NONE: + if(ntohl(hdr->ih_load) == data) { + printf (" XIP ... "); + } else { + memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); + } + break; +#ifdef CONFIG_CMD_BOOTM_ZLIB + case IH_COMP_GZIP: + printf (" Uncompressing ... "); + if (gunzip (load_address, unc_len, + (uchar *)data, &len) != 0) + return -1; + break; +#endif +#ifdef CONFIG_CMD_BOOTM_BZLIB + case IH_COMP_BZIP2: + printf (" Uncompressing ... "); + /* + * If we've got less than 4 MB of malloc() space, + * use slower decompression algorithm which requires + * at most 2300 KB of memory. + */ + ret = BZ2_bzBuffToBuffDecompress (load_address, + &unc_len, (char *)data, len, + CFG_MALLOC_LEN < (4096 * 1024), 0); + if (ret != BZ_OK) + return -1; + break; +#endif + default: + printf ("Unimplemented compression type %d\n", hdr->ih_comp); + return -1; + } + + return 0; +} + +image_header_t *map_image(const char *filename, int verify) +{ + int fd; + uint32_t checksum, len; + void *data; + image_header_t *header, *tmp_header; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + printf("could not open: %s\n", errno_str()); + return NULL; + } + + header = xmalloc(sizeof(image_header_t)); + + if (read(fd, header, sizeof(image_header_t)) < 0) { + printf("could not read: %s\n", errno_str()); + goto err_out; + } + + if (ntohl(header->ih_magic) != IH_MAGIC) { + puts ("Bad Magic Number\n"); + goto err_out; + } + + checksum = ntohl(header->ih_hcrc); + header->ih_hcrc = 0; + + if (crc32 (0, (uchar *)header, sizeof(image_header_t)) != checksum) { + puts ("Bad Header Checksum\n"); + goto err_out; + } + len = ntohl(header->ih_size); + + tmp_header = realloc(header, sizeof(image_header_t) + len); + if (!tmp_header) + goto err_out; + header = tmp_header; + + data = (void *)(header + 1); + + if (read(fd, data, len) < 0) { + printf("could not read: %s\n", errno_str()); + goto err_out; + } + + if (verify) { + puts (" Verifying Checksum ... "); + if (crc32 (0, data, len) != ntohl(header->ih_dcrc)) { + printf ("Bad Data CRC\n"); + goto err_out; + } + puts ("OK\n"); + } + + print_image_hdr (header); + + close(fd); + + return header; +err_out: + close(fd); + free(header); + return NULL; +} + +int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong iflag; + int verify = 1; + int opt; + char *initrd = NULL; + image_header_t *os_header; + image_header_t *initrd_header = NULL; +#ifdef CONFIG_OF_FLAT_TREE + char *oftree = NULL; +#endif + int ignore_load_address = 0; + + getopt_reset(); + + while((opt = getopt(argc, argv, "r:ni" OPT_OFTREE)) > 0) { + switch(opt) { + case 'r': + initrd = optarg; + break; + case 'n': + verify = 0; + break; + case 'i': + ignore_load_address = 1; + break; +#ifdef CONFIG_OF_FLAT_TREE + case 'o': + oftree = optarg; + break; +#endif + default: + return 1; + } + } + + if (optind == argc) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + os_header = map_image(argv[optind], verify); + if (!os_header) + return 1; + + if (os_header->ih_arch != IH_CPU) { + printf ("Unsupported Architecture 0x%x\n", os_header->ih_arch); + goto err_out; + } + + if (initrd) { + initrd_header = map_image(initrd, verify); + if (!initrd_header) + goto err_out; + } +#if 0 + switch (os_header->ih_type) { + case IH_TYPE_STANDALONE: + name = "Standalone Application"; + /* A second argument overwrites the load address */ + if (argc > 2) { + os_header->ih_load = htonl(simple_strtoul(argv[2], NULL, 16)); + } + break; + case IH_TYPE_KERNEL: + name = "Kernel Image"; + break; + case IH_TYPE_MULTI: + name = "Multi-File Image"; + len = ntohl(len_ptr[0]); + /* OS kernel is always the first image */ + data += 8; /* kernel_len + terminator */ + for (i=1; len_ptr[i]; ++i) + data += 4; + break; + default: printf ("Wrong Image Type for %s command\n", cmdtp->name); + return 1; + } +#endif + /* + * We have reached the point of no return: we are going to + * overwrite all exception vector code, so we cannot easily + * recover from any failures any more... + */ + + iflag = disable_interrupts(); + + puts ("OK\n"); + + switch (os_header->ih_os) { + default: /* handled by (original) Linux case */ + case IH_OS_LINUX: +#ifdef CONFIG_SILENT_CONSOLE + fixup_silent_linux(); +#endif +#ifdef CONFIG_OF_FLAT_TREE + do_bootm_linux(os_header, initrd_header, oftree); +#else + do_bootm_linux(os_header, initrd_header); +#endif + break; +#ifdef CONFIG_NETBSD + case IH_OS_NETBSD: + do_bootm_netbsd (cmdtp, flag, argc, argv, + addr, len_ptr, verify); + break; +#endif + +#ifdef CONFIG_LYNXKDI + case IH_OS_LYNXOS: + do_bootm_lynxkdi (cmdtp, flag, argc, argv, + addr, len_ptr, verify); + break; +#endif + +#ifdef CONFIG_RTEMS + case IH_OS_RTEMS: + do_bootm_rtems (cmdtp, flag, argc, argv, + addr, len_ptr, verify); + break; +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_ELF) + case IH_OS_VXWORKS: + do_bootm_vxworks (cmdtp, flag, argc, argv, + addr, len_ptr, verify); + break; + case IH_OS_QNX: + do_bootm_qnxelf (cmdtp, flag, argc, argv, + addr, len_ptr, verify); + break; +#endif /* CFG_CMD_ELF */ +#ifdef CONFIG_ARTOS + case IH_OS_ARTOS: + do_bootm_artos (cmdtp, flag, argc, argv, + addr, len_ptr, verify); + break; +#endif + } + + SHOW_BOOT_PROGRESS (-9); +#ifdef DEBUG + puts ("\n## Control returned to monitor - resetting...\n"); + do_reset (cmdtp, flag, argc, argv); +#endif + +err_out: + if (os_header) + free(os_header); + if (initrd_header) + free(initrd_header); + return 1; +} + +U_BOOT_CMD_START(bootm) + .maxargs = CONFIG_MAXARGS, + .cmd = do_bootm, + .usage = "boot application image from memory", + U_BOOT_CMD_HELP( + "[addr [arg ...]]\n - boot application image stored in memory\n" + "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n" + "\t'arg' can be the address of an initrd image\n" +#ifdef CONFIG_OF_FLAT_TREE + "\tWhen booting a Linux kernel which requires a flat device-tree\n" + "\ta third argument is required which is the address of the of the\n" + "\tdevice-tree blob. To boot that kernel without an initrd image,\n" + "\tuse a '-' for the second argument. If you do not pass a third\n" + "\ta bd_info struct will be passed instead\n" +#endif + ) +U_BOOT_CMD_END + +#ifdef CONFIG_SILENT_CONSOLE +static void +fixup_silent_linux () +{ + char buf[256], *start, *end; + char *cmdline = getenv ("bootargs"); + + /* Only fix cmdline when requested */ + if (!(gd->flags & GD_FLG_SILENT)) + return; + + debug ("before silent fix-up: %s\n", cmdline); + if (cmdline) { + if ((start = strstr (cmdline, "console=")) != NULL) { + end = strchr (start, ' '); + strncpy (buf, cmdline, (start - cmdline + 8)); + if (end) + strcpy (buf + (start - cmdline + 8), end); + else + buf[start - cmdline + 8] = '\0'; + } else { + strcpy (buf, cmdline); + strcat (buf, " console="); + } + } else { + strcpy (buf, "console="); + } + + setenv ("bootargs", buf); + debug ("after silent fix-up: %s\n", buf); +} +#endif /* CONFIG_SILENT_CONSOLE */ + +#ifdef CONFIG_NETBSD +static void +do_bootm_netbsd (cmd_tbl_t *cmdtp, int flag, + int argc, char *argv[], + ulong addr, + ulong *len_ptr, + int verify) +{ + image_header_t *hdr = &header; +#if 0 + void (*loader)(bd_t *, image_header_t *, char *, char *); +#endif + image_header_t *img_addr; + char *consdev; + char *cmdline; + + + /* + * Booting a (NetBSD) kernel image + * + * This process is pretty similar to a standalone application: + * The (first part of an multi-) image must be a stage-2 loader, + * which in turn is responsible for loading & invoking the actual + * kernel. The only differences are the parameters being passed: + * besides the board info strucure, the loader expects a command + * line, the name of the console device, and (optionally) the + * address of the original image header. + */ + + img_addr = 0; + if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) + img_addr = (image_header_t *) addr; + + + consdev = ""; +#if defined (CONFIG_8xx_CONS_SMC1) + consdev = "smc1"; +#elif defined (CONFIG_8xx_CONS_SMC2) + consdev = "smc2"; +#elif defined (CONFIG_8xx_CONS_SCC2) + consdev = "scc2"; +#elif defined (CONFIG_8xx_CONS_SCC3) + consdev = "scc3"; +#endif + + if (argc > 2) { + ulong len; + int i; + + for (i=2, len=0 ; i<argc ; i+=1) + len += strlen (argv[i]) + 1; + cmdline = malloc (len); + + for (i=2, len=0 ; i<argc ; i+=1) { + if (i > 2) + cmdline[len++] = ' '; + strcpy (&cmdline[len], argv[i]); + len += strlen (argv[i]); + } + } else if ((cmdline = (char *)getenv("bootargs")) == NULL) { + cmdline = ""; + } +#if 0 + loader = (void (*)(bd_t *, image_header_t *, char *, char *)) ntohl(hdr->ih_ep); + + printf ("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n", + (ulong)loader); +#endif + SHOW_BOOT_PROGRESS (15); + + /* + * NetBSD Stage-2 Loader Parameters: + * r3: ptr to board info data + * r4: image address + * r5: console device + * r6: boot args string + */ +#if 0 + (*loader) (gd->bd, img_addr, consdev, cmdline); +#else +#warning NetBSD Support is broken +#endif +} +#endif + +#ifdef CONFIG_ARTOS + +/* Function that returns a character from the environment */ +extern uchar (*env_get_char)(int); + +static void +do_bootm_artos (cmd_tbl_t *cmdtp, int flag, + int argc, char *argv[], + ulong addr, + ulong *len_ptr, + int verify) +{ + ulong top; + char *s, *cmdline; + char **fwenv, **ss; + int i, j, nxt, len, envno, envsz; + bd_t *kbd; + void (*entry)(bd_t *bd, char *cmdline, char **fwenv, ulong top); + image_header_t *hdr = &header; + + /* + * Booting an ARTOS kernel image + application + */ + + /* this used to be the top of memory, but was wrong... */ + + /* get stack pointer */ + asm volatile ("mr %0,1" : "=r"(top) ); + + debug ("## Current stack ends at 0x%08lX ", top); + + top -= 2048; /* just to be sure */ + if (top > CFG_BOOTMAPSZ) + top = CFG_BOOTMAPSZ; + top &= ~0xF; + + debug ("=> set upper limit to 0x%08lX\n", top); + + /* first check the artos specific boot args, then the linux args*/ + if ((s = getenv("abootargs")) == NULL && (s = getenv("bootargs")) == NULL) + s = ""; + + /* get length of cmdline, and place it */ + len = strlen(s); + top = (top - (len + 1)) & ~0xF; + cmdline = (char *)top; + debug ("## cmdline at 0x%08lX ", top); + strcpy(cmdline, s); + + /* copy bdinfo */ + top = (top - sizeof(bd_t)) & ~0xF; + debug ("## bd at 0x%08lX ", top); + kbd = (bd_t *)top; + memcpy(kbd, gd->bd, sizeof(bd_t)); + + /* first find number of env entries, and their size */ + envno = 0; + envsz = 0; + for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { + for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) + ; + envno++; + envsz += (nxt - i) + 1; /* plus trailing zero */ + } + envno++; /* plus the terminating zero */ + debug ("## %u envvars total size %u ", envno, envsz); + + top = (top - sizeof(char **)*envno) & ~0xF; + fwenv = (char **)top; + debug ("## fwenv at 0x%08lX ", top); + + top = (top - envsz) & ~0xF; + s = (char *)top; + ss = fwenv; + + /* now copy them */ + for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { + for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) + ; + *ss++ = s; + for (j = i; j < nxt; ++j) + *s++ = env_get_char(j); + *s++ = '\0'; + } + *ss++ = NULL; /* terminate */ + + entry = (void (*)(bd_t *, char *, char **, ulong))ntohl(hdr->ih_ep); + (*entry)(kbd, cmdline, fwenv, top); +} +#endif + +int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int rcode = 0; +#ifndef CONFIG_HUSH_PARSER + if (run_command (getenv ("bootcmd"), flag) < 0) rcode = 1; +#else + if (parse_string_outer(getenv("bootcmd"), + FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0 ) rcode = 1; +#endif + return rcode; +} + +U_BOOT_CMD_START(boot) + .maxargs = 1, + .cmd = do_bootd, + .usage = "boot default, i.e., run 'bootcmd'", +U_BOOT_CMD_END + +#if 0 +int do_iminfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int arg; + ulong addr; + int rcode=0; + + if (argc < 2) { + return image_info (load_addr); + } + + for (arg=1; arg <argc; ++arg) { + addr = simple_strtoul(argv[arg], NULL, 16); + if (image_info (addr) != 0) rcode = 1; + } + return rcode; +} + +static int image_info (ulong addr) +{ + ulong data, len, checksum; + image_header_t *hdr = &header; + + printf ("\n## Checking Image at %08lx ...\n", addr); + + /* Copy header so we can blank CRC field for re-calculation */ + memmove (&header, (char *)addr, sizeof(image_header_t)); + + if (ntohl(hdr->ih_magic) != IH_MAGIC) { + puts (" Bad Magic Number\n"); + return 1; + } + + data = (ulong)&header; + len = sizeof(image_header_t); + + checksum = ntohl(hdr->ih_hcrc); + hdr->ih_hcrc = 0; + + if (crc32 (0, (uchar *)data, len) != checksum) { + puts (" Bad Header Checksum\n"); + return 1; + } + + /* for multi-file images we need the data part, too */ + print_image_hdr ((image_header_t *)addr); + + data = addr + sizeof(image_header_t); + len = ntohl(hdr->ih_size); + + puts (" Verifying Checksum ... "); + if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) { + puts (" Bad Data CRC\n"); + return 1; + } + puts ("OK\n"); + return 0; +} + +U_BOOT_CMD( + iminfo, CONFIG_MAXARGS, 1, do_iminfo, + "iminfo - print header information for application image\n", + "addr [addr ...]\n" + " - print header information for application image starting at\n" + " address 'addr' in memory; this includes verification of the\n" + " image contents (magic number, header and payload checksums)\n" +); + +#endif /* CFG_CMD_IMI */ + +#if (CONFIG_COMMANDS & CFG_CMD_IMLS) +#if 0 +/*----------------------------------------------------------------------- + * List all images found in flash. + */ +int do_imls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + flash_info_t *info; + int i, j; + image_header_t *hdr; + ulong data, len, checksum; + + for (i=0, info=&flash_info[0]; i<CFG_MAX_FLASH_BANKS; ++i, ++info) { + if (info->flash_id == FLASH_UNKNOWN) + goto next_bank; + for (j=0; j<info->sector_count; ++j) { + + if (!(hdr=(image_header_t *)info->start[j]) || + (ntohl(hdr->ih_magic) != IH_MAGIC)) + goto next_sector; + + /* Copy header so we can blank CRC field for re-calculation */ + memmove (&header, (char *)hdr, sizeof(image_header_t)); + + checksum = ntohl(header.ih_hcrc); + header.ih_hcrc = 0; + + if (crc32 (0, (uchar *)&header, sizeof(image_header_t)) + != checksum) + goto next_sector; + + printf ("Image at %08lX:\n", (ulong)hdr); + print_image_hdr( hdr ); + + data = (ulong)hdr + sizeof(image_header_t); + len = ntohl(hdr->ih_size); + + puts (" Verifying Checksum ... "); + if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) { + puts (" Bad Data CRC\n"); + } + puts ("OK\n"); +next_sector: ; + } +next_bank: ; + } + + return (0); +} + +U_BOOT_CMD( + imls, 1, 1, do_imls, + "imls - list all images found in flash\n", + "\n" + " - Prints information about all images found at sector\n" + " boundaries in flash.\n" +); +#endif /* CFG_CMD_IMLS */ +#endif + +void +print_image_hdr (image_header_t *hdr) +{ +#if defined(CONFIG_CMD_DATE) || defined(CONFIG_TIMESTAMP) + time_t timestamp = (time_t)ntohl(hdr->ih_time); + struct rtc_time tm; +#endif + + printf (" Image Name: %.*s\n", IH_NMLEN, hdr->ih_name); +#if defined(CONFIG_CMD_DATE) || defined(CONFIG_TIMESTAMP) + to_tm (timestamp, &tm); + printf (" Created: %4d-%02d-%02d %2d:%02d:%02d UTC\n", + tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +#endif /* CONFIG_CMD_DATE, CONFIG_TIMESTAMP */ + puts (" Image Type: "); print_type(hdr); + printf ("\n Data Size: %d Bytes = ", ntohl(hdr->ih_size)); + print_size (ntohl(hdr->ih_size), "\n"); + printf (" Load Address: %08x\n" + " Entry Point: %08x\n", + ntohl(hdr->ih_load), ntohl(hdr->ih_ep)); + + if (hdr->ih_type == IH_TYPE_MULTI) { + int i; + ulong len; + ulong *len_ptr = (ulong *)((ulong)hdr + sizeof(image_header_t)); + + puts (" Contents:\n"); + for (i=0; (len = ntohl(*len_ptr)); ++i, ++len_ptr) { + printf (" Image %d: %8ld Bytes = ", i, len); + print_size (len, "\n"); + } + } +} + + +static void +print_type (image_header_t *hdr) +{ + char *os, *arch, *type, *comp; + + switch (hdr->ih_os) { + case IH_OS_INVALID: os = "Invalid OS"; break; + case IH_OS_NETBSD: os = "NetBSD"; break; + case IH_OS_LINUX: os = "Linux"; break; + case IH_OS_VXWORKS: os = "VxWorks"; break; + case IH_OS_QNX: os = "QNX"; break; + case IH_OS_U_BOOT: os = "U-Boot"; break; + case IH_OS_RTEMS: os = "RTEMS"; break; +#ifdef CONFIG_ARTOS + case IH_OS_ARTOS: os = "ARTOS"; break; +#endif +#ifdef CONFIG_LYNXKDI + case IH_OS_LYNXOS: os = "LynxOS"; break; +#endif + default: os = "Unknown OS"; break; + } + + switch (hdr->ih_arch) { + case IH_CPU_INVALID: arch = "Invalid CPU"; break; + case IH_CPU_ALPHA: arch = "Alpha"; break; + case IH_CPU_ARM: arch = "ARM"; break; + case IH_CPU_AVR32: arch = "AVR32"; break; + case IH_CPU_I386: arch = "Intel x86"; break; + case IH_CPU_IA64: arch = "IA64"; break; + case IH_CPU_MIPS: arch = "MIPS"; break; + case IH_CPU_MIPS64: arch = "MIPS 64 Bit"; break; + case IH_CPU_PPC: arch = "PowerPC"; break; + case IH_CPU_S390: arch = "IBM S390"; break; + case IH_CPU_SH: arch = "SuperH"; break; + case IH_CPU_SPARC: arch = "SPARC"; break; + case IH_CPU_SPARC64: arch = "SPARC 64 Bit"; break; + case IH_CPU_M68K: arch = "M68K"; break; + case IH_CPU_MICROBLAZE: arch = "Microblaze"; break; + case IH_CPU_NIOS: arch = "Nios"; break; + case IH_CPU_NIOS2: arch = "Nios-II"; break; + default: arch = "Unknown Architecture"; break; + } + + switch (hdr->ih_type) { + case IH_TYPE_INVALID: type = "Invalid Image"; break; + case IH_TYPE_STANDALONE:type = "Standalone Program"; break; + case IH_TYPE_KERNEL: type = "Kernel Image"; break; + case IH_TYPE_RAMDISK: type = "RAMDisk Image"; break; + case IH_TYPE_MULTI: type = "Multi-File Image"; break; + case IH_TYPE_FIRMWARE: type = "Firmware"; break; + case IH_TYPE_SCRIPT: type = "Script"; break; + case IH_TYPE_FLATDT: type = "Flat Device Tree"; break; + default: type = "Unknown Image"; break; + } + + switch (hdr->ih_comp) { + case IH_COMP_NONE: comp = "uncompressed"; break; + case IH_COMP_GZIP: comp = "gzip compressed"; break; + case IH_COMP_BZIP2: comp = "bzip2 compressed"; break; + default: comp = "unknown compression"; break; + } + + printf ("%s %s %s (%s)", arch, os, type, comp); +} + +#ifdef CONFIG_ZLIB + +#define ZALLOC_ALIGNMENT 16 + +static void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p; + + size *= items; + size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1); + + p = malloc (size); + + return (p); +} + +static void zfree(void *x, void *addr, unsigned nb) +{ + free (addr); +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + puts ("Error: Bad gzipped data\n"); + return (-1); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + puts ("Error: gunzip out of data in header\n"); + return (-1); + } + + s.zalloc = zalloc; + s.zfree = zfree; +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + s.outcb = (cb_func)WATCHDOG_RESET; +#else + s.outcb = Z_NULL; +#endif /* CONFIG_HW_WATCHDOG */ + + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf ("Error: inflateInit2() returned %d\n", r); + return (-1); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf ("Error: inflate() returned %d\n", r); + return (-1); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); + + return (0); +} +#endif + +#ifdef CONFIG_BZLIB +void bz_internal_error(int errcode) +{ + printf ("BZIP2 internal error %d\n", errcode); +} +#endif /* CONFIG_BZLIB */ + +#ifdef CONFIG_RTEMS +static void +do_bootm_rtems (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], + ulong addr, ulong *len_ptr, int verify) +{ +#if 0 + image_header_t *hdr = &header; + void (*entry_point)(bd_t *); + + entry_point = (void (*)(bd_t *)) ntohl(hdr->ih_ep); + + printf ("## Transferring control to RTEMS (at address %08lx) ...\n", + (ulong)entry_point); +#endif + SHOW_BOOT_PROGRESS (15); + + /* + * RTEMS Parameters: + * r3: ptr to board info data + */ +#if 0 + (*entry_point ) ( gd->bd ); +#else +#warning RTEMS support is broken +#endif +} +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_ELF) +static void +do_bootm_vxworks (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], + ulong addr, ulong *len_ptr, int verify) +{ + image_header_t *hdr = &header; + char str[80]; + + sprintf(str, "%x", ntohl(hdr->ih_ep)); /* write entry-point into string */ + setenv("loadaddr", str); + do_bootvx(cmdtp, 0, 0, NULL); +} + +static void +do_bootm_qnxelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], + ulong addr, ulong *len_ptr, int verify) +{ + image_header_t *hdr = &header; + char *local_args[2]; + char str[16]; + + sprintf(str, "%x", ntohl(hdr->ih_ep)); /* write entry-point into string */ + local_args[0] = argv[0]; + local_args[1] = str; /* and provide it via the arguments */ + do_bootelf(cmdtp, 0, 2, local_args); +} +#endif /* CFG_CMD_ELF */ + +#ifdef CONFIG_LYNXKDI +static void +do_bootm_lynxkdi (cmd_tbl_t *cmdtp, int flag, + int argc, char *argv[], + ulong addr, + ulong *len_ptr, + int verify) +{ + lynxkdi_boot( &header ); +} + +#endif /* CONFIG_LYNXKDI */ diff --git a/commands/clear.c b/commands/clear.c new file mode 100644 index 0000000000..ee7ab07c05 --- /dev/null +++ b/commands/clear.c @@ -0,0 +1,15 @@ +#include <common.h> +#include <command.h> + +int do_clear (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + printf(ANSI_CLEAR_SCREEN); + + return 0; +} + +U_BOOT_CMD_START(clear) + .maxargs = 1, + .cmd = do_clear, + .usage = "clear screen", +U_BOOT_CMD_END diff --git a/commands/echo.c b/commands/echo.c new file mode 100644 index 0000000000..1314f2d971 --- /dev/null +++ b/commands/echo.c @@ -0,0 +1,82 @@ +#include <common.h> +#include <command.h> +#include <fs.h> +#include <fcntl.h> +#include <errno.h> + +static int do_echo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int i, optind = 1; + int fd = stdout, opt, newline = 1; + char *file = NULL; + int oflags = O_WRONLY | O_CREAT; + + /* We can't use getopt() here because we want to + * echo all things we don't understand. + */ + while (optind < argc && *argv[optind] == '-') { + if (!*(argv[optind] + 1) || *(argv[optind] + 2)) + break; + + opt = *(argv[optind] + 1); + switch (opt) { + case 'n': + newline = 0; + break; + case 'a': + oflags |= O_APPEND; + if (optind + 1 < argc) + file = argv[optind + 1]; + else + goto no_optarg_out; + optind++; + break; + case 'o': + oflags |= O_TRUNC; + file = argv[optind + 1]; + if (optind + 1 < argc) + file = argv[optind + 1]; + else + goto no_optarg_out; + optind++; + break; + default: + goto exit_parse; + } + optind++; + } + +exit_parse: + if (file) { + fd = open(file, oflags); + if (fd < 0) { + perror("open"); + return 1; + } + } + + for (i = optind; i < argc; i++) { + if (i > optind) + fputc(fd, ' '); + fputs(fd, argv[i]); + } + + if (newline) + fputc(fd, '\n'); + + if (file) + close(fd); + + return 0; + +no_optarg_out: + printf("option requires an argument -- %c\n", opt); + return 1; +} + +U_BOOT_CMD_START(echo) + .maxargs = CONFIG_MAXARGS, + .cmd = do_echo, + .usage = "echo args to console", +U_BOOT_CMD_END + diff --git a/commands/edit.c b/commands/edit.c new file mode 100644 index 0000000000..902bce28fe --- /dev/null +++ b/commands/edit.c @@ -0,0 +1,486 @@ +#include <common.h> +#include <command.h> +#include <malloc.h> +#include <fs.h> +#include <linux/ctype.h> +#include <fcntl.h> +#include <readkey.h> +#include <errno.h> +#include <xfuncs.h> +#include <linux/stat.h> + +#define TABSPACE 8 + +struct line { + int length; + struct line *next; + struct line *prev; + char *data; +}; + +static struct line *buffer; + +static struct line *lastscrline; + +static int screenwidth = 80; +static int screenheight = 25; + +static int cursx = 0; /* position on screen */ +static int cursy = 0; + +static int textx = 0; /* position in text */ + +static struct line *curline; /* line where the cursor is */ + +static struct line *scrline; /* the first line on screen */ +int scrcol = 0; /* the first column on screen */ + +static void pos(int x, int y) +{ + printf("%c[%d;%dH", 27, y + 1, x + 1); +} + +static char *screenline(char *line, int *pos) +{ + int i, outpos = 0; + static char lbuf[1024]; + + memset(lbuf, 0, 1024); + + if (!line) { + lbuf[0] = '~'; + return lbuf; + } + + for (i = 0; outpos < 1024; i++) { + if (i == textx && pos) + *pos = outpos; + if (!line[i]) + break; + if (line[i] == '\t') { + lbuf[outpos++] = ' '; + while (outpos % TABSPACE) + lbuf[outpos++] = ' '; + continue; + } + lbuf[outpos++] = line[i]; + } + + return lbuf; +} + +static int setpos(char *line, int position) +{ + int i = 0; + int linepos = 0; + + while(line[linepos]) { + if (line[linepos] == '\t') + while ((i + 1) % TABSPACE) + i++; + if (i >= position) + return linepos; + linepos++; + i++; + } + + return linepos; +} + +static void refresh_line(struct line *line, int ypos) +{ + char *str = screenline(line->data, NULL) + scrcol; + pos(0, ypos); + str[screenwidth] = 0; + printf("%s%c[K", str, 27); + pos(cursx, cursy); +} + +static void refresh(int full) +{ + int i; + struct line *l = scrline; + + if (!full) { + if (scrline->next == lastscrline) { + printf("%c[1T", 27); + refresh_line(scrline, 0); + pos(0, screenheight); + printf("%*s", screenwidth, ""); + return; + } + + if (scrline->prev == lastscrline) { + printf("%c[1S", 27); + for (i = 0; i < screenheight - 1; i++) { + l = l->next; + if (!l) + return; + } + refresh_line(l, screenheight - 1); + return; + } + } + + for (i = 0; i < screenheight; i++) { + refresh_line(l, i); + l = l->next; + if (!l) + break; + } + + i++; + while (i < screenheight) { + pos(0, i++); + printf("~"); + } +} + +static void line_free(struct line *line) +{ + free(line->data); + free(line); +} + +static struct line *line_realloc(int len, struct line *line) +{ + int size = 32; + + if (!line) { + line = xzalloc(sizeof(struct line)); + line->data = malloc(32); + } + + while (size < len) + size <<= 1; + + line->data = realloc(line->data, size); + return line; +} + +static int edit_read_file(const char *path) +{ + struct line *line; + struct line *lastline = NULL; + char *filebuffer; + char *linestr; + struct stat s; + + if (!stat(path, &s)) { + filebuffer = read_file(path); + if (!filebuffer) { + printf("could not read %s: %s\n", path, errno_str()); + return -1; + } + + linestr = strtok(filebuffer, "\r\n"); + while (linestr) { + line = line_realloc(strlen(linestr) + 1, NULL); + if (!buffer) + buffer = line; + memcpy(line->data, linestr, strlen(linestr) + 1); + line->prev = lastline; + if (lastline) + lastline->next = line; + line->next = 0; + lastline = line; + linestr = strtok(NULL, "\r\n"); + } + } + + if (!buffer) { + buffer = line_realloc(0, NULL); + buffer->data[0] = 0; + } + + return 0; +} + +static int save_file(const char *path) +{ + struct line *line, *tmp; + int fd; + + fd = open(path, O_WRONLY | O_TRUNC | O_CREAT); + if (fd < 0) { + printf("could not open file for writing: %s\n", errno_str()); + return -1; + } + + line = buffer; + + while(line) { + tmp = line->next; + write(fd, line->data, strlen(line->data)); + write(fd, "\n", 1); + line_free(line); + line = tmp; + } + close(fd); + return 0; +} + +static void insert_char(char c) +{ + int pos = textx; + char *line = curline->data; + int end = strlen(line); + + line_realloc(strlen(curline->data) + 2, curline); + + while (end >= pos) { + line[end + 1] = line[end]; + end--; + } + line[pos] = c; + textx++; + refresh_line(curline, cursy); +} + +static void delete_char(int pos) +{ + char *line = curline->data; + int end = strlen(line); + + while (pos < end) { + line[pos] = line[pos + 1]; + pos++; + } + refresh_line(curline, cursy); +} + +static void split_line(void) +{ + int length = strlen(curline->data + textx); + struct line *newline = line_realloc(length + 1, NULL); + struct line *tmp; + + memcpy(newline->data, curline->data + textx, length + 1); + + curline->data[textx] = 0; + + tmp = curline->next; + curline->next = newline; + newline->prev = curline; + newline->next = tmp; + if (tmp) + tmp->prev = newline; + + textx = 0; + cursy++; + curline = curline->next; + refresh(1); +} + +static void merge_line(struct line *line) +{ + struct line *tmp; + + line_realloc(strlen(line->data) + strlen(line->next->data) + 1, line); + + tmp = line->next; + + line->next = line->next->next; + if (line->next) + line->next->prev = line; + strcat(line->data, tmp->data); + + line_free(tmp); + + refresh(1); +} + +/* not a good idea on slow serial lines */ +/* #define GETWINSIZE */ + +#ifdef GETWINSIZE +static void getwinsize(void) { + int y, yy = 25, xx = 80, i, n, r; + char buf[100]; + char *endp; + + for (y = 25; y < 320; y++) { + pos(y, y); + printf("%c[6n", 27); + i = 0; + while ((r = getc()) != 'R') { + buf[i] = r; + i++; + } + n = simple_strtoul(buf + 2, &endp, 10); + if (n == y + 1) + yy = y + 1; + n = simple_strtoul(endp + 1, NULL, 10); + if (n == y + 1) + xx = y + 1; + } + pos(0,0); + screenheight = yy; + screenwidth = xx; + printf("%d %d\n", xx, yy); + mdelay(1000); +} +#endif + +int do_edit(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + int lastscrcol; + int i; + int linepos; + char c; + + buffer = NULL; + if(edit_read_file(argv[1])) + return 1; + +#ifdef GETWINSIZE + getwinsize(); +#endif + + cursx = 0; + cursy = 0; + textx = 0; + scrcol = 0; + curline = buffer; + scrline = curline; + lastscrline = scrline; + lastscrcol = 0; + + printf("%c[2J", 27); + refresh(1); + + while (1) { + int curlen = strlen(curline->data); + + if (textx > curlen) + textx = curlen; + if (textx < 0) + textx = 0; + + screenline(curline->data, &linepos); + + if (linepos > scrcol + screenwidth) + scrcol = linepos - screenwidth; + + if (scrcol > linepos) + scrcol = linepos; + + cursx = linepos - scrcol; + + while (cursy >= screenheight) { + cursy--; + scrline = scrline->next; + } + + while (cursy < 0) { + cursy++; + scrline = scrline->prev; + } + + if (scrline != lastscrline || scrcol != lastscrcol) + refresh(0); + + lastscrcol = scrcol; + lastscrline = scrline; + pos(cursx, cursy); + + c = read_key(); + switch (c) { + case KEY_UP: + if (!curline->prev) + continue; + + curline = curline->prev; + cursy--; + textx = setpos(curline->data, linepos); + break; + case KEY_DOWN: + if (!curline->next) + continue; + + curline = curline->next; + cursy++; + textx = setpos(curline->data, linepos); + break; + case KEY_RIGHT: + textx++; + break; + case KEY_LEFT: + textx--; + break; + case KEY_HOME: + textx = 0; + break; + case KEY_END: + textx = curlen; + break; + case KEY_PAGEUP: + for (i = 0; i < screenheight - 1; i++) { + if (!curline->prev) + break; + cursy--; + curline = curline->prev; + } + textx = setpos(curline->data, linepos); + break; + case KEY_PAGEDOWN: + for (i = 0; i < screenheight - 1; i++) { + if (!curline->next) + break; + cursy++; + curline = curline->next; + } + textx = setpos(curline->data, linepos); + break; + case KEY_DEL: + if (textx == curlen) { + if (curline->next) + merge_line(curline); + } else + delete_char(textx); + break; + case 13: + case 10: + split_line(); + break; + case 127: + if (textx > 0) { + textx--; + delete_char(textx); + } else { + if (!curline->prev) + break; + curline = curline->prev; + cursy--; + textx = strlen(curline->data); + merge_line(curline); + } + break; + case 4: + save_file(argv[1]); + goto out; + case 3: + goto out; + default: + if ((signed char)c != -1) + insert_char(c); + } + } +out: + printf("%c[2J", 27); + return 0; +} + +static __maybe_unused char cmd_edit_help[] = +"Usage: edit <file>\n" +"This is a very small editor. Its only features are moving the cursor with\n" +"the usual keys and typing characters.\n" +"<ctrl-c> quits the editor without saving,\n" +"<ctrl-d> quits the editor with saving the current file.\n"; + +U_BOOT_CMD_START(edit) + .maxargs = 2, + .cmd = do_edit, + .usage = "edit a file", + U_BOOT_CMD_HELP(cmd_edit_help) +U_BOOT_CMD_END diff --git a/commands/environment.c b/commands/environment.c new file mode 100644 index 0000000000..148b6e9d6e --- /dev/null +++ b/commands/environment.c @@ -0,0 +1,236 @@ +#ifdef __U_BOOT__ +#include <common.h> +#include <command.h> +#include <driver.h> +#include <malloc.h> +#include <errno.h> +#include <fs.h> +#include <fcntl.h> +#include <linux/stat.h> +#include <envfs.h> +#include <xfuncs.h> +#endif + +int envfs_save(char *filename, char *dirname) +{ + DIR *dir; + struct dirent *d; + int malloc_size = 0; + struct stat s; + struct envfs_super super; + void *buf = NULL; + char tmp[PATH_MAX]; + int isize; + int envfd; + struct envfs_inode *inode = NULL; + int fd; + + envfd = open(filename, O_WRONLY); + if (envfd < 0) { + perror("open"); + return -1; + } + + super.magic = ENVFS_MAGIC; + + write(envfd, &super, sizeof(struct envfs_super)); + + dir = opendir(dirname); + if (!dir) { + perror("opendir"); + close(envfd); + return errno; + } + + while ((d = readdir(dir))) { + sprintf(tmp, "%s/%s", dirname, d->d_name); + if (stat(tmp, &s)) { + perror("stat"); + goto out; + } + if (s.st_mode & S_IFDIR) + continue; + + isize = ((s.st_size + 3) & ~3) + sizeof(struct envfs_inode); + if (isize > malloc_size) { + if (buf) + free(buf); + inode = xmalloc(isize); + buf = inode; + malloc_size = isize; + } + fd = open(tmp, O_RDONLY); + if (fd < 0) { + perror("open"); + goto out; + } + if (read(fd, inode->data, s.st_size) < s.st_size) { + perror("read"); + goto out; + } + + close(fd); + inode->magic = ENVFS_INODE_MAGIC; + inode->size = s.st_size; + strcpy(inode->name, d->d_name); /* FIXME: strncpy */ + /* FIXME: calc crc */ + if (write(envfd, inode, isize) < isize) { + perror("write"); + goto out; + } + } + + memset(inode, 0, sizeof(struct envfs_inode)); + inode->magic = ENVFS_END_MAGIC; + if (write(envfd, inode, sizeof(struct envfs_inode)) < sizeof(struct envfs_inode)) { + perror("write"); + goto out; + } +out: + if (buf) + free(buf); + close(envfd); + closedir(dir); + return 0; +} + +#ifdef __U_BOOT__ +int do_saveenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int ret; + char *filename, *dirname; + + printf("saving environment\n"); + if (argc < 3) + dirname = "/env"; + else + dirname = argv[2]; + if (argc < 2) + filename = "/dev/env0"; + else + filename = argv[1]; + + ret = envfs_save(filename, dirname); + if (ret) + printf("saveenv failed\n"); + return ret; +} + +static __maybe_unused char cmd_saveenv_help[] = +"Usage: saveenv [DIRECTORY] [ENVFS]\n" +"Save the files in <directory> to the persistent storage device <envfs>.\n" +"<envfs> is normally a block in flash, but could be any other file.\n" +"If ommitted <directory> defaults to /env and <envfs> defaults to /dev/env0.\n" +"Note that envfs can only handle files. Directories are skipped silently.\n"; + +U_BOOT_CMD_START(saveenv) + .maxargs = 3, + .cmd = do_saveenv, + .usage = "save environment to persistent storage", + U_BOOT_CMD_HELP(cmd_saveenv_help) +U_BOOT_CMD_END +#endif /* __U_BOOT__ */ + +int envfs_load(char *filename, char *dirname) +{ + int malloc_size = 0; + struct envfs_super super; + void *buf = NULL; + char tmp[PATH_MAX]; + int envfd; + struct envfs_inode inode; + int fd; + + envfd = open(filename, O_RDONLY); + if (envfd < 0) { + perror("open"); + return -1; + } + + if (read(envfd, &super, sizeof(struct envfs_super)) < sizeof(struct envfs_super)) { + perror("read"); + goto out; + } + + while (1) { + if (read(envfd, &inode, sizeof(struct envfs_inode)) < sizeof(struct envfs_inode)) { + perror("read"); + goto out; + } + if (inode.magic == ENVFS_END_MAGIC) + break; + if (inode.magic != ENVFS_INODE_MAGIC) { + printf("envfs: wrong magic on %s\n", filename); + goto out; + } + if (inode.size > malloc_size) { + if (buf) + free(buf); + buf = xmalloc(inode.size); + malloc_size = inode.size; + } + if (read(envfd, buf, inode.size) < inode.size) { + perror("read"); + goto out; + } + sprintf(tmp, "%s/%s", dirname, inode.name); + + fd = open(tmp, O_WRONLY | O_CREAT); + if (fd < 0) { + perror("open"); + goto out; + } + + if (write(fd, buf, inode.size) < inode.size) { + perror("write"); + close(fd); + goto out; + } + close(fd); + + if (inode.size & 0x3) { + if (read(envfd, buf, 4 - (inode.size & 0x3)) < 4 - (inode.size & 0x3)) { + perror("read"); + goto out; + } + } + } + +out: + close(envfd); + if (buf) + free(buf); + return errno; +} + +#ifdef __U_BOOT__ +int do_loadenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + char *filename, *dirname; + + if (argc < 3) + dirname = "/env"; + else + dirname = argv[2]; + if (argc < 2) + filename = "/dev/env0"; + else + filename = argv[1]; + printf("loading environment from %s\n", filename); + return envfs_load(filename, dirname); +} + +static __maybe_unused char cmd_loadenv_help[] = +"Usage: loadenv [DIRECTORY] [ENVFS]\n" +"Load the persistent storage contained in <envfs> to the directory\n" +"<directory>.\n" +"If ommitted <directory> defaults to /env and <envfs> defaults to /dev/env0.\n" +"Note that envfs can only handle files. Directories are skipped silently.\n"; + +U_BOOT_CMD_START(loadenv) + .maxargs = 3, + .cmd = do_loadenv, + .usage = "load environment from persistent storage", + U_BOOT_CMD_HELP(cmd_loadenv_help) +U_BOOT_CMD_END +#endif /* __U_BOOT__ */ diff --git a/commands/exec.c b/commands/exec.c new file mode 100644 index 0000000000..2cba507519 --- /dev/null +++ b/commands/exec.c @@ -0,0 +1,44 @@ +#include <common.h> +#include <command.h> +#include <fs.h> +#include <fcntl.h> +#include <linux/stat.h> +#include <errno.h> +#include <malloc.h> +#include <xfuncs.h> + +#ifdef CONFIG_HUSH_PARSER +#include <hush.h> +#endif + +static int do_exec(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + int i; + char *script; + + if (argc < 2) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + for (i=1; i<argc; ++i) { + script = read_file(argv[i]); + if (!script) + return 1; + + if (run_command (script, flag) == -1) + goto out; + free(script); + } + return 0; + +out: + free(script); + return 1; +} + +U_BOOT_CMD_START(exec) + .maxargs = CONFIG_MAXARGS, + .cmd = do_exec, + .usage = "execute a script", +U_BOOT_CMD_END diff --git a/commands/fs.c b/commands/fs.c new file mode 100644 index 0000000000..2eca365016 --- /dev/null +++ b/commands/fs.c @@ -0,0 +1,391 @@ +#include <common.h> +#include <command.h> +#include <fs.h> +#include <errno.h> +#include <malloc.h> +#include <linux/ctype.h> +#include <getopt.h> +#include <linux/stat.h> +#include <xfuncs.h> + +static void ls_one(const char *path, struct stat *s) +{ + char modestr[11]; + unsigned long namelen = strlen(path); + + mkmodestr(s->st_mode, modestr); + printf("%s %8d %*.*s\n",modestr, s->st_size, namelen, namelen, path); +} + +int ls(const char *path, ulong flags) +{ + DIR *dir; + struct dirent *d; + char tmp[PATH_MAX]; + struct stat s; + + if (flags & LS_SHOWARG) + printf("%s:\n", path); + + if (stat(path, &s)) { + perror("stat"); + return errno; + } + + if (!(s.st_mode & S_IFDIR)) { + ls_one(path, &s); + return 0; + } + + dir = opendir(path); + if (!dir) + return errno; + + while ((d = readdir(dir))) { + sprintf(tmp, "%s/%s", path, d->d_name); + if (stat(tmp, &s)) + goto out; + ls_one(d->d_name, &s); + } + + closedir(dir); + + if (!(flags & LS_RECURSIVE)) + return 0; + + dir = opendir(path); + if (!dir) { + errno = -ENOENT; + return -ENOENT; + } + + while ((d = readdir(dir))) { + sprintf(tmp, "%s/%s", path, d->d_name); + normalise_path(tmp); + if (stat(tmp, &s)) + goto out; + if (!strcmp(d->d_name, ".")) + continue; + if (!strcmp(d->d_name, "..")) + continue; + if (s.st_mode & S_IFDIR) + ls(tmp, flags); + } +out: + closedir(dir); + + return 0; +} + +static int do_ls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int ret, opt; + ulong flags = 0; + + getopt_reset(); + + while((opt = getopt(argc, argv, "R")) > 0) { + switch(opt) { + case 'R': + flags |= LS_RECURSIVE | LS_SHOWARG; + break; + } + } + + if (argc - optind > 1) + flags |= LS_SHOWARG; + + if (optind == argc) { + ret = ls(getcwd(), flags); + return ret ? 1 : 0; + } + + while (optind < argc) { + ret = ls(argv[optind], flags); + if (ret) { + perror("ls"); + return 1; + } + optind++; + } + + return 0; +} + +static __maybe_unused char cmd_ls_help[] = +"Usage: ls [OPTION]... [FILE]...\n" +"List information about the FILEs (the current directory by default).\n" +" -R list subdirectories recursively\n"; + +U_BOOT_CMD_START(ls) + .maxargs = CONFIG_MAXARGS, + .cmd = do_ls, + .usage = "list a file or directory", + U_BOOT_CMD_HELP(cmd_ls_help) +U_BOOT_CMD_END + +static int do_cd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int ret; + + if (argc == 1) + ret = chdir("/"); + else + ret = chdir(argv[1]); + + if (ret) { + perror("chdir"); + return 1; + } + + return 0; +} + +static __maybe_unused char cmd_cd_help[] = +"Usage: cd [directory]\n" +"change to directory. If called without argument, change to /\n"; + +U_BOOT_CMD_START(cd) + .maxargs = 2, + .cmd = do_cd, + .usage = "change working directory", + U_BOOT_CMD_HELP(cmd_cd_help) +U_BOOT_CMD_END + +static int do_pwd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + printf("%s\n", getcwd()); + return 0; +} + +U_BOOT_CMD_START(pwd) + .maxargs = 2, + .cmd = do_pwd, + .usage = "print working directory", +U_BOOT_CMD_END + +static int do_mkdir (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int i = 1; + + if (argc < 2) { + u_boot_cmd_usage(cmdtp); + return 1; + } + + while (i < argc) { + if (mkdir(argv[i])) { + printf("could not create %s: %s\n", argv[i], errno_str()); + return 1; + } + i++; + } + + return 0; +} + +static __maybe_unused char cmd_mkdir_help[] = +"Usage: mkdir [directories]\n" +"Create new directories\n"; + +U_BOOT_CMD_START(mkdir) + .maxargs = CONFIG_MAXARGS, + .cmd = do_mkdir, + .usage = "make directories", + U_BOOT_CMD_HELP(cmd_mkdir_help) +U_BOOT_CMD_END + +static int do_rm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int i = 1; + + if (argc < 2) { + u_boot_cmd_usage(cmdtp); + return 1; + } + + while (i < argc) { + if (unlink(argv[i])) { + printf("could not remove %s: %s\n", argv[i], errno_str()); + return 1; + } + i++; + } + + return 0; +} + +static __maybe_unused char cmd_rm_help[] = +"Usage: rm [FILES]\n" +"Remove files\n"; + +U_BOOT_CMD_START(rm) + .maxargs = CONFIG_MAXARGS, + .cmd = do_rm, + .usage = "remove files", + U_BOOT_CMD_HELP(cmd_rm_help) +U_BOOT_CMD_END + +static int do_rmdir (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int i = 1; + + if (argc < 2) { + u_boot_cmd_usage(cmdtp); + return 1; + } + + while (i < argc) { + if (rmdir(argv[i])) { + printf("could not remove %s: %s\n", argv[i], errno_str()); + return 1; + } + i++; + } + + return 0; +} + +static __maybe_unused char cmd_rmdir_help[] = +"Usage: rmdir [directories]\n" +"Remove directories. The directories have to be empty.\n"; + +U_BOOT_CMD_START(rmdir) + .maxargs = CONFIG_MAXARGS, + .cmd = do_rmdir, + .usage = "remove directorie(s)", + U_BOOT_CMD_HELP(cmd_rmdir_help) +U_BOOT_CMD_END + +static int do_mount (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int ret = 0; + struct mtab_entry *entry = NULL; + + if (argc == 1) { + do { + entry = mtab_next_entry(entry); + if (entry) { + printf("%s on %s type %s\n", + entry->parent_device ? entry->parent_device->id : "none", + entry->path, + entry->dev->name); + } + } while (entry); + return 0; + } + + if (argc != 4) { + u_boot_cmd_usage(cmdtp); + return 1; + } + + if ((ret = mount(argv[1], argv[2], argv[3]))) { + perror("mount"); + return 1; + } + return 0; +} + +static __maybe_unused char cmd_mount_help[] = +"Usage: mount: list mounted filesystems\n" +"or: mount <device> <fstype> <mountpoint>\n" +"\n" +"Mount a filesystem of a given type to a mountpoint.\n" +"<device> can be one of /dev/* or some arbitrary string if no\n" +"device is needed for this driver (for example ramfs).\n" +"<fstype> is the filesystem driver to use. Try the 'devinfo' command\n" +"for a list of available drivers.\n" +"<mountpoint> must be an empty directory descending directly from the\n" +"root directory.\n"; + +U_BOOT_CMD_START(mount) + .maxargs = 4, + .cmd = do_mount, + .usage = "mount a filesystem to a device", + U_BOOT_CMD_HELP(cmd_mount_help) +U_BOOT_CMD_END + +static int do_umount (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int ret = 0; + + if (argc != 2) { + u_boot_cmd_usage(cmdtp); + return 1; + } + + if ((ret = umount(argv[1]))) { + perror("umount"); + return 1; + } + return 0; +} + +static __maybe_unused char cmd_umount_help[] = +"Usage: umount <mountpoint>\n" +"umount a filesystem mounted on a specific mountpoint\n"; + +U_BOOT_CMD_START(umount) + .maxargs = 2, + .cmd = do_umount, + .usage = "umount a filesystem", + U_BOOT_CMD_HELP(cmd_umount_help) +U_BOOT_CMD_END + +static int do_cat(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int ret; + int fd, i; + char *buf; + int err = 0; + int args = 1; + + if (argc < 2) { + perror("cat"); + return 1; + } + + buf = xmalloc(1024); + + while (args < argc) { + fd = open(argv[args], 0); + if (fd < 0) { + printf("could not open %s: %s\n", argv[args], errno_str()); + goto out; + } + + while((ret = read(fd, buf, 1024)) > 0) { + for(i = 0; i < ret; i++) { + if (isprint(buf[i]) || buf[i] == '\n' || buf[i] == '\t') + putc(buf[i]); + else + putc('.'); + } + if(ctrlc()) { + err = 1; + close(fd); + goto out; + } + } + close(fd); + args++; + } + +out: + free(buf); + + return err; +} + +static __maybe_unused char cmd_cat_help[] = +"Usage: cat [FILES]\n" +"Concatenate files on stdout. Currently only printable characters\n" +"and \\n and \\t are printed, but this should be optional\n"; + +U_BOOT_CMD_START(cat) + .maxargs = CONFIG_MAXARGS, + .cmd = do_cat, + .usage = "concatenate file(s)", + U_BOOT_CMD_HELP(cmd_cat_help) +U_BOOT_CMD_END diff --git a/commands/go.c b/commands/go.c new file mode 100644 index 0000000000..accda18da1 --- /dev/null +++ b/commands/go.c @@ -0,0 +1,79 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Misc boot support + */ + +#include <common.h> +#include <command.h> + +int do_go (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong addr, rc; + int rcode = 0; + + if (argc < 2) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + addr = simple_strtoul(argv[1], NULL, 16); + + printf ("## Starting application at 0x%08lX ...\n", addr); + + /* + * pass address parameter as argv[0] (aka command name), + * and all remaining args + */ +#if defined(CONFIG_I386) + /* + * x86 does not use a dedicated register to pass the pointer + * to the global_data + */ + argv[0] = (char *)gd; +#endif +#if !defined(CONFIG_NIOS) + rc = ((ulong (*)(int, char *[]))addr) (--argc, &argv[1]); +#else + /* + * Nios function pointers are address >> 1 + */ + rc = ((ulong (*)(int, char *[]))(addr>>1)) (--argc, &argv[1]); +#endif + if (rc != 0) rcode = 1; + + printf ("## Application terminated, rc = 0x%lX\n", rc); + return rcode; +} + +/* -------------------------------------------------------------------- */ + +U_BOOT_CMD_START(go) + .maxargs = CONFIG_MAXARGS, + .cmd = do_go, + .usage = "start application at address 'addr'", + U_BOOT_CMD_HELP( + "addr [arg ...]\n - start application at address 'addr'\n" + " passing 'arg' as arguments\n") +U_BOOT_CMD_END diff --git a/commands/loadb.c b/commands/loadb.c new file mode 100644 index 0000000000..8da4b73574 --- /dev/null +++ b/commands/loadb.c @@ -0,0 +1,651 @@ +/* + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Serial up- and download support + */ +#include <common.h> +#include <command.h> +#include <s_record.h> +#include <net.h> +#include <exports.h> +#include <xyzModem.h> + +DECLARE_GLOBAL_DATA_PTR; + +static ulong load_serial_ymodem (ulong offset); + +#define XON_CHAR 17 +#define XOFF_CHAR 19 +#define START_CHAR 0x01 +#define ETX_CHAR 0x03 +#define END_CHAR 0x0D +#define SPACE 0x20 +#define K_ESCAPE 0x23 +#define SEND_TYPE 'S' +#define DATA_TYPE 'D' +#define ACK_TYPE 'Y' +#define NACK_TYPE 'N' +#define BREAK_TYPE 'B' +#define tochar(x) ((char) (((x) + SPACE) & 0xff)) +#define untochar(x) ((int) (((x) - SPACE) & 0xff)) + +extern int os_data_count; +extern int os_data_header[8]; + +static void set_kerm_bin_mode(unsigned long *); +static int k_recv(void); +static ulong load_serial_bin (ulong offset); + + +char his_eol; /* character he needs at end of packet */ +int his_pad_count; /* number of pad chars he needs */ +char his_pad_char; /* pad chars he needs */ +char his_quote; /* quote chars he'll use */ + +int do_load_serial_bin (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong offset = 0; + ulong addr; + int load_baudrate, current_baudrate; + int rcode = 0; + char *s; + + /* pre-set offset from CFG_LOAD_ADDR */ + offset = CFG_LOAD_ADDR; + + /* pre-set offset from $loadaddr */ + if ((s = getenv("loadaddr")) != NULL) { + offset = simple_strtoul(s, NULL, 16); + } + + load_baudrate = current_baudrate = gd->baudrate; + + if (argc >= 2) { + offset = simple_strtoul(argv[1], NULL, 16); + } + if (argc == 3) { + load_baudrate = (int)simple_strtoul(argv[2], NULL, 10); + + /* default to current baudrate */ + if (load_baudrate == 0) + load_baudrate = current_baudrate; + } + + if (load_baudrate != current_baudrate) { + printf ("## Switch baudrate to %d bps and press ENTER ...\n", + load_baudrate); + udelay(50000); + gd->baudrate = load_baudrate; + serial_setbrg (); + udelay(50000); + for (;;) { + if (getc() == '\r') + break; + } + } + + if (strcmp(argv[0],"loady")==0) { + printf ("## Ready for binary (ymodem) download " + "to 0x%08lX at %d bps...\n", + offset, + load_baudrate); + + addr = load_serial_ymodem (offset); + + } else { + + printf ("## Ready for binary (kermit) download " + "to 0x%08lX at %d bps...\n", + offset, + load_baudrate); + addr = load_serial_bin (offset); + + if (addr == ~0) { + load_addr = 0; + printf ("## Binary (kermit) download aborted\n"); + rcode = 1; + } else { + printf ("## Start Addr = 0x%08lX\n", addr); + load_addr = addr; + } + } + if (load_baudrate != current_baudrate) { + printf ("## Switch baudrate to %d bps and press ESC ...\n", + current_baudrate); + udelay (50000); + gd->baudrate = current_baudrate; + serial_setbrg (); + udelay (50000); + for (;;) { + if (getc() == 0x1B) /* ESC */ + break; + } + } + + return rcode; +} + + +static ulong load_serial_bin (ulong offset) +{ + int size, i; + char buf[32]; + + set_kerm_bin_mode ((ulong *) offset); + size = k_recv (); + + /* + * Gather any trailing characters (for instance, the ^D which + * is sent by 'cu' after sending a file), and give the + * box some time (100 * 1 ms) + */ + for (i=0; i<100; ++i) { + if (tstc()) { + (void) getc(); + } + udelay(1000); + } + + flush_cache (offset, size); + + printf("## Total Size = 0x%08x = %d Bytes\n", size, size); + sprintf(buf, "%X", size); + setenv("filesize", buf); + + return offset; +} + +void send_pad (void) +{ + int count = his_pad_count; + + while (count-- > 0) + putc (his_pad_char); +} + +/* converts escaped kermit char to binary char */ +char ktrans (char in) +{ + if ((in & 0x60) == 0x40) { + return (char) (in & ~0x40); + } else if ((in & 0x7f) == 0x3f) { + return (char) (in | 0x40); + } else + return in; +} + +int chk1 (char *buffer) +{ + int total = 0; + + while (*buffer) { + total += *buffer++; + } + return (int) ((total + ((total >> 6) & 0x03)) & 0x3f); +} + +void s1_sendpacket (char *packet) +{ + send_pad (); + while (*packet) { + putc (*packet++); + } +} + +static char a_b[24]; +void send_ack (int n) +{ + a_b[0] = START_CHAR; + a_b[1] = tochar (3); + a_b[2] = tochar (n); + a_b[3] = ACK_TYPE; + a_b[4] = '\0'; + a_b[4] = tochar (chk1 (&a_b[1])); + a_b[5] = his_eol; + a_b[6] = '\0'; + s1_sendpacket (a_b); +} + +void send_nack (int n) +{ + a_b[0] = START_CHAR; + a_b[1] = tochar (3); + a_b[2] = tochar (n); + a_b[3] = NACK_TYPE; + a_b[4] = '\0'; + a_b[4] = tochar (chk1 (&a_b[1])); + a_b[5] = his_eol; + a_b[6] = '\0'; + s1_sendpacket (a_b); +} + + +/* os_data_* takes an OS Open image and puts it into memory, and + puts the boot header in an array named os_data_header + + if image is binary, no header is stored in os_data_header. +*/ +void (*os_data_init) (void); +void (*os_data_char) (char new_char); +static int os_data_state, os_data_state_saved; +int os_data_count; +static int os_data_count_saved; +static char *os_data_addr, *os_data_addr_saved; +static char *bin_start_address; +int os_data_header[8]; +static void bin_data_init (void) +{ + os_data_state = 0; + os_data_count = 0; + os_data_addr = bin_start_address; +} +static void os_data_save (void) +{ + os_data_state_saved = os_data_state; + os_data_count_saved = os_data_count; + os_data_addr_saved = os_data_addr; +} +static void os_data_restore (void) +{ + os_data_state = os_data_state_saved; + os_data_count = os_data_count_saved; + os_data_addr = os_data_addr_saved; +} +static void bin_data_char (char new_char) +{ + switch (os_data_state) { + case 0: /* data */ + *os_data_addr++ = new_char; + --os_data_count; + break; + } +} +static void set_kerm_bin_mode (unsigned long *addr) +{ + bin_start_address = (char *) addr; + os_data_init = bin_data_init; + os_data_char = bin_data_char; +} + + +/* k_data_* simply handles the kermit escape translations */ +static int k_data_escape, k_data_escape_saved; +void k_data_init (void) +{ + k_data_escape = 0; + os_data_init (); +} +void k_data_save (void) +{ + k_data_escape_saved = k_data_escape; + os_data_save (); +} +void k_data_restore (void) +{ + k_data_escape = k_data_escape_saved; + os_data_restore (); +} +void k_data_char (char new_char) +{ + if (k_data_escape) { + /* last char was escape - translate this character */ + os_data_char (ktrans (new_char)); + k_data_escape = 0; + } else { + if (new_char == his_quote) { + /* this char is escape - remember */ + k_data_escape = 1; + } else { + /* otherwise send this char as-is */ + os_data_char (new_char); + } + } +} + +#define SEND_DATA_SIZE 20 +char send_parms[SEND_DATA_SIZE]; +char *send_ptr; + +/* handle_send_packet interprits the protocol info and builds and + sends an appropriate ack for what we can do */ +void handle_send_packet (int n) +{ + int length = 3; + int bytes; + + /* initialize some protocol parameters */ + his_eol = END_CHAR; /* default end of line character */ + his_pad_count = 0; + his_pad_char = '\0'; + his_quote = K_ESCAPE; + + /* ignore last character if it filled the buffer */ + if (send_ptr == &send_parms[SEND_DATA_SIZE - 1]) + --send_ptr; + bytes = send_ptr - send_parms; /* how many bytes we'll process */ + do { + if (bytes-- <= 0) + break; + /* handle MAXL - max length */ + /* ignore what he says - most I'll take (here) is 94 */ + a_b[++length] = tochar (94); + if (bytes-- <= 0) + break; + /* handle TIME - time you should wait for my packets */ + /* ignore what he says - don't wait for my ack longer than 1 second */ + a_b[++length] = tochar (1); + if (bytes-- <= 0) + break; + /* handle NPAD - number of pad chars I need */ + /* remember what he says - I need none */ + his_pad_count = untochar (send_parms[2]); + a_b[++length] = tochar (0); + if (bytes-- <= 0) + break; + /* handle PADC - pad chars I need */ + /* remember what he says - I need none */ + his_pad_char = ktrans (send_parms[3]); + a_b[++length] = 0x40; /* He should ignore this */ + if (bytes-- <= 0) + break; + /* handle EOL - end of line he needs */ + /* remember what he says - I need CR */ + his_eol = untochar (send_parms[4]); + a_b[++length] = tochar (END_CHAR); + if (bytes-- <= 0) + break; + /* handle QCTL - quote control char he'll use */ + /* remember what he says - I'll use '#' */ + his_quote = send_parms[5]; + a_b[++length] = '#'; + if (bytes-- <= 0) + break; + /* handle QBIN - 8-th bit prefixing */ + /* ignore what he says - I refuse */ + a_b[++length] = 'N'; + if (bytes-- <= 0) + break; + /* handle CHKT - the clock check type */ + /* ignore what he says - I do type 1 (for now) */ + a_b[++length] = '1'; + if (bytes-- <= 0) + break; + /* handle REPT - the repeat prefix */ + /* ignore what he says - I refuse (for now) */ + a_b[++length] = 'N'; + if (bytes-- <= 0) + break; + /* handle CAPAS - the capabilities mask */ + /* ignore what he says - I only do long packets - I don't do windows */ + a_b[++length] = tochar (2); /* only long packets */ + a_b[++length] = tochar (0); /* no windows */ + a_b[++length] = tochar (94); /* large packet msb */ + a_b[++length] = tochar (94); /* large packet lsb */ + } while (0); + + a_b[0] = START_CHAR; + a_b[1] = tochar (length); + a_b[2] = tochar (n); + a_b[3] = ACK_TYPE; + a_b[++length] = '\0'; + a_b[length] = tochar (chk1 (&a_b[1])); + a_b[++length] = his_eol; + a_b[++length] = '\0'; + s1_sendpacket (a_b); +} + +/* k_recv receives a OS Open image file over kermit line */ +static int k_recv (void) +{ + char new_char; + char k_state, k_state_saved; + int sum; + int done; + int length; + int n, last_n; + int z = 0; + int len_lo, len_hi; + + /* initialize some protocol parameters */ + his_eol = END_CHAR; /* default end of line character */ + his_pad_count = 0; + his_pad_char = '\0'; + his_quote = K_ESCAPE; + + /* initialize the k_recv and k_data state machine */ + done = 0; + k_state = 0; + k_data_init (); + k_state_saved = k_state; + k_data_save (); + n = 0; /* just to get rid of a warning */ + last_n = -1; + + /* expect this "type" sequence (but don't check): + S: send initiate + F: file header + D: data (multiple) + Z: end of file + B: break transmission + */ + + /* enter main loop */ + while (!done) { + /* set the send packet pointer to begining of send packet parms */ + send_ptr = send_parms; + + /* With each packet, start summing the bytes starting with the length. + Save the current sequence number. + Note the type of the packet. + If a character less than SPACE (0x20) is received - error. + */ + + + /* get a packet */ + /* wait for the starting character or ^C */ + for (;;) { + switch (getc ()) { + case START_CHAR: /* start packet */ + goto START; + case ETX_CHAR: /* ^C waiting for packet */ + return (0); + default: + ; + } + } +START: + /* get length of packet */ + sum = 0; + new_char = getc (); + if ((new_char & 0xE0) == 0) + goto packet_error; + sum += new_char & 0xff; + length = untochar (new_char); + /* get sequence number */ + new_char = getc (); + if ((new_char & 0xE0) == 0) + goto packet_error; + sum += new_char & 0xff; + n = untochar (new_char); + --length; + + /* NEW CODE - check sequence numbers for retried packets */ + /* Note - this new code assumes that the sequence number is correctly + * received. Handling an invalid sequence number adds another layer + * of complexity that may not be needed - yet! At this time, I'm hoping + * that I don't need to buffer the incoming data packets and can write + * the data into memory in real time. + */ + if (n == last_n) { + /* same sequence number, restore the previous state */ + k_state = k_state_saved; + k_data_restore (); + } else { + /* new sequence number, checkpoint the download */ + last_n = n; + k_state_saved = k_state; + k_data_save (); + } + /* END NEW CODE */ + + /* get packet type */ + new_char = getc (); + if ((new_char & 0xE0) == 0) + goto packet_error; + sum += new_char & 0xff; + k_state = new_char; + --length; + /* check for extended length */ + if (length == -2) { + /* (length byte was 0, decremented twice) */ + /* get the two length bytes */ + new_char = getc (); + if ((new_char & 0xE0) == 0) + goto packet_error; + sum += new_char & 0xff; + len_hi = untochar (new_char); + new_char = getc (); + if ((new_char & 0xE0) == 0) + goto packet_error; + sum += new_char & 0xff; + len_lo = untochar (new_char); + length = len_hi * 95 + len_lo; + /* check header checksum */ + new_char = getc (); + if ((new_char & 0xE0) == 0) + goto packet_error; + if (new_char != tochar ((sum + ((sum >> 6) & 0x03)) & 0x3f)) + goto packet_error; + sum += new_char & 0xff; +/* --length; */ /* new length includes only data and block check to come */ + } + /* bring in rest of packet */ + while (length > 1) { + new_char = getc (); + if ((new_char & 0xE0) == 0) + goto packet_error; + sum += new_char & 0xff; + --length; + if (k_state == DATA_TYPE) { + /* pass on the data if this is a data packet */ + k_data_char (new_char); + } else if (k_state == SEND_TYPE) { + /* save send pack in buffer as is */ + *send_ptr++ = new_char; + /* if too much data, back off the pointer */ + if (send_ptr >= &send_parms[SEND_DATA_SIZE]) + --send_ptr; + } + } + /* get and validate checksum character */ + new_char = getc (); + if ((new_char & 0xE0) == 0) + goto packet_error; + if (new_char != tochar ((sum + ((sum >> 6) & 0x03)) & 0x3f)) + goto packet_error; + /* get END_CHAR */ + new_char = getc (); + if (new_char != END_CHAR) { + packet_error: + /* restore state machines */ + k_state = k_state_saved; + k_data_restore (); + /* send a negative acknowledge packet in */ + send_nack (n); + } else if (k_state == SEND_TYPE) { + /* crack the protocol parms, build an appropriate ack packet */ + handle_send_packet (n); + } else { + /* send simple acknowledge packet in */ + send_ack (n); + /* quit if end of transmission */ + if (k_state == BREAK_TYPE) + done = 1; + } + ++z; + } + return ((ulong) os_data_addr - (ulong) bin_start_address); +} + +static int getcxmodem(void) { + if (tstc()) + return (getc()); + return -1; +} +static ulong load_serial_ymodem (ulong offset) +{ + int size; + char buf[32]; + int err; + int res; + connection_info_t info; + char ymodemBuf[1024]; + ulong store_addr = ~0; + ulong addr = 0; + + size = 0; + info.mode = xyzModem_ymodem; + res = xyzModem_stream_open (&info, &err); + if (!res) { + + while ((res = + xyzModem_stream_read (ymodemBuf, 1024, &err)) > 0) { + store_addr = addr + offset; + size += res; + addr += res; + memcpy ((char *) (store_addr), ymodemBuf, res); + + } + } else { + printf ("%s\n", xyzModem_error (err)); + } + + xyzModem_stream_close (&err); + xyzModem_stream_terminate (false, &getcxmodem); + + + flush_cache (offset, size); + + printf ("## Total Size = 0x%08x = %d Bytes\n", size, size); + sprintf (buf, "%X", size); + setenv ("filesize", buf); + + return offset; +} + +U_BOOT_CMD( + loadb, 3, 0, do_load_serial_bin, + "loadb - load binary file over serial line (kermit mode)\n", + "[ off ] [ baud ]\n" + " - load binary file over serial line" + " with offset 'off' and baudrate 'baud'\n" +); + +U_BOOT_CMD( + loady, 3, 0, do_load_serial_bin, + "loady - load binary file over serial line (ymodem mode)\n", + "[ off ] [ baud ]\n" + " - load binary file over serial line" + " with offset 'off' and baudrate 'baud'\n" +); diff --git a/commands/loads.c b/commands/loads.c new file mode 100644 index 0000000000..f0254bcc20 --- /dev/null +++ b/commands/loads.c @@ -0,0 +1,423 @@ +/* + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Serial up- and download support + */ +#include <common.h> +#include <command.h> +#include <s_record.h> +#include <net.h> +#include <exports.h> +#include <xyzModem.h> + +DECLARE_GLOBAL_DATA_PTR; + +static ulong load_serial (ulong offset); +static int read_record (char *buf, ulong len); +static int do_echo = 1; + +# if (CONFIG_COMMANDS & CFG_CMD_SAVES) +static int save_serial (ulong offset, ulong size); +static int write_record (char *buf); +# endif /* CFG_CMD_SAVES */ + +int do_load_serial (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong offset = 0; + ulong addr; + int i; + char *env_echo; + int rcode = 0; +#ifdef CFG_LOADS_BAUD_CHANGE + int load_baudrate, current_baudrate; + + load_baudrate = current_baudrate = gd->baudrate; +#endif + + if (((env_echo = getenv("loads_echo")) != NULL) && (*env_echo == '1')) { + do_echo = 1; + } else { + do_echo = 0; + } + +#ifdef CFG_LOADS_BAUD_CHANGE + if (argc >= 2) { + offset = simple_strtoul(argv[1], NULL, 16); + } + if (argc == 3) { + load_baudrate = (int)simple_strtoul(argv[2], NULL, 10); + + /* default to current baudrate */ + if (load_baudrate == 0) + load_baudrate = current_baudrate; + } + if (load_baudrate != current_baudrate) { + printf ("## Switch baudrate to %d bps and press ENTER ...\n", + load_baudrate); + udelay(50000); + gd->baudrate = load_baudrate; + serial_setbrg (); + udelay(50000); + for (;;) { + if (getc() == '\r') + break; + } + } +#else /* ! CFG_LOADS_BAUD_CHANGE */ + if (argc == 2) { + offset = simple_strtoul(argv[1], NULL, 16); + } +#endif /* CFG_LOADS_BAUD_CHANGE */ + + printf ("## Ready for S-Record download ...\n"); + + addr = load_serial (offset); + + /* + * Gather any trailing characters (for instance, the ^D which + * is sent by 'cu' after sending a file), and give the + * box some time (100 * 1 ms) + */ + for (i=0; i<100; ++i) { + if (tstc()) { + (void) getc(); + } + udelay(1000); + } + + if (addr == ~0) { + printf ("## S-Record download aborted\n"); + rcode = 1; + } else { + printf ("## Start Addr = 0x%08lX\n", addr); + load_addr = addr; + } + +#ifdef CFG_LOADS_BAUD_CHANGE + if (load_baudrate != current_baudrate) { + printf ("## Switch baudrate to %d bps and press ESC ...\n", + current_baudrate); + udelay (50000); + gd->baudrate = current_baudrate; + serial_setbrg (); + udelay (50000); + for (;;) { + if (getc() == 0x1B) /* ESC */ + break; + } + } +#endif + return rcode; +} + +static ulong +load_serial (ulong offset) +{ + char record[SREC_MAXRECLEN + 1]; /* buffer for one S-Record */ + char binbuf[SREC_MAXBINLEN]; /* buffer for binary data */ + int binlen; /* no. of data bytes in S-Rec. */ + int type; /* return code for record type */ + ulong addr; /* load address from S-Record */ + ulong size; /* number of bytes transferred */ + char buf[32]; + ulong store_addr; + ulong start_addr = ~0; + ulong end_addr = 0; + int line_count = 0; + + while (read_record(record, SREC_MAXRECLEN + 1) >= 0) { + type = srec_decode (record, &binlen, &addr, binbuf); + + if (type < 0) { + return (~0); /* Invalid S-Record */ + } + + switch (type) { + case SREC_DATA2: + case SREC_DATA3: + case SREC_DATA4: + store_addr = addr + offset; + memcpy ((char *)(store_addr), binbuf, binlen); + if ((store_addr) < start_addr) + start_addr = store_addr; + if ((store_addr + binlen - 1) > end_addr) + end_addr = store_addr + binlen - 1; + break; + case SREC_END2: + case SREC_END3: + case SREC_END4: + udelay (10000); + size = end_addr - start_addr + 1; + printf ("\n" + "## First Load Addr = 0x%08lX\n" + "## Last Load Addr = 0x%08lX\n" + "## Total Size = 0x%08lX = %ld Bytes\n", + start_addr, end_addr, size, size + ); + flush_cache (start_addr, size); + sprintf(buf, "%lX", size); + setenv("filesize", buf); + return (addr); + case SREC_START: + break; + default: + break; + } + if (!do_echo) { /* print a '.' every 100 lines */ + if ((++line_count % 100) == 0) + putc ('.'); + } + } + + return (~0); /* Download aborted */ +} + +static int +read_record (char *buf, ulong len) +{ + char *p; + char c; + + --len; /* always leave room for terminating '\0' byte */ + + for (p=buf; p < buf+len; ++p) { + c = getc(); /* read character */ + if (do_echo) + putc (c); /* ... and echo it */ + + switch (c) { + case '\r': + case '\n': + *p = '\0'; + return (p - buf); + case '\0': + case 0x03: /* ^C - Control C */ + return (-1); + default: + *p = c; + } + + /* Check for the console hangup (if any different from serial) */ + if (gd->jt[XF_getc] != getc) { + if (ctrlc()) { + return (-1); + } + } + } + + /* line too long - truncate */ + *p = '\0'; + return (p - buf); +} + +#if (CONFIG_COMMANDS & CFG_CMD_SAVES) + +int do_save_serial (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong offset = 0; + ulong size = 0; +#ifdef CFG_LOADS_BAUD_CHANGE + int save_baudrate, current_baudrate; + + save_baudrate = current_baudrate = gd->baudrate; +#endif + + if (argc >= 2) { + offset = simple_strtoul(argv[1], NULL, 16); + } +#ifdef CFG_LOADS_BAUD_CHANGE + if (argc >= 3) { + size = simple_strtoul(argv[2], NULL, 16); + } + if (argc == 4) { + save_baudrate = (int)simple_strtoul(argv[3], NULL, 10); + + /* default to current baudrate */ + if (save_baudrate == 0) + save_baudrate = current_baudrate; + } + if (save_baudrate != current_baudrate) { + printf ("## Switch baudrate to %d bps and press ENTER ...\n", + save_baudrate); + udelay(50000); + gd->baudrate = save_baudrate; + serial_setbrg (); + udelay(50000); + for (;;) { + if (getc() == '\r') + break; + } + } +#else /* ! CFG_LOADS_BAUD_CHANGE */ + if (argc == 3) { + size = simple_strtoul(argv[2], NULL, 16); + } +#endif /* CFG_LOADS_BAUD_CHANGE */ + + printf ("## Ready for S-Record upload, press ENTER to proceed ...\n"); + for (;;) { + if (getc() == '\r') + break; + } + if(save_serial (offset, size)) { + printf ("## S-Record upload aborted\n"); + } else { + printf ("## S-Record upload complete\n"); + } +#ifdef CFG_LOADS_BAUD_CHANGE + if (save_baudrate != current_baudrate) { + printf ("## Switch baudrate to %d bps and press ESC ...\n", + (int)current_baudrate); + udelay (50000); + gd->baudrate = current_baudrate; + serial_setbrg (); + udelay (50000); + for (;;) { + if (getc() == 0x1B) /* ESC */ + break; + } + } +#endif + return 0; +} + +#define SREC3_START "S0030000FC\n" +#define SREC3_FORMAT "S3%02X%08lX%s%02X\n" +#define SREC3_END "S70500000000FA\n" +#define SREC_BYTES_PER_RECORD 16 + +static int save_serial (ulong address, ulong count) +{ + int i, c, reclen, checksum, length; + char *hex = "0123456789ABCDEF"; + char record[2*SREC_BYTES_PER_RECORD+16]; /* buffer for one S-Record */ + char data[2*SREC_BYTES_PER_RECORD+1]; /* buffer for hex data */ + + reclen = 0; + checksum = 0; + + if(write_record(SREC3_START)) /* write the header */ + return (-1); + do { + if(count) { /* collect hex data in the buffer */ + c = *(volatile uchar*)(address + reclen); /* get one byte */ + checksum += c; /* accumulate checksum */ + data[2*reclen] = hex[(c>>4)&0x0f]; + data[2*reclen+1] = hex[c & 0x0f]; + data[2*reclen+2] = '\0'; + ++reclen; + --count; + } + if(reclen == SREC_BYTES_PER_RECORD || count == 0) { + /* enough data collected for one record: dump it */ + if(reclen) { /* build & write a data record: */ + /* address + data + checksum */ + length = 4 + reclen + 1; + + /* accumulate length bytes into checksum */ + for(i = 0; i < 2; i++) + checksum += (length >> (8*i)) & 0xff; + + /* accumulate address bytes into checksum: */ + for(i = 0; i < 4; i++) + checksum += (address >> (8*i)) & 0xff; + + /* make proper checksum byte: */ + checksum = ~checksum & 0xff; + + /* output one record: */ + sprintf(record, SREC3_FORMAT, length, address, data, checksum); + if(write_record(record)) + return (-1); + } + address += reclen; /* increment address */ + checksum = 0; + reclen = 0; + } + } + while(count); + if(write_record(SREC3_END)) /* write the final record */ + return (-1); + return(0); +} + +static int +write_record (char *buf) +{ + char c; + + while((c = *buf++)) + putc(c); + + /* Check for the console hangup (if any different from serial) */ + + if (ctrlc()) { + return (-1); + } + return (0); +} +# endif /* CFG_CMD_SAVES */ + +#ifdef CFG_LOADS_BAUD_CHANGE +U_BOOT_CMD( + loads, 3, 0, do_load_serial, + "loads - load S-Record file over serial line\n", + "[ off ] [ baud ]\n" + " - load S-Record file over serial line" + " with offset 'off' and baudrate 'baud'\n" +); + +#else /* ! CFG_LOADS_BAUD_CHANGE */ +U_BOOT_CMD( + loads, 2, 0, do_load_serial, + "loads - load S-Record file over serial line\n", + "[ off ]\n" + " - load S-Record file over serial line with offset 'off'\n" +); +#endif /* CFG_LOADS_BAUD_CHANGE */ + +/* + * SAVES always requires LOADS support, but not vice versa + */ + + +#if (CONFIG_COMMANDS & CFG_CMD_SAVES) +#ifdef CFG_LOADS_BAUD_CHANGE +U_BOOT_CMD( + saves, 4, 0, do_save_serial, + "saves - save S-Record file over serial line\n", + "[ off ] [size] [ baud ]\n" + " - save S-Record file over serial line" + " with offset 'off', size 'size' and baudrate 'baud'\n" +); +#else /* ! CFG_LOADS_BAUD_CHANGE */ +U_BOOT_CMD( + saves, 3, 0, do_save_serial, + "saves - save S-Record file over serial line\n", + "[ off ] [size]\n" + " - save S-Record file over serial line with offset 'off' and size 'size'\n" +); +#endif /* CFG_LOADS_BAUD_CHANGE */ +#endif /* CFG_CMD_SAVES */ + diff --git a/commands/mem.c b/commands/mem.c new file mode 100644 index 0000000000..d7cd7fb96d --- /dev/null +++ b/commands/mem.c @@ -0,0 +1,705 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Memory Functions + * + * Copied from FADS ROM, Dan Malek (dmalek@jlc.net) + */ + +#include <common.h> +#include <command.h> +#include <init.h> +#include <driver.h> +#include <malloc.h> +#include <errno.h> +#include <fs.h> +#include <fcntl.h> +#include <getopt.h> + +#ifdef CMD_MEM_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +#define RW_BUF_SIZE (ulong)4096 +static char *rw_buf; + +/* Memory Display + * + * Syntax: + * md{.b, .w, .l} {addr} {len} + */ +#define DISP_LINE_LEN 16 + +int memory_display(char *addr, ulong offs, ulong nbytes, int size) +{ + ulong linebytes, i; + u_char *cp; + + /* Print the lines. + * + * We buffer all read data, so we can make sure data is read only + * once, and all accesses are with the specified bus width. + */ + do { + char linebuf[DISP_LINE_LEN]; + uint *uip = (uint *)linebuf; + ushort *usp = (ushort *)linebuf; + u_char *ucp = (u_char *)linebuf; + + printf("%08lx:", offs); + linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes; + + for (i=0; i<linebytes; i+= size) { + if (size == 4) { + printf(" %08x", (*uip++ = *((uint *)addr))); + } else if (size == 2) { + printf(" %04x", (*usp++ = *((ushort *)addr))); + } else { + printf(" %02x", (*ucp++ = *((u_char *)addr))); + } + addr += size; + offs += size; + } + + puts (" "); + cp = (u_char *)linebuf; + for (i=0; i<linebytes; i++) { + if ((*cp < 0x20) || (*cp > 0x7e)) + putc ('.'); + else + printf("%c", *cp); + cp++; + } + putc ('\n'); + nbytes -= linebytes; + if (ctrlc()) { + return -EINTR; + } + } while (nbytes > 0); + + return 0; +} + +static int do_mem_md ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong start = 0, size = 0x100; + int r, now; + int ret = 0; + int fd; + char *filename = "/dev/mem"; + int mode = O_RWSIZE_4; + int opt; + + errno = 0; + + getopt_reset(); + + while((opt = getopt(argc, argv, "bwlf:")) > 0) { + switch(opt) { + case 'b': + mode = O_RWSIZE_1; + break; + case 'w': + mode = O_RWSIZE_2; + break; + case 'l': + mode = O_RWSIZE_4; + break; + case 'f': + filename = optarg; + break; + default: + return 1; + } + } + + if (optind < argc) { + parse_area_spec(argv[optind], &start, &size); + if (size == ~0) + size = 0x100; + } + + fd = open(filename, mode | O_RDONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + if (lseek(fd, start, SEEK_SET)) { + perror("lseek"); + goto out; + } + + do { + now = min(size, RW_BUF_SIZE); + r = read(fd, rw_buf, now); + if (r < 0) { + perror("read"); + goto out; + } + if (!r) + goto out; + + if ((ret = memory_display(rw_buf, start, r, mode >> O_RWSIZE_SHIFT))) + goto out; + + start += r; + size -= r; + } while (size); + +out: + close(fd); + + return errno; +} + +static __maybe_unused char cmd_md_help[] = +"Usage md [OPTIONS] <region>\n" +"display (hexdump) a memory region.\n" +"options:\n" +" -f <file> display file (default /dev/mem)\n" +" -b output in bytes\n" +" -w output in halfwords (16bit)\n" +" -l output in words (32bit)\n" +"\n" +"Memory regions:\n" +"Memory regions can be specified in two different forms: start+size\n" +"or start-end, If <start> is ommitted it defaults to 0. If end is ommited it\n" +"defaults to the end of the device, except for interactive commands like md\n" +"and mw for which it defaults to 0x100.\n" +"Sizes can be specified as decimal, or if prefixed with 0x as hexadecimal.\n" +"an optional suffix of k, M or G is for kibibytes, Megabytes or Gigabytes,\n" +"respectively\n"; + + +U_BOOT_CMD_START(md) + .maxargs = CONFIG_MAXARGS, + .cmd = do_mem_md, + .usage = "memory display", + U_BOOT_CMD_HELP(cmd_md_help) +U_BOOT_CMD_END + +int do_mem_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int ret = 0; + int fd; + char *filename = "/dev/mem"; + int mode = O_RWSIZE_4; + int opt; + ulong adr; + + errno = 0; + + getopt_reset(); + + while((opt = getopt(argc, argv, "bwlf:")) > 0) { + switch(opt) { + case 'b': + mode = O_RWSIZE_1; + break; + case 'w': + mode = O_RWSIZE_2; + break; + case 'l': + mode = O_RWSIZE_4; + break; + case 'f': + filename = optarg; + break; + default: + return 1; + } + } + + if (optind + 1 >= argc) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + fd = open(filename, mode | O_WRONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + adr = strtoul_suffix(argv[optind++], NULL, 0); + + if (lseek(fd, adr, SEEK_SET)) { + perror("lseek"); + goto out; + } + + while (optind < argc) { + u8 val8; + u16 val16; + u32 val32; + switch (mode) { + case O_RWSIZE_1: + val8 = simple_strtoul(argv[optind], NULL, 0); + ret = write(fd, &val8, 1); + printf("write %d\n", val8); + break; + case O_RWSIZE_2: + val16 = simple_strtoul(argv[optind], NULL, 0); + ret = write(fd, &val16, 2); + break; + case O_RWSIZE_4: + val32 = simple_strtoul(argv[optind], NULL, 0); + ret = write(fd, &val32, 4); + break; + } + if (ret < 0) { + perror("write"); + break; + } + optind++; + } + +out: + close(fd); + + return errno; +} + +static __maybe_unused char cmd_mw_help[] = +"Usage mw [OPTIONS] <region> <value(s)>\n" +"Write value(s) to the specifies region.\n" +"see 'help md' for supported options.\n"; + +U_BOOT_CMD_START(mw) + .maxargs = CONFIG_MAXARGS, + .cmd = do_mem_mw, + .usage = "memory write (fill)", + U_BOOT_CMD_HELP(cmd_mw_help) +U_BOOT_CMD_END + +int do_mem_cmp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong addr1, addr2, count, ngood; + int size; + int rcode = 0; + + if (argc != 4) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* Check for size specification. + */ + if ((size = cmd_get_data_size(argv[0], 4)) < 0) + return 1; + + addr1 = simple_strtoul(argv[1], NULL, 16); + + addr2 = simple_strtoul(argv[2], NULL, 16); + + count = simple_strtoul(argv[3], NULL, 16); + + ngood = 0; + + while (count-- > 0) { + if (size == 4) { + ulong word1 = *(ulong *)addr1; + ulong word2 = *(ulong *)addr2; + if (word1 != word2) { + printf("word at 0x%08lx (0x%08lx) " + "!= word at 0x%08lx (0x%08lx)\n", + addr1, word1, addr2, word2); + rcode = 1; + break; + } + } + else if (size == 2) { + ushort hword1 = *(ushort *)addr1; + ushort hword2 = *(ushort *)addr2; + if (hword1 != hword2) { + printf("halfword at 0x%08lx (0x%04x) " + "!= halfword at 0x%08lx (0x%04x)\n", + addr1, hword1, addr2, hword2); + rcode = 1; + break; + } + } + else { + u_char byte1 = *(u_char *)addr1; + u_char byte2 = *(u_char *)addr2; + if (byte1 != byte2) { + printf("byte at 0x%08lx (0x%02x) " + "!= byte at 0x%08lx (0x%02x)\n", + addr1, byte1, addr2, byte2); + rcode = 1; + break; + } + } + ngood++; + addr1 += size; + addr2 += size; + } + + printf("Total of %ld %s%s were the same\n", + ngood, size == 4 ? "word" : size == 2 ? "halfword" : "byte", + ngood == 1 ? "" : "s"); + return rcode; +} +#if 0 +int do_mem_cp ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong count, offset, now; + int ret; + struct memarea_info dst, src; + + int size; + + if (argc != 3) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* Check for size specification. + */ + if ((size = cmd_get_data_size(argv[0], 4)) < 0) + return 1; + + if (spec_str_to_info(argv[1], &src)) { + printf("-ENOPARSE\n"); + return -1; + } + + if (spec_str_to_info(argv[2], &dst)) { + printf("-ENOPARSE\n"); + return -1; + } + + if (!src.size || !dst.size) + count = dst.size | src.size; + else + count = min(src.size, dst.size); + + printf("copy from 0x%08x to 0x%08x count %d\n",src.start, dst.start, count); + + offset = 0; + while (count > 0) { + now = min(RW_BUF_SIZE, count); + + ret = dev_read(src.device, rw_buf, now, src.start + offset, RW_SIZE(size)); + if (ret <= 0) + return ret; + + ret = dev_write(dst.device, rw_buf, ret, dst.start + offset, RW_SIZE(size)); + if (ret <= 0) + return ret; + if (ret < now) + return 0; + offset += now; + count -= now; + } + + return 0; +} + +U_BOOT_CMD( + cp, 4, 0, do_mem_cp, + "cp - memory copy\n", + "[.b, .w, .l] source target count\n - copy memory\n" +); +#endif + +int do_cp ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int r, w, ret = 1; + int src, dst; + + src = open(argv[1], O_RDONLY); + if (src < 0) { + perror("open"); + return 1; + } + + dst = open(argv[2], O_WRONLY | O_CREAT); + if ( dst < 0) { + perror("open"); + close(src); + return 1; + } + + while(1) { + r = read(src, rw_buf, RW_BUF_SIZE); + if (read < 0) { + perror("read"); + goto out; + } + if (!r) + break; + w = write(dst, rw_buf, r); + if (w < 0) { + perror("write"); + goto out; + } + } + ret = 0; +out: + close(src); + close(dst); + return ret; +} + +static __maybe_unused char cmd_cp_help[] = +"Usage: cp <source> <destination>\n" +"cp copies file <source> to <destination>.\n" +"Currently only this form is supported and you have to specify the exact target\n" +"filename (not a target directory).\n" +"Note: This command was previously used as memory copy. Currently there is no\n" +"equivalent command for this. This must be fixed of course.\n"; + +U_BOOT_CMD_START(cp) + .maxargs = CONFIG_MAXARGS, + .cmd = do_cp, + .usage = "copy files", + U_BOOT_CMD_HELP(cmd_cp_help) +U_BOOT_CMD_END + +#ifndef CONFIG_CRC32_VERIFY + +int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong addr, length; + ulong crc; + ulong *ptr; + + if (argc < 3) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + addr = simple_strtoul (argv[1], NULL, 16); + + length = simple_strtoul (argv[2], NULL, 16); + + crc = crc32 (0, (const uchar *) addr, length); + + printf ("CRC32 for %08lx ... %08lx ==> %08lx\n", + addr, addr + length - 1, crc); + + if (argc > 3) { + ptr = (ulong *) simple_strtoul (argv[3], NULL, 16); + *ptr = crc; + } + + return 0; +} + +#else /* CONFIG_CRC32_VERIFY */ + +int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong addr, length; + ulong crc; + ulong *ptr; + ulong vcrc; + int verify; + int ac; + char **av; + + if (argc < 3) { + usage: + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + av = argv + 1; + ac = argc - 1; + if (strcmp(*av, "-v") == 0) { + verify = 1; + av++; + ac--; + if (ac < 3) + goto usage; + } else + verify = 0; + + addr = simple_strtoul(*av++, NULL, 16); + length = simple_strtoul(*av++, NULL, 16); + + crc = crc32(0, (const uchar *) addr, length); + + if (!verify) { + printf ("CRC32 for %08lx ... %08lx ==> %08lx\n", + addr, addr + length - 1, crc); + if (ac > 2) { + ptr = (ulong *) simple_strtoul (*av++, NULL, 16); + *ptr = crc; + } + } else { + vcrc = simple_strtoul(*av++, NULL, 16); + if (vcrc != crc) { + printf ("CRC32 for %08lx ... %08lx ==> %08lx != %08lx ** ERROR **\n", + addr, addr + length - 1, crc, vcrc); + return 1; + } + } + + return 0; + +} +#endif /* CONFIG_CRC32_VERIFY */ + +static void memcpy_sz(void *_dst, const void *_src, ulong count, ulong rwsize) +{ + ulong dst = (ulong)_dst; + ulong src = (ulong)_src; + + /* no rwsize specification given. Do whatever memcpy likes best */ + if (!rwsize) { + memcpy(_dst, _src, count); + return; + } + + rwsize = rwsize >> O_RWSIZE_SHIFT; + + count /= rwsize; + + while (count-- > 0) { + switch (rwsize) { + case 1: + *((u_char *)dst) = *((u_char *)src); + break; + case 2: + *((ushort *)dst) = *((ushort *)src); + break; + case 4: + *((ulong *)dst) = *((ulong *)src); + break; + } + dst += rwsize; + src += rwsize; + } +} + +ssize_t mem_read(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags) +{ + ulong size; + size = min(count, dev->size - offset); + printf("mem_read: dev->map_base: %p size: %d offset: %d\n",dev->map_base, size, offset); + memcpy_sz(buf, (void *)(dev->map_base + offset), size, flags & O_RWSIZE_MASK); + return size; +} + +ssize_t mem_write(struct device_d *dev, const void *buf, size_t count, ulong offset, ulong flags) +{ + ulong size; + size = min(count, dev->size - offset); + memcpy_sz((void *)(dev->map_base + offset), buf, size, flags & O_RWSIZE_MASK); + return size; +} + +static struct device_d mem_dev = { + .name = "mem", + .id = "mem", + .map_base = 0, + .size = ~0, /* FIXME: should be 0x100000000, ahem... */ +}; + +static struct driver_d mem_drv = { + .name = "mem", + .probe = dummy_probe, + .read = mem_read, + .write = mem_write, +}; + +static struct driver_d ram_drv = { + .name = "ram", + .probe = dummy_probe, + .read = mem_read, + .write = mem_write, + .type = DEVICE_TYPE_DRAM, +}; + +static int mem_init(void) +{ + rw_buf = malloc(RW_BUF_SIZE); + if(!rw_buf) { + printf("%s: Out of memory\n", __FUNCTION__); + return -1; + } + + register_device(&mem_dev); + register_driver(&mem_drv); + register_driver(&ram_drv); + return 0; +} + +device_initcall(mem_init); + +U_BOOT_CMD_START(cmp) + .maxargs = 4, + .cmd = do_mem_cmp, + .usage = "memory compare", + U_BOOT_CMD_HELP("write me\n") +U_BOOT_CMD_END + +#ifndef CONFIG_CRC32_VERIFY + +U_BOOT_CMD_START(crc32) + .maxargs = 4, + .cmd = do_mem_crc, + .usage = "checksum calculation", + U_BOOT_CMD_HELP("address count [addr]\n - compute CRC32 checksum [save at addr]\n") +U_BOOT_CMD_END + +#else /* CONFIG_CRC32_VERIFY */ + +U_BOOT_CMD( + crc32, 5, 0, do_mem_crc, + "crc32 - checksum calculation\n", + "address count [addr]\n - compute CRC32 checksum [save at addr]\n" + "-v address count crc\n - verify crc of memory area\n" +); + +#endif /* CONFIG_CRC32_VERIFY */ + +#ifdef CONFIG_LOOPW +U_BOOT_CMD( + loopw, 4, 0, do_mem_loopw, + "loopw - infinite write loop on address range\n", + "[.b, .w, .l] address number_of_objects data_to_write\n" + " - loop on a set of addresses\n" +); +#endif /* CONFIG_LOOPW */ + +#ifdef CONFIG_MX_CYCLIC +U_BOOT_CMD( + mdc, 4, 0, do_mem_mdc, + "mdc - memory display cyclic\n", + "[.b, .w, .l] address count delay(ms)\n - memory display cyclic\n" +); + +U_BOOT_CMD( + mwc, 4, 0, do_mem_mwc, + "mwc - memory write cyclic\n", + "[.b, .w, .l] address value delay(ms)\n - memory write cyclic\n" +); +#endif /* CONFIG_MX_CYCLIC */ + diff --git a/commands/meminfo.c b/commands/meminfo.c new file mode 100644 index 0000000000..16b7a8f4cb --- /dev/null +++ b/commands/meminfo.c @@ -0,0 +1,15 @@ +#include <common.h> +#include <command.h> + +int do_meminfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + malloc_stats(); + + return 0; +} + +U_BOOT_CMD_START(meminfo) + .maxargs = 1, + .cmd = do_meminfo, + .usage = "print info about memory usage", +U_BOOT_CMD_END diff --git a/commands/memtest.c b/commands/memtest.c new file mode 100644 index 0000000000..877e97a45c --- /dev/null +++ b/commands/memtest.c @@ -0,0 +1,348 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> + +#ifdef CMD_MEM_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* + * Perform a memory test. A more complete alternative test can be + * configured using CFG_ALT_MEMTEST. The complete test loops until + * interrupted by ctrl-c or by a failure of one of the sub-tests. + */ + +int do_mem_mtest (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + vu_long *addr, *start, *end; + ulong val; + ulong readback; + +#ifdef CONFIG_CMD_MTEST_ALTERNATIVE + vu_long addr_mask; + vu_long offset; + vu_long test_offset; + vu_long pattern; + vu_long temp; + vu_long anti_pattern; + vu_long num_words; +#ifdef GFG_MEMTEST_SCRATCH + vu_long *dummy = (vu_long*)CFG_MEMTEST_SCRATCH; +#else + vu_long *dummy = 0; /* yes, this is address 0x0, not NULL */ +#endif + int j; + int iterations = 1; + + static const ulong bitpattern[] = { + 0x00000001, /* single bit */ + 0x00000003, /* two adjacent bits */ + 0x00000007, /* three adjacent bits */ + 0x0000000F, /* four adjacent bits */ + 0x00000005, /* two non-adjacent bits */ + 0x00000015, /* three non-adjacent bits */ + 0x00000055, /* four non-adjacent bits */ + 0xaaaaaaaa, /* alternating 1/0 */ + }; +#else + ulong incr; + ulong pattern; + int rcode = 0; +#endif + + if (argc > 1) { + start = (ulong *)simple_strtoul(argv[1], NULL, 16); + } else { + start = (ulong *)CONFIG_CMD_MTEST_START; + } + + if (argc > 2) { + end = (ulong *)simple_strtoul(argv[2], NULL, 16); + } else { + end = (ulong *)(CONFIG_CMD_MTEST_END); + } + + if (argc > 3) { + pattern = (ulong)simple_strtoul(argv[3], NULL, 16); + } else { + pattern = 0; + } + +#if defined(CONFIG_CMD_MTEST_ALTERNATIVE) + printf ("Testing %08x ... %08x:\n", (uint)start, (uint)end); + PRINTF("%s:%d: start 0x%p end 0x%p\n", + __FUNCTION__, __LINE__, start, end); + + for (;;) { + if (ctrlc()) { + putc ('\n'); + return 1; + } + + printf("Iteration: %6d\r", iterations); + PRINTF("Iteration: %6d\n", iterations); + iterations++; + + /* + * Data line test: write a pattern to the first + * location, write the 1's complement to a 'parking' + * address (changes the state of the data bus so a + * floating bus doen't give a false OK), and then + * read the value back. Note that we read it back + * into a variable because the next time we read it, + * it might be right (been there, tough to explain to + * the quality guys why it prints a failure when the + * "is" and "should be" are obviously the same in the + * error message). + * + * Rather than exhaustively testing, we test some + * patterns by shifting '1' bits through a field of + * '0's and '0' bits through a field of '1's (i.e. + * pattern and ~pattern). + */ + addr = start; + for (j = 0; j < sizeof(bitpattern)/sizeof(bitpattern[0]); j++) { + val = bitpattern[j]; + for(; val != 0; val <<= 1) { + *addr = val; + *dummy = ~val; /* clear the test data off of the bus */ + readback = *addr; + if(readback != val) { + printf ("FAILURE (data line): " + "expected %08lx, actual %08lx\n", + val, readback); + } + *addr = ~val; + *dummy = val; + readback = *addr; + if(readback != ~val) { + printf ("FAILURE (data line): " + "Is %08lx, should be %08lx\n", + readback, ~val); + } + } + } + + /* + * Based on code whose Original Author and Copyright + * information follows: Copyright (c) 1998 by Michael + * Barr. This software is placed into the public + * domain and may be used for any purpose. However, + * this notice must not be changed or removed and no + * warranty is either expressed or implied by its + * publication or distribution. + */ + + /* + * Address line test + * + * Description: Test the address bus wiring in a + * memory region by performing a walking + * 1's test on the relevant bits of the + * address and checking for aliasing. + * This test will find single-bit + * address failures such as stuck -high, + * stuck-low, and shorted pins. The base + * address and size of the region are + * selected by the caller. + * + * Notes: For best results, the selected base + * address should have enough LSB 0's to + * guarantee single address bit changes. + * For example, to test a 64-Kbyte + * region, select a base address on a + * 64-Kbyte boundary. Also, select the + * region size as a power-of-two if at + * all possible. + * + * Returns: 0 if the test succeeds, 1 if the test fails. + * + * ## NOTE ## Be sure to specify start and end + * addresses such that addr_mask has + * lots of bits set. For example an + * address range of 01000000 02000000 is + * bad while a range of 01000000 + * 01ffffff is perfect. + */ + addr_mask = ((ulong)end - (ulong)start)/sizeof(vu_long); + pattern = (vu_long) 0xaaaaaaaa; + anti_pattern = (vu_long) 0x55555555; + + PRINTF("%s:%d: addr mask = 0x%.8lx\n", + __FUNCTION__, __LINE__, + addr_mask); + /* + * Write the default pattern at each of the + * power-of-two offsets. + */ + for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { + start[offset] = pattern; + } + + /* + * Check for address bits stuck high. + */ + test_offset = 0; + start[test_offset] = anti_pattern; + + for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { + temp = start[offset]; + if (temp != pattern) { + printf ("\nFAILURE: Address bit stuck high @ 0x%.8lx:" + " expected 0x%.8lx, actual 0x%.8lx\n", + (ulong)&start[offset], pattern, temp); + return 1; + } + } + start[test_offset] = pattern; + + /* + * Check for addr bits stuck low or shorted. + */ + for (test_offset = 1; (test_offset & addr_mask) != 0; test_offset <<= 1) { + start[test_offset] = anti_pattern; + + for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { + temp = start[offset]; + if ((temp != pattern) && (offset != test_offset)) { + printf ("\nFAILURE: Address bit stuck low or shorted @" + " 0x%.8lx: expected 0x%.8lx, actual 0x%.8lx\n", + (ulong)&start[offset], pattern, temp); + return 1; + } + } + start[test_offset] = pattern; + } + + /* + * Description: Test the integrity of a physical + * memory device by performing an + * increment/decrement test over the + * entire region. In the process every + * storage bit in the device is tested + * as a zero and a one. The base address + * and the size of the region are + * selected by the caller. + * + * Returns: 0 if the test succeeds, 1 if the test fails. + */ + num_words = ((ulong)end - (ulong)start)/sizeof(vu_long) + 1; + + /* + * Fill memory with a known pattern. + */ + for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { + start[offset] = pattern; + } + + /* + * Check each location and invert it for the second pass. + */ + for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { + temp = start[offset]; + if (temp != pattern) { + printf ("\nFAILURE (read/write) @ 0x%.8lx:" + " expected 0x%.8lx, actual 0x%.8lx)\n", + (ulong)&start[offset], pattern, temp); + return 1; + } + + anti_pattern = ~pattern; + start[offset] = anti_pattern; + } + + /* + * Check each location for the inverted pattern and zero it. + */ + for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { + anti_pattern = ~pattern; + temp = start[offset]; + if (temp != anti_pattern) { + printf ("\nFAILURE (read/write): @ 0x%.8lx:" + " expected 0x%.8lx, actual 0x%.8lx)\n", + (ulong)&start[offset], anti_pattern, temp); + return 1; + } + start[offset] = 0; + } + } + +#else /* The original, quickie test */ + incr = 1; + for (;;) { + if (ctrlc()) { + putc ('\n'); + return 1; + } + + printf ("\rPattern %08lX Writing..." + "%12s" + "\b\b\b\b\b\b\b\b\b\b", + pattern, ""); + + for (addr=start,val=pattern; addr<end; addr++) { + *addr = val; + val += incr; + } + + puts ("Reading..."); + + for (addr=start,val=pattern; addr<end; addr++) { + readback = *addr; + if (readback != val) { + printf ("\nMem error @ 0x%08X: " + "found %08lX, expected %08lX\n", + (uint)addr, readback, val); + rcode = 1; + } + val += incr; + } + + /* + * Flip the pattern each time to make lots of zeros and + * then, the next time, lots of ones. We decrement + * the "negative" patterns and increment the "positive" + * patterns to preserve this feature. + */ + if(pattern & 0x80000000) { + pattern = -pattern; /* complement & increment */ + } + else { + pattern = ~pattern; + } + incr = -incr; + } + return rcode; +#endif +} + +U_BOOT_CMD( + mtest, 4, 0, do_mem_mtest, + "mtest - simple RAM test\n", + "[start [end [pattern]]]\n" + " - simple RAM read/write test\n" +); diff --git a/commands/reset.c b/commands/reset.c new file mode 100644 index 0000000000..1cc3702ff9 --- /dev/null +++ b/commands/reset.c @@ -0,0 +1,16 @@ +#include <common.h> +#include <command.h> + +static int cmd_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + do_reset(); + + /* Not reached */ + return 1; +} + +U_BOOT_CMD_START(reset) + .maxargs = 1, + .cmd = cmd_reset, + .usage = "Perform RESET of the CPU", +U_BOOT_CMD_END diff --git a/commands/sleep.c b/commands/sleep.c new file mode 100644 index 0000000000..99afc5f9ba --- /dev/null +++ b/commands/sleep.c @@ -0,0 +1,30 @@ +#include <common.h> +#include <command.h> +#include <clock.h> + +int do_sleep (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + uint64_t start; + ulong delay; + + if (argc != 2) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + delay = simple_strtoul(argv[1], NULL, 10); + + start = get_time_ns(); + while (!is_timeout(start, delay * SECOND)) { + if (ctrlc()) + return 1; + } + + return 0; +} + +U_BOOT_CMD_START(sleep) + .maxargs = 2, + .cmd = do_sleep, + .usage = "delay execution for n seconds", +U_BOOT_CMD_END |