You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
5.3 KiB
C
217 lines
5.3 KiB
C
/* CiscoLoad - Bootloader for Cisco Routers
|
|
* (c) 2008 Philippe Vachon <philippe@cowpig.ca>
|
|
* Licensed under the GNU General Public License v2
|
|
*/
|
|
#include <printf.h>
|
|
#include <addr.h>
|
|
#include <elf.h>
|
|
#include <elf_loader.h>
|
|
#include <string.h>
|
|
#include <promlib.h>
|
|
|
|
/* platform-specific defines */
|
|
#include <platform.h>
|
|
|
|
#define FS_FILE_MAGIC 0xbad00b1e
|
|
|
|
/**
|
|
* Dump 0x10 bytes of RAM in canonical hexadecimal form
|
|
* @param addr Starting address to dump from
|
|
*/
|
|
void hex_dump(uint32_t addr)
|
|
{
|
|
uint8_t *rgn = (uint8_t *)addr;
|
|
int i;
|
|
|
|
/* print out the address of the 16 bytes of interest */
|
|
printf("%8x " , addr);
|
|
|
|
/* print out hex value for individual bytes */
|
|
for (i = 0; i < 16; i++) {
|
|
printf("%02x ", rgn[i]);
|
|
}
|
|
/* print out as chars */
|
|
for (i = 0; i < 16; i++) {
|
|
printf("%c", rgn[i] >= 32 && rgn[i] <= 126 ? rgn[i] : '.');
|
|
}
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
struct fs_ent {
|
|
uint32_t magic;
|
|
uint32_t length;
|
|
/* guesses -- one of these is probably a CRC16 + flags */
|
|
uint32_t crc32; /* ? */
|
|
uint32_t date; /* ? */
|
|
char filename[48];
|
|
};
|
|
|
|
/**
|
|
* Check the sanity of flash -- just look for the filesystem magic number
|
|
* in the first 4 bytes of flash
|
|
* @param base base address of flash
|
|
* @returns 0 on failure, 1 on success
|
|
*/
|
|
int check_flash(uint32_t base)
|
|
{
|
|
uint32_t *ptr = (uint32_t *)base;
|
|
|
|
if (*ptr != FS_FILE_MAGIC) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**
|
|
* Find file in flash.
|
|
* @param filename Name of the kernel ELF file to be loaded.
|
|
* @param base Base address of flash
|
|
* @returns offset of the file within the flash memory space.
|
|
*/
|
|
uint32_t find_file(const char *filename, uint32_t base)
|
|
{
|
|
/* Actual file offset */
|
|
uint32_t offset = 0;
|
|
|
|
uint32_t file_offset = 0;
|
|
|
|
struct fs_ent *f = (struct fs_ent *)(base + offset);
|
|
|
|
/* iterate over files in flash */
|
|
while (f->magic == FS_FILE_MAGIC) {
|
|
if (!strncmp(f->filename, filename, 48)) {
|
|
file_offset = offset + sizeof(struct fs_ent);
|
|
break;
|
|
}
|
|
|
|
offset += sizeof(struct fs_ent) + f->length;
|
|
f = (struct fs_ent *)(base + offset);
|
|
}
|
|
|
|
return file_offset;
|
|
}
|
|
|
|
/**
|
|
* Print a directory listing of all files in flash
|
|
* @param base Base address of flash
|
|
*/
|
|
void flash_directory(uint32_t base)
|
|
{
|
|
struct fs_ent *f = (struct fs_ent *)base;
|
|
uint32_t offset = 0;
|
|
|
|
/* Iterate over the files; f->magic is 0 if an invalid file is
|
|
* found.
|
|
*/
|
|
while (f->magic == FS_FILE_MAGIC) {
|
|
printf("%s\n", f->filename);
|
|
offset += sizeof(struct fs_ent) + f->length;
|
|
f = (struct fs_ent *)(base + offset);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Locate the stage two loader.
|
|
* @param base Flash base.
|
|
* @return address of stage two loader
|
|
*/
|
|
uint32_t locate_stage_two(uint32_t base)
|
|
{
|
|
return find_file("ciscoload.two", base);
|
|
}
|
|
|
|
/**
|
|
* Entry Point for CiscoLoad
|
|
*/
|
|
void start_bootloader()
|
|
{
|
|
int r = 0;
|
|
int f;
|
|
char buf[129];
|
|
char *cmd_line = (char *)MEMORY_BASE;
|
|
char kernel[49];
|
|
|
|
buf[128] = '\0';
|
|
kernel[48] = '\0';
|
|
|
|
/* determine amount of RAM present */
|
|
c_putc('I');
|
|
|
|
r = c_memsz();
|
|
|
|
/* check flash filesystem sanity */
|
|
c_putc('L');
|
|
|
|
f = check_flash(FLASH_BASE);
|
|
|
|
if (!f) {
|
|
printf("\nError: Unable to find any valid flash! Aborting load.\n");
|
|
return;
|
|
}
|
|
|
|
c_putc('O');
|
|
|
|
/* locate the stage two loader */
|
|
if (!locate_stage_two(FLASH_BASE)) {
|
|
printf("\nError: Unable to find valid stage two loader. "
|
|
"Aborting load.\n");
|
|
return;
|
|
}
|
|
|
|
printf("\nCiscoLoader (CILO) - Linux bootloader for Cisco Routers\n");
|
|
printf("Available RAM: %d kB\n", r);
|
|
|
|
printf("Available files:\n");
|
|
flash_directory(FLASH_BASE);
|
|
|
|
enter_filename:
|
|
printf("\nEnter filename to boot:\n> ");
|
|
c_gets(buf, 128);
|
|
|
|
/* determine if a command line string has been appended to kernel name */
|
|
const char *cmd_line_append;
|
|
if ((cmd_line_append = strchr(buf, ' ')) != NULL) {
|
|
strcpy(cmd_line, (char *)(cmd_line_append + 1));
|
|
printf("DEBUG: Command line: [%s]\n");
|
|
/* extract the kernel file name now */
|
|
uint32_t kernel_name_len = cmd_line_append - buf;
|
|
printf("DEBUG: kernel name is %d bytes long\n", kernel_name_len);
|
|
strncpy(kernel, buf, kernel_name_len);
|
|
printf("DEBUG: kernel name is %s\n", kernel);
|
|
kernel[kernel_name_len + 1] = '\0';
|
|
} else {
|
|
cmd_line[0] = '\0';
|
|
strncpy(kernel, buf, 48);
|
|
}
|
|
|
|
printf("\n\nAttempting to load file %s\n", kernel);
|
|
|
|
uint32_t kernel_off = find_file(kernel, FLASH_BASE);
|
|
uint32_t loader_off = find_file("ciscoload.two", FLASH_BASE);
|
|
|
|
if (loader_off == 0) {
|
|
printf("Unable to find the second stage loader. Please copy the "
|
|
"second\nstage loader to the flash filesystem (ciscoload.two).");
|
|
return;
|
|
}
|
|
|
|
if (kernel_off == 0) {
|
|
printf("Unable to find \"%s\" on the flash filesystem.\n", kernel);
|
|
} else {
|
|
printf("Booting \"%s\" from flash at 0x%08x\n", kernel,
|
|
FLASH_BASE + kernel_off);
|
|
printf("DEBUG: cmd_line: %s\n", cmd_line);
|
|
if (load_elf32_file(FLASH_BASE + kernel_off, FLASH_BASE + loader_off)
|
|
< 0)
|
|
{
|
|
printf("Fatal error while loading kernel. Aborting.\n");
|
|
}
|
|
}
|
|
goto enter_filename;
|
|
|
|
/* return to ROMMON */
|
|
}
|