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