loader_prompt.c revision 161370
1/******************************************************************************
2 *
3 * Filename: loader_prompt.c
4 *
5 * Instantiation of the interactive loader functions.
6 *
7 * Revision information:
8 *
9 * 20AUG2004	kb_admin	initial creation
10 * 12JAN2005	kb_admin	massive changes for tftp, strings, and more
11 * 05JUL2005	kb_admin	save tag address, and set registers on boot
12 *
13 * BEGIN_KBDD_BLOCK
14 * No warranty, expressed or implied, is included with this software.  It is
15 * provided "AS IS" and no warranty of any kind including statutory or aspects
16 * relating to merchantability or fitness for any purpose is provided.  All
17 * intellectual property rights of others is maintained with the respective
18 * owners.  This software is not copyrighted and is intended for reference
19 * only.
20 * END_BLOCK
21 *
22 * $FreeBSD: head/sys/boot/arm/at91/bootspi/loader_prompt.c 161370 2006-08-16 23:39:58Z imp $
23 *****************************************************************************/
24
25#include "at91rm9200_lowlevel.h"
26#include "at91rm9200.h"
27#include "emac.h"
28#include "loader_prompt.h"
29#include "env_vars.h"
30#include "lib.h"
31#include "spi_flash.h"
32
33/******************************* GLOBALS *************************************/
34
35
36/*********************** PRIVATE FUNCTIONS/DATA ******************************/
37
38static char	inputBuffer[MAX_INPUT_SIZE];
39static int	buffCount;
40
41// argv pointer are either NULL or point to locations in inputBuffer
42static char	*argv[MAX_COMMAND_PARAMS];
43
44#define FLASH_OFFSET (0 * FLASH_PAGE_SIZE)
45#define FPGA_OFFSET  (15 * FLASH_PAGE_SIZE)
46#define FPGA_LEN     (212608)
47#define KERNEL_OFFSET (220 * FLASH_PAGE_SIZE)
48#define KERNEL_LEN (6 * 1024 * FLASH_PAGE_SIZE)
49static const char *backspaceString = "\010 \010";
50
51static const command_entry_t	CommandTable[] = {
52	{COMMAND_DUMP, "d"},
53	{COMMAND_EXEC, "e"},
54	{COMMAND_LOCAL_IP, "ip"},
55	{COMMAND_MAC, "m"},
56	{COMMAND_SERVER_IP, "server_ip"},
57	{COMMAND_TFTP, "tftp"},
58	{COMMAND_XMODEM, "x"},
59	{COMMAND_RESET, "R"},
60	{COMMAND_LOAD_SPI_KERNEL, "k"},
61	{COMMAND_REPLACE_KERNEL_VIA_XMODEM, "K"},
62	{COMMAND_REPLACE_FLASH_VIA_XMODEM, "I"},
63	{COMMAND_REPLACE_FPGA_VIA_XMODEM, "F"},
64	{COMMAND_REPLACE_ID_EEPROM, "E"},
65	{COMMAND_FINAL_FLAG, 0}
66};
67
68/*
69 * .KB_C_FN_DEFINITION_START
70 * unsigned BuildIP(void)
71 *  This private function packs the test IP info to an unsigned value.
72 * .KB_C_FN_DEFINITION_END
73 */
74static unsigned
75BuildIP(void)
76{
77	return ((p_ASCIIToDec(argv[1]) << 24) |
78	    (p_ASCIIToDec(argv[2]) << 16) |
79	    (p_ASCIIToDec(argv[3]) << 8) |
80	    p_ASCIIToDec(argv[4]));
81}
82
83
84/*
85 * .KB_C_FN_DEFINITION_START
86 * int StringToCommand(char *cPtr)
87 *  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 (!p_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 * int BreakCommand(char *)
106 *  This private function splits the buffer into separate strings as pointed
107 * by argv and returns the number of parameters (< 0 on failure).
108 * .KB_C_FN_DEFINITION_END
109 */
110static int
111BreakCommand(char *buffer)
112{
113	int	pCount, cCount, state;
114
115	state = pCount = 0;
116	p_memset((char*)argv, 0, sizeof(argv));
117
118	for (cCount = 0; cCount < MAX_INPUT_SIZE; ++cCount) {
119
120		if (!state) {
121			/* look for next command */
122			if (!p_IsWhiteSpace(buffer[cCount])) {
123				argv[pCount++] = &buffer[cCount];
124				state = 1;
125			} else {
126				buffer[cCount] = 0;
127			}
128		} else {
129			/* in command, find next white space */
130			if (p_IsWhiteSpace(buffer[cCount])) {
131				buffer[cCount] = 0;
132				state = 0;
133			}
134		}
135
136		if (pCount >= MAX_COMMAND_PARAMS) {
137			return (-1);
138		}
139	}
140
141	return (pCount);
142}
143
144#if 0
145static void
146UpdateEEProm(int eeaddr)
147{
148	char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */
149	int len;
150
151	while ((len = xmodem_rx(addr)) == -1)
152		continue;
153	printf("\r\nDownloaded %u bytes.\r\n", len);
154	WriteEEPROM(eeaddr, 0, addr, len);
155}
156#endif
157
158static void
159UpdateFlash(int offset)
160{
161	char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */
162	int len, i, off;
163
164	while ((len = xmodem_rx(addr)) == -1)
165		continue;
166	printf("\r\nDownloaded %u bytes.\r\n", len);
167	for (i = 0; i < len; i+= FLASH_PAGE_SIZE) {
168		off = i + offset;
169		SPI_WriteFlash(off, addr + i, FLASH_PAGE_SIZE);
170	}
171}
172
173static void
174LoadKernelFromSpi(char *addr)
175{
176	int i, off;
177
178	for (i = 0; i < KERNEL_LEN; i+= FLASH_PAGE_SIZE) {
179		off = i + KERNEL_OFFSET;
180		SPI_ReadFlash(off, addr + i, FLASH_PAGE_SIZE);
181	}
182}
183
184/*
185 * .KB_C_FN_DEFINITION_START
186 * void ParseCommand(char *)
187 *  This private function executes matching functions.
188 * .KB_C_FN_DEFINITION_END
189 */
190static void
191ParseCommand(char *buffer)
192{
193	int		argc, i;
194
195	if ((argc = BreakCommand(buffer)) < 1)
196		return;
197
198	switch (StringToCommand(argv[0])) {
199	case COMMAND_DUMP:
200		// display boot commands
201		DumpBootCommands();
202		break;
203
204	case COMMAND_EXEC:
205	{
206		// "e <address>"
207		// execute at address
208		void (*execAddr)(unsigned, unsigned);
209
210		if (argc > 1) {
211			/* in future, include machtypes (MACH_KB9200 = 612) */
212			execAddr = (void (*)(unsigned, unsigned))
213			    p_ASCIIToHex(argv[1]);
214			(*execAddr)(0, 612);
215		}
216		break;
217	}
218
219	case COMMAND_TFTP:
220	{
221		// "tftp <local_dest_addr filename>"
222		//  tftp download
223		unsigned address = 0;
224
225		if (argc > 2)
226			address = p_ASCIIToHex(argv[1]);
227		TFTP_Download(address, argv[2]);
228		break;
229	}
230
231	case COMMAND_SERVER_IP:
232		// "server_ip <server IP 192 200 1 20>"
233		// set download server address
234		if (argc > 4)
235			SetServerIPAddress(BuildIP());
236		break;
237
238	case COMMAND_LOCAL_IP:
239		// "local_ip <local IP 192 200 1 21>
240		// set ip of this module
241		if (argc > 4)
242			SetLocalIPAddress(BuildIP());
243		break;
244
245	case COMMAND_MAC:
246	{
247		// "m <mac address 12 34 56 78 9a bc>
248		// set mac address using 6 byte values
249		unsigned char mac[6];
250
251		if (argc > 6) {
252			for (i = 0; i < 6; i++)
253				mac[i] = p_ASCIIToHex(argv[i + 1]);
254			EMAC_SetMACAddress(mac);
255		}
256		break;
257	}
258
259	case COMMAND_LOAD_SPI_KERNEL:
260		// "k <address>"
261		if (argc > 1)
262			LoadKernelFromSpi((char *)p_ASCIIToHex(argv[1]));
263		break;
264
265	case COMMAND_XMODEM:
266		// "x <address>"
267		// download X-modem record at address
268		if (argc > 1)
269			xmodem_rx((char *)p_ASCIIToHex(argv[1]));
270		break;
271
272	case COMMAND_RESET:
273		printf("Reset\r\n");
274		reset();
275		while (1) continue;
276		break;
277
278	case COMMAND_REPLACE_KERNEL_VIA_XMODEM:
279		printf("Updating KERNEL image\r\n");
280		UpdateFlash(KERNEL_OFFSET);
281		break;
282	case COMMAND_REPLACE_FPGA_VIA_XMODEM:
283		printf("Updating FPGA image\r\n");
284		UpdateFlash(FPGA_OFFSET);
285		break;
286	case COMMAND_REPLACE_FLASH_VIA_XMODEM:
287		printf("Updating FLASH image\r\n");
288		UpdateFlash(FLASH_OFFSET);
289		break;
290
291	default:
292		break;
293	}
294
295	printf("\r\n");
296}
297
298
299/*
300 * .KB_C_FN_DEFINITION_START
301 * void ServicePrompt(char)
302 *  This private function process each character checking for valid commands.
303 * This function is only executed if the character is considered valid.
304 * Each command is terminated with NULL (0) or '\r'.
305 * .KB_C_FN_DEFINITION_END
306 */
307static void
308ServicePrompt(char p_char)
309{
310	if (p_char == '\r')
311		p_char = 0;
312
313	if (p_char == '\010') {
314		if (buffCount) {
315			/* handle backspace BS */
316			inputBuffer[--buffCount] = 0;
317			printf(backspaceString);
318		}
319		return;
320	}
321	if (buffCount < MAX_INPUT_SIZE - 1) {
322		inputBuffer[buffCount++] = p_char;
323		putchar(p_char);
324	}
325	if (!p_char) {
326		printf("\r\n");
327		ParseCommand(inputBuffer);
328		p_memset(inputBuffer, 0, MAX_INPUT_SIZE);
329		buffCount = 0;
330		printf("\r\n>");
331	}
332}
333
334
335/* ************************** GLOBAL FUNCTIONS ********************************/
336
337
338/*
339 * .KB_C_FN_DEFINITION_START
340 * void Bootloader(void *inputFunction)
341 *  This global function is the entry point for the bootloader.  If the
342 * inputFunction pointer is NULL, the loader input will be serviced from
343 * the uart.  Otherwise, inputFunction is called to get characters which
344 * the loader will parse.
345 * .KB_C_FN_DEFINITION_END
346 */
347void
348Bootloader(int(*inputFunction)(int))
349{
350	int	ch = 0;
351
352	p_memset((void*)inputBuffer, 0, sizeof(inputBuffer));
353	buffCount = 0;
354
355	printf("\r\n>");
356
357	while (1)
358		if ((ch = ((*inputFunction)(0))) > 0)
359			ServicePrompt(ch);
360}
361