loader_prompt.c revision 163596
166458Sdfr/******************************************************************************
266458Sdfr *
366458Sdfr * Filename: loader_prompt.c
466458Sdfr *
566458Sdfr * Instantiation of the interactive loader functions.
666458Sdfr *
766458Sdfr * Revision information:
866458Sdfr *
966458Sdfr * 20AUG2004	kb_admin	initial creation
1066458Sdfr * 12JAN2005	kb_admin	massive changes for tftp, strings, and more
1166458Sdfr * 05JUL2005	kb_admin	save tag address, and set registers on boot
1266458Sdfr *
1366458Sdfr * BEGIN_KBDD_BLOCK
1466458Sdfr * No warranty, expressed or implied, is included with this software.  It is
1566458Sdfr * provided "AS IS" and no warranty of any kind including statutory or aspects
1666458Sdfr * relating to merchantability or fitness for any purpose is provided.  All
1766458Sdfr * intellectual property rights of others is maintained with the respective
1866458Sdfr * owners.  This software is not copyrighted and is intended for reference
1966458Sdfr * only.
2066458Sdfr * END_BLOCK
2166458Sdfr *
2266458Sdfr * $FreeBSD: head/sys/boot/arm/at91/bootiic/loader_prompt.c 163596 2006-10-21 22:43:39Z imp $
2366458Sdfr *****************************************************************************/
2466458Sdfr
2566458Sdfr#include "at91rm9200_lowlevel.h"
2666458Sdfr#ifdef SUPPORT_TAG_LIST
2766458Sdfr#include "tag_list.h"
2866458Sdfr#endif
2966458Sdfr#include "emac.h"
3066458Sdfr#include "loader_prompt.h"
3166458Sdfr#include "env_vars.h"
3266458Sdfr#include "lib.h"
3366458Sdfr
3466458Sdfr
3583511Sdfr/******************************* GLOBALS *************************************/
3696912Smarcel
3766458Sdfr
3893264Sdillon/*********************** PRIVATE FUNCTIONS/DATA ******************************/
3988088Sjhb
40127253Smarcelstatic char	inputBuffer[MAX_INPUT_SIZE];
41127253Smarcelstatic int	buffCount;
4266458Sdfr
4366458Sdfr// argv pointer are either NULL or point to locations in inputBuffer
4466458Sdfrstatic char	*argv[MAX_COMMAND_PARAMS];
4566458Sdfr
4666458Sdfrstatic const char *backspaceString = "\010 \010";
47127253Smarcel
4866458Sdfrstatic const command_entry_t	CommandTable[] = {
4966458Sdfr	{COMMAND_COPY, "c"},
50124478Sdes	{COMMAND_DUMP, "d"},
51123419Speter	{COMMAND_EXEC, "e"},
52123419Speter	{COMMAND_HELP, "?"},
53123419Speter	{COMMAND_LOCAL_IP, "ip"},
54123419Speter	{COMMAND_MAC, "m"},
55123419Speter	{COMMAND_SERVER_IP, "server_ip"},
56123419Speter	{COMMAND_SET, "s"},
57123419Speter#ifdef SUPPORT_TAG_LIST
5866458Sdfr	{COMMAND_TAG, "t"},
5966458Sdfr#endif
60114208Smarcel	{COMMAND_TFTP, "tftp"},
61114208Smarcel	{COMMAND_WRITE, "w"},
62114208Smarcel	{COMMAND_XMODEM, "x"},
63114208Smarcel	{COMMAND_FINAL_FLAG, 0}
6483511Sdfr};
65114208Smarcel
66114208Smarcelstatic unsigned tagAddress;
67114208Smarcel
68114208Smarcel/*
69114208Smarcel * .KB_C_FN_DEFINITION_START
7083511Sdfr * unsigned BuildIP(void)
71114208Smarcel *  This private function packs the test IP info to an unsigned value.
72114208Smarcel * .KB_C_FN_DEFINITION_END
73114208Smarcel */
7483511Sdfrstatic unsigned
75114208SmarcelBuildIP(void)
76114208Smarcel{
77114208Smarcel	return ((p_ASCIIToDec(argv[1]) << 24) |
78114208Smarcel	    (p_ASCIIToDec(argv[2]) << 16) |
7966458Sdfr	    (p_ASCIIToDec(argv[3]) << 8) |
8066458Sdfr	    p_ASCIIToDec(argv[4]));
81114208Smarcel}
82114208Smarcel
8366458Sdfr
84114208Smarcel/*
85114208Smarcel * .KB_C_FN_DEFINITION_START
86114208Smarcel * int StringToCommand(char *cPtr)
8783511Sdfr *  This private function converts a command string to a command code.
88114208Smarcel * .KB_C_FN_DEFINITION_END
89114208Smarcel */
90114208Smarcelstatic int
91114208SmarcelStringToCommand(char *cPtr)
9266458Sdfr{
9366458Sdfr	int	i;
94114208Smarcel
95114208Smarcel	for (i = 0; CommandTable[i].command != COMMAND_FINAL_FLAG; ++i)
9666458Sdfr		if (!strcmp(CommandTable[i].c_string, cPtr))
97114208Smarcel			return (CommandTable[i].command);
98114208Smarcel
99114208Smarcel	return (COMMAND_INVALID);
10083511Sdfr}
101114208Smarcel
102114208Smarcel
103114208Smarcel/*
104114208Smarcel * .KB_C_FN_DEFINITION_START
10566458Sdfr * void RestoreSpace(int)
10666458Sdfr *  This private function restores NULL characters to spaces in order to
10766458Sdfr * process the remaining args as a string.  The number passed is the argc
108114208Smarcel * of the first entry to begin restoring space in the inputBuffer.
10966458Sdfr * .KB_C_FN_DEFINITION_END
110114208Smarcel */
11166458Sdfrstatic void
112114208SmarcelRestoreSpace(int startArgc)
11366458Sdfr{
11466458Sdfr	char	*cPtr;
11566458Sdfr
116114208Smarcel	for (startArgc++; startArgc < MAX_COMMAND_PARAMS; startArgc++) {
11766458Sdfr		if ((cPtr = argv[startArgc]))
118114208Smarcel			*(cPtr - 1) = ' ';
11966458Sdfr	}
120114208Smarcel}
12166458Sdfr
12266458Sdfr
12366458Sdfr/*
124114208Smarcel * .KB_C_FN_DEFINITION_START
12566458Sdfr * int BreakCommand(char *)
126114208Smarcel *  This private function splits the buffer into separate strings as pointed
12766458Sdfr * by argv and returns the number of parameters (< 0 on failure).
128114208Smarcel * .KB_C_FN_DEFINITION_END
12966458Sdfr */
13066458Sdfrstatic int
13166458SdfrBreakCommand(char *buffer)
132114208Smarcel{
13366458Sdfr	int	pCount, cCount, state;
134114208Smarcel
135114208Smarcel	state = pCount = 0;
13683511Sdfr	p_memset((char*)argv, 0, sizeof(argv));
13783511Sdfr
138114208Smarcel	for (cCount = 0; cCount < MAX_INPUT_SIZE; ++cCount) {
13983511Sdfr
14066458Sdfr		if (!state) {
14166458Sdfr			/* look for next command */
14266458Sdfr			if (!p_IsWhiteSpace(buffer[cCount])) {
143114208Smarcel				argv[pCount++] = &buffer[cCount];
14466458Sdfr				state = 1;
145114208Smarcel			} else {
146114208Smarcel				buffer[cCount] = 0;
14783511Sdfr			}
14883836Sdfr		} else {
149114208Smarcel			/* in command, find next white space */
15083836Sdfr			if (p_IsWhiteSpace(buffer[cCount])) {
15166458Sdfr				buffer[cCount] = 0;
15266458Sdfr				state = 0;
15366458Sdfr			}
154114208Smarcel		}
15566458Sdfr
156114208Smarcel		if (pCount >= MAX_COMMAND_PARAMS) {
157114208Smarcel			return (-1);
15883836Sdfr		}
15983836Sdfr	}
160114208Smarcel
16183836Sdfr	return (pCount);
16266458Sdfr}
16366458Sdfr
16466458Sdfr
165114208Smarcel/*
16684581Smarcel * .KB_C_FN_DEFINITION_START
167114208Smarcel * void ParseCommand(char *)
16884581Smarcel *  This private function executes matching functions.
169114208Smarcel * .KB_C_FN_DEFINITION_END
17084581Smarcel */
17184581Smarcelstatic void
17284581SmarcelParseCommand(char *buffer)
173114208Smarcel{
17484581Smarcel	int		argc, i;
175114208Smarcel
17684581Smarcel	if ((argc = BreakCommand(buffer)) < 1)
177114208Smarcel		return;
17884581Smarcel
17984581Smarcel	switch (StringToCommand(argv[0])) {
18084581Smarcel	case COMMAND_COPY:
181114208Smarcel	{
18284581Smarcel		// "c <to> <from> <size in bytes>"
183114208Smarcel		// copy memory
18484581Smarcel		char		*to, *from;
185114208Smarcel		unsigned	size;
18684581Smarcel
18784581Smarcel		if (argc > 3) {
18884581Smarcel			to = (char *)p_ASCIIToHex(argv[1]);
18966458Sdfr			from = (char *)p_ASCIIToHex(argv[2]);
19066458Sdfr			size = p_ASCIIToHex(argv[3]);
191114208Smarcel			memcpy(to, from, size);
19266458Sdfr		}
19366458Sdfr		break;
19466458Sdfr	}
19566458Sdfr
19666458Sdfr	case COMMAND_DUMP:
197114208Smarcel		// display boot commands
19866458Sdfr		DumpBootCommands();
19966458Sdfr		break;
20092870Sdfr
20192781Sdfr	case COMMAND_EXEC:
20266458Sdfr	{
20392870Sdfr		// "e <address>"
204114208Smarcel		// execute at address
20574897Sjhb		void (*execAddr)(unsigned, unsigned, unsigned);
206115295Smarcel
20766458Sdfr		if (argc > 1) {
20866458Sdfr			/* in future, include machtypes (MACH_KB9200 = 612) */
20966458Sdfr			execAddr = (void (*)(unsigned, unsigned, unsigned))
210115295Smarcel			  p_ASCIIToHex(argv[1]);
21166458Sdfr			(*execAddr)(0, 612, tagAddress);
212115295Smarcel		}
213115295Smarcel		break;
21466458Sdfr	}
21566458Sdfr
21666458Sdfr	case COMMAND_TFTP:
21766458Sdfr	{
21866458Sdfr		// "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