1 /***************************************************************************
\r
2 * Copyright (C) 2007-2008 by Øyvind Harboe *
\r
4 * This program is free software; you can redistribute it and/or modify *
\r
5 * it under the terms of the GNU General Public License as published by *
\r
6 * the Free Software Foundation; either version 2 of the License, or *
\r
7 * (at your option) any later version. *
\r
9 * This program is distributed in the hope that it will be useful, *
\r
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
\r
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
\r
12 * GNU General Public License for more details. *
\r
14 * You should have received a copy of the GNU General Public License *
\r
15 * along with this program; if not, write to the *
\r
16 * Free Software Foundation, Inc., *
\r
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
\r
18 ***************************************************************************/
\r
20 #ifdef HAVE_CONFIG_H
\r
27 #include "configuration.h"
\r
34 #include "command.h"
\r
36 #include "telnet_server.h"
\r
37 #include "gdb_server.h"
\r
39 #include <time_support.h>
\r
40 #include <sys/time.h>
\r
41 #include <sys/types.h>
\r
42 #include <strings.h>
\r
49 #include <cyg/io/flash.h>
\r
50 #include <pkgconf/fs_jffs2.h> // Address of JFFS2
\r
51 #include <network.h>
\r
54 #include <sys/stat.h>
\r
55 #include <cyg/fileio/fileio.h>
\r
57 #include <cyg/athttpd/http.h>
\r
58 #include <cyg/athttpd/socket.h>
\r
59 #include <cyg/athttpd/handler.h>
\r
60 #include <cyg/athttpd/cgi.h>
\r
61 #include <cyg/athttpd/forms.h>
\r
62 #include <cyg/hal/hal_diag.h>
\r
63 #include <cyg/kernel/kapi.h>
\r
64 #include <cyg/io/serialio.h>
\r
65 #include <cyg/io/io.h>
\r
66 #include <netinet/tcp.h>
\r
68 #include <sys/ioctl.h>
\r
69 #include <sys/socket.h>
\r
70 #include <netinet/in.h>
\r
72 #include <arpa/inet.h>
\r
73 #include <sys/types.h>
\r
74 #include <sys/socket.h>
\r
76 #include <netinet/in.h>
\r
78 #include <arpa/inet.h>
\r
80 #include <ifaddrs.h>
\r
86 #if defined(CYGPKG_NET_FREEBSD_STACK)
\r
87 #include <tftp_support.h>
\r
88 /* posix compatibility broken*/
\r
89 struct tftpd_fileops fileops =
\r
91 (int (*)(const char *, int))open,
\r
93 (int (*)(int, const void *, int))write,
\r
94 ( int (*)(int, void *, int))read
\r
99 #define ZYLIN_VERSION "1.42"
\r
100 #define ZYLIN_DATE __DATE__
\r
101 #define ZYLIN_TIME __TIME__
\r
102 #define ZYLIN_OPENOCD 921
\r
103 #define ZYLIN_OPENOCD_VERSION "Zylin JTAG ZY1000 " ZYLIN_VERSION " " ZYLIN_DATE " " ZYLIN_TIME
\r
104 #define ZYLIN_CONFIG_DIR "/config/settings"
\r
106 void diag_write(char *buf, int len)
\r
109 for (j = 0; j < len; j++)
\r
111 diag_printf("%c", buf[j]);
\r
115 static bool serialLog = true;
\r
116 static bool writeLog = true;
\r
127 static int fastload_num;
\r
128 static struct FastLoad *fastload;
\r
130 static void free_fastload()
\r
132 if (fastload!=NULL)
\r
135 for (i=0; i<fastload_num; i++)
\r
137 if (fastload[i].data)
\r
138 free(fastload[i].data);
\r
146 int handle_fast_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
\r
152 u32 max_address=0xffffffff;
\r
158 duration_t duration;
\r
159 char *duration_text;
\r
161 if ((argc < 1)||(argc > 5))
\r
163 return ERROR_COMMAND_SYNTAX_ERROR;
\r
166 /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */
\r
169 image.base_address_set = 1;
\r
170 image.base_address = strtoul(args[1], NULL, 0);
\r
174 image.base_address_set = 0;
\r
178 image.start_address_set = 0;
\r
182 min_address=strtoul(args[3], NULL, 0);
\r
186 max_address=strtoul(args[4], NULL, 0)+min_address;
\r
189 if (min_address>max_address)
\r
191 return ERROR_COMMAND_SYNTAX_ERROR;
\r
194 duration_start_measure(&duration);
\r
196 if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK)
\r
203 fastload_num=image.num_sections;
\r
204 fastload=(struct FastLoad *)malloc(sizeof(struct FastLoad)*image.num_sections);
\r
205 if (fastload==NULL)
\r
207 image_close(&image);
\r
210 memset(fastload, 0, sizeof(struct FastLoad)*image.num_sections);
\r
211 for (i = 0; i < image.num_sections; i++)
\r
213 buffer = malloc(image.sections[i].size);
\r
214 if (buffer == NULL)
\r
216 command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size);
\r
220 if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)
\r
227 u32 length=buf_cnt;
\r
230 /* DANGER!!! beware of unsigned comparision here!!! */
\r
232 if ((image.sections[i].base_address+buf_cnt>=min_address)&&
\r
233 (image.sections[i].base_address<max_address))
\r
235 if (image.sections[i].base_address<min_address)
\r
237 /* clip addresses below */
\r
238 offset+=min_address-image.sections[i].base_address;
\r
242 if (image.sections[i].base_address+buf_cnt>max_address)
\r
244 length-=(image.sections[i].base_address+buf_cnt)-max_address;
\r
247 fastload[i].address=image.sections[i].base_address+offset;
\r
248 fastload[i].data=malloc(length);
\r
249 if (fastload[i].data==NULL)
\r
254 memcpy(fastload[i].data, buffer+offset, length);
\r
255 fastload[i].length=length;
\r
257 image_size += length;
\r
258 command_print(cmd_ctx, "%u byte written at address 0x%8.8x", length, image.sections[i].base_address+offset);
\r
264 duration_stop_measure(&duration, &duration_text);
\r
265 if (retval==ERROR_OK)
\r
267 command_print(cmd_ctx, "downloaded %u byte in %s", image_size, duration_text);
\r
269 free(duration_text);
\r
271 image_close(&image);
\r
273 if (retval!=ERROR_OK)
\r
281 int handle_fast_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
\r
284 return ERROR_COMMAND_SYNTAX_ERROR;
\r
285 if (fastload==NULL)
\r
287 LOG_ERROR("No image in memory");
\r
291 int ms=timeval_ms();
\r
293 for (i=0; i<fastload_num;i++)
\r
296 target_t *target = get_current_target(cmd_ctx);
\r
297 if ((retval = target_write_buffer(target, fastload[i].address, fastload[i].length, fastload[i].data)) != ERROR_OK)
\r
301 size+=fastload[i].length;
\r
303 int after=timeval_ms();
\r
304 command_print(cmd_ctx, "Loaded image %f kBytes/s", (float)(size/1024.0)/((float)(after-ms)/1000.0));
\r
309 /* Give TELNET a way to find out what version this is */
\r
310 int handle_zy1000_version_command(struct command_context_s *cmd_ctx, char *cmd,
\r
311 char **args, int argc)
\r
315 return ERROR_COMMAND_SYNTAX_ERROR;
\r
319 command_print(cmd_ctx, ZYLIN_OPENOCD_VERSION);
\r
320 } else if (strcmp("openocd", args[0])==0)
\r
322 command_print(cmd_ctx, "%d", ZYLIN_OPENOCD);
\r
323 } else if (strcmp("zy1000", args[0])==0)
\r
325 command_print(cmd_ctx, "%s", ZYLIN_VERSION);
\r
326 } else if (strcmp("date", args[0])==0)
\r
328 command_print(cmd_ctx, "%s", ZYLIN_DATE);
\r
331 return ERROR_COMMAND_SYNTAX_ERROR;
\r
337 extern flash_driver_t *flash_drivers[];
\r
338 extern target_type_t *target_types[];
\r
340 #ifdef CYGPKG_PROFILE_GPROF
\r
341 #include <cyg/profile/profile.h>
\r
343 extern char _stext, _etext; // Defined by the linker
\r
345 void start_profile(void)
\r
347 // This starts up the system-wide profiling, gathering
\r
348 // profile information on all of the code, with a 16 byte
\r
349 // "bucket" size, at a rate of 100us/profile hit.
\r
350 // Note: a bucket size of 16 will give pretty good function
\r
351 // resolution. Much smaller and the buffer becomes
\r
352 // much too large for very little gain.
\r
353 // Note: a timer period of 100us is also a reasonable
\r
354 // compromise. Any smaller and the overhead of
\r
355 // handling the timter (profile) interrupt could
\r
356 // swamp the system. A fast processor might get
\r
357 // by with a smaller value, but a slow one could
\r
358 // even be swamped by this value. If the value is
\r
359 // too large, the usefulness of the profile is reduced.
\r
361 // no more interrupts than 1/10ms.
\r
362 // profile_on(&_stext, &_etext, 16, 10000); // DRAM
\r
363 //profile_on((void *)0, (void *)0x40000, 16, 10000); // SRAM
\r
364 profile_on(0, &_etext, 16, 10000); // SRAM & DRAM
\r
368 // launch GDB server if a config file exists
\r
369 bool zylinjtag_parse_config_file(struct command_context_s *cmd_ctx, const char *config_file_name)
\r
371 bool foundFile = false;
\r
372 FILE *config_file = NULL;
\r
373 command_print(cmd_ctx, "executing config file %s", config_file_name);
\r
374 config_file = fopen(config_file_name, "r");
\r
377 fclose(config_file);
\r
379 retval = command_run_linef(cmd_ctx, "script %s", config_file_name);
\r
380 if (retval == ERROR_OK)
\r
386 command_print(cmd_ctx, "Failed executing %s %d", config_file_name, retval);
\r
391 command_print(cmd_ctx, "No %s found", config_file_name);
\r
397 extern int eth0_up;
\r
400 static char reboot_stack[2048];
\r
404 zylinjtag_reboot(cyg_addrword_t data)
\r
407 diag_printf("Rebooting in 100 ticks..\n");
\r
408 cyg_thread_delay(100);
\r
409 diag_printf("Unmounting /config..\n");
\r
411 diag_printf("Rebooting..\n");
\r
412 HAL_PLATFORM_RESET();
\r
414 static cyg_thread zylinjtag_thread_object;
\r
415 static cyg_handle_t zylinjtag_thread_handle;
\r
419 cyg_thread_create(1,
\r
423 (void *)reboot_stack,
\r
424 sizeof(reboot_stack),
\r
425 &zylinjtag_thread_handle,
\r
426 &zylinjtag_thread_object);
\r
427 cyg_thread_resume(zylinjtag_thread_handle);
\r
430 int configuration_output_handler(struct command_context_s *context, const char* line)
\r
432 diag_printf("%s", line);
\r
437 int zy1000_configuration_output_handler_log(struct command_context_s *context, const char* line)
\r
439 LOG_USER_N("%s", line);
\r
444 int handle_rm_command(struct command_context_s *cmd_ctx, char *cmd,
\r
445 char **args, int argc)
\r
449 command_print(cmd_ctx, "rm <filename>");
\r
450 return ERROR_INVALID_ARGUMENTS;
\r
453 if (unlink(args[0]) != 0)
\r
455 command_print(cmd_ctx, "failed: %d", errno);
\r
461 int loadFile(const char *fileName, void **data, int *len);
\r
463 int handle_cat_command(struct command_context_s *cmd_ctx, char *cmd,
\r
464 char **args, int argc)
\r
468 command_print(cmd_ctx, "cat <filename>");
\r
469 return ERROR_INVALID_ARGUMENTS;
\r
472 // NOTE!!! we only have line printing capability so we print the entire file as a single line.
\r
476 int retval = loadFile(args[0], &data, &len);
\r
477 if (retval == ERROR_OK)
\r
479 command_print(cmd_ctx, "%s", data);
\r
484 command_print(cmd_ctx, "%s not found %d", args[0], retval);
\r
489 int handle_trunc_command(struct command_context_s *cmd_ctx, char *cmd,
\r
490 char **args, int argc)
\r
494 command_print(cmd_ctx, "trunc <filename>");
\r
495 return ERROR_INVALID_ARGUMENTS;
\r
498 FILE *config_file = NULL;
\r
499 config_file = fopen(args[0], "w");
\r
500 if (config_file != NULL)
\r
501 fclose(config_file);
\r
507 int handle_meminfo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
\r
509 static int prev = 0;
\r
510 struct mallinfo info;
\r
514 command_print(cmd_ctx, "meminfo");
\r
515 return ERROR_INVALID_ARGUMENTS;
\r
522 command_print(cmd_ctx, "Diff: %d", prev - info.fordblks);
\r
524 prev = info.fordblks;
\r
526 command_print(cmd_ctx, "Available ram: %d", info.fordblks );
\r
531 static bool savePower;
\r
533 static void setPower(bool power)
\r
538 HAL_WRITE_UINT32(0x08000014, 0x8);
\r
541 HAL_WRITE_UINT32(0x08000010, 0x8);
\r
545 int handle_power_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
\r
549 return ERROR_INVALID_ARGUMENTS;
\r
554 if (strcmp(args[0], "on") == 0)
\r
558 else if (strcmp(args[0], "off") == 0)
\r
563 command_print(cmd_ctx, "arg is \"on\" or \"off\"");
\r
564 return ERROR_INVALID_ARGUMENTS;
\r
568 command_print(cmd_ctx, "Target power %s", savePower ? "on" : "off");
\r
573 int handle_append_command(struct command_context_s *cmd_ctx, char *cmd,
\r
574 char **args, int argc)
\r
578 command_print(cmd_ctx,
\r
579 "append <filename> [<string1>, [<string2>, ...]]");
\r
580 return ERROR_INVALID_ARGUMENTS;
\r
583 FILE *config_file = NULL;
\r
584 config_file = fopen(args[0], "a");
\r
585 if (config_file != NULL)
\r
588 fseek(config_file, 0, SEEK_END);
\r
590 for (i = 1; i < argc; i++)
\r
592 fwrite(args[i], strlen(args[i]), 1, config_file);
\r
595 fwrite(" ", 1, 1, config_file);
\r
598 fwrite("\n", 1, 1, config_file);
\r
599 fclose(config_file);
\r
605 extern int telnet_socket;
\r
607 int readMore(int fd, void *data, int length)
\r
609 /* used in select() */
\r
612 /* monitor sockets for acitvity */
\r
614 FD_ZERO(&read_fds);
\r
615 /* listen for new connections */
\r
616 FD_SET(fd, &read_fds);
\r
618 // Maximum 5 seconds.
\r
623 int retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv);
\r
626 diag_printf("Timed out waiting for binary payload\n");
\r
632 return read_socket(fd, data, length);
\r
635 int readAll(int fd, void *data, int length)
\r
640 int actual = readMore(fd, ((char *) data) + pos, length - pos);
\r
641 // diag_printf("Read %d bytes(pos=%d, length=%d)\n", actual, pos, length);
\r
651 int handle_peek_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
\r
656 return ERROR_INVALID_ARGUMENTS;
\r
658 HAL_READ_UINT32(strtoul(args[0], NULL, 0), value);
\r
659 command_print(cmd_ctx, "0x%x : 0x%x", strtoul(args[0], NULL, 0), value);
\r
663 int handle_poke_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
\r
667 return ERROR_INVALID_ARGUMENTS;
\r
669 HAL_WRITE_UINT32(strtoul(args[0], NULL, 0), strtoul(args[1], NULL, 0));
\r
673 int handle_cp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
\r
677 return ERROR_INVALID_ARGUMENTS;
\r
680 // NOTE!!! we only have line printing capability so we print the entire file as a single line.
\r
684 int retval = loadFile(args[0], &data, &len);
\r
685 if (retval != ERROR_OK)
\r
688 FILE *f = fopen(args[1], "wb");
\r
690 retval = ERROR_INVALID_ARGUMENTS;
\r
695 int chunk = len - pos;
\r
696 static const int maxChunk = 512 * 1024; // ~1/sec
\r
697 if (chunk > maxChunk)
\r
702 if ((retval==ERROR_OK)&&(fwrite(((char *)data)+pos, 1, chunk, f)!=chunk))
\r
703 retval = ERROR_INVALID_ARGUMENTS;
\r
705 if (retval != ERROR_OK)
\r
710 command_print(cmd_ctx, "%d", len - pos);
\r
718 if (retval == ERROR_OK)
\r
720 command_print(cmd_ctx, "Copied %s to %s", args[0], args[1]);
\r
723 command_print(cmd_ctx, "Failed: %d", retval);
\r
731 if (retval != ERROR_OK)
\r
737 #ifdef CYGPKG_PROFILE_GPROF
\r
738 extern void start_profile();
\r
740 int eCosBoard_handle_eCosBoard_profile_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
\r
742 command_print(cmd_ctx, "Profiling started");
\r
749 externC void phi_init_all_network_interfaces();
\r
751 command_context_t *cmd_ctx;
\r
753 static bool webRunning = false;
\r
755 void keep_webserver()
\r
757 // Target initialisation is only attempted at startup, so we sleep forever and
\r
758 // let the http server bail us out(i.e. get config files set up).
\r
759 diag_printf("OpenOCD has invoked exit().\n"
\r
760 "Use web server to correct any configuration settings and reboot.\n");
\r
764 // exit() will terminate the current thread and we we'll then sleep eternally or
\r
765 // we'll have a reboot scheduled.
\r
768 extern void printDccChar(char c);
\r
770 static char logBuffer[128 * 1024];
\r
771 static const int logSize = sizeof(logBuffer);
\r
775 void _zylinjtag_diag_write_char(char c, void **param)
\r
779 logBuffer[writePtr] = c;
\r
780 writePtr = (writePtr + 1) % logSize;
\r
787 HAL_DIAG_WRITE_CHAR('\r');
\r
789 HAL_DIAG_WRITE_CHAR(c);
\r
795 #define SHOW_RESULT(a, b) diag_printf(#a " failed %d\n", (int)b)
\r
798 static void copyfile(char *name2, char *name1)
\r
804 ssize_t done, wrote;
\r
806 fd1 = open(name1, O_WRONLY | O_CREAT);
\r
808 SHOW_RESULT( open, fd1 );
\r
810 fd2 = open(name2, O_RDONLY);
\r
812 SHOW_RESULT( open, fd2 );
\r
816 done = read(fd2, buf, IOSIZE );
\r
819 SHOW_RESULT( read, done );
\r
823 if( done == 0 ) break;
\r
825 wrote = write(fd1, buf, done);
\r
826 if( wrote != done ) SHOW_RESULT( write, wrote );
\r
828 if( wrote != done ) break;
\r
832 if( err < 0 ) SHOW_RESULT( close, err );
\r
835 if( err < 0 ) SHOW_RESULT( close, err );
\r
838 static void copydir(char *name)
\r
843 mkdir("/ram/cgi", 0777);
\r
845 dirp = opendir(name);
\r
846 if( dirp == NULL ) SHOW_RESULT( opendir, -1 );
\r
850 struct dirent *entry = readdir(dirp);
\r
855 if (strcmp(entry->d_name, ".") == 0)
\r
857 if (strcmp(entry->d_name, "..") == 0)
\r
860 bool isDir = false;
\r
862 char fullPath[PATH_MAX];
\r
863 strncpy(fullPath, name, PATH_MAX);
\r
864 strcat(fullPath, "/");
\r
865 strncat(fullPath, entry->d_name, PATH_MAX - strlen(fullPath));
\r
867 if (stat(fullPath, &buf) == -1)
\r
869 diag_printf("unable to read status from %s", fullPath);
\r
872 isDir = S_ISDIR(buf.st_mode) != 0;
\r
877 // diag_printf("<INFO>: entry %14s",entry->d_name);
\r
878 char fullname[PATH_MAX];
\r
879 char fullname2[PATH_MAX];
\r
881 strcpy(fullname, name);
\r
882 strcat(fullname, entry->d_name);
\r
884 strcpy(fullname2, "/ram/cgi/");
\r
885 strcat(fullname2, entry->d_name);
\r
886 // diag_printf("from %s to %s\n", fullname, fullname2);
\r
887 copyfile(fullname, fullname2);
\r
889 // diag_printf("\n");
\r
892 err = closedir(dirp);
\r
893 if( err < 0 ) SHOW_RESULT( stat, err );
\r
897 MTAB_ENTRY( romfs_mte1,
\r
901 (CYG_ADDRWORD) &filedata[0] );
\r
904 void openocd_sleep_prelude()
\r
906 cyg_mutex_unlock(&httpstate.jim_lock);
\r
909 void openocd_sleep_postlude()
\r
911 cyg_mutex_lock(&httpstate.jim_lock);
\r
915 zylinjtag_Jim_Command_rm(Jim_Interp *interp,
\r
917 Jim_Obj * const *argv)
\r
922 Jim_WrongNumArgs(interp, 1, argv, "rm ?dirorfile?");
\r
927 if (unlink(Jim_GetString(argv[1], NULL)) == 0)
\r
929 if (rmdir(Jim_GetString(argv[1], NULL)) == 0)
\r
932 return del ? JIM_OK : JIM_ERR;
\r
936 zylinjtag_Jim_Command_ls(Jim_Interp *interp,
\r
938 Jim_Obj * const *argv)
\r
942 Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?");
\r
946 char *name = (char*) Jim_GetString(argv[1], NULL);
\r
949 dirp = opendir(name);
\r
954 Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
\r
958 struct dirent *entry = NULL;
\r
959 entry = readdir(dirp);
\r
963 if ((strcmp(".", entry->d_name)==0)||(strcmp("..", entry->d_name)==0))
\r
966 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, entry->d_name, strlen(entry->d_name)));
\r
970 Jim_SetResult(interp, objPtr);
\r
977 zylinjtag_Jim_Command_getmem(Jim_Interp *interp,
\r
979 Jim_Obj * const *argv)
\r
983 Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?");
\r
989 if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)
\r
991 if (Jim_GetLong(interp, argv[2], &length) != JIM_OK)
\r
994 if (length < 0 && length > (4096 * 1024))
\r
996 Jim_WrongNumArgs(interp, 1, argv, "getmem ?dir?");
\r
1000 void *mem = malloc(length);
\r
1004 target_t *target = get_current_target(cmd_ctx);
\r
1008 int count = length;
\r
1009 if ((address % 4 == 0) && (count % 4 == 0))
\r
1015 if ((retval = target->type->read_memory(target, address, size, count, mem)) != ERROR_OK)
\r
1021 Jim_Obj *objPtr = Jim_NewStringObj(interp, mem, length);
\r
1022 Jim_SetResult(interp, objPtr);
\r
1030 zylinjtag_Jim_Command_peek(Jim_Interp *interp,
\r
1032 Jim_Obj * const *argv)
\r
1036 Jim_WrongNumArgs(interp, 1, argv, "peek ?address?");
\r
1041 if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)
\r
1044 int value = *((volatile int *) address);
\r
1046 Jim_SetResult(interp, Jim_NewIntObj(interp, value));
\r
1052 zylinjtag_Jim_Command_poke(Jim_Interp *interp,
\r
1054 Jim_Obj * const *argv)
\r
1058 Jim_WrongNumArgs(interp, 1, argv, "poke ?address? ?value?");
\r
1063 if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)
\r
1066 if (Jim_GetLong(interp, argv[2], &value) != JIM_OK)
\r
1069 *((volatile int *) address) = value;
\r
1077 zylinjtag_Jim_Command_flash(Jim_Interp *interp,
\r
1079 Jim_Obj * const *argv)
\r
1083 flash_bank_t *t = get_flash_bank_by_num_noprobe(0);
\r
1093 if (retval == JIM_OK)
\r
1095 Jim_SetResult(interp, Jim_NewIntObj(interp, base));
\r
1106 zylinjtag_Jim_Command_log(Jim_Interp *interp,
\r
1108 Jim_Obj * const *argv)
\r
1110 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
\r
1112 if (logCount >= logSize)
\r
1114 Jim_AppendString(httpstate.jim_interp, tclOutput, logBuffer+logCount%logSize, logSize-logCount%logSize);
\r
1116 Jim_AppendString(httpstate.jim_interp, tclOutput, logBuffer, writePtr);
\r
1118 Jim_SetResult(interp, tclOutput);
\r
1123 zylinjtag_Jim_Command_reboot(Jim_Interp *interp,
\r
1125 Jim_Obj * const *argv)
\r
1132 zylinjtag_Jim_Command_mac(Jim_Interp *interp,
\r
1134 Jim_Obj * const *argv)
\r
1138 s = socket(AF_INET, SOCK_DGRAM, 0);
\r
1141 strcpy(ifr.ifr_name, "eth0");
\r
1143 res = ioctl(s, SIOCGIFHWADDR, &ifr);
\r
1152 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
\r
1155 sprintf(hwaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
\r
1156 (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[0],
\r
1157 (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[1],
\r
1158 (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[2],
\r
1159 (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[3],
\r
1160 (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[4],
\r
1161 (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[5]);
\r
1163 Jim_AppendString(httpstate.jim_interp, tclOutput, hwaddr, strlen(hwaddr));
\r
1165 Jim_SetResult(interp, tclOutput);
\r
1171 zylinjtag_Jim_Command_ip(Jim_Interp *interp,
\r
1173 Jim_Obj * const *argv)
\r
1175 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
\r
1177 struct ifaddrs *ifa = NULL, *ifp = NULL;
\r
1179 if (getifaddrs(&ifp) < 0)
\r
1184 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
\r
1189 if (ifa->ifa_addr->sa_family == AF_INET)
\r
1190 salen = sizeof(struct sockaddr_in);
\r
1191 else if (ifa->ifa_addr->sa_family == AF_INET6)
\r
1192 salen = sizeof(struct sockaddr_in6);
\r
1196 if (getnameinfo(ifa->ifa_addr, salen, ip, sizeof(ip), NULL, 0,
\r
1197 NI_NUMERICHOST) < 0)
\r
1202 Jim_AppendString(httpstate.jim_interp, tclOutput, ip, strlen(ip));
\r
1209 Jim_SetResult(interp, tclOutput);
\r
1214 extern Jim_Interp *interp;
\r
1216 static void zylinjtag_startNetwork()
\r
1218 // Bring TCP/IP up immediately before we're ready to accept commands.
\r
1220 // That is as soon as a PING responds, we're accepting telnet sessions.
\r
1221 #if defined(CYGPKG_NET_FREEBSD_STACK)
\r
1222 phi_init_all_network_interfaces();
\r
1228 diag_printf("Network not up and running\n");
\r
1231 #if defined(CYGPKG_NET_FREEBSD_STACK)
\r
1233 tftpd_start(69, &fileops);
\r
1236 cyg_httpd_init_tcl_interpreter();
\r
1238 interp = httpstate.jim_interp;
\r
1240 Jim_CreateCommand(httpstate.jim_interp, "log", zylinjtag_Jim_Command_log, NULL, NULL);
\r
1241 Jim_CreateCommand(httpstate.jim_interp, "reboot", zylinjtag_Jim_Command_reboot, NULL, NULL);
\r
1242 Jim_CreateCommand(httpstate.jim_interp, "peek", zylinjtag_Jim_Command_peek, NULL, NULL);
\r
1243 Jim_CreateCommand(httpstate.jim_interp, "zy1000_flash", zylinjtag_Jim_Command_flash, NULL, NULL);
\r
1244 Jim_CreateCommand(httpstate.jim_interp, "poke", zylinjtag_Jim_Command_poke, NULL, NULL);
\r
1245 Jim_CreateCommand(httpstate.jim_interp, "ls", zylinjtag_Jim_Command_ls, NULL, NULL);
\r
1246 Jim_CreateCommand(httpstate.jim_interp, "getmem", zylinjtag_Jim_Command_getmem, NULL, NULL);
\r
1247 Jim_CreateCommand(httpstate.jim_interp, "mac", zylinjtag_Jim_Command_mac, NULL, NULL);
\r
1248 Jim_CreateCommand(httpstate.jim_interp, "ip", zylinjtag_Jim_Command_ip, NULL, NULL);
\r
1249 Jim_CreateCommand(httpstate.jim_interp, "rm", zylinjtag_Jim_Command_rm, NULL, NULL);
\r
1251 cyg_httpd_start();
\r
1253 webRunning = true;
\r
1255 diag_printf("Web server running\n");
\r
1258 static bool readPowerDropout()
\r
1261 // sample and clear power dropout
\r
1262 HAL_WRITE_UINT32(0x08000010, 0x80);
\r
1263 HAL_READ_UINT32(0x08000010, state);
\r
1264 bool powerDropout;
\r
1265 powerDropout = (state & 0x80) != 0;
\r
1266 return powerDropout;
\r
1272 // sample and clear SRST sensing
\r
1273 HAL_WRITE_UINT32(0x08000010, 0x00000040);
\r
1274 HAL_READ_UINT32(0x08000010, state);
\r
1275 bool srstAsserted;
\r
1276 srstAsserted = (state & 0x40) != 0;
\r
1277 return srstAsserted;
\r
1280 // every 300ms we check for reset & powerdropout and issue a "reset halt" if
\r
1284 static int sense_handler(void *priv)
\r
1286 struct command_context_s *cmd_ctx;
\r
1287 cmd_ctx = (struct command_context_s *) priv;
\r
1289 static bool prevSrstAsserted = false;
\r
1290 static bool prevPowerdropout = false;
\r
1292 bool powerDropout;
\r
1293 powerDropout = readPowerDropout();
\r
1295 bool powerRestored;
\r
1296 powerRestored = prevPowerdropout && !powerDropout;
\r
1297 if (powerRestored)
\r
1299 LOG_USER("Sensed power restore.");
\r
1302 cyg_tick_count_t current = cyg_current_time();
\r
1303 static cyg_tick_count_t lastPower = 0;
\r
1304 bool waitMore = lastPower + 200 > current;
\r
1305 if (powerDropout && !waitMore)
\r
1307 LOG_USER("Sensed power dropout.");
\r
1308 lastPower = current;
\r
1311 bool srstAsserted = readSRST();
\r
1313 bool srstDeasserted;
\r
1314 srstDeasserted = prevSrstAsserted && !srstAsserted;
\r
1316 static cyg_tick_count_t lastSrst = 0;
\r
1317 waitMore = lastSrst + 200 > current;
\r
1318 if (srstDeasserted && !waitMore)
\r
1320 LOG_USER("Sensed nSRST deasserted");
\r
1321 lastSrst = current;
\r
1324 if (!prevSrstAsserted && srstAsserted)
\r
1326 LOG_USER("Sensed nSRST asserted");
\r
1329 prevSrstAsserted = srstAsserted;
\r
1330 prevPowerdropout = powerDropout;
\r
1332 if (srstDeasserted || powerRestored)
\r
1334 /* Other than logging the event we can't do anything here.
\r
1335 * Issuing a reset is a particularly bad idea as we might
\r
1336 * be inside a reset already.
\r
1346 print_exception_handler(cyg_addrword_t data, cyg_code_t exception, cyg_addrword_t info)
\r
1350 char *infoStr = "unknown";
\r
1351 switch (exception)
\r
1353 case CYGNUM_HAL_VECTOR_UNDEF_INSTRUCTION:
\r
1354 infoStr = "undefined instruction";
\r
1356 case CYGNUM_HAL_VECTOR_SOFTWARE_INTERRUPT:
\r
1357 infoStr = "software interrupt";
\r
1359 case CYGNUM_HAL_VECTOR_ABORT_PREFETCH:
\r
1360 infoStr = "abort prefetch";
\r
1362 case CYGNUM_HAL_VECTOR_ABORT_DATA:
\r
1363 infoStr = "abort data";
\r
1369 diag_printf("Exception: %08x(%s) %08x\n", exception, infoStr, info);
\r
1371 diag_printf("Dumping log\n---\n");
\r
1372 if (logCount >= logSize)
\r
1374 diag_write(logBuffer + logCount % logSize, logSize - logCount % logSize);
\r
1376 diag_write(logBuffer, writePtr);
\r
1378 diag_printf("---\nLogdump complete.\n");
\r
1379 diag_printf("Exception: %08x(%s) %08x\n", exception, infoStr, info);
\r
1380 diag_printf("\n---\nRebooting\n");
\r
1381 HAL_PLATFORM_RESET();
\r
1385 static void setHandler(cyg_code_t exception)
\r
1387 cyg_exception_handler_t *old_handler;
\r
1388 cyg_addrword_t old_data;
\r
1390 cyg_exception_set_handler(exception,
\r
1391 print_exception_handler,
\r
1397 static cyg_thread zylinjtag_uart_thread_object;
\r
1398 static cyg_handle_t zylinjtag_uart_thread_handle;
\r
1399 static char uart_stack[4096];
\r
1401 static char forwardBuffer[1024]; // NB! must be smaller than a TCP/IP packet!!!!!
\r
1402 static char backwardBuffer[1024];
\r
1404 static cyg_io_handle_t serial_handle;
\r
1406 void setNoDelay(int session, int flag)
\r
1409 // This decreases latency dramatically for e.g. GDB load which
\r
1410 // does not have a sliding window protocol
\r
1412 // Can cause *lots* of TCP/IP packets to be sent and it would have
\r
1413 // to be enabled/disabled on the fly to avoid the CPU being
\r
1415 setsockopt(session, /* socket affected */
\r
1416 IPPROTO_TCP, /* set option at TCP level */
\r
1417 TCP_NODELAY, /* name of option */
\r
1418 (char *) &flag, /* the cast is historical
\r
1420 sizeof(int)); /* length of option value */
\r
1430 } tcpipSent[512 * 1024];
\r
1434 zylinjtag_uart(cyg_addrword_t data)
\r
1436 int so_reuseaddr_option = 1;
\r
1439 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
\r
1441 LOG_ERROR("error creating socket: %s", strerror(errno));
\r
1445 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int));
\r
1447 struct sockaddr_in sin;
\r
1448 unsigned int address_size;
\r
1449 address_size = sizeof(sin);
\r
1450 memset(&sin, 0, sizeof(sin));
\r
1451 sin.sin_family = AF_INET;
\r
1452 sin.sin_addr.s_addr = INADDR_ANY;
\r
1453 sin.sin_port = htons(5555);
\r
1455 if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) == -1)
\r
1457 LOG_ERROR("couldn't bind to socket: %s", strerror(errno));
\r
1461 if (listen(fd, 1) == -1)
\r
1463 LOG_ERROR("couldn't listen on socket: %s", strerror(errno));
\r
1466 // socket_nonblock(fd);
\r
1471 int session = accept(fd, (struct sockaddr *) &sin, &address_size);
\r
1477 setNoDelay(session, 1);
\r
1478 int oldopts = fcntl(session, F_GETFL, 0);
\r
1479 fcntl(session, F_SETFL, oldopts | O_NONBLOCK); //
\r
1481 int serHandle = open("/dev/ser0", O_RDWR | O_NONBLOCK);
\r
1482 if (serHandle < 0)
\r
1499 FD_ZERO(&write_fds);
\r
1500 FD_ZERO(&read_fds);
\r
1502 FD_SET(session, &read_fds);
\r
1504 FD_SET(serHandle, &read_fds);
\r
1505 if (serHandle > fd_max)
\r
1507 fd_max = serHandle;
\r
1511 cyg_thread_delay(5); // 50ms fixed delay to wait for data to be sent/received
\r
1512 if ((actual == 0) && (actual2 == 0))
\r
1514 int retval = select(fd_max + 1, &read_fds, NULL, NULL, NULL);
\r
1523 memset(backwardBuffer, 's', sizeof(backwardBuffer));
\r
1524 actual2=read(serHandle, backwardBuffer, sizeof(backwardBuffer));
\r
1527 if (errno != EAGAIN)
\r
1529 goto closeSession;
\r
1540 int written = write(session, backwardBuffer + pos2, actual2);
\r
1542 goto closeSession;
\r
1543 actual2 -= written;
\r
1548 if (FD_ISSET(session, &read_fds)&&(sizeof(forwardBuffer)>actual))
\r
1550 // NB! Here it is important that we empty the TCP/IP read buffer
\r
1551 // to make transmission tick right
\r
1552 memmove(forwardBuffer, forwardBuffer + pos, actual);
\r
1555 // this will block if there is no data at all
\r
1556 t=read_socket(session, forwardBuffer+actual, sizeof(forwardBuffer)-actual);
\r
1559 goto closeSession;
\r
1568 /* Do not put things into the serial buffer if it has something to send
\r
1569 * as that can cause a single byte to be sent at the time.
\r
1573 int written = write(serHandle, forwardBuffer + pos, actual);
\r
1576 if (errno != EAGAIN)
\r
1578 goto closeSession;
\r
1580 // The serial buffer is full
\r
1584 actual -= written;
\r
1591 tcpipSent[cur].req = x;
\r
1592 tcpipSent[cur].actual = y;
\r
1593 tcpipSent[cur].req2 = x2;
\r
1594 tcpipSent[cur].actual2 = y2;
\r
1604 for (i = 0; i < 1024; i++)
\r
1606 diag_printf("%d %d %d %d\n", tcpipSent[i].req, tcpipSent[i].actual, tcpipSent[i].req2, tcpipSent[i].actual2);
\r
1614 void startUart(void)
\r
1616 cyg_thread_create(1,
\r
1618 (cyg_addrword_t)0,
\r
1620 (void *)uart_stack,
\r
1621 sizeof(uart_stack),
\r
1622 &zylinjtag_uart_thread_handle,
\r
1623 &zylinjtag_uart_thread_object);
\r
1624 cyg_thread_set_priority(zylinjtag_uart_thread_handle, 1); // low priority as it sits in a busy loop
\r
1625 cyg_thread_resume(zylinjtag_uart_thread_handle);
\r
1630 int handle_uart_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
\r
1634 command_print(cmd_ctx, "usage: uart <baudrate>");
\r
1635 return ERROR_INVALID_ARGUMENTS;
\r
1638 int baud = atol(args[0]);
\r
1643 baud = CYGNUM_SERIAL_BAUD_9600;
\r
1646 baud = CYGNUM_SERIAL_BAUD_19200;
\r
1649 baud = CYGNUM_SERIAL_BAUD_38400;
\r
1652 baud = CYGNUM_SERIAL_BAUD_57600;
\r
1655 baud = CYGNUM_SERIAL_BAUD_115200;
\r
1658 baud = CYGNUM_SERIAL_BAUD_230400;
\r
1661 command_print(cmd_ctx, "unsupported baudrate");
\r
1662 return ERROR_INVALID_ARGUMENTS;
\r
1665 cyg_serial_info_t buf;
\r
1666 cyg_uint32 len = 1;
\r
1667 //get existing serial configuration
\r
1668 len = sizeof(cyg_serial_info_t);
\r
1670 err = cyg_io_get_config(serial_handle, CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN, &buf, &len);
\r
1671 err = cyg_io_get_config(serial_handle, CYG_IO_GET_CONFIG_SERIAL_INFO, &buf, &len);
\r
1672 if (err != ENOERR)
\r
1674 command_print(cmd_ctx, "Failed to get serial port settings %d", err);
\r
1679 err = cyg_io_set_config(serial_handle, CYG_IO_SET_CONFIG_SERIAL_INFO, &buf, &len);
\r
1680 if (err != ENOERR)
\r
1682 command_print(cmd_ctx, "Failed to set serial port settings %d", err);
\r
1689 bool logAllToSerial = false;
\r
1691 /* boolean parameter stored on config */
\r
1692 bool boolParam(char *var)
\r
1694 bool result = false;
\r
1695 char *name = alloc_printf(ZYLIN_CONFIG_DIR "/%s", var);
\r
1701 if (loadFile(name, &data, &len) == ERROR_OK)
\r
1705 result = strncmp((char *) data, "1", len) == 0;
\r
1712 command_context_t *setup_command_handler();
\r
1714 int add_default_dirs(void)
\r
1716 add_script_search_dir(ZYLIN_CONFIG_DIR);
\r
1717 add_script_search_dir("/rom/lib/openocd");
\r
1718 add_script_search_dir("/rom");
\r
1722 int main(int argc, char *argv[])
\r
1724 setHandler(CYGNUM_HAL_VECTOR_UNDEF_INSTRUCTION);
\r
1725 setHandler(CYGNUM_HAL_VECTOR_ABORT_PREFETCH);
\r
1726 setHandler(CYGNUM_HAL_VECTOR_ABORT_DATA);
\r
1729 err = cyg_io_lookup("/dev/ser0", &serial_handle);
\r
1730 if (err != ENOERR)
\r
1732 diag_printf("/dev/ser0 not found\n");
\r
1736 setPower(true); // on by default
\r
1738 atexit(keep_webserver);
\r
1740 err = mount("", "/ram", "ramfs");
\r
1743 diag_printf("unable to mount ramfs\n");
\r
1748 sprintf(address, "%p", &filedata[0]);
\r
1749 err = mount(address, "/rom", "romfs");
\r
1752 diag_printf("unable to mount /rom\n");
\r
1755 err = mount("", "/log", "logfs");
\r
1758 diag_printf("unable to mount logfs\n");
\r
1761 err = mount("", "/tftp", "tftpfs");
\r
1764 diag_printf("unable to mount logfs\n");
\r
1767 log = fopen("/log/log", "w");
\r
1770 diag_printf("Could not open log file /ram/log\n");
\r
1774 diag_init_putc(_zylinjtag_diag_write_char);
\r
1776 // We want this in the log.
\r
1777 diag_printf("Zylin ZY1000. Copyright Zylin AS 2007-2008.\n");
\r
1778 diag_printf("%s\n", ZYLIN_OPENOCD_VERSION);
\r
1782 err = mount("/dev/flash1", "/config", "jffs2");
\r
1785 diag_printf("unable to mount jffs\n");
\r
1789 mkdir(ZYLIN_CONFIG_DIR, 0777);
\r
1790 mkdir(ZYLIN_CONFIG_DIR "/target", 0777);
\r
1791 mkdir(ZYLIN_CONFIG_DIR "/event", 0777);
\r
1793 logAllToSerial = boolParam("logserial");
\r
1795 // We need the network & web server in case there is something wrong with
\r
1796 // the config files that invoke exit()
\r
1797 zylinjtag_startNetwork();
\r
1799 /* we're going to access the jim interpreter from here on... */
\r
1800 openocd_sleep_postlude();
\r
1803 add_default_dirs();
\r
1805 /* initialize commandline interface */
\r
1806 command_context_t *cmd_ctx;
\r
1807 cmd_ctx = setup_command_handler();
\r
1808 command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
\r
1809 command_context_mode(cmd_ctx, COMMAND_CONFIG);
\r
1812 register_command(cmd_ctx, NULL, "zy1000_version", handle_zy1000_version_command,
\r
1813 COMMAND_EXEC, "show zy1000 version numbers");
\r
1815 register_command(cmd_ctx, NULL, "rm", handle_rm_command, COMMAND_ANY,
\r
1818 register_command(cmd_ctx, NULL, "fast_load_image", handle_fast_load_image_command, COMMAND_ANY,
\r
1819 "same args as load_image, image stored in memory");
\r
1821 register_command(cmd_ctx, NULL, "fast_load", handle_fast_load_command, COMMAND_ANY,
\r
1822 "loads active fast load image to current target");
\r
1824 register_command(cmd_ctx, NULL, "cat", handle_cat_command, COMMAND_ANY,
\r
1827 register_command(cmd_ctx, NULL, "trunc", handle_trunc_command, COMMAND_ANY,
\r
1828 "trunc <filname>");
\r
1830 register_command(cmd_ctx, NULL, "append_file", handle_append_command,
\r
1831 COMMAND_ANY, "append <filname>");
\r
1833 register_command(cmd_ctx, NULL, "power", handle_power_command, COMMAND_ANY,
\r
1834 "power <on/off> - turn power switch to target on/off. No arguments - print status.");
\r
1836 register_command(cmd_ctx, NULL, "meminfo", handle_meminfo_command,
\r
1837 COMMAND_ANY, "meminfo");
\r
1839 register_command(cmd_ctx, NULL, "cp", handle_cp_command,
\r
1840 COMMAND_ANY, "cp <from> <to>");
\r
1842 #ifdef CYGPKG_PROFILE_GPROF
\r
1843 register_command(cmd_ctx, NULL, "ecosboard_profile", eCosBoard_handle_eCosBoard_profile_command,
\r
1844 COMMAND_ANY, NULL);
\r
1846 register_command(cmd_ctx, NULL, "uart", handle_uart_command,
\r
1847 COMMAND_ANY, "uart <baud> - forward uart on port 5555");
\r
1851 errVal = log_init(cmd_ctx);
\r
1852 if (errVal != ERROR_OK)
\r
1854 diag_printf("log_init() failed %d\n", errVal);
\r
1858 set_log_output(cmd_ctx, log);
\r
1860 LOG_DEBUG("log init complete");
\r
1862 // diag_printf("Executing config files\n");
\r
1864 if (logAllToSerial)
\r
1866 diag_printf(ZYLIN_CONFIG_DIR "/logserial=1 => sending log output to serial port using \"debug_level 3\" as default.\n");
\r
1867 command_run_line(cmd_ctx, "debug_level 3");
\r
1870 zylinjtag_parse_config_file(cmd_ctx, "/rom/openocd.cfg");
\r
1872 target_register_timer_callback(sense_handler, 200, 1, cmd_ctx);
\r
1875 // diag_printf() is really invoked from many more places than we trust it
\r
1876 // not to cause instabilities(e.g. invoking fputc() from an interrupt is *BAD*).
\r
1878 // Disabling it here is safe and gives us enough logged debug output for now. Crossing
\r
1879 // fingers that it doesn't cause any crashes.
\r
1880 diag_printf("Init complete, GDB & telnet servers launched.\n");
\r
1881 command_set_output_handler(cmd_ctx, zy1000_configuration_output_handler_log, NULL);
\r
1882 if (!logAllToSerial)
\r
1884 serialLog = false;
\r
1887 /* handle network connections */
\r
1888 server_loop(cmd_ctx);
\r
1889 openocd_sleep_prelude();
\r
1891 /* shut server down */
\r
1894 /* free commandline interface */
\r
1895 command_done(cmd_ctx);
\r
1896 umount("/config");
\r
1905 cyg_httpd_exec_cgi_tcl(char *file_name);
\r
1906 cyg_int32 homeForm(CYG_HTTPD_STATE *p)
\r
1908 cyg_httpd_exec_cgi_tcl("/ram/cgi/index.tcl");
\r
1912 CYG_HTTPD_HANDLER_TABLE_ENTRY(root_label, "/", homeForm);
\r
1914 CYG_HTTPD_MIME_TABLE_ENTRY(text_mime_label, "text", "text/plain");
\r
1915 CYG_HTTPD_MIME_TABLE_ENTRY(bin_mime_label, "bin", "application/octet-stream");
\r
1917 #include <pkgconf/system.h>
\r
1918 #include <pkgconf/hal.h>
\r
1919 #include <pkgconf/kernel.h>
\r
1920 #include <pkgconf/io_fileio.h>
\r
1921 #include <pkgconf/fs_rom.h>
\r
1923 #include <cyg/kernel/ktypes.h> // base kernel types
\r
1924 #include <cyg/infra/cyg_trac.h> // tracing macros
\r
1925 #include <cyg/infra/cyg_ass.h> // assertion macros
\r
1926 #include <unistd.h>
\r
1927 #include <sys/types.h>
\r
1928 #include <fcntl.h>
\r
1929 #include <sys/stat.h>
\r
1930 #include <errno.h>
\r
1931 #include <dirent.h>
\r
1933 #include <stdarg.h>
\r
1934 #include <stdio.h>
\r
1935 #include <stdlib.h>
\r
1936 #include <string.h>
\r
1938 #include <cyg/fileio/fileio.h>
\r
1940 #include <cyg/kernel/kapi.h>
\r
1941 #include <cyg/infra/diag.h>
\r
1943 //==========================================================================
\r
1944 // Eventually we want to eXecute In Place from the ROM in a protected
\r
1945 // environment, so we'll need executables to be aligned to a boundary
\r
1946 // suitable for MMU protection. A suitable boundary would be the 4k
\r
1947 // boundary in all the CPU architectures I am currently aware of.
\r
1949 // Forward definitions
\r
1951 // Filesystem operations
\r
1952 static int tftpfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte);
\r
1953 static int tftpfs_umount(cyg_mtab_entry *mte);
\r
1954 static int tftpfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
\r
1955 int mode, cyg_file *fte);
\r
1956 static int tftpfs_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
\r
1957 static int tftpfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
\r
1959 // File operations
\r
1960 static int tftpfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode);
\r
1961 static int tftpfs_fo_close(struct CYG_FILE_TAG *fp);
\r
1962 static int tftpfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence);
\r
1964 //==========================================================================
\r
1965 // Filesystem table entries
\r
1967 // -------------------------------------------------------------------------
\r
1969 // This defines the entry in the filesystem table.
\r
1970 // For simplicity we use _FILESYSTEM synchronization for all accesses since
\r
1971 // we should never block in any filesystem operations.
\r
1973 FSTAB_ENTRY( tftpfs_fste, "tftpfs", 0,
\r
1974 CYG_SYNCMODE_NONE,
\r
1978 (cyg_fsop_unlink *)cyg_fileio_erofs,
\r
1979 (cyg_fsop_mkdir *)cyg_fileio_erofs,
\r
1980 (cyg_fsop_rmdir *)cyg_fileio_erofs,
\r
1981 (cyg_fsop_rename *)cyg_fileio_erofs,
\r
1982 (cyg_fsop_link *)cyg_fileio_erofs,
\r
1983 (cyg_fsop_opendir *)cyg_fileio_erofs,
\r
1984 (cyg_fsop_chdir *)cyg_fileio_erofs,
\r
1985 (cyg_fsop_stat *)cyg_fileio_erofs,
\r
1986 (cyg_fsop_getinfo *)cyg_fileio_erofs,
\r
1987 (cyg_fsop_setinfo *)cyg_fileio_erofs);
\r
1990 // -------------------------------------------------------------------------
\r
1992 // This defines a single ROMFS loaded into ROM at the configured address
\r
1994 // MTAB_ENTRY( rom_mte, // structure name
\r
1995 // "/rom", // mount point
\r
1996 // "romfs", // FIlesystem type
\r
1997 // "", // hardware device
\r
1998 // (CYG_ADDRWORD) CYGNUM_FS_ROM_BASE_ADDRESS // Address in ROM
\r
2002 // -------------------------------------------------------------------------
\r
2003 // File operations.
\r
2004 // This set of file operations are used for normal open files.
\r
2006 static cyg_fileops tftpfs_fileops =
\r
2011 (cyg_fileop_ioctl *)cyg_fileio_erofs,
\r
2012 cyg_fileio_seltrue,
\r
2015 (cyg_fileop_fstat *) cyg_fileio_erofs,
\r
2016 (cyg_fileop_getinfo *) cyg_fileio_erofs,
\r
2017 (cyg_fileop_setinfo *)cyg_fileio_erofs,
\r
2020 // -------------------------------------------------------------------------
\r
2022 // Process a mount request. This mainly finds root for the
\r
2025 static int tftpfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte)
\r
2030 static int tftpfs_umount(cyg_mtab_entry *mte)
\r
2045 static void freeTftp(struct Tftp *t)
\r
2058 static const int tftpMaxSize = 8192 * 1024;
\r
2059 static int tftpfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
\r
2060 int mode, cyg_file *file)
\r
2062 struct Tftp *tftp;
\r
2063 tftp = malloc(sizeof(struct Tftp));
\r
2066 memset(tftp, 0, sizeof(struct Tftp));
\r
2068 file->f_flag |= mode & CYG_FILE_MODE_MASK;
\r
2069 file->f_type = CYG_FILE_TYPE_FILE;
\r
2070 file->f_ops = &tftpfs_fileops;
\r
2071 file->f_offset = 0;
\r
2075 tftp->mem = malloc(tftpMaxSize);
\r
2076 if (tftp->mem == NULL)
\r
2082 char *server = strchr(name, '/');
\r
2083 if (server == NULL)
\r
2089 tftp->server = malloc(server - name + 1);
\r
2090 if (tftp->server == NULL)
\r
2095 strncpy(tftp->server, name, server - name);
\r
2096 tftp->server[server - name] = 0;
\r
2098 tftp->file = strdup(server + 1);
\r
2099 if (tftp->file == NULL)
\r
2105 file->f_data = (CYG_ADDRWORD) tftp;
\r
2110 static int fetchTftp(struct Tftp *tftp)
\r
2112 if (!tftp->readFile)
\r
2115 tftp->actual = tftp_client_get( tftp->file, tftp->server, 0, tftp->mem, tftpMaxSize, TFTP_OCTET, &err);
\r
2117 if (tftp->actual < 0)
\r
2121 tftp->readFile = 1;
\r
2126 // -------------------------------------------------------------------------
\r
2127 // tftpfs_fo_write()
\r
2128 // Read data from file.
\r
2131 tftpfs_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
\r
2133 struct Tftp *tftp = (struct Tftp *) fp->f_data;
\r
2135 if (fetchTftp(tftp) != ENOERR)
\r
2139 off_t pos = fp->f_offset;
\r
2141 for (i = 0; i < uio->uio_iovcnt; i++)
\r
2143 cyg_iovec *iov = &uio->uio_iov[i];
\r
2144 char *buf = (char *) iov->iov_base;
\r
2145 off_t len = iov->iov_len;
\r
2147 if (len + pos > tftp->actual)
\r
2149 len = tftp->actual - pos;
\r
2151 resid += iov->iov_len - len;
\r
2153 memcpy(buf, tftp->mem + pos, len);
\r
2157 uio->uio_resid = resid;
\r
2158 fp->f_offset = pos;
\r
2165 tftpfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
\r
2167 struct Tftp *tftp = (struct Tftp *) fp->f_data;
\r
2170 off_t pos = fp->f_offset;
\r
2172 for (i = 0; i < uio->uio_iovcnt; i++)
\r
2174 cyg_iovec *iov = &uio->uio_iov[i];
\r
2175 char *buf = (char *) iov->iov_base;
\r
2176 off_t len = iov->iov_len;
\r
2178 if (len + pos > tftpMaxSize)
\r
2180 len = tftpMaxSize - pos;
\r
2182 resid += iov->iov_len - len;
\r
2184 memcpy(tftp->mem + pos, buf, len);
\r
2188 uio->uio_resid = resid;
\r
2189 fp->f_offset = pos;
\r
2197 tftpfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
\r
2199 int error = ENOERR;
\r
2203 // -------------------------------------------------------------------------
\r
2204 // romfs_fo_close()
\r
2205 // Close a file. We just clear out the data pointer.
\r
2207 static int tftpfs_fo_close(struct CYG_FILE_TAG *fp)
\r
2209 struct Tftp *tftp = (struct Tftp *) fp->f_data;
\r
2210 int error = ENOERR;
\r
2214 tftp_client_put( tftp->file, tftp->server, 0, tftp->mem, fp->f_offset, TFTP_OCTET, &error);
\r
2222 // -------------------------------------------------------------------------
\r
2223 // romfs_fo_lseek()
\r
2224 // Seek to a new file position.
\r
2226 static int tftpfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence)
\r
2228 struct Tftp *tftp = (struct Tftp *) fp->f_data;
\r
2229 off_t pos = *apos;
\r
2231 if (fetchTftp(tftp) != ENOERR)
\r
2237 // Pos is already where we want to be.
\r
2241 // Add pos to current offset.
\r
2242 pos += fp->f_offset;
\r
2246 // Add pos to file size.
\r
2247 pos += tftp->actual;
\r
2254 // Check that pos is still within current file size, or at the
\r
2256 if (pos < 0 || pos > tftp->actual)
\r
2259 // All OK, set fp offset and return new position.
\r
2260 *apos = fp->f_offset = pos;
\r
2265 void usleep(int us)
\r
2268 cyg_thread_delay(us / 10000 + 1);
\r
2273 // Chunked version.
\r
2275 show_log_entry(CYG_HTTPD_STATE *phttpstate)
\r
2277 cyg_httpd_start_chunked("text");
\r
2278 if (logCount >= logSize)
\r
2280 cyg_httpd_write_chunked(logBuffer+logCount%logSize, logSize-logCount%logSize);
\r
2282 cyg_httpd_write_chunked(logBuffer, writePtr);
\r
2283 cyg_httpd_end_chunked();
\r
2287 CYG_HTTPD_HANDLER_TABLE_ENTRY(show_log, "/ram/log", show_log_entry);
\r
2289 // Filesystem operations
\r
2290 static int logfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte);
\r
2291 static int logfs_umount(cyg_mtab_entry *mte);
\r
2292 static int logfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
\r
2293 int mode, cyg_file *fte);
\r
2295 logfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
\r
2297 // File operations
\r
2298 static int logfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode);
\r
2299 static int logfs_fo_close(struct CYG_FILE_TAG *fp);
\r
2301 //==========================================================================
\r
2302 // Filesystem table entries
\r
2304 // -------------------------------------------------------------------------
\r
2306 // This defines the entry in the filesystem table.
\r
2307 // For simplicity we use _FILESYSTEM synchronization for all accesses since
\r
2308 // we should never block in any filesystem operations.
\r
2309 FSTAB_ENTRY( logfs_fste, "logfs", 0,
\r
2310 CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
\r
2314 (cyg_fsop_unlink *)cyg_fileio_erofs,
\r
2315 (cyg_fsop_mkdir *)cyg_fileio_erofs,
\r
2316 (cyg_fsop_rmdir *)cyg_fileio_erofs,
\r
2317 (cyg_fsop_rename *)cyg_fileio_erofs,
\r
2318 (cyg_fsop_link *)cyg_fileio_erofs,
\r
2319 (cyg_fsop_opendir *)cyg_fileio_erofs,
\r
2320 (cyg_fsop_chdir *)cyg_fileio_erofs,
\r
2321 (cyg_fsop_stat *)cyg_fileio_erofs,
\r
2322 (cyg_fsop_getinfo *)cyg_fileio_erofs,
\r
2323 (cyg_fsop_setinfo *)cyg_fileio_erofs);
\r
2325 // -------------------------------------------------------------------------
\r
2326 // File operations.
\r
2327 // This set of file operations are used for normal open files.
\r
2329 static cyg_fileops logfs_fileops =
\r
2331 (cyg_fileop_read *)cyg_fileio_erofs,
\r
2332 (cyg_fileop_write *)logfs_fo_write,
\r
2333 (cyg_fileop_lseek *) cyg_fileio_erofs,
\r
2334 (cyg_fileop_ioctl *)cyg_fileio_erofs,
\r
2335 cyg_fileio_seltrue,
\r
2338 (cyg_fileop_fstat *)cyg_fileio_erofs,
\r
2339 (cyg_fileop_getinfo *) cyg_fileio_erofs,
\r
2340 (cyg_fileop_setinfo *)cyg_fileio_erofs,
\r
2343 // -------------------------------------------------------------------------
\r
2345 // Process a mount request. This mainly finds root for the
\r
2348 static int logfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte)
\r
2353 static int logfs_umount(cyg_mtab_entry *mte)
\r
2358 static int logfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
\r
2359 int mode, cyg_file *file)
\r
2361 file->f_flag |= mode & CYG_FILE_MODE_MASK;
\r
2362 file->f_type = CYG_FILE_TYPE_FILE;
\r
2363 file->f_ops = &logfs_fileops;
\r
2364 file->f_offset = 0;
\r
2370 // -------------------------------------------------------------------------
\r
2371 // logfs_fo_write()
\r
2372 // Write data to file.
\r
2375 logfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
\r
2378 for (i = 0; i < uio->uio_iovcnt; i++)
\r
2380 cyg_iovec *iov = &uio->uio_iov[i];
\r
2381 char *buf = (char *) iov->iov_base;
\r
2382 off_t len = iov->iov_len;
\r
2384 diag_write(buf, len);
\r
2386 uio->uio_resid = 0;
\r
2391 logfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
\r
2396 // -------------------------------------------------------------------------
\r
2397 // romfs_fo_close()
\r
2398 // Close a file. We just clear out the data pointer.
\r
2400 static int logfs_fo_close(struct CYG_FILE_TAG *fp)
\r