FreeCalypso > hg > freecalypso-sw
changeset 865:f5affe83ba2d
lldbg hack (poor girl's substitute for JTAG) implemented
author | Space Falcon <falcon@ivan.Harhan.ORG> |
---|---|
date | Fri, 15 May 2015 00:02:03 +0000 |
parents | 4fa939eada22 |
children | 3adb4154f02f |
files | gsm-fw/Makefile gsm-fw/cfgmagic/feature.lldbg gsm-fw/cfgmagic/processconf.sh gsm-fw/finlink/Makefile gsm-fw/lldbg/Makefile gsm-fw/lldbg/README gsm-fw/lldbg/cmd_dump.c gsm-fw/lldbg/cmd_r16.c gsm-fw/lldbg/cmd_r32.c gsm-fw/lldbg/cmd_r8.c gsm-fw/lldbg/cmd_w16.c gsm-fw/lldbg/cmd_w32.c gsm-fw/lldbg/cmd_w8.c gsm-fw/lldbg/cmdentry.c gsm-fw/lldbg/cmdtab.c gsm-fw/lldbg/cmdtab.h gsm-fw/lldbg/dispatch.c gsm-fw/lldbg/doprnt.c gsm-fw/lldbg/entry.S gsm-fw/lldbg/entryinfo.c gsm-fw/lldbg/getchar.c gsm-fw/lldbg/hexarg.c gsm-fw/lldbg/main.c gsm-fw/lldbg/ns16550.h gsm-fw/lldbg/parseargs.c gsm-fw/lldbg/printf.c gsm-fw/lldbg/putchar.c gsm-fw/lldbg/serio.S gsm-fw/lldbg/types.h |
diffstat | 29 files changed, 999 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/gsm-fw/Makefile Sun May 10 19:35:29 2015 +0000 +++ b/gsm-fw/Makefile Fri May 15 00:02:03 2015 +0000 @@ -1,5 +1,5 @@ SUBDIR= L1 bsp ccd comlib finlink g23m-aci g23m-glue g23m-gsm gpf include \ - libiram nucleus riviera serial services sprintf sysglue + libiram lldbg nucleus riviera serial services sprintf sysglue default: config.stamp ${MAKE} ${MFLAGS} -f Makefile.build $@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/cfgmagic/feature.lldbg Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,3 @@ +CONFIG_LLDBG=1 +export_to_c CONFIG_LLDBG CONFIG_LLDBG_UART_BASE +export_to_mk CONFIG_LLDBG
--- a/gsm-fw/cfgmagic/processconf.sh Sun May 10 19:35:29 2015 +0000 +++ b/gsm-fw/cfgmagic/processconf.sh Fri May 15 00:02:03 2015 +0000 @@ -53,8 +53,10 @@ # Serial configuration case "$RVTMUX_UART_port" in IrDA) + CONFIG_LLDBG_UART_BASE=0xFFFF5000 ;; MODEM) + CONFIG_LLDBG_UART_BASE=0xFFFF5800 CONFIG_RVTMUX_ON_MODEM=1 export_to_c CONFIG_RVTMUX_ON_MODEM ;; @@ -118,6 +120,10 @@ BUILD_COMPONENTS="$BUILD_COMPONENTS ccd comlib" BUILD_COMPONENTS="$BUILD_COMPONENTS g23m-aci g23m-glue g23m-gsm" fi +if [ "$CONFIG_LLDBG" = 1 ] +then + BUILD_COMPONENTS="$BUILD_COMPONENTS lldbg" +fi export_to_mk BUILD_COMPONENTS
--- a/gsm-fw/finlink/Makefile Sun May 10 19:35:29 2015 +0000 +++ b/gsm-fw/finlink/Makefile Fri May 15 00:02:03 2015 +0000 @@ -53,6 +53,9 @@ ifeq (${RVM_ETM_SWE},1) EXT_PIECES+= ../services/etm/xipcode.o endif +ifeq (${CONFIG_LLDBG},1) +EXT_PIECES+= ../lldbg/xipcode.o +endif flashImage: ${FLASH_TARGET} ramImage: ${RAM_TARGET}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/Makefile Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,16 @@ +CC= arm-elf-gcc +CFLAGS= -Os -fno-builtin -mthumb-interwork -mthumb +ASFLAGS=-mthumb-interwork +LD= arm-elf-ld + +OBJS= cmd_dump.o cmd_r16.o cmd_r32.o cmd_r8.o cmd_w16.o cmd_w32.o cmd_w8.o \ + cmdentry.o cmdtab.o dispatch.o doprnt.o entry.o entryinfo.o getchar.o \ + hexarg.o main.o parseargs.o printf.o putchar.o serio.o + +all: xipcode.o + +xipcode.o: ${OBJS} + ${LD} -r -o $@ ${OBJS} + +clean: + rm -f *.[oa] *errs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/README Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,30 @@ +The hack implemented in this directory is a poor girl's substitute for JTAG, +concocted for the purpose of debugging hard crashes in the firmware. The +intended usage is that the developer seeking to troubleshoot perplexing +misbehavior in the firmware inserts a call to lldbg_entry() as a form of +breakpoint at the earliest place in the main fw where it is seen that something +has gone astray, and when the thread of code execution hits this lldbg_entry() +function, the regular Nucleus environment gets completely frozen. Lldbg entry +code saves all registers and the return address (LR) on whatever stack it is +was called on, then disables all interrupts and switches to its own stack which +is not used by any other part of the fw. + +This lldbg code is linked together with the main fw when feature lldbg is +enabled in build.conf, but it stands as its own separate body. All functions +and variables within lldbg are prefixed with lldbg_ to avoid any clashes, and +once this lldbg code gains control, it does everything on its own without making +use of *any* part of the regular fw. The code that forms lldbg is based on +FreeCalypso target-utils (loadagent) and is fully independent of the regular fw. + +Lldbg uses its own UART input and output code as well: the entry code waits for +any previous output (presumably RVTMUX) to go out, then sends out an STX-wrapped +message to make the lldbg entry visible in rvtdump/rvinterf, preceded by 3 STX +characters to terminate any RVTMUX packet in progress. From this point onward +all further communication is done in an ASCII terminal fashion: upon seeing the +lldbg entry message, the user needs to kill rvtdump/rvinterf and switch to +fc-serterm. All lldbg code runs with interrupts disabled, thus UART input and +output are polled. + +Once in lldbg mode, the user (developer) can execute various memory dump +commands to see the frozen state of the fw upon lldbg entry, and hopefully +figure out what went wrong earlier.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/cmd_dump.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,50 @@ +/* + * This is a human-oriented memory dump command. The dump is given in + * both hex and ASCII, with readable spacing. + */ + +#include <sys/types.h> +#include "types.h" + +void +lldbg_cmd_dump(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long start, length; + u_long offset; + u_char intbuf[16]; + int i, c; + + if (lldbg_parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (lldbg_parse_hexarg(argv[0], 8, &start) < 0) { + lldbg_printf("ERROR: arg1 must be a valid 32-bit hex address\n"); + return; + } + if (lldbg_parse_hexarg(argv[1], 8, &length) < 0) { + lldbg_printf("ERROR: arg2 must be a valid 32-bit hex value (length)\n"); + return; + } + if (start & 0xF || length & 0xF) { + lldbg_printf("ERROR: implementation limit: 16-byte alignment required\n"); + return; + } + for (offset = 0; offset < length; offset += 0x10) { + bcopy(start + offset, intbuf, 0x10); + lldbg_printf("%08X: ", start + offset); + for (i = 0; i < 16; i++) { + lldbg_printf("%02X ", intbuf[i]); + if ((i & 3) == 3) + lldbg_putchar(' '); + } + for (i = 0; i < 16; i++) { + c = intbuf[i]; + if (c >= ' ' && c <= '~') + lldbg_putchar(c); + else + lldbg_putchar('.'); + } + lldbg_putchar('\n'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/cmd_r16.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,26 @@ +/* + * r16 hexaddr -- read a 16-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +lldbg_cmd_r16(argbulk) + char *argbulk; +{ + char *argv[2]; + u_long addr; + + if (lldbg_parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (lldbg_parse_hexarg(argv[0], 8, &addr) < 0) { + lldbg_printf("ERROR: argument must be a valid 32-bit hex address\n"); + return; + } + if (addr & 1) { + lldbg_printf("ERROR: unaligned address\n"); + return; + } + lldbg_printf("%04X\n", *(volatile u16 *)addr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/cmd_r32.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,26 @@ +/* + * r32 hexaddr -- read a 32-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +lldbg_cmd_r32(argbulk) + char *argbulk; +{ + char *argv[2]; + u_long addr; + + if (lldbg_parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (lldbg_parse_hexarg(argv[0], 8, &addr) < 0) { + lldbg_printf("ERROR: argument must be a valid 32-bit hex address\n"); + return; + } + if (addr & 3) { + lldbg_printf("ERROR: unaligned address\n"); + return; + } + lldbg_printf("%08X\n", *(volatile u32 *)addr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/cmd_r8.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,22 @@ +/* + * r8 hexaddr -- read an 8-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +lldbg_cmd_r8(argbulk) + char *argbulk; +{ + char *argv[2]; + u_long addr; + + if (lldbg_parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (lldbg_parse_hexarg(argv[0], 8, &addr) < 0) { + lldbg_printf("ERROR: argument must be a valid 32-bit hex address\n"); + return; + } + lldbg_printf("%02X\n", *(volatile u8 *)addr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/cmd_w16.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,30 @@ +/* + * w16 hexaddr xxxx -- write a 16-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +lldbg_cmd_w16(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long addr, data; + + if (lldbg_parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (lldbg_parse_hexarg(argv[0], 8, &addr) < 0) { + lldbg_printf("ERROR: arg1 must be a valid 32-bit hex address\n"); + return; + } + if (addr & 1) { + lldbg_printf("ERROR: unaligned address\n"); + return; + } + if (lldbg_parse_hexarg(argv[1], 4, &data) < 0) { + lldbg_printf("ERROR: arg2 must be a valid 16-bit hex value\n"); + return; + } + *(volatile u16 *)addr = data; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/cmd_w32.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,30 @@ +/* + * w32 hexaddr xxxxxxxx -- write a 32-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +lldbg_cmd_w32(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long addr, data; + + if (lldbg_parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (lldbg_parse_hexarg(argv[0], 8, &addr) < 0) { + lldbg_printf("ERROR: arg1 must be a valid 32-bit hex address\n"); + return; + } + if (addr & 3) { + lldbg_printf("ERROR: unaligned address\n"); + return; + } + if (lldbg_parse_hexarg(argv[1], 8, &data) < 0) { + lldbg_printf("ERROR: arg2 must be a valid 32-bit hex value\n"); + return; + } + *(volatile u32 *)addr = data; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/cmd_w8.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,26 @@ +/* + * w8 hexaddr xx -- write an 8-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +lldbg_cmd_w8(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long addr, data; + + if (lldbg_parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (lldbg_parse_hexarg(argv[0], 8, &addr) < 0) { + lldbg_printf("ERROR: arg1 must be a valid 32-bit hex address\n"); + return; + } + if (lldbg_parse_hexarg(argv[1], 2, &data) < 0) { + lldbg_printf("ERROR: arg2 must be a valid 8-bit hex value\n"); + return; + } + *(volatile u8 *)addr = data; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/cmdentry.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,72 @@ +/* + * This module implements ASCII command entry via the serial port, + * with normal echo and minimal editing (rubout and kill). + * + * The command string buffer is bss-allocated here as well. It is + * sized to allow a maximum-size S-record to be sent as a command, + * as that is how we expect flash loading and XRAM chain-loading + * to be done. + */ + +#define MAXCMD 527 + +char lldbg_command[MAXCMD+1]; + +/* + * The command_entry() function takes no arguments, and begins by waiting + * for serial input - hence the prompt should be printed before calling it. + * + * This function returns when one of the following characters is received: + * CR - accepts the command + * ^C or ^U - cancels the command + * + * The return value is non-zero if a non-empty command was accepted with CR, + * or 0 if the user hit CR with no input or if the command was canceled + * with ^C or ^U. In any case a CRLF is sent out the serial port + * to close the input echo line before this function returns. + */ +lldbg_command_entry() +{ + int inlen, ch; + + for (inlen = 0; ; ) { + ch = lldbg_getchar(); + if (ch >= ' ' && ch <= '~') { + if (inlen < MAXCMD) { + lldbg_command[inlen++] = ch; + lldbg_putchar(ch); + } else + /* putchar(7) */; + continue; + } + switch (ch) { + case '\r': + case '\n': + lldbg_command[inlen] = '\0'; + lldbg_putchar('\n'); + return(inlen); + case '\b': /* BS */ + case 0x7F: /* DEL */ + if (inlen) { + lldbg_putchar('\b'); + lldbg_putchar(' '); + lldbg_putchar('\b'); + inlen--; + } else + /* putchar(7) */; + continue; + case 0x03: /* ^C */ + lldbg_putchar('^'); + lldbg_putchar('C'); + lldbg_putchar('\n'); + return(0); + case 0x15: /* ^U */ + lldbg_putchar('^'); + lldbg_putchar('U'); + lldbg_putchar('\n'); + return(0); + default: + /* putchar(7) */; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/cmdtab.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,22 @@ +#include "cmdtab.h" + +extern void lldbg_cmd_dump(); +extern void lldbg_cmd_entry(); +extern void lldbg_cmd_r8(); +extern void lldbg_cmd_r16(); +extern void lldbg_cmd_r32(); +extern void lldbg_cmd_w8(); +extern void lldbg_cmd_w16(); +extern void lldbg_cmd_w32(); + +const struct cmdtab lldbg_cmdtab[] = { + {"dump", lldbg_cmd_dump}, + {"entry", lldbg_cmd_entry}, + {"r8", lldbg_cmd_r8}, + {"r16", lldbg_cmd_r16}, + {"r32", lldbg_cmd_r32}, + {"w8", lldbg_cmd_w8}, + {"w16", lldbg_cmd_w16}, + {"w32", lldbg_cmd_w32}, + {0, 0} +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/cmdtab.h Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,6 @@ +/* this structure is used for interactive command dispatch */ + +struct cmdtab { + char *cmd; + void (*func)(); +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/dispatch.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,32 @@ +/* + * This module implements the dispatch of interactively entered + * commands to their respective implementation functions via cmdtab. + */ + +#include "cmdtab.h" + +extern char lldbg_command[]; +extern struct cmdtab lldbg_cmdtab[]; + +void +lldbg_command_dispatch() +{ + char *cp, *np; + struct cmdtab *tp; + + for (cp = lldbg_command; *cp == ' '; cp++) + ; + if (!*cp) + return; + for (np = cp; *cp && *cp != ' '; cp++) + ; + if (*cp) + *cp++ = '\0'; + for (tp = lldbg_cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, np)) + break; + if (tp->func) + tp->func(cp); + else + lldbg_printf("ERROR: unknown or unimplemented command\n"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/doprnt.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,298 @@ +/* the guts of printf - this implementation came from 4.3BSD-Tahoe */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdarg.h> + +extern void lldbg_putchar(); +#define PUTC lldbg_putchar + +#define ARG() \ + _ulong = flags&LONGINT ? va_arg(argp, long) : va_arg(argp, int); + +#define BUF 12 + +#define todigit(c) ((c) - '0') +#define tochar(n) ((n) + '0') + +#define LONGINT 0x01 /* long integer */ +#define LONGDBL 0x02 /* long double; unimplemented */ +#define SHORTINT 0x04 /* short integer */ +#define ALT 0x08 /* alternate form */ +#define LADJUST 0x10 /* left adjustment */ +#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ +#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ + +lldbg_doprnt(fmt0, argp, outfunc, outfunc_param) + u_char *fmt0; + va_list argp; + void (*outfunc)(); + void *outfunc_param; +{ + register u_char *fmt; /* format string */ + register int ch; /* character from fmt */ + register int cnt; /* return value accumulator */ + register int n; /* random handy integer */ + register char *t; /* buffer pointer */ + u_long _ulong; /* integer arguments %[diouxX] */ + int base; /* base for [diouxX] conversion */ + int dprec; /* decimal precision in [diouxX] */ + int fieldsz; /* field size expanded by sign, etc */ + int flags; /* flags as above */ + int prec; /* precision from format (%.3d), or -1 */ + int realsz; /* field size expanded by decimal precision */ + int size; /* size of converted field or string */ + int width; /* width from format (%8d), or 0 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ + char softsign; /* temporary negative sign for floats */ + char *digs; /* digits for [diouxX] conversion */ + char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ + + fmt = fmt0; + digs = "0123456789abcdef"; + for (cnt = 0;; ++fmt) { + for (; (ch = *fmt) && ch != '%'; ++cnt, ++fmt) + PUTC(ch); + if (!ch) + return (cnt); + + flags = 0; dprec = 0; width = 0; + prec = -1; + sign = '\0'; + +rflag: switch (*++fmt) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if ((width = va_arg(argp, int)) >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if (*++fmt == '*') + n = va_arg(argp, int); + else { + n = 0; + while (isascii(*fmt) && isdigit(*fmt)) + n = 10 * n + todigit(*fmt++); + --fmt; + } + prec = n < 0 ? -1 : n; + goto rflag; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + todigit(*fmt); + } while (isascii(*++fmt) && isdigit(*fmt)); + width = n; + --fmt; + goto rflag; + case 'L': + flags |= LONGDBL; + goto rflag; + case 'h': + flags |= SHORTINT; + goto rflag; + case 'l': + flags |= LONGINT; + goto rflag; + case 'c': + *(t = buf) = va_arg(argp, int); + size = 1; + sign = '\0'; + goto pforw; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + ARG(); + if ((long)_ulong < 0) { + _ulong = -_ulong; + sign = '-'; + } + base = 10; + goto number; + case 'n': + if (flags & LONGINT) + *va_arg(argp, long *) = cnt; + else if (flags & SHORTINT) + *va_arg(argp, short *) = cnt; + else + *va_arg(argp, int *) = cnt; + break; + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + ARG(); + base = 8; + goto nosign; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + /* NOSTRICT */ + _ulong = (u_long)va_arg(argp, void *); + base = 16; + goto nosign; + case 's': + if (!(t = va_arg(argp, char *))) + t = "(null)"; + if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen() will go further. + */ + char *p; + + for (p = t, size = 0; size < prec; p++, size++) + if (*p == '\0') + break; + } else + size = strlen(t); + sign = '\0'; + goto pforw; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + ARG(); + base = 10; + goto nosign; + case 'X': + digs = "0123456789ABCDEF"; + /* FALLTHROUGH */ + case 'x': + ARG(); + base = 16; + /* leading 0x/X only if non-zero */ + if (flags & ALT && _ulong != 0) + flags |= HEXPREFIX; + + /* unsigned conversions */ +nosign: sign = '\0'; + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ +number: if ((dprec = prec) >= 0) + flags &= ~ZEROPAD; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + t = buf + BUF; + if (_ulong != 0 || prec != 0) { + do { + *--t = digs[_ulong % base]; + _ulong /= base; + } while (_ulong); + digs = "0123456789abcdef"; + if (flags & ALT && base == 8 && *t != '0') + *--t = '0'; /* octal leading 0 */ + } + size = buf + BUF - t; + +pforw: + /* + * All reasonable formats wind up here. At this point, + * `t' points to a string which (if not flags&LADJUST) + * should be padded out to `width' places. If + * flags&ZEROPAD, it should first be prefixed by any + * sign or other prefix; otherwise, it should be blank + * padded before the prefix is emitted. After any + * left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print + * the string proper, then emit zeroes required by any + * leftover floating precision; finally, if LADJUST, + * pad with blanks. + */ + + /* + * compute actual size, so we know how much to pad + * fieldsz excludes decimal prec; realsz includes it + */ + fieldsz = size; + if (sign) + fieldsz++; + if (flags & HEXPREFIX) + fieldsz += 2; + realsz = dprec > fieldsz ? dprec : fieldsz; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0 && width) + for (n = realsz; n < width; n++) + PUTC(' '); + /* prefix */ + if (sign) + PUTC(sign); + if (flags & HEXPREFIX) { + PUTC('0'); + PUTC((char)*fmt); + } + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + for (n = realsz; n < width; n++) + PUTC('0'); + /* leading zeroes from decimal precision */ + for (n = fieldsz; n < dprec; n++) + PUTC('0'); + + for (n = size; --n >= 0; ) + PUTC(*t++); + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + for (n = realsz; n < width; n++) + PUTC(' '); + /* finally, adjust cnt */ + cnt += width > realsz ? width : realsz; + break; + case '\0': /* "%?" prints ?, unless ? is NULL */ + return (cnt); + default: + PUTC((char)*fmt); + cnt++; + } + } + /* NOTREACHED */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/entry.S Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,23 @@ + .section "ext.ram","aw",%nobits + .balign 4 + .globl lldbg_stack +lldbg_stack: + .space 2048 +lldbg_init_sp: + + .text + .code 32 + .globl lldbg_entry +lldbg_entry: + stmfd sp!, {r0-r12,lr} + mrs r0, CPSR + mov r1, sp + /* supervisor mode, disable all interrupts */ + msr CPSR_c, #0xd3 + ldr sp, =lldbg_init_sp + /* save entry SP and CPSR */ + ldr r2, =lldbg_entry_cpsr + str r0, [r2] + ldr r2, =lldbg_entry_sp + str r1, [r2] + b lldbg_main
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/entryinfo.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,11 @@ +#include "types.h" + +u32 lldbg_entry_cpsr; +u32 lldbg_entry_sp; + +void +lldbg_cmd_entry() +{ + lldbg_printf("CPSR on entry: %08X\n", lldbg_entry_cpsr); + lldbg_printf("SP on entry after register save: %08X\n", lldbg_entry_sp); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/getchar.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,12 @@ +extern int lldbg_serial_in_poll(); + +int +lldbg_getchar() +{ + register int c; + + do + c = lldbg_serial_in_poll(); + while (c < 0); + return c; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/hexarg.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,29 @@ +/* + * Many commands take hex arguments. This module contains the parse_hexarg() + * function, which is a wrapper around strtoul that performs some additional + * checks. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdlib.h> + +lldbg_parse_hexarg(arg, maxdigits, valp) + char *arg; + int maxdigits; + u_long *valp; +{ + char *cp = arg, *bp; + int len; + + if (cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X')) + cp += 2; + for (bp = cp; *cp; cp++) + if (!isxdigit(*cp)) + return(-1); + len = cp - bp; + if (len < 1 || len > maxdigits) + return(-1); + *valp = strtoul(arg, 0, 16); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/main.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,11 @@ +#include "types.h" + +lldbg_main() +{ + lldbg_printf("\2\2\2*Low Level Debug mode entered\2"); + for (;;) { + lldbg_putchar('>'); + if (lldbg_command_entry()) + lldbg_command_dispatch(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/ns16550.h Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,101 @@ +#ifndef __NS16550_H +#define __NS16550_H + +/* NS16550 registers */ +#define NS16550_RBR 0 +#define NS16550_THR 0 +#define NS16550_IER 1 +#define NS16550_IIR 2 +#define NS16550_FCR 2 +#define NS16550_LCR 3 +#define NS16550_MCR 4 +#define NS16550_LSR 5 +#define NS16550_MSR 6 +#define NS16550_SCR 7 +#define NS16550_DLL 0 +#define NS16550_DLM 1 + +#ifndef __ASSEMBLER__ +#include "types.h" + +struct ns16550_regs { + u8 datareg; + u8 ier; + u8 iir_fcr; + u8 lcr; + u8 mcr; + u8 lsr; + u8 msr; + u8 scr; +}; +#endif + +/* IER bits */ +#define NS16550_IER_EDSSI 0x08 +#define NS16550_IER_ELSI 0x04 +#define NS16550_IER_ETBEI 0x02 +#define NS16550_IER_ERBFI 0x01 + +/* IIR bits */ +#define NS16550_IIR_FIFOEN 0xC0 +#define NS16550_IIR_INTID 0x0E +#define NS16550_IIR_INT_RLS 0x06 +#define NS16550_IIR_INT_RDA 0x04 +#define NS16550_IIR_INT_CTO 0x0C +#define NS16550_IIR_INT_THRE 0x02 +#define NS16550_IIR_INT_MODEM 0x00 +#define NS16550_IIR_INTPEND 0x01 + +/* FCR bits */ + +#define NS16550_FCR_RXTR 0xC0 +#define NS16550_FCR_RXTR_1 0x00 +#define NS16550_FCR_RXTR_4 0x40 +#define NS16550_FCR_RXTR_8 0x80 +#define NS16550_FCR_RXTR_14 0xC0 +#define NS16550_FCR_DMAMODE 0x08 +#define NS16550_FCR_TXRST 0x04 +#define NS16550_FCR_RXRST 0x02 +#define NS16550_FCR_FIFOEN 0x01 + +/* LCR bits */ +#define NS16550_LCR_DLAB 0x80 +#define NS16550_LCR_BREAK 0x40 +#define NS16550_LCR_STICK 0x20 +#define NS16550_LCR_EPS 0x10 +#define NS16550_LCR_PEN 0x08 +#define NS16550_LCR_STB 0x04 +#define NS16550_LCR_WLS 0x03 +#define NS16550_LCR_WLS_5 0x00 +#define NS16550_LCR_WLS_6 0x01 +#define NS16550_LCR_WLS_7 0x02 +#define NS16550_LCR_WLS_8 0x03 + +/* MCR bits */ +#define NS16550_MCR_LOOP 0x10 +#define NS16550_MCR_OUT2 0x08 +#define NS16550_MCR_OUT1 0x04 +#define NS16550_MCR_RTS 0x02 +#define NS16550_MCR_DTR 0x01 + +/* LSR bits */ +#define NS16550_LSR_ERR 0x80 +#define NS16550_LSR_TEMP 0x40 +#define NS16550_LSR_THRE 0x20 +#define NS16550_LSR_BI 0x10 +#define NS16550_LSR_FE 0x08 +#define NS16550_LSR_PE 0x04 +#define NS16550_LSR_OE 0x02 +#define NS16550_LSR_DR 0x01 + +/* MSR bits */ +#define NS16550_MSR_DCD 0x80 +#define NS16550_MSR_RI 0x40 +#define NS16550_MSR_DSR 0x20 +#define NS16550_MSR_CTS 0x10 +#define NS16550_MSR_DDCD 0x08 +#define NS16550_MSR_TERI 0x04 +#define NS16550_MSR_DDSR 0x02 +#define NS16550_MSR_DCTS 0x01 + +#endif /* __NS16550_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/parseargs.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,39 @@ +/* + * This module contains the parse_args() function, which parses the "rest" + * part of an entered command into an argc/argv-style argument array. + */ + +lldbg_parse_args(unparsed, minargs, maxargs, argv, argcp) + char *unparsed; + int minargs, maxargs; + char **argv; + int *argcp; +{ + int argc; + char *cp; + + argc = 0; + for (cp = unparsed; ; ) { + while (*cp == ' ') + cp++; + if (!*cp) + break; + if (argc >= maxargs) { + lldbg_printf("ERROR: too many arguments\n"); + return(-1); + } + argv[argc++] = cp; + while (*cp && *cp != ' ') + cp++; + if (*cp) + *cp++ = '\0'; + } + if (argc < minargs) { + lldbg_printf("ERROR: too few arguments\n"); + return(-1); + } + argv[argc] = 0; + if (argcp) + *argcp = argc; + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/printf.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,13 @@ +#include <stdarg.h> + +int +lldbg_printf(char *fmt, ...) +{ + va_list ap; + int len; + + va_start(ap, fmt); + len = lldbg_doprnt(fmt, ap); + va_end(ap); + return(len); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/putchar.c Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,9 @@ +extern void lldbg_serial_out(); + +void +lldbg_putchar(ch) +{ + if (ch == '\n') + lldbg_serial_out('\r'); + lldbg_serial_out(ch); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/serio.S Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,34 @@ +#include "../include/config.h" +#include "ns16550.h" + +/* this module implements the elementary serial I/O operations */ + + .text + .code 32 + .globl lldbg_serial_out +lldbg_serial_out: + ldr r2, =CONFIG_LLDBG_UART_BASE +1: ldrb r3, [r2, #NS16550_LSR] + tst r3, #NS16550_LSR_THRE + beq 1b + strb r0, [r2, #NS16550_THR] + bx lr + + .globl lldbg_serial_in_poll +lldbg_serial_in_poll: + ldr r2, =CONFIG_LLDBG_UART_BASE + ldrb r3, [r2, #NS16550_LSR] + tst r3, #NS16550_LSR_DR + ldrneb r0, [r2, #NS16550_RBR] + mvneq r0, #0 + bx lr + +#if 0 // not needed currently + .globl lldbg_serial_flush +lldbg_serial_flush: + ldr r2, =CONFIG_LLDBG_UART_BASE +1: ldrb r3, [r2, #NS16550_LSR] + tst r3, #NS16550_LSR_TEMP + beq 1b + bx lr +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/lldbg/types.h Fri May 15 00:02:03 2015 +0000 @@ -0,0 +1,18 @@ +/* + * I personally like the u8/u16/u32 types, but I don't see them + * being defined in any of the headers provided by newlib. + * So we'll define them ourselves. + */ + +#ifndef __OUR_OWN_TYPES_H +#define __OUR_OWN_TYPES_H + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; + +#endif /* include guard */