/****************************************************************************** * * Filename: loader_prompt.c * * Instantiation of the interactive loader functions. * * Revision information: * * 20AUG2004 kb_admin initial creation * 12JAN2005 kb_admin massive changes for tftp, strings, and more * 05JUL2005 kb_admin save tag address, and set registers on boot * * BEGIN_KBDD_BLOCK * No warranty, expressed or implied, is included with this software. It is * provided "AS IS" and no warranty of any kind including statutory or aspects * relating to merchantability or fitness for any purpose is provided. All * intellectual property rights of others is maintained with the respective * owners. This software is not copyrighted and is intended for reference * only. * END_BLOCK * * $FreeBSD$ *****************************************************************************/ #include "at91rm9200_lowlevel.h" #include "at91rm9200.h" #include "emac.h" #include "loader_prompt.h" #include "env_vars.h" #include "lib.h" #include "spi_flash.h" #include "ee.h" /******************************* GLOBALS *************************************/ /*********************** PRIVATE FUNCTIONS/DATA ******************************/ static char inputBuffer[MAX_INPUT_SIZE]; static int buffCount; // argv pointer are either NULL or point to locations in inputBuffer static char *argv[MAX_COMMAND_PARAMS]; #define FLASH_OFFSET (0 * FLASH_PAGE_SIZE) #define KERNEL_OFFSET (220 * FLASH_PAGE_SIZE) #define KERNEL_LEN (6 * 1024 * FLASH_PAGE_SIZE) static const char *backspaceString = "\010 \010"; static const command_entry_t CommandTable[] = { {COMMAND_DUMP, "d"}, {COMMAND_EXEC, "e"}, {COMMAND_LOCAL_IP, "ip"}, {COMMAND_MAC, "m"}, {COMMAND_SERVER_IP, "server_ip"}, {COMMAND_TFTP, "tftp"}, {COMMAND_XMODEM, "x"}, {COMMAND_RESET, "R"}, {COMMAND_LOAD_SPI_KERNEL, "k"}, {COMMAND_REPLACE_KERNEL_VIA_XMODEM, "K"}, {COMMAND_REPLACE_FLASH_VIA_XMODEM, "I"}, {COMMAND_REPLACE_ID_EEPROM, "E"}, {COMMAND_FINAL_FLAG, 0} }; /* * .KB_C_FN_DEFINITION_START * unsigned BuildIP(void) * This private function packs the test IP info to an unsigned value. * .KB_C_FN_DEFINITION_END */ static unsigned BuildIP(void) { return ((p_ASCIIToDec(argv[1]) << 24) | (p_ASCIIToDec(argv[2]) << 16) | (p_ASCIIToDec(argv[3]) << 8) | p_ASCIIToDec(argv[4])); } /* * .KB_C_FN_DEFINITION_START * int StringToCommand(char *cPtr) * This private function converts a command string to a command code. * .KB_C_FN_DEFINITION_END */ static int StringToCommand(char *cPtr) { int i; for (i = 0; CommandTable[i].command != COMMAND_FINAL_FLAG; ++i) if (!strcmp(CommandTable[i].c_string, cPtr)) return (CommandTable[i].command); return (COMMAND_INVALID); } /* * .KB_C_FN_DEFINITION_START * int BreakCommand(char *) * This private function splits the buffer into separate strings as pointed * by argv and returns the number of parameters (< 0 on failure). * .KB_C_FN_DEFINITION_END */ static int BreakCommand(char *buffer) { int pCount, cCount, state; state = pCount = 0; p_memset((char*)argv, 0, sizeof(argv)); for (cCount = 0; cCount < MAX_INPUT_SIZE; ++cCount) { if (!state) { /* look for next command */ if (!p_IsWhiteSpace(buffer[cCount])) { argv[pCount++] = &buffer[cCount]; state = 1; } else { buffer[cCount] = 0; } } else { /* in command, find next white space */ if (p_IsWhiteSpace(buffer[cCount])) { buffer[cCount] = 0; state = 0; } } if (pCount >= MAX_COMMAND_PARAMS) { return (-1); } } return (pCount); } #if 0 static void UpdateEEProm(int eeaddr) { char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */ int len; while ((len = xmodem_rx(addr)) == -1) continue; printf("\nDownloaded %u bytes.\n", len); WriteEEPROM(eeaddr, 0, addr, len); } #endif static void UpdateFlash(int offset) { char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */ int len, i, off; while ((len = xmodem_rx(addr)) == -1) continue; printf("\nDownloaded %u bytes.\n", len); for (i = 0; i < len; i+= FLASH_PAGE_SIZE) { off = i + offset; SPI_WriteFlash(off, addr + i, FLASH_PAGE_SIZE); } } static void LoadKernelFromSpi(char *addr) { int i, off; for (i = 0; i < KERNEL_LEN; i+= FLASH_PAGE_SIZE) { off = i + KERNEL_OFFSET; SPI_ReadFlash(off, addr + i, FLASH_PAGE_SIZE); } } /* * .KB_C_FN_DEFINITION_START * void ParseCommand(char *) * This private function executes matching functions. * .KB_C_FN_DEFINITION_END */ static void ParseCommand(char *buffer) { int argc, i; if ((argc = BreakCommand(buffer)) < 1) return; switch (StringToCommand(argv[0])) { case COMMAND_DUMP: // display boot commands DumpBootCommands(); break; case COMMAND_EXEC: { // "e
" // execute at address void (*execAddr)(unsigned, unsigned); if (argc > 1) { /* in future, include machtypes (MACH_KB9200 = 612) */ execAddr = (void (*)(unsigned, unsigned)) p_ASCIIToHex(argv[1]); (*execAddr)(0, 612); } break; } case COMMAND_TFTP: { // "tftp " // tftp download unsigned address = 0; if (argc > 2) address = p_ASCIIToHex(argv[1]); TFTP_Download(address, argv[2]); break; } case COMMAND_SERVER_IP: // "server_ip " // set download server address if (argc > 4) SetServerIPAddress(BuildIP()); break; case COMMAND_LOCAL_IP: // "local_ip // set ip of this module if (argc > 4) SetLocalIPAddress(BuildIP()); break; case COMMAND_MAC: { // "m // set mac address using 6 byte values unsigned char mac[6]; if (argc > 6) { for (i = 0; i < 6; i++) mac[i] = p_ASCIIToHex(argv[i + 1]); EMAC_SetMACAddress(mac); } break; } case COMMAND_LOAD_SPI_KERNEL: // "k
" if (argc > 1) LoadKernelFromSpi((char *)p_ASCIIToHex(argv[1])); break; case COMMAND_XMODEM: // "x
" // download X-modem record at address if (argc > 1) xmodem_rx((char *)p_ASCIIToHex(argv[1])); break; case COMMAND_RESET: printf("Reset\n"); reset(); while (1) continue; break; case COMMAND_REPLACE_KERNEL_VIA_XMODEM: printf("Updating KERNEL image\n"); UpdateFlash(KERNEL_OFFSET); break; case COMMAND_REPLACE_FLASH_VIA_XMODEM: printf("Updating FLASH image\n"); UpdateFlash(FLASH_OFFSET); break; case COMMAND_REPLACE_ID_EEPROM: { char buf[25]; printf("Testing Config EEPROM\n"); EEWrite(0, "This is a test", 15); EERead(0, buf, 15); printf("Found '%s'\n", buf); break; } default: break; } printf("\n"); } /* * .KB_C_FN_DEFINITION_START * void ServicePrompt(char) * This private function process each character checking for valid commands. * This function is only executed if the character is considered valid. * Each command is terminated with NULL (0) or ''. * .KB_C_FN_DEFINITION_END */ static void ServicePrompt(char p_char) { if (p_char == '\r') p_char = 0; if (p_char == '\010') { if (buffCount) { /* handle backspace BS */ inputBuffer[--buffCount] = 0; printf(backspaceString); } return; } if (buffCount < MAX_INPUT_SIZE - 1) { inputBuffer[buffCount++] = p_char; putchar(p_char); } if (!p_char) { printf("\n"); ParseCommand(inputBuffer); p_memset(inputBuffer, 0, MAX_INPUT_SIZE); buffCount = 0; printf("\n>"); } } /* ************************** GLOBAL FUNCTIONS ********************************/ /* * .KB_C_FN_DEFINITION_START * void Bootloader(void *inputFunction) * This global function is the entry point for the bootloader. If the * inputFunction pointer is NULL, the loader input will be serviced from * the uart. Otherwise, inputFunction is called to get characters which * the loader will parse. * .KB_C_FN_DEFINITION_END */ void Bootloader(int(*inputFunction)(int)) { int ch = 0; p_memset((void*)inputBuffer, 0, sizeof(inputBuffer)); buffCount = 0; printf("\n>"); while (1) if ((ch = ((*inputFunction)(0))) > 0) ServicePrompt(ch); }