/************************************************************/ /* Spidcom Technologies FILE NAME : commands.c DESCRIPTION : command file HISTORY : -------------------------------------------------------------- DATE | AUTHOR | Version | Description -------------------------------------------------------------- 27/01/04 | Petillon | 1.0 | Creation */ /************************************************************/ #include #include #include #include #include #include "platform.h" #include "sdrams.h" #include "configuration.h" #include "commands.h" #include "cli.h" #include "image_table.h" #include "xmodem.h" #include "flash_device.h" #include "jump.h" #include "uart.h" #include "image_run.h" #include "hex_image.h" #include "elf_image.h" #include "bootloader.h" #include "wait.h" #include "irq_management.h" #include "time_management.h" #include "gpio_management.h" #include "boot_stats.h" #ifdef USE_CRC #include "posix_crc.h" #endif #ifdef USE_ZLIB #include "gunzip.h" #endif #define MAX_LINE_LENGTH 256 static char line[MAX_LINE_LENGTH]; static int32_t valid_baudrates[] = { 9600, 19200, 38400, 57600, 115200, 0 }; static int check_image_name(const char *name) { const char *p; int len; int result = 1; p = name; len = strlen(name); if (!isalpha(*p)) return 0; p++; while (result && p0 && !format_error) { led_switch(2); p += data_length; *size += data_length; nbpacket++; if (!raw && *format==iBin) { #ifdef USE_ZLIB if (!gz_checked && *format==iBin && *size>=32) { gz_checked = 1; if (test_gz(address)) raw = 1; else if (elf_checked && hex_checked) format_error = 1; } #endif #ifdef USE_HEX if (!raw && !hex_checked && *format==iBin && *size>=hex_header_min_size()) { hex_checked = 1; if (check_hex_header(address,*size)) *format = iHex; else if (elf_checked && gz_checked) format_error = 1; } #endif #ifdef USE_ELF if (!raw && !elf_checked && *format==iBin && *size>=elf_header_min_size()) { elf_checked = 1; if (check_elf_header(address,*size,&entry_point)) *format = iElf; else if (hex_checked && gz_checked) format_error = 1; } #endif } } led_off(2); if (format_error) { xm_rx_stop(); printf("\nError: invalid image format, or binary without entry point.\n" "Supported formats are: hex, gz-hex, elf, gz-elf.\n"); return 0; } else if (result!=XM_END_OF_TRANSFER) { printf("\nError: %s.\n",xmodem_error()); return 0; } else { xm_rx_stats(&stats); printf("\nTransfer completed.\n%d packets of %u bytes received, %d CRC errors, %d packets retransmitted.\n", nbpacket, data_length, stats.CRC_errs, stats.retransmitted); p = address+*size-1; while (*p==0x1A) { p--; (*size)--; } printf("Received file is %u bytes.\n",*size); #ifdef USE_CRC printf("Performing checksum ..."); fflush(0); checksum = posix_crc(address,*size); printf("OK\n"); printf("Posix checksum for area 0x%.8lx-0x%.8lx is\n",(unsigned long)address,(unsigned long)address+*size-1); printf("%u %u\n\n",checksum,*size); #endif return 1; } } else { printf("\nError: %s.\n",xmodem_error()); return 0; } } static void find_image_format(caddr_t address, size_t size, image_format_t *format, caddr_t *entry_point, int *compressed) { caddr_t header; size_t min_header_size; min_header_size = 0; #ifdef USE_HEX min_header_size = hex_header_min_size(); #endif #ifdef USE_ELF if (min_header_size=(caddr_t)(SDRAM_BASE+SDRAM_SIZE)) printf("WARNING: load address 0x%.8lx is not located in SDRAM, and might not be\nwriteable.\n", (unsigned long)address); if (xload_image(1, address, &size, &format, get_reserved_segments())) { find_image_format(address,size,&format,&entry_point, &compressed); if (!compressed) { #ifdef USE_HEX if (format==iHex) { printf("Loading Hex image...\n"); if (load_hex_image(address,size,&entry_point,get_reserved_segments())<0) printf("Error:%s\n",hex_image_error()); else printf("Image entry point is 0x%.8lx\n",(unsigned long)entry_point); } #endif #ifdef USE_ELF if (format==iElf) { printf("Loading Elf image...\n"); if (load_elf_image(address,size,&entry_point,get_reserved_segments())<0) printf("Error:%s\n",elf_image_error()); else printf("Image entry point is 0x%.8lx\n",(unsigned long)entry_point); } #endif } } } #ifdef USE_ZLIB static void uncompress(int argc, char **argv) { caddr_t address = NULL; size_t length; caddr_t dest = NULL; int addset; int destset; int v; char c; length = 0; addset = 0; destset = 0; opterr = 0; optind = 1; while ((v=getopt(argc, argv, "a:l:d:"))!=EOF) { c = (char) v; switch (c) { case 'a': address = (caddr_t)strtoul(optarg,NULL,0); addset = 1; break; case 'l': length = (uint32_t)strtoul(optarg,NULL,0); break; case 'd': dest = (caddr_t)strtoul(optarg,NULL,0); destset = 1; break; default: display_usage("uncompress"); return; break; } } if (length==0 || !addset || !destset) { display_usage("uncompress"); return; } if (gunzip(dest,0xFFFFFFFF,address,length,get_reserved_segments())<0) printf("Error: %s.\n",gunzip_error()); } #endif static void go(int argc, char **argv) { if (argc<2) display_usage("go"); else { void *location; location = (void *)strtoul(argv[1],NULL,0); printf("Jumping execution to 0x%.8lx.\n",(unsigned long)location); fflush(0); wait(200000); // wait for the message to be written jump(location); } } static void create(int argc, char **argv) { image_desc_t image_desc; char *name; int v; char c; caddr_t address; size_t size; int flash_result; int raw; int addset; if (argc<2) { display_usage("create"); return; } if (!table_is_setup()) { printf("Error: Table not set-up or corrupted.\n\n"); return; } name = argv[1]; if (!check_image_name(name)) printf("Error: invalid image name \"%s\". Image name must be [a-zA-Z][a-zA-Z0-9-_.]*.\n",name); else if (get_entry(name,&image_desc,&v)>=0) printf("Error: name \"%s\" already used.\n",name); else { argc -= 1; argv += 1; image_desc.load_address = (caddr_t)0x0; image_desc.size = 0; image_desc.entry_point = (caddr_t)0x0; image_desc.storage_address = (caddr_t)0x0; image_desc.format = iBin; image_desc.compressed = 0; addset = 0; opterr = 0; optind = 1; while ((v=getopt(argc, argv, "a:e:f:"))!=EOF) { c = (char) v; switch (c) { case 'a': image_desc.load_address = (caddr_t)strtoul(optarg,NULL,0); addset = 1; break; case 'e': image_desc.entry_point = (caddr_t)strtoul(optarg,NULL,0); break; case 'f': image_desc.storage_address = (caddr_t)strtoul(optarg,NULL,0); break; default: display_usage("create"); return; break; } } if (image_desc.storage_address!=0x0 && (image_desc.storage_address=available_flash_base()+available_flash_size())) { printf("Invalid storage address 0x%.8lx\n",(unsigned long)image_desc.storage_address); return; } if (!addset) { image_desc.load_address = (caddr_t)(SDRAM_BASE+SDRAM_SIZE/2); raw = 0; } else { if (image_desc.entry_point==(caddr_t)0x0) image_desc.entry_point = image_desc.load_address; if (image_desc.load_address<(caddr_t)SDRAM_BASE || image_desc.load_address>=(caddr_t)(SDRAM_BASE+SDRAM_SIZE)) printf("WARNING: load address 0x%.8lx is not located in SDRAM, and might not be\nwriteable.\n", (unsigned long)image_desc.load_address); raw = 1; } if (xload_image(raw,image_desc.load_address,&image_desc.size,&image_desc.format, get_reserved_segments())) { find_image_format(image_desc.load_address,image_desc.size, &image_desc.format,&image_desc.entry_point,&image_desc.compressed); if (image_desc.format==iBin && !addset) { printf("Error: invalid image format, or binary without entry point.\n" "Supported formats are: hex, gz-hex, elf, gz-elf.\n"); return; } if (test_add_entry(name,&image_desc)<0) printf("Error: %s\n",image_table_error()); else { address = image_desc.storage_address; size = image_desc.size; printf("Writing image data in flash memory...\n"); if ((flash_result=flash_get_area(flash_device,&address, &size))>=0) { if ((flash_result=flash_unlock_blocks(flash_device,address, size))>=0) { if ((flash_result=flash_erase_blocks(flash_device,address, size))>=0) { if ((flash_result=flash_write_area(flash_device,image_desc.storage_address, image_desc.load_address, size))>=0) flash_lock_blocks(flash_device,address, size); } } } if (flash_result<0) printf("Flash error: %s.\n",flash_error()); else { printf("Updating table in flash memory...\n"); add_entry(name,&image_desc); printf("created image \"%s\"\n",name); } } } } } static void createraw(int argc, char **argv) { image_desc_t image_desc; char *name; int v; char c; caddr_t address; size_t size; int flash_result; int addset; int entryset; addset = 0; entryset = 0; if (argc<2) { display_usage("createraw"); return; } if (!table_is_setup()) { printf("Error: Table not set-up or corrupted.\n\n"); return; } name = argv[1]; if (!check_image_name(name)) printf("Error: invalid image name \"%s\". Image name must be [a-zA-Z0-9-_]*.\n",name); else if (get_entry(name,&image_desc,&v)>=0) printf("Error: name \"%s\" already used.\n",name); else { argc -= 1; argv += 1; image_desc.load_address = (caddr_t)0x0; image_desc.size = 0; image_desc.entry_point = (caddr_t)0x0; image_desc.storage_address = (caddr_t)0x0; image_desc.format = iBin; image_desc.compressed = 0; opterr = 0; optind = 1; while ((v=getopt(argc, argv, "a:l:e:f:"))!=EOF) { c = (char) v; switch (c) { case 'a': image_desc.load_address = (caddr_t)strtoul(optarg,NULL,0); addset = 1; break; case 'l': image_desc.size = strtoul(optarg,NULL,0); break; case 'e': image_desc.entry_point = (caddr_t)strtoul(optarg,NULL,0); entryset = 1; break; case 'f': image_desc.storage_address = (caddr_t)strtoul(optarg,NULL,0); break; default: display_usage("createraw"); return; break; } } if (image_desc.storage_address!=0x0 && (image_desc.storage_address=available_flash_base()+available_flash_size())) { printf("Invalid storage address 0x%.8lx\n",(unsigned long)image_desc.storage_address); return; } if (!addset || image_desc.size==0) display_usage("createraw"); else if (test_add_entry(name,&image_desc)<0) printf("Error: %s\n",image_table_error()); else { find_image_format(image_desc.load_address,image_desc.size, &image_desc.format,&image_desc.entry_point,&image_desc.compressed); if (image_desc.format==iBin && !entryset) { printf("Error: invalid image format, or binary without entry point.\n" "Supported formats are: hex, gz-hex, elf, gz-elf.\n"); return; } address = image_desc.storage_address; size = image_desc.size; if ((flash_result=flash_get_area(flash_device,&address, &size))>=0) { if ((flash_result=flash_unlock_blocks(flash_device,address, size))>=0) { if ((flash_result=flash_erase_blocks(flash_device,address, size))>=0) { if ((flash_result=flash_write_area(flash_device,image_desc.storage_address, image_desc.load_address, size))>=0) flash_lock_blocks(flash_device,address, size); } } } if (flash_result<0) printf("Flash error: %s.\n",flash_error()); else { printf("Updating table in flash memory...\n"); add_entry(name,&image_desc); printf("created raw image \"%s\"\n",name); } } } } static void createentry(int argc, char **argv) { image_desc_t image_desc; char *name; int v; char c; int addset; int entryset; if (argc<2) { display_usage("createentry"); return; } if (!table_is_setup()) { printf("Error: Table not set-up or corrupted.\n\n"); return; } name = argv[1]; if (!check_image_name(name)) printf("Error: invalid image name \"%s\". Image name must be [a-zA-Z0-9-_]*.\n",name); else if (get_entry(name,&image_desc,&v)>=0) printf("Error: name \"%s\" already used.\n",name); else { argc -= 1; argv += 1; image_desc.load_address = (caddr_t)0x0; image_desc.size = 0; image_desc.entry_point = (caddr_t)0x0; image_desc.storage_address = (caddr_t)0x0; image_desc.format = iBin; image_desc.compressed = 0; addset = 0; entryset = 0; opterr = 0; optind = 1; while ((v=getopt(argc, argv, "a:l:e:f:"))!=EOF) { c = (char) v; switch (c) { case 'a': image_desc.load_address = (caddr_t)strtoul(optarg,NULL,0); addset = 1; break; case 'l': image_desc.size = strtoul(optarg,NULL,0); break; case 'e': image_desc.entry_point = (caddr_t)strtoul(optarg,NULL,0); entryset = 1; break; case 'f': image_desc.storage_address = (caddr_t)strtoul(optarg,NULL,0); break; default: display_usage("createentry"); return; break; } } if (image_desc.storage_address==0 || image_desc.size==0) display_usage("createentry"); else { find_image_format(image_desc.storage_address,image_desc.size, &image_desc.format,&image_desc.entry_point,&image_desc.compressed); if (image_desc.format==iBin && (!entryset || !addset)) { printf("Error: invalid image format, or binary without entry point.\n" "Supported formats are: hex, gz-hex, elf, gz-elf.\n"); return; } printf("Updating table in flash memory...\n"); if (add_entry(name,&image_desc)<0) printf("Error: %s\n",image_table_error()); else printf("created entry \"%s\"\n",name); } } } static void erase(int argc, char **argv) { if (argc<2) display_usage("erase"); else { printf("Erase entry \"%s\" from table(y/n)? ",argv[1]); fflush(0); readline(line,MAX_LINE_LENGTH); if (!strncasecmp(line,"y",1)) { if (remove_entry(argv[1])<0) printf("Error: %s.\n",image_table_error()); } } } #ifdef USE_CRC static void cksum(int argc, char **argv) { image_desc_t image_desc; uint32_t checksum; int selected; if (argc<2) display_usage("cksum"); else { if (get_entry(argv[1],&image_desc,&selected)<0) printf("Error: %s.\n",image_table_error()); else { printf("Performing checksum on image \"%s\" (0x%.8lx-0x%.8lx)...", argv[1],(unsigned long)image_desc.storage_address,(unsigned long)image_desc.storage_address+image_desc.size-1); fflush(0); checksum = posix_crc(image_desc.storage_address,image_desc.size); printf("OK\n"); printf("Posix checksum for area 0x%.8lx-0x%.8lx is\n", (unsigned long)image_desc.storage_address,(unsigned long)image_desc.storage_address+image_desc.size-1); printf("%u %u\n\n",checksum,image_desc.size); } } } #endif static void baudrate(int argc, char **argv) { int baudrate; if (argc<2) { if ((baudrate=uart_get_param(UART_NO,UART_BAUDRATE))<0) printf("Error: unable to get baudrate.\n"); else printf("Current baudrate = %d.\n",baudrate); } else { int i; baudrate = atoi(argv[1]); i = 0; while(valid_baudrates[i]!=0 && baudrate!=valid_baudrates[i]) i++; if (valid_baudrates[i]!=0) { if (uart_stop(UART_NO)<0 || uart_set_param(UART_NO,UART_BAUDRATE,baudrate)<0 || uart_start(UART_NO)<0) printf("Error: unable to set baudrate.\n"); } else { printf("Error: invalid baudrate %d.\n",baudrate); printf("Supported baudrates are: %d", valid_baudrates[0]); i = 1; while(valid_baudrates[i]!=0) printf(", %d",valid_baudrates[i++]); printf(".\n"); } } } static void dumpw(const volatile uint8_t *data, size_t len, uint8_t width) { char ascii_str[17]; int i; int j; char c; if (width!=2 && width!=4) width = 1; c = '\0'; while (len && c!=0x03) { i = 0; printf("%.8lx: ", (unsigned long)data); while (i<16/width && len) { switch(width) { case 4: printf("%.8x ", *((unsigned int *)data)); break; case 2: printf("%.4x ",(unsigned int) *((uint16_t *)data)); break; case 1: default: // width should be 1 printf("%.2x ",(unsigned int) *data); break; } for (j=0;j=0) { printf("Error: attempt to write in reserved region '%s': 0x%.8lx-0x%.8lx\n", reserved_segments->segments[rsv_seg_index].name, (unsigned long)reserved_segments->segments[rsv_seg_index].address, (unsigned long)reserved_segments->segments[rsv_seg_index].address+ reserved_segments->segments[rsv_seg_index].size-1); return; } switch (width) { case 4: *((volatile uint32_t *)address) = (uint32_t) value; break; case 2: *((volatile uint16_t *)address) = (uint16_t) value; break; case 1: default: *((volatile uint8_t *)address) = (uint8_t) value; break; } } static void reset(int argc, char **argv) { printf("Reset the board (y/n)? "); fflush(0); readline(line,MAX_LINE_LENGTH); if (!strncasecmp(line,"y",1)) { printf("Resetting...\n\n"); strncpy(BOOT_MAGIC_ADDR,SWRESET_MAGIC_KEY,BOOT_MAGIC_LEN); software_reset(); } } #ifdef IRQ_STATS static void istat(int argc, char **argv) { uint32_t ml; uint32_t sp; uint32_t tt; uint32_t nt; if (argc==1) { get_irq_stats(&ml,&sp,&tt,&nt); printf("Interrupt stats:\n"); printf(" %u interrupts handled\n",tt); printf(" %u spurious interrupts detected\n",sp); printf(" %u nested interrupts handled\n",nt); printf(" Max interrupt level = %u\n",ml); } else if (!strcmp(argv[1],"-r")) reset_irq_stats(); else display_usage("istat"); } #endif // IRQ_STATS #ifdef LATENCY_STATS static void lstat(int argc, char **argv) { uint32_t latency; if (argc==1) { latency = get_max_latency(); printf("Latency stats:\n"); printf(" %u us max latency\n",latency); } else if (!strcmp(argv[1],"-r")) reset_max_latency(); else display_usage("lstat"); } #endif // LATENCY_STATS #ifdef FLASH_DEBUG static void flash(int argc, char **argv) { flash_describe(flash_device); } #endif // registration void register_commands(void) { register_command("setup", "", "setup", "Resets the table of the images stored in flash memory.", setup); register_command("images", "i", "images", "Display the images stored in flash memory.", images); register_command("run", "r", "run ", "Load and run the image named .", run); register_command("select", "s", "select ", "Select the image named for automatic execution.", select_); register_command("load", "l", "load -a
", "Load an image from the UART, at address
.", load); #ifdef USE_ZLIB register_command("uncompress", "u", "uncompress -a -l -d ", "Uncompress a data region at address .", uncompress); #endif register_command("go", "g", "go
", "Jump to address
", go); register_command("create", "c", "create [-a
[-e ]] [-f ]", "Load an image from the UART, at address
, and create a flash image\n" "named . The image can be in binary, Hex or Elf format, and compressed.", create); register_command("createraw", "w", "createraw -a
-l [ -e ] [-f ]", "Create a flash image named from a block of raw memory data at \n" "address
. The image can be in binary, Hex or Elf format, and compressed.", createraw); register_command("createentry", "y", "createentry [ -a
-e ] -l -f ", "Create a flash image named from a block of flash memory data at \n" "address . The image can be in binary, Hex or Elf format, and \n" "compressed.", createentry); register_command("erase", "e", "erase ", "Erase the flash image named from the image table.\n" "The image data remain stored.", erase); #ifdef USE_CRC register_command("cksum", "k", "cksum ", "Performs a Posix checksum of the image named .", cksum); #endif register_command("baudrate", "b", "baudrate []", "Set the baud rate of the serial channel. Display the current rate if no \n" "argument is given.", baudrate); register_command("dump", "d", "dump -a
-l [-w 1|2|4]", "Dump a memory block at address
, using the specified width.", dump); register_command("set" , "t", "set -a
-v [-w 1|2|4]", "Set the value of the memory data at address
,using the specified width.", set); register_command("reset" , "", "reset", "Reset the board.", reset); #ifdef IRQ_STATS register_command("istat" , "", "istat [-r]", "Interrupt statistics.\nUse -r to reset.", istat); #endif // IRQ_STATS #ifdef LATENCY_STATS register_command("lstat" , "", "lstat [-r]", "Interrupt latency statistics.\nUse -r to reset.", lstat); #endif // LATENCY_STATS #ifdef FLASH_DEBUG register_command("flash" , "f", "flash", "Flash device CFI description.", flash); #endif }