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 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 KERNEL_OFFSET (220 * FLASH_PAGE_SIZE) 47#define KERNEL_LEN (6 * 1024 * FLASH_PAGE_SIZE) 48static const char *backspaceString = "\010 \010"; 49 50static 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 */ 72static unsigned 73BuildIP(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 */ 88static int 89StringToCommand(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 */ 108static int 109BreakCommand(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 143static void 144UpdateEEProm(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 156static void 157UpdateFlash(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 171static void 172LoadKernelFromSpi(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 */ 188static void 189ParseCommand(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 */ 310static void 311ServicePrompt(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 */ 350void 351Bootloader(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