diff --git a/Makefile b/Makefile index aa18520..14d1ed9 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,8 @@ ifndef CROSS_COMPILE CROSS_COMPILE=mips-elf- endif CFLAGS=-mno-abicalls -LDFLAGS=-Ttext ${TEXTADDR} +LDFLAGS=-Ttext=${TEXTADDR} +LINKSCRIPT=mips.lds # Configuration for the Cisco 3660 Routers # TARGET=c3600 @@ -18,7 +19,8 @@ LDFLAGS=-Ttext ${TEXTADDR} # CROSS_COMPILE=mips-elf- # endif # CFLAGS=-mno-abicalls -# LDFLAGS=-Ttext ${TEXTADDR} +# LDFLAGS=-Ttext=${TEXTADDR} +# LINKSCRIPT=mips.lds # Configuration for the Cisco 1700 Series Routers # TARGET=c1700 @@ -29,6 +31,18 @@ LDFLAGS=-Ttext ${TEXTADDR} # CROSS_COMPILE=powerpc-elf- # endif # LDFLAGS=-Ttext=${TEXTADDR} +# LINKSCRIPT=powerpc.lds + +# Configuration for the Cisco 2600 Series Routers +# TARGET=c2600 +# MACHCODE=0x2b +# TEXTADDR=0x80008000 +# LOADADDR=0x80028000 +# ifndef CROSS_COMPILE +# CROSS_COMPILE=powerpc-elf- +# endif +# LDFLAGS=-Ttext=${TEXTADDR} +# LINKSCRIPT=powerpc.lds # Configuration for the Cisco 7200 Series Routers # TARGET=c7200 @@ -39,7 +53,8 @@ LDFLAGS=-Ttext ${TEXTADDR} # CROSS_COMPILE=mips-elf- # endif # CFLAGS=-DDEBUG -mno-abicalls -# LDFLAGS=-Ttext ${TEXTADDR} +# LDFLAGS=-Ttext=${TEXTADDR} +# LINKSCRIPT=mips.lds # additional CFLAGS CFLAGS+= @@ -67,7 +82,7 @@ CFLAGS+=-fno-builtin -fomit-frame-pointer -fno-pic \ ASFLAGS=-D__ASSEMBLY__-xassembler-with-cpp -traditional-cpp LDFLAGS+=--omagic -nostartfiles -nostdlib --discard-all --strip-all \ - --entry _start + --entry _start -Wl,-T -Wl,${LINKSCRIPT} OBJECTS=string.o main.o ciloio.o printf.o elf_loader.o lzma_loader.o \ LzmaDecode.o diff --git a/include/mach/c2600/platform.h b/include/mach/c2600/platform.h new file mode 100644 index 0000000..d63dc9f --- /dev/null +++ b/include/mach/c2600/platform.h @@ -0,0 +1,16 @@ +#ifndef _INCLUDE_MACH_C2600_PLATFORM_H +#define _INCLUDE_MACH_C2600_PLATFORM_H + +#include + +#define FLASH_BASE 0x60000000 +#define MEMORY_BASE 0x80000000 + +void platform_init(); +uint32_t check_flash(); +void flash_directory(); +uint32_t locate_stage_two(); +void stage_two(uint32_t kern_off, uint32_t kern_entry, uint32_t kern_size, + uint32_t kern_loadpt); + +#endif /* _INCLUDE_MACH_C2600_PLATFORM_H */ diff --git a/include/mach/c2600/platio.h b/include/mach/c2600/platio.h new file mode 100644 index 0000000..5ef7316 --- /dev/null +++ b/include/mach/c2600/platio.h @@ -0,0 +1,24 @@ +#ifndef _INCLUDE_MACH_C2600_PLATIO +#define _INCLUDE_MACH_C2600_PLATIO + +#include +#include + +/* a flash filesystem entry for the C2600 */ +struct fs_ent { + uint32_t magic; + uint32_t length; + /* todo: figure out exactly what these two fields contain */ + uint32_t crc32; + uint32_t date; + char filename[48]; +}; + +void platio_file_open(struct file *fp, const char *filename); +uint32_t platio_read(void *pbuf, uint32_t size, uint32_t nmemb, + struct file *fp); +uint8_t platio_find_file(const char *filename); + +#define FS_FILE_MAGIC 0xbad00b1e + +#endif /* _INCLUDE_MACH_C2600_PLATIO */ diff --git a/mach/c2600/Makefile b/mach/c2600/Makefile new file mode 100644 index 0000000..226cf8a --- /dev/null +++ b/mach/c2600/Makefile @@ -0,0 +1,18 @@ +ifndef CROSS_COMPILE +CROSS_COMPILE=powerpc-elf- +endif + +OBJECTS=start.o promlib.o platform.o platio.o + +INCLUDE=-I../../include + +all: ${OBJECTS} + +.c.o: + $(CC) ${CFLAGS} ${INCLUDE} -c $< + +.S.o: + $(CC) ${CFLAGS} ${INCLUDE} ${ASFLAGS} -c $< + +clean: + -rm -f *.o diff --git a/mach/c2600/platform.c b/mach/c2600/platform.c new file mode 100644 index 0000000..8d32972 --- /dev/null +++ b/mach/c2600/platform.c @@ -0,0 +1,75 @@ +/* Platform-specific operations for the Cisco 2600 Series router + * (c) 2009 Philippe Vachon + * + * Licensed under the GNU General Public License v.2.0. See the COPYING + * file in the root directory of this source distribution for more info. + */ +#include +#include +#include +#include + +/** + * perform hardware-specifc initialization for this platform + */ +void platform_init() +{ +} + +/** + * Perform a sanity check on flash + * @returns 0 if no flash found, number of flash devices found otherwise + */ +uint32_t check_flash() +{ + uint32_t *ptr = (uint32_t *)FLASH_BASE; + + if (*ptr != FS_FILE_MAGIC) { + return 0; + } + + return 1; + /* TODO: add support for PCMCIA flash */ +} + +/** + * print a directory listing of the 'main' flash device in the system + */ + +void flash_directory() +{ + struct fs_ent *f = (struct fs_ent *)FLASH_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 *)(FLASH_BASE + offset); + } +} + +/** + * Locate the stage two loader for CiscoLoad for this particular platform + * returns 0 if not found, 1 if found + */ +uint32_t locate_stage_two() +{ + return platio_find_file("ciscoload.two"); +} + +/** + * Kick into the stage two loader. + */ +void stage_two(uint32_t kern_off, uint32_t kern_entry, uint32_t kern_size, + uint32_t kern_loadpt) +{ + uint32_t s2addr = ((uint32_t)find_file("ciscoload.two", FLASH_BASE)) + + sizeof(struct fs_ent); + + + ((void (*)(uint32_t data_offset, uint32_t data_length, uint32_t entry_pt, + uint32_t load_offset)) (s2addr)) + (kern_off, kern_size, kern_entry, kern_loadpt); + +} diff --git a/mach/c2600/platio.c b/mach/c2600/platio.c new file mode 100644 index 0000000..853b922 --- /dev/null +++ b/mach/c2600/platio.c @@ -0,0 +1,98 @@ +/* Platform specific operations for I/O for the cisco 2600 Series + * (C) 2008 Philippe Vachon + * + * Licensed under the GNU General Public License v2. + */ +#include +#include +#include +#include + +#include + +/* find file in filesystem starting at base */ +struct fs_ent *find_file(const char *filename, uint32_t base) +{ + /* Actual file offset */ + uint32_t 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)) { + return f; + } + + offset += sizeof(struct fs_ent) + f->length; + f = (struct fs_ent *)(base + offset); + } + + return NULL; +} + +/** + * Find a file within the platform-supported I/O devices + * @param filename the file + * @returns 0 on failure, device ID number on success + */ +uint8_t platio_find_file(const char *filename) +{ + if (find_file(filename, FLASH_BASE)) { + return 1; + } + /* todo: add support for PCMCIA devices */ + + return 0; +} + +/** + * Open a file. + * @param fp File structure to hold file information + * @param filename name of the file + */ +void platio_file_open(struct file *fp, const char *filename) +{ + struct fs_ent *ent = find_file(filename, FLASH_BASE); + + if (ent == NULL) { + fp->code = 0; + fp->private = NULL; + return; + } + + fp->dev = 1; /* TODO: add support for PCMCIA flash */ + + fp->private = (void *)ent; + + fp->file_len = ent->length; + fp->file_pos = 0; + + /* copy the filename */ + strncpy(fp->filename, ent->filename, 48); + + fp->code = 1; + +} + +/** + * Read data from a given file + * @param pbuf Buffer to read data into + * @param size size of entity to be read + * @param nmemb number of members to read + * @param fp file information structure to read from. + * @returns number of bytes read (should = size * nmemb for C3600) + */ +uint32_t platio_read(void *pbuf, uint32_t size, uint32_t nmemb, struct file *fp) +{ + /* calculate the effective offset of the data we want to read: */ + char *from = (char *)((uint32_t)(fp->private) + sizeof(struct fs_ent) + + fp->file_pos); + + memcpy(pbuf, from, size * nmemb); + + fp->file_pos += size * nmemb; + + return nmemb * size; + +} diff --git a/mach/c2600/promlib.c b/mach/c2600/promlib.c new file mode 100644 index 0000000..05057a5 --- /dev/null +++ b/mach/c2600/promlib.c @@ -0,0 +1,163 @@ +/** + * low-level prom and I/O library for the Cisco 2600 series + * (C) 2008 Philippe Vachon + * ----------------------------------------------------------- + * Licensed under the GNU General Public License v2.0. See + * COPYING in the root directory of the source distribution for details. + */ + +#include +#include +#include + +#define UART_BASE 0xffe00000 +#define UART_LSR 0x5 + + +/* putc + * output character c to console + * @param c ASCII number for character + */ +void c_putc(const char c) +{ + while (!(*((char *)(UART_BASE + UART_LSR)) & 0x20)); + ((char *)UART_BASE)[0] = c; +} + +/* puts - wrapper for putc + * output the string pointed to by s + * @param s String to be written to the console + */ +void c_puts(const char *s) +{ + while(*s != '\0') { + c_putc(*(s++)); + if (*s == '\n') { + c_putc('\r'); + } + } +} + +/* putsn - put a string of length n on the console + * @param s string to be written + * @param n length + */ +void c_putsn(const char *s, int n) +{ + int i = 0; + while (*s != '\0' && i != n) { + c_putc(*(s++)); + i++; + } +} + + +/* getc - Syscall n + * get one character of input from the console + * @return ASCII code for character read from console + */ +char c_getc(void) +{ + char c; + while (!(*((uint8_t *)(UART_BASE + UART_LSR)) & 0x01)); + c = ((uint8_t *)UART_BASE)[0]; + return c; +} + +/* gets - wrapper for getc + * reads up to n characters into buffer b + * @param b Buffer to read characters into + * @param n size of buffer + * @return the number of characters read into b + */ +int c_gets(char *b, int n) +{ + int i = 0; + do { + b[i] = c_getc(); + c_putc(b[i]); + i++; + if (b[i - 1] == '\n' || b[i-1] == '\r') { + break; + } + else if (b[i - 1] == 0x8 || b[i - 1] == 0x7f) { + i-=2; + } + } while (i < n); + + b[i - 1] = '\0'; + + return i; + +} + +/* c_version - get version string + * @return pointer to version string + */ +char *c_verstr(void) +{ + return "Cisco 2600 Series Router"; +} + +/* memsz - get total memory size (in bytes) + * @return the size of the memory installed in the router, in bytes + */ +int c_memsz(void) +{ + int m = 0; + + __asm__ ( + "li 3, 4\n" + "sc\n" + "mr %[memsz], 3\n" + : [memsz]"=r"(m) + : /* no inputs */ + : "r3","memory","cc" + ); + + + return m; +} + +/* timer - get number of ticks from timer + * @return the value in the timer + */ +long c_timer(void) +{ + return 0; +} + +/* String length with a maximum length allowed + * @param s pointer to string + * @param maxlen maximum length + */ +int c_strnlen(const char *s, int maxlen) +{ + int i = 0; + if (!s) return 0; + + while (*(s++) != '\0' && i != maxlen) { + i++; + } + + return i; +} + +/* baud - get console baud rate + * @return boot console baud rate + */ +int c_baud(void) +{ + int b = 115200; + + __asm__ ( + "li 3, 62\n" + "sc\n" + "mr %[baud], 3\n" + : [baud]"=r"(b) + : /* no returns */ + : "r3", "memory", "cc" + ); + + return b; +} diff --git a/mach/c2600/start.S b/mach/c2600/start.S new file mode 100644 index 0000000..aa6a644 --- /dev/null +++ b/mach/c2600/start.S @@ -0,0 +1,29 @@ +/* CILO entry point for the Cisco 2600 Series Routers + * (C) 2009 Philippe Vachon + * Licensed under the GNU General Public License v2.0 or later. See + * COPYING in the root of the source distribution for more details. + */ + +#include + + .text + .globl _start + +_start: + + /* put a letter C to show we are alive */ + lis r26, 0xffe0 +putchar: + lbz r0, 5(r26) + andi. r0, r0, 0x20 + beq putchar + + /* put the C */ + li r3, 67 + stb r3, 0(r26) + + /* jump to the C code */ + bl start_bootloader + + .end _start + .size _start, .-_start diff --git a/mips.lds b/mips.lds new file mode 100644 index 0000000..2ffb8bd --- /dev/null +++ b/mips.lds @@ -0,0 +1,28 @@ +OUTPUT_ARCH(mips) +ENTRY(_start) +EXTERN(_start) + +SECTIONS +{ + .text : + { + . = ALIGN(4096); + *(.reginfo) + *(.text) + *(.rodata*) + *(.data*) + *(.sdata*) + *(.got2) + *(.bss) + *(.sbss) + *(.pdr) + } + + /DISCARD/ : + { + *(.comment) + *(.note.GNU-stack) + *(.gnu.attributes) + } + +} diff --git a/powerpc.lds b/powerpc.lds new file mode 100644 index 0000000..0992d8a --- /dev/null +++ b/powerpc.lds @@ -0,0 +1,30 @@ +OUTPUT_ARCH(powerpc:common) +ENTRY(_start) +EXTERN(_start) +PHDRS +{ + text PT_LOAD FILEHDR PHDRS ; +} + +SECTIONS +{ + .text : + { + . = ALIGN(4096); + *(.text) + *(.rodata*) + *(.data*) + *(.sdata*) + *(.got2) + *(.bss) + *(.sbss) + } :text + + /DISCARD/ : + { + *(.comment) + *(.note.GNU-stack) + *(.gnu.attributes) + } + +}