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