loader_prompt.c revision 285830
1269369Sbr/******************************************************************************
2269369Sbr *
3269369Sbr * Filename: loader_prompt.c
4269369Sbr *
5269369Sbr * Instantiation of the interactive loader functions.
6269369Sbr *
7269369Sbr * Revision information:
8269369Sbr *
9269369Sbr * 20AUG2004	kb_admin	initial creation
10269369Sbr * 12JAN2005	kb_admin	massive changes for tftp, strings, and more
11269369Sbr * 05JUL2005	kb_admin	save tag address, and set registers on boot
12269369Sbr *
13269369Sbr * BEGIN_KBDD_BLOCK
14269369Sbr * No warranty, expressed or implied, is included with this software.  It is
15269369Sbr * provided "AS IS" and no warranty of any kind including statutory or aspects
16269369Sbr * relating to merchantability or fitness for any purpose is provided.  All
17269369Sbr * intellectual property rights of others is maintained with the respective
18269369Sbr * owners.  This software is not copyrighted and is intended for reference
19269369Sbr * only.
20269369Sbr * END_BLOCK
21269369Sbr *
22269369Sbr * $FreeBSD: releng/10.2/sys/boot/arm/at91/bootiic/loader_prompt.c 163596 2006-10-21 22:43:39Z imp $
23269369Sbr *****************************************************************************/
24269369Sbr
25269369Sbr#include "at91rm9200_lowlevel.h"
26269369Sbr#ifdef SUPPORT_TAG_LIST
27269369Sbr#include "tag_list.h"
28269369Sbr#endif
29269369Sbr#include "emac.h"
30269369Sbr#include "loader_prompt.h"
31269369Sbr#include "env_vars.h"
32269369Sbr#include "lib.h"
33269369Sbr
34269369Sbr
35269369Sbr/******************************* GLOBALS *************************************/
36269369Sbr
37269369Sbr
38269369Sbr/*********************** PRIVATE FUNCTIONS/DATA ******************************/
39269369Sbr
40269369Sbrstatic char	inputBuffer[MAX_INPUT_SIZE];
41269369Sbrstatic int	buffCount;
42269369Sbr
43269369Sbr// argv pointer are either NULL or point to locations in inputBuffer
44269369Sbrstatic char	*argv[MAX_COMMAND_PARAMS];
45269369Sbr
46269369Sbrstatic const char *backspaceString = "\010 \010";
47269369Sbr
48269369Sbrstatic const command_entry_t	CommandTable[] = {
49269369Sbr	{COMMAND_COPY, "c"},
50269369Sbr	{COMMAND_DUMP, "d"},
51269369Sbr	{COMMAND_EXEC, "e"},
52269369Sbr	{COMMAND_HELP, "?"},
53269369Sbr	{COMMAND_LOCAL_IP, "ip"},
54269369Sbr	{COMMAND_MAC, "m"},
55269369Sbr	{COMMAND_SERVER_IP, "server_ip"},
56269369Sbr	{COMMAND_SET, "s"},
57269369Sbr#ifdef SUPPORT_TAG_LIST
58269369Sbr	{COMMAND_TAG, "t"},
59269369Sbr#endif
60269369Sbr	{COMMAND_TFTP, "tftp"},
61269369Sbr	{COMMAND_WRITE, "w"},
62269369Sbr	{COMMAND_XMODEM, "x"},
63269369Sbr	{COMMAND_FINAL_FLAG, 0}
64269369Sbr};
65269369Sbr
66269369Sbrstatic unsigned tagAddress;
67269369Sbr
68269369Sbr/*
69269369Sbr * .KB_C_FN_DEFINITION_START
70269369Sbr * unsigned BuildIP(void)
71272712Sbr *  This private function packs the test IP info to an unsigned value.
72272712Sbr * .KB_C_FN_DEFINITION_END
73272712Sbr */
74272712Sbrstatic unsigned
75272712SbrBuildIP(void)
76272712Sbr{
77272712Sbr	return ((p_ASCIIToDec(argv[1]) << 24) |
78272712Sbr	    (p_ASCIIToDec(argv[2]) << 16) |
79272712Sbr	    (p_ASCIIToDec(argv[3]) << 8) |
80272712Sbr	    p_ASCIIToDec(argv[4]));
81272712Sbr}
82272712Sbr
83272712Sbr
84272712Sbr/*
85272712Sbr * .KB_C_FN_DEFINITION_START
86269369Sbr * int StringToCommand(char *cPtr)
87269369Sbr *  This private function converts a command string to a command code.
88 * .KB_C_FN_DEFINITION_END
89 */
90static int
91StringToCommand(char *cPtr)
92{
93	int	i;
94
95	for (i = 0; CommandTable[i].command != COMMAND_FINAL_FLAG; ++i)
96		if (!strcmp(CommandTable[i].c_string, cPtr))
97			return (CommandTable[i].command);
98
99	return (COMMAND_INVALID);
100}
101
102
103/*
104 * .KB_C_FN_DEFINITION_START
105 * void RestoreSpace(int)
106 *  This private function restores NULL characters to spaces in order to
107 * process the remaining args as a string.  The number passed is the argc
108 * of the first entry to begin restoring space in the inputBuffer.
109 * .KB_C_FN_DEFINITION_END
110 */
111static void
112RestoreSpace(int startArgc)
113{
114	char	*cPtr;
115
116	for (startArgc++; startArgc < MAX_COMMAND_PARAMS; startArgc++) {
117		if ((cPtr = argv[startArgc]))
118			*(cPtr - 1) = ' ';
119	}
120}
121
122
123/*
124 * .KB_C_FN_DEFINITION_START
125 * int BreakCommand(char *)
126 *  This private function splits the buffer into separate strings as pointed
127 * by argv and returns the number of parameters (< 0 on failure).
128 * .KB_C_FN_DEFINITION_END
129 */
130static int
131BreakCommand(char *buffer)
132{
133	int	pCount, cCount, state;
134
135	state = pCount = 0;
136	p_memset((char*)argv, 0, sizeof(argv));
137
138	for (cCount = 0; cCount < MAX_INPUT_SIZE; ++cCount) {
139
140		if (!state) {
141			/* look for next command */
142			if (!p_IsWhiteSpace(buffer[cCount])) {
143				argv[pCount++] = &buffer[cCount];
144				state = 1;
145			} else {
146				buffer[cCount] = 0;
147			}
148		} else {
149			/* in command, find next white space */
150			if (p_IsWhiteSpace(buffer[cCount])) {
151				buffer[cCount] = 0;
152				state = 0;
153			}
154		}
155
156		if (pCount >= MAX_COMMAND_PARAMS) {
157			return (-1);
158		}
159	}
160
161	return (pCount);
162}
163
164
165/*
166 * .KB_C_FN_DEFINITION_START
167 * void ParseCommand(char *)
168 *  This private function executes matching functions.
169 * .KB_C_FN_DEFINITION_END
170 */
171static void
172ParseCommand(char *buffer)
173{
174	int		argc, i;
175
176	if ((argc = BreakCommand(buffer)) < 1)
177		return;
178
179	switch (StringToCommand(argv[0])) {
180	case COMMAND_COPY:
181	{
182		// "c <to> <from> <size in bytes>"
183		// copy memory
184		char		*to, *from;
185		unsigned	size;
186
187		if (argc > 3) {
188			to = (char *)p_ASCIIToHex(argv[1]);
189			from = (char *)p_ASCIIToHex(argv[2]);
190			size = p_ASCIIToHex(argv[3]);
191			memcpy(to, from, size);
192		}
193		break;
194	}
195
196	case COMMAND_DUMP:
197		// display boot commands
198		DumpBootCommands();
199		break;
200
201	case COMMAND_EXEC:
202	{
203		// "e <address>"
204		// execute at address
205		void (*execAddr)(unsigned, unsigned, unsigned);
206
207		if (argc > 1) {
208			/* in future, include machtypes (MACH_KB9200 = 612) */
209			execAddr = (void (*)(unsigned, unsigned, unsigned))
210			  p_ASCIIToHex(argv[1]);
211			(*execAddr)(0, 612, tagAddress);
212		}
213		break;
214	}
215
216	case COMMAND_TFTP:
217	{
218		// "tftp <local_dest_addr filename>"
219		//  tftp download
220		unsigned address = 0;
221
222		if (argc > 2)
223			address = p_ASCIIToHex(argv[1]);
224		TFTP_Download(address, argv[2]);
225		break;
226	}
227
228	case COMMAND_SERVER_IP:
229		// "server_ip <server IP 192 200 1 20>"
230		// set download server address
231		if (argc > 4)
232			SetServerIPAddress(BuildIP());
233		break;
234
235	case COMMAND_HELP:
236		// dump command info
237		printf("Commands:\n"
238		"\tc\n"
239		"\td\n"
240		"\te\n"
241		"\tip\n"
242		"\tserver_ip\n"
243		"\tm\n"
244		"\ttftp\n"
245		"\ts\n"
246#ifdef SUPPORT_TAG_LIST
247		"\tt\n"
248#endif
249		"\tw\n"
250		"\tx\n");
251		break;
252
253	case COMMAND_LOCAL_IP:
254		// "local_ip <local IP 192 200 1 21>
255		// set ip of this module
256		if (argc > 4)
257			SetLocalIPAddress(BuildIP());
258		break;
259
260	case COMMAND_MAC:
261	{
262		// "m <mac address 12 34 56 78 9a bc>
263		// set mac address using 6 byte values
264		unsigned char mac[6];
265
266		if (argc > 6) {
267			for (i = 0; i < 6; i++)
268				mac[i] = p_ASCIIToHex(argv[i + 1]);
269			EMAC_SetMACAddress(mac);
270		}
271		break;
272	}
273
274	case COMMAND_SET:
275	{
276		// s <index> <new boot command>
277		// set the boot command at index (0-based)
278		unsigned	index;
279
280		if (argc > 1) {
281			RestoreSpace(2);
282			index = p_ASCIIToHex(argv[1]);
283			SetBootCommand(index, argv[2]);
284		}
285		break;
286	}
287
288#ifdef SUPPORT_TAG_LIST
289	case COMMAND_TAG:
290		// t <address> <boot command line>
291		// create tag-list for linux boot
292		if (argc > 2) {
293			RestoreSpace(2);
294			tagAddress = p_ASCIIToHex(argv[1]);
295			InitTagList(argv[2], (void*)tagAddress);
296		}
297		break;
298#endif
299
300	case COMMAND_WRITE:
301		// write the command table to non-volatile
302		WriteCommandTable();
303		break;
304
305	case COMMAND_XMODEM:
306	{
307		// "x <address>"
308		// download X-modem record at address
309		if (argc > 1)
310			xmodem_rx((char *)p_ASCIIToHex(argv[1]));
311		break;
312	}
313
314	default:
315		break;
316	}
317
318	printf("\n");
319}
320
321
322/*
323 * .KB_C_FN_DEFINITION_START
324 * void ServicePrompt(char)
325 *  This private function process each character checking for valid commands.
326 * This function is only executed if the character is considered valid.
327 * Each command is terminated with NULL (0) or ''.
328 * .KB_C_FN_DEFINITION_END
329 */
330static void
331ServicePrompt(char p_char)
332{
333	if (p_char == '\r')
334		p_char = 0;
335
336	if (p_char == '\010') {
337		if (buffCount) {
338			/* handle backspace BS */
339			inputBuffer[--buffCount] = 0;
340			printf(backspaceString);
341		}
342		return;
343	}
344	if (buffCount < MAX_INPUT_SIZE - 1) {
345		inputBuffer[buffCount++] = p_char;
346		putchar(p_char);
347	}
348	if (!p_char) {
349		printf("\n");
350		ParseCommand(inputBuffer);
351		p_memset(inputBuffer, 0, MAX_INPUT_SIZE);
352		buffCount = 0;
353		printf("\n>");
354	}
355}
356
357
358/* ************************** GLOBAL FUNCTIONS ********************************/
359
360
361/*
362 * .KB_C_FN_DEFINITION_START
363 * void Bootloader(void *inputFunction)
364 *  This global function is the entry point for the bootloader.  If the
365 * inputFunction pointer is NULL, the loader input will be serviced from
366 * the uart.  Otherwise, inputFunction is called to get characters which
367 * the loader will parse.
368 * .KB_C_FN_DEFINITION_END
369 */
370void
371Bootloader(int(*inputFunction)(int))
372{
373	int	ch = 0;
374
375	p_memset((void*)inputBuffer, 0, sizeof(inputBuffer));
376
377	buffCount = 0;
378	if (!inputFunction) {
379		inputFunction = getc;
380	}
381
382	printf("\n>");
383
384	while (1)
385		if ((ch = ((*inputFunction)(0))) > 0)
386			ServicePrompt(ch);
387}
388