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