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