Initial commit.
commit
6d598a23e0
@ -0,0 +1,24 @@
|
|||||||
|
1. Adding a new platform
|
||||||
|
0) Create a mach/${PLATFORM} directory, which must contain the platform-
|
||||||
|
specific I/O routines for user interface and filesystem access.
|
||||||
|
1) Specify platform storage types, setup platform specific access methods
|
||||||
|
and strategies, or fall back on the defaults
|
||||||
|
2) Create platform-specific c_putc, c_getc, c_memsz
|
||||||
|
3) Create a platform_init() method; this will be the first method to be
|
||||||
|
called from start_bootloader(). This must register platform-specific
|
||||||
|
4) Build up any re-usable peripheral methods required - for example, if
|
||||||
|
your platform requires a new filesystem class (that may be seen in
|
||||||
|
other platforms), please add support for it in filesys.
|
||||||
|
|
||||||
|
2. Directory Structure
|
||||||
|
-> / - entry points, simple, common code
|
||||||
|
-> storage/ - the storage manager registering multiple storage classes
|
||||||
|
-> console/ - console I/O drivers
|
||||||
|
-> net/ - networking code (future)
|
||||||
|
-> mach/ - machine-specific code
|
||||||
|
-> c3600 - support for the Cisco 3600 Series
|
||||||
|
-> c1750 - support for the Cisco 1750 Series
|
||||||
|
-> c3725 - support for the Cisco 3725 Multiservice Router
|
||||||
|
-> include/ - headers for generic code
|
||||||
|
|
||||||
|
3.
|
@ -0,0 +1,68 @@
|
|||||||
|
# Configuration for the Cisco 3620/3640 Routers
|
||||||
|
TARGET=c3600
|
||||||
|
MACHCODE=0x1e
|
||||||
|
TEXTADDR=0x80008000
|
||||||
|
ifndef CROSS_COMPILE
|
||||||
|
CROSS_COMPILE=mips-elf-
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Configuration for the Cisco 3660 Routers
|
||||||
|
# TARGET=c3600
|
||||||
|
# MACHCODE=0x34
|
||||||
|
# TEXTADDR=0x80008000
|
||||||
|
# ifndef CROSS_COMPILE
|
||||||
|
# CROSS_COMPILE=mips-elf-
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# Configuration for the Cisco 1700 Series Routers
|
||||||
|
# TARGET=c1700
|
||||||
|
# MACHINE=0x33
|
||||||
|
# TEXTADDR=0x80008000
|
||||||
|
# ifndef CROSS_COMPILE
|
||||||
|
# CROSS_COMPILE=powerpc-elf-
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# additional CFLAGS
|
||||||
|
CFLAGS=
|
||||||
|
|
||||||
|
# don't modify anything below here
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
PROG=ciscoload
|
||||||
|
|
||||||
|
CC=$(CROSS_COMPILE)gcc
|
||||||
|
AR=$(CROSS_COMPILE)ar
|
||||||
|
LD=$(CROSS_COMPILE)ld
|
||||||
|
OBJCOPY=$(CROSS_COMPILE)objcopy
|
||||||
|
|
||||||
|
# command to prepare a binary
|
||||||
|
RAW=${OBJCOPY} --strip-unneeded --alt-machine-code ${MACHCODE}
|
||||||
|
|
||||||
|
INCLUDE=-Iinclude/ -Imach/${TARGET}
|
||||||
|
|
||||||
|
CFLAGS=$(INCLUDE) -fno-builtin -fomit-frame-pointer -fno-pic -mno-abicalls \
|
||||||
|
-Wall
|
||||||
|
|
||||||
|
ASFLAGS=-xassembler-with-cpp -traditional-cpp
|
||||||
|
|
||||||
|
LDFLAGS=--omagic -nostartfiles -nostdlib --discard-all --strip-all \
|
||||||
|
-Ttext ${TEXTADDR} --entry _start
|
||||||
|
|
||||||
|
OBJECTS=start.o main.o printf.o promlib.o elf_loader.o
|
||||||
|
|
||||||
|
all: ${OBJECTS} ${PROG}
|
||||||
|
|
||||||
|
${PROG}: ${OBJECTS}
|
||||||
|
${CC} ${LDFLAGS} ${OBJECTS} -o ${PROG}.elf
|
||||||
|
${RAW} ${PROG}.elf ${PROG}.bin
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
${CC} ${CFLAGS} -c $<
|
||||||
|
|
||||||
|
.S.o:
|
||||||
|
${CC} ${CFLAGS} ${ASFLAGS} -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *.o
|
||||||
|
rm ${PROG}.elf
|
||||||
|
rm ${PROG}.bin
|
@ -0,0 +1,53 @@
|
|||||||
|
CILO - CiscoLoad Sane Bootloader for real ELF Files
|
||||||
|
|
||||||
|
1. What is this?
|
||||||
|
CILO, or CiscoLoad is a ROMMON bootloader replacement for Cisco Routers.
|
||||||
|
The ROMMON bootloader will load CILO, which then can be used to boot IOS
|
||||||
|
or an alternative operating system.
|
||||||
|
|
||||||
|
2. Why do I need this?
|
||||||
|
The ROMMON bootloader is extremely broken -- it is only capable of
|
||||||
|
understanding a single ELF segment in an ELF file. Of course, because Linux
|
||||||
|
and other operating systems rely fairly heavily on being able to have more
|
||||||
|
than one segment in the output ELF file, this clearly isn't acceptable.
|
||||||
|
|
||||||
|
3. How do I build CILO?
|
||||||
|
Assuming you have a mips-elf toolchain installed (how to do this is beyond
|
||||||
|
the scope of this document, but it should be simple to do. Just remember the
|
||||||
|
target architecture is mips-elf and not mips-unknown-linux-gnu), just go
|
||||||
|
to the root directory of the source distribution and type make. Everything
|
||||||
|
should build from there.
|
||||||
|
|
||||||
|
Next, build the second stage bootloader by going to the second/ directory
|
||||||
|
and typing make.
|
||||||
|
|
||||||
|
Copy the ciscoload.bin and ciscoload.two files to the router's flash along
|
||||||
|
with your kernel and set the router boot image to be ciscoload.bin.
|
||||||
|
|
||||||
|
4. How do I use CILO?
|
||||||
|
Assuming you have one of the supported routers, it is really quite easy.
|
||||||
|
In short, you must build CiscoLoad, build the stage-two loader and copy
|
||||||
|
them to your device's flash, typically using IOS.
|
||||||
|
|
||||||
|
When the router boots, it will load CILO; CILO then will prompt you to
|
||||||
|
select the file you want to boot. Enter the file name you wish to boot, and
|
||||||
|
away you go!
|
||||||
|
|
||||||
|
5. What hardware is supported?
|
||||||
|
At this time, the Cisco 3600 Series of routers (3620 and 3640 at least) are
|
||||||
|
very well supported. As well, preliminary support is underway for the
|
||||||
|
Cisco 1700 Series routers.
|
||||||
|
|
||||||
|
6. What is ELFTool?
|
||||||
|
ELFTool is a small app that can be used to analyze ELF32 files. It is used
|
||||||
|
as a test case for the elf.h header and the ELF reading support in
|
||||||
|
CiscoLoad. To build it, go to the elftool/ directory in the source dist-
|
||||||
|
ribution, and type make.
|
||||||
|
|
||||||
|
7. Who wrote CiscoLoad?
|
||||||
|
CiscoLoad was the result of many wasted hours of Phil Vachon, who can be
|
||||||
|
reached at philippe@cowpig.ca.
|
||||||
|
|
||||||
|
8. What License is CiscoLoad shipped under
|
||||||
|
While CiscoLoad is a simple piece of software, the code is covered under the
|
||||||
|
GNU General Public License version 2.
|
@ -0,0 +1,4 @@
|
|||||||
|
1. Add support for multiple classes of mass storage
|
||||||
|
-> support for ATA Flash (i.e. 3725, 7200 series, etc...)
|
||||||
|
-> support for linear PCMCIA Flash (i.e. 3600 series)
|
||||||
|
-> support for multiple devices
|
@ -0,0 +1,242 @@
|
|||||||
|
#include <elf.h>
|
||||||
|
#include <promlib.h>
|
||||||
|
#include <printf.h>
|
||||||
|
|
||||||
|
|
||||||
|
void read(void *ptr, uint32_t size, uint32_t count, uint32_t base,
|
||||||
|
uint32_t offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load a single ELF section into memory at address. Assumes ELF data is
|
||||||
|
* contiguous in memory.
|
||||||
|
* @param base location (in memory) of the ELF file
|
||||||
|
* @param address address at which the ELF section will be loaded
|
||||||
|
* @param file_offset offset (in bytes) in the ELF file where the section is
|
||||||
|
* @param length Length of the section (in bytes)
|
||||||
|
*/
|
||||||
|
void load_elf32_section(uint32_t base, uint32_t address,
|
||||||
|
uint32_t file_offset, uint32_t length)
|
||||||
|
{
|
||||||
|
uint8_t *elf_loc = (uint8_t *)address;
|
||||||
|
|
||||||
|
printf("read(%08x, %08x, 1, %08x, %08x);\n",
|
||||||
|
address, length, base, file_offset);
|
||||||
|
|
||||||
|
read(elf_loc, length, 1, base, file_offset);
|
||||||
|
|
||||||
|
printf("Read %d bytes into memory at location %#8x.\n", length, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an uninitialized data (.bss) region of memory.
|
||||||
|
* @param address Start address of this region
|
||||||
|
* @param lenght length of this region
|
||||||
|
*/
|
||||||
|
void load_elf32_uninitialized_memory(uint32_t address, uint32_t length)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
uint8_t *p = (uint8_t *)address;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
p[i] = 0;
|
||||||
|
}
|
||||||
|
printf("Created uninitialized data section of %d bytes at %#8x.\n", i,
|
||||||
|
address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read data into a given pointer
|
||||||
|
* @param ptr Pointer to write data out to
|
||||||
|
* @param size Size of the data to be read
|
||||||
|
* @param count number of elements to read
|
||||||
|
* @param base base address to start read from
|
||||||
|
* @param offset offset from base to read from
|
||||||
|
*/
|
||||||
|
void read(void *ptr, uint32_t size, uint32_t count, uint32_t base,
|
||||||
|
uint32_t offset)
|
||||||
|
{
|
||||||
|
uint8_t *data = (uint8_t *)ptr;
|
||||||
|
uint8_t *src = (uint8_t *)(base + offset);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < size * count; i++) {
|
||||||
|
data[i] = src[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an ELF file into memory from the given base. Loads at
|
||||||
|
* offset + image_size so that a later memcpy routine can be used to copy
|
||||||
|
* things into RAM and then kick off the boot process.
|
||||||
|
* @param base The address of the ELF file in memory
|
||||||
|
* @param loader_addr address of the loader binary in memory
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int load_elf32_file(uint32_t base, uint32_t loader_addr)
|
||||||
|
{
|
||||||
|
struct elf32_header hdr;
|
||||||
|
|
||||||
|
uint32_t mem_sz = 0;
|
||||||
|
|
||||||
|
/* read in header entries */
|
||||||
|
read(&hdr, sizeof(struct elf32_header), 1, base, 0);
|
||||||
|
|
||||||
|
/* check the file magic */
|
||||||
|
if (hdr.ident[0] != ELF_MAGIC_1 || hdr.ident[1] != ELF_MAGIC_2 ||
|
||||||
|
hdr.ident[2] != ELF_MAGIC_3 || hdr.ident[3] != ELF_MAGIC_4)
|
||||||
|
{
|
||||||
|
printf("Bad ELF magic found. Found: %#2x %#2x %#2x %#2x.\n",
|
||||||
|
hdr.ident[0], hdr.ident[1], hdr.ident[2], hdr.ident[3]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* check machine class: */
|
||||||
|
if (!(hdr.ident[ELF_INDEX_CLASS] == ELF_CLASS_32 ||
|
||||||
|
hdr.ident[ELF_INDEX_CLASS] == ELF_CLASS_64))
|
||||||
|
{
|
||||||
|
printf("Invalid ELF machine class found. Found: %2x.\n",
|
||||||
|
hdr.ident[ELF_INDEX_CLASS]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check endianess: */
|
||||||
|
if (hdr.ident[ELF_INDEX_DATA] != ELF_DATA_MSB) {
|
||||||
|
printf("Non-big endian ELF file detected. Aborting load.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (hdr.machine != ELF_MACH_MIPS || hdr.machine != ELF_MACH_MIPS_R4K_BE ||
|
||||||
|
hdr.machine != 0x1e)
|
||||||
|
{
|
||||||
|
printf("Warning: Unexpected machine type %#4x found.\n", hdr.machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr.ehsize != 52 /* bytes */) {
|
||||||
|
printf("Warning: ELF header greater than 52 bytes found. Found: %u\n",
|
||||||
|
hdr.ehsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr.shnum == 0) {
|
||||||
|
printf("Can't be zero section headers in a kernel image! Aborting.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
struct elf32_phdr phdr;
|
||||||
|
uint32_t ph_offset = hdr.phoff;
|
||||||
|
|
||||||
|
/* read in program header(s), determine total memory size of image */
|
||||||
|
/* TODO: figure out if there's a better way to determine this */
|
||||||
|
for (i = 0; i < hdr.phnum; i++) {
|
||||||
|
read(&phdr, sizeof(struct elf32_phdr), 1, base, ph_offset);
|
||||||
|
|
||||||
|
mem_sz += phdr.memsz;
|
||||||
|
|
||||||
|
/*increment program header offset */
|
||||||
|
ph_offset += sizeof(struct elf32_phdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read the PT_LOAD segments into memory at paddr + mem_sz
|
||||||
|
*/
|
||||||
|
ph_offset = hdr.phoff;
|
||||||
|
for (i = 0; i < hdr.phnum; i++) {
|
||||||
|
read(&phdr, sizeof(struct elf32_phdr), 1, base, ph_offset);
|
||||||
|
|
||||||
|
/* skip unloadable segments */
|
||||||
|
if (phdr.type != ELF_PT_LOAD) continue;
|
||||||
|
|
||||||
|
uint32_t leftover = phdr.memsz - phdr.filesz;
|
||||||
|
load_elf32_section(base, mem_sz + hdr.entry + phdr.paddr,
|
||||||
|
phdr.offset, phdr.filesz);
|
||||||
|
|
||||||
|
if (leftover > 0) {
|
||||||
|
load_elf32_uninitialized_memory(mem_sz + hdr.entry + phdr.paddr +
|
||||||
|
phdr.filesz, leftover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assume the entry point is the smallest address we're loading */
|
||||||
|
uint32_t load_offset = mem_sz + hdr.entry;
|
||||||
|
|
||||||
|
printf("Loaded %d bytes at %08x.\n", mem_sz, load_offset);
|
||||||
|
|
||||||
|
/* struct elf32_section_header shdr; */
|
||||||
|
|
||||||
|
/* read in section headers, load sections */
|
||||||
|
#if 0
|
||||||
|
uint32_t sh_offset = hdr.shoff;
|
||||||
|
for (i = 0; i < hdr.shnum; i++) {
|
||||||
|
printf("reading: base: %08x, sh_offset: %08x\n", base, sh_offset);
|
||||||
|
read(&shdr, sizeof(struct elf32_section_header), 1, base, sh_offset);
|
||||||
|
|
||||||
|
printf("\n\nJust read section header %d\n", i);
|
||||||
|
|
||||||
|
printf("\tName: %u\n", shdr.name);
|
||||||
|
printf("\tType: %#8x: %s\n", shdr.type, sh_type_to_string(shdr.type));
|
||||||
|
printf("\tFlags: %#8x\n", shdr.flags);
|
||||||
|
printf("\t\t%c%c%c\n", ELF_SHF_ALLOCD(shdr.flags) ? 'A' : '-',
|
||||||
|
ELF_SHF_WRITABLE(shdr.flags) ? 'w' : '-',
|
||||||
|
ELF_SHF_EXECUTABLE(shdr.flags) ? 'x' : '-');
|
||||||
|
printf("\tAddress: %#8x\n", shdr.addr);
|
||||||
|
printf("\tOffset: %u bytes\n", shdr.offset);
|
||||||
|
printf("\tSize: %u bytes\n", shdr.size);
|
||||||
|
printf("\tLink: %#8x\n", shdr.link);
|
||||||
|
printf("\tAdditional Info: %#8x\n", shdr.info);
|
||||||
|
printf("\tAddress Alignment: %#8x\n", shdr.addralign);
|
||||||
|
printf("\tPer-Entry Size: %u bytes\n\n", shdr.entsize);
|
||||||
|
|
||||||
|
if (!ELF_SHF_ALLOCD(shdr.flags)) {
|
||||||
|
sh_offset += sizeof(struct elf32_section_header);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Param: base: %08x addr: %08x offset: %08x size: %08x\n",
|
||||||
|
base, shdr.addr, shdr.offset, shdr.size);
|
||||||
|
|
||||||
|
/* load section */
|
||||||
|
switch (shdr.type) {
|
||||||
|
case ELF_SHT_NULL: /* no data to be loaded */
|
||||||
|
break;
|
||||||
|
case ELF_SHT_NOBITS:
|
||||||
|
/* zero out this data */
|
||||||
|
load_elf32_uninitialized_memory(shdr.addr + mem_sz,
|
||||||
|
shdr.size);
|
||||||
|
break;
|
||||||
|
case ELF_SHT_PROGBITS:
|
||||||
|
/* program bits and such */
|
||||||
|
load_elf32_section(base, shdr.addr + mem_sz, shdr.offset,
|
||||||
|
shdr.size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("WARNING: Section type %08x cannot be loaded by "
|
||||||
|
"CiscoLoad.\n", shdr.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
sh_offset += sizeof(struct elf32_section_header);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
printf("Kicking into Linux.\n");
|
||||||
|
printf("bootcpy: %08x, kdataoffset: %08x, kdatalength: %08x\n",
|
||||||
|
loader_addr, load_offset, mem_sz);
|
||||||
|
printf("kentrypt: %08x, kloadoffset: %08x\n", hdr.entry, hdr.entry);
|
||||||
|
|
||||||
|
/* Jump to the copy routine */
|
||||||
|
asm (".set noreorder\n"
|
||||||
|
"move $k0, %[bootcpy]\n"
|
||||||
|
"move $a0, %[kdataoffset]\n"
|
||||||
|
"move $a1, %[kdatalength]\n"
|
||||||
|
"move $a2, %[kentrypt]\n"
|
||||||
|
"move $a3, %[kloadoffset]\n"
|
||||||
|
"jr $k0\n"
|
||||||
|
" nop\n"
|
||||||
|
: /* no outputs */
|
||||||
|
: [bootcpy] "r"(loader_addr), [kdataoffset] "r"(load_offset),
|
||||||
|
[kdatalength] "r"(mem_sz), [kentrypt]"r"(hdr.entry),
|
||||||
|
[kloadoffset] "r"(hdr.entry)
|
||||||
|
: "k0", "a0", "a1", "a2", "a3"
|
||||||
|
);
|
||||||
|
|
||||||
|
return -1; /* something failed, badly */
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
OBJECTS = elftool.o
|
||||||
|
INCLUDES = -I../include/
|
||||||
|
CFLAGS = $(INCLUDES)
|
||||||
|
PROG = elftool
|
||||||
|
|
||||||
|
all: elftool
|
||||||
|
|
||||||
|
elftool: $(OBJECTS)
|
||||||
|
gcc $(OBJECTS) -o $(PROG)
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
gcc $(CFLAGS) -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *.o
|
||||||
|
rm $(PROG)
|
@ -0,0 +1,374 @@
|
|||||||
|
/**
|
||||||
|
* ELFTool: A tool for analyzing ELF32 files and a test case for the ELF
|
||||||
|
* structures in elf.h for CiscoLoad
|
||||||
|
* (c) 2008 Philippe Vachon <philippe@cowpig.ca>
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License v2
|
||||||
|
* See COPYING in the root directory of the CiscoLoad source distribution for
|
||||||
|
* more information
|
||||||
|
*/
|
||||||
|
#include <elf.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* swap functions - convert a header structure's endianess to the native
|
||||||
|
* machine's endianess. Determined by the contents of the e_ident bytes in
|
||||||
|
* the ELF file header.
|
||||||
|
* @param hdr header structure to be translated
|
||||||
|
*/
|
||||||
|
void swap_elf32_header(struct elf32_header *hdr)
|
||||||
|
{
|
||||||
|
hdr->type = SWAP_16(hdr->type);
|
||||||
|
hdr->machine = SWAP_16(hdr->machine);
|
||||||
|
hdr->version = SWAP_32(hdr->version);
|
||||||
|
hdr->entry = SWAP_32(hdr->entry);
|
||||||
|
hdr->phoff = SWAP_32(hdr->phoff);
|
||||||
|
hdr->shoff = SWAP_32(hdr->shoff);
|
||||||
|
hdr->flags = SWAP_32(hdr->flags);
|
||||||
|
hdr->ehsize = SWAP_16(hdr->ehsize);
|
||||||
|
hdr->phentsize = SWAP_16(hdr->phentsize);
|
||||||
|
hdr->phnum = SWAP_16(hdr->phnum);
|
||||||
|
hdr->shentsize = SWAP_16(hdr->shentsize);
|
||||||
|
hdr->shnum = SWAP_16(hdr->shnum);
|
||||||
|
hdr->shstrndx = SWAP_16(hdr->shstrndx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap_elf32_section_header(struct elf32_section_header *shdr)
|
||||||
|
{
|
||||||
|
shdr->name = SWAP_32(shdr->name);
|
||||||
|
shdr->type = SWAP_32(shdr->type);
|
||||||
|
shdr->flags = SWAP_32(shdr->flags);
|
||||||
|
shdr->addr = SWAP_32(shdr->addr);
|
||||||
|
shdr->offset = SWAP_32(shdr->offset);
|
||||||
|
shdr->size = SWAP_32(shdr->size);
|
||||||
|
shdr->link = SWAP_32(shdr->link);
|
||||||
|
shdr->info = SWAP_32(shdr->info);
|
||||||
|
shdr->addralign = SWAP_32(shdr->addralign);
|
||||||
|
shdr->entsize = SWAP_32(shdr->entsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap_elf32_program_header(struct elf32_phdr *phdr)
|
||||||
|
{
|
||||||
|
phdr->type = SWAP_32(phdr->type);
|
||||||
|
phdr->offset = SWAP_32(phdr->offset);
|
||||||
|
phdr->vaddr = SWAP_32(phdr->vaddr);
|
||||||
|
phdr->paddr = SWAP_32(phdr->paddr);
|
||||||
|
phdr->filesz = SWAP_32(phdr->filesz);
|
||||||
|
phdr->memsz = SWAP_32(phdr->memsz);
|
||||||
|
phdr->flags = SWAP_32(phdr->flags);
|
||||||
|
phdr->align = SWAP_32(phdr->align);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a e_machine code to a human-readable string, if it's a machine
|
||||||
|
* we are aware of. 0x0 through 0xa are specified as a part of the ELF
|
||||||
|
* specification, anything else has been found through experimentation or
|
||||||
|
* through other sources of such information.
|
||||||
|
* @param machine the e_machine code read from the ELF file.
|
||||||
|
* @return a string containing the machine type name.
|
||||||
|
*/
|
||||||
|
const char *machine_id_to_string(uint16_t machine)
|
||||||
|
{
|
||||||
|
switch (machine) {
|
||||||
|
case 0:
|
||||||
|
return "Unknown";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
return "AT&T WE 32100";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
return "SPARC";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
return "Intel 80386";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
return "Motorola 68000";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
return "Motorola 88000";
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
return "Intel 80860";
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
return "MIPS R3000";
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
return "MIPS R4000";
|
||||||
|
break;
|
||||||
|
case 0x19:
|
||||||
|
/* note: can also be c6000 it would seem? */
|
||||||
|
return "Cisco 7200 Series Router (Big Endian)";
|
||||||
|
break;
|
||||||
|
case 0x1e:
|
||||||
|
return "Cisco 3620/40 Router (MIPS, IDT R4700, Big Endian)";
|
||||||
|
break;
|
||||||
|
case 0x2b:
|
||||||
|
return "Cisco 2600 Series Router (PowerPC, MPC860, Big Endian)";
|
||||||
|
break;
|
||||||
|
case 0x33:
|
||||||
|
return "Cisco 1700 Series Router (PowerPC, MPC860, Big Endian)";
|
||||||
|
break;
|
||||||
|
case 0x34:
|
||||||
|
return "Cisco 3660 Router (MIPS, R5000, Big Endian)";
|
||||||
|
break;
|
||||||
|
case 0x61:
|
||||||
|
return "Cisco 3725 Router (MIPS, Big Endian)";
|
||||||
|
break;
|
||||||
|
case 0x66:
|
||||||
|
return "Cisco 2691 Router (MIPS, Big Endian)";
|
||||||
|
break;
|
||||||
|
case 0x69:
|
||||||
|
return "Cisco 3745 Router (MIPS, Big Endian)";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "Reserved";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert section header type (e_type) to a human-readable string
|
||||||
|
* @param sh_type the section header type
|
||||||
|
* @return string with the human-readable name of the section header type
|
||||||
|
*/
|
||||||
|
char *sh_type_to_string(unsigned int sh_type)
|
||||||
|
{
|
||||||
|
switch (sh_type) {
|
||||||
|
case 0:
|
||||||
|
return "SHT_NULL";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
return "SHT_PROGBITS";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
return "SHT_SYMTAB";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
return "SHT_STRTAB";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
return "SHT_RELA";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
return "SHT_HASH";
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
return "SHT_DYNAMIC";
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
return "SHT_NOTE";
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
return "SHT_NOBITS";
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
return "SHT_REL";
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
return "SHT_SHLIB";
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
return "SHT_DYNSYM";
|
||||||
|
break;
|
||||||
|
case 0x70000000:
|
||||||
|
return "SHT_MIPS_LIBLIST";
|
||||||
|
break;
|
||||||
|
case 0x70000002:
|
||||||
|
return "SHT_MIPS_CONFLICT";
|
||||||
|
break;
|
||||||
|
case 0x70000003:
|
||||||
|
return "SHT_MIPS_GPTAB";
|
||||||
|
break;
|
||||||
|
case 0x70000004:
|
||||||
|
return "SHT_MIPS_UCODE";
|
||||||
|
break;
|
||||||
|
case 0x70000005:
|
||||||
|
return "SHT_MIPS_DEBUG";
|
||||||
|
break;
|
||||||
|
case 0x70000006:
|
||||||
|
return "SHT_MIPS_REGINFO";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "SHT_CUSTOM";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the segment/program header type number (e_type) to a human readable
|
||||||
|
* string (based on the contents of the ELF specification)
|
||||||
|
* @param type the e_type value read from the section header
|
||||||
|
* @return a string containing the human-readable section type
|
||||||
|
*/
|
||||||
|
char *segment_type_to_string(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case ELF_PT_NULL:
|
||||||
|
return "PT_NULL";
|
||||||
|
break;
|
||||||
|
case ELF_PT_LOAD:
|
||||||
|
return "PT_LOAD";
|
||||||
|
break;
|
||||||
|
case ELF_PT_DYNAMIC:
|
||||||
|
return "PT_DYNAMIC";
|
||||||
|
break;
|
||||||
|
case ELF_PT_INTERP:
|
||||||
|
return "PT_INTERP";
|
||||||
|
break;
|
||||||
|
case ELF_PT_NOTE:
|
||||||
|
return "PT_NOTE";
|
||||||
|
break;
|
||||||
|
case ELF_PT_SHLIB:
|
||||||
|
return "PT_SHLIB";
|
||||||
|
break;
|
||||||
|
case ELF_PT_PHDR:
|
||||||
|
return "PT_PHDR";
|
||||||
|
break;
|
||||||
|
case 0x70000000:
|
||||||
|
return "PT_MIPS_REGINFO";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "PT_CUSTOM";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(const int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
uint8_t magic[4];
|
||||||
|
struct elf32_header hdr;
|
||||||
|
int swap = 0;
|
||||||
|
|
||||||
|
printf("ELFTool - a simple tool for viewing ELF file structures.\n");
|
||||||
|
printf("(c) 2008 Philippe Vachon <philippe@cowpig.ca>\n\n");
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("A file must be specified for analysis.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fp = fopen(argv[1], "rb")) == NULL) {
|
||||||
|
printf("Unable to open file %s. Aborting.\n",argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(magic, 1, 4, fp);
|
||||||
|
|
||||||
|
if (magic[0] != ELF_MAGIC_1 || magic[1] != ELF_MAGIC_2 ||
|
||||||
|
magic[2] != ELF_MAGIC_3 || magic[3] != ELF_MAGIC_4)
|
||||||
|
{
|
||||||
|
printf("ELF magic number not found. Aborting.\n");
|
||||||
|
printf("Magic found: 0x%08x.\n", magic);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read in the ELF header fields */
|
||||||
|
rewind(fp);
|
||||||
|
fread(&hdr, 1, sizeof(struct elf32_header), fp);
|
||||||
|
|
||||||
|
/* check endianess: */
|
||||||
|
if (hdr.ident[ELF_INDEX_DATA] == ELF_DATA_MSB) {
|
||||||
|
swap = 1;
|
||||||
|
swap_elf32_header(&hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* print the ELF header structure: */
|
||||||
|
printf("ELF File Header:\n");
|
||||||
|
printf("================================================\n");
|
||||||
|
|
||||||
|
printf("Ident bytes:\n");
|
||||||
|
printf("\tClass: %d-bit\n", hdr.ident[ELF_INDEX_CLASS] == ELF_CLASS_64 ?
|
||||||
|
64 : 32);
|
||||||
|
printf("\tData type: %s\n", hdr.ident[ELF_INDEX_DATA] == ELF_DATA_MSB ?
|
||||||
|
"Big endian" : "Little endian");
|
||||||
|
printf("\tVersion: %u\n\n", hdr.ident[ELF_INDEX_VERSION]);
|
||||||
|
|
||||||
|
printf("Machine ID: %#4x\n\t%s\n", hdr.machine, machine_id_to_string(hdr.machine));
|
||||||
|
printf("Version: 0x%08x\n", hdr.version);
|
||||||
|
printf("Entry point: 0x%08x\n", hdr.entry);
|
||||||
|
printf("Program header offset: 0x%08x\n", hdr.phoff);
|
||||||
|
printf("Section header offset: 0x%08x\n", hdr.shoff);
|
||||||
|
printf("Flags: 0x%08x\n", hdr.flags);
|
||||||
|
printf("ELF Header Size: %u bytes\n", hdr.ehsize);
|
||||||
|
printf("Program Header Entry Size: %u bytes\n", hdr.phentsize);
|
||||||
|
printf("Program Header Count: %u\n", hdr.phnum);
|
||||||
|
printf("Section header Entry Size: %u bytes\n", hdr.shentsize);
|
||||||
|
printf("Section Header Count: %u\n", hdr.shnum);
|
||||||
|
printf("String table entry index: %u\n\n", hdr.shstrndx);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* now start looking at the ELF sections */
|
||||||
|
fseek(fp, hdr.shoff, SEEK_SET);
|
||||||
|
|
||||||
|
printf("Section Header Entries: \n");
|
||||||
|
printf("================================================\n");
|
||||||
|
|
||||||
|
int i;
|
||||||
|
struct elf32_section_header shdr;
|
||||||
|
for (i = 0; i < hdr.shnum; i++) {
|
||||||
|
fread(&shdr.name, 1, 4, fp);
|
||||||
|
fread(&shdr.type, 1, 4, fp);
|
||||||
|
fread(&shdr.flags, 1, 4, fp);
|
||||||
|
fread(&shdr.addr, 1, 4, fp);
|
||||||
|
fread(&shdr.offset, 1, 4, fp);
|
||||||
|
|
||||||
|
fread(&shdr.size, 1, 4, fp);
|
||||||
|
fread(&shdr.link, 1, 4, fp);
|
||||||
|
fread(&shdr.info, 1, 4, fp);
|
||||||
|
fread(&shdr.addralign, 1, 4, fp);
|
||||||
|
fread(&shdr.entsize, 1, 4, fp);
|
||||||
|
|
||||||
|
if (swap) {
|
||||||
|
swap_elf32_section_header(&shdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Section %d\n", i);
|
||||||
|
printf("\tName: %u\n", shdr.name);
|
||||||
|
printf("\tType: %s (0x%08x)\n", sh_type_to_string(shdr.type),
|
||||||
|
shdr.type);
|
||||||
|
printf("\tFlags: 0x%08x\n", shdr.flags);
|
||||||
|
printf("\t\t%c%c%c\n", ELF_SHF_ALLOCD(shdr.flags) ? 'A' : '-',
|
||||||
|
ELF_SHF_WRITABLE(shdr.flags) ? 'w' : '-',
|
||||||
|
ELF_SHF_EXECUTABLE(shdr.flags) ? 'x' : '-');
|
||||||
|
printf("\tAddress: 0x%08x\n", shdr.addr);
|
||||||
|
printf("\tOffset: %u bytes\n", shdr.offset);
|
||||||
|
printf("\tSize: %u bytes\n", shdr.size);
|
||||||
|
printf("\tLink: 0x%08x\n", shdr.link);
|
||||||
|
printf("\tAdditional Info: 0x%08x\n", shdr.info);
|
||||||
|
printf("\tAddress Alignment: 0x%08x\n", shdr.addralign);
|
||||||
|
printf("\tPer-Entry Size: %u bytes\n\n", shdr.entsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No program headers present; exit. */
|
||||||
|
if (hdr.phnum == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fseek(fp, hdr.phoff, SEEK_SET);
|
||||||
|
printf("\nProgram Header Entries\n");
|
||||||
|
printf("================================================\n");
|
||||||
|
struct elf32_phdr phdr;
|
||||||
|
for (i = 0; i < hdr.phnum; i++) {
|
||||||
|
fread(&phdr, 1, sizeof(struct elf32_phdr), fp);
|
||||||
|
if (swap) {
|
||||||
|
swap_elf32_program_header(&phdr);
|
||||||
|
}
|
||||||
|
printf("Segment %d\n", i);
|
||||||
|
printf("\tType: %s (0x%08x)\n", segment_type_to_string(phdr.type),
|
||||||
|
phdr.type);
|
||||||
|
printf("\tOffset: 0x%08x\n", phdr.offset);
|
||||||
|
printf("\tVirtual Address: 0x%08x\n", phdr.vaddr);
|
||||||
|
printf("\tPhysical Address: 0x%08x\n", phdr.paddr);
|
||||||
|
printf("\tSize in File: %u bytes\n", phdr.filesz);
|
||||||
|
printf("\tSize in Memory: %u bytes\n", phdr.memsz);
|
||||||
|
printf("\tFlags: 0x%08x\n", phdr.flags);
|
||||||
|
printf("\tAlignment: 0x%08x\n\n", phdr.align);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef _ADDR_H
|
||||||
|
#define _ADDR_H
|
||||||
|
|
||||||
|
/* Address conversion macros to simplify dealing with known addresses
|
||||||
|
* of devices in the system. Applies to all MIPS devices
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 32-bit addresses */
|
||||||
|
|
||||||
|
#define KSEG0_TO_PHYS32(a) ((a) & 0x7FFFFFFFul)
|
||||||
|
#define KSEG1_TO_PHYS32(a) ((a) & 0x1FFFFFFFul)
|
||||||
|
|
||||||
|
#define PHYS_TO_KSEG032(a) ((a) + 0x80000000ul)
|
||||||
|
#define PHYS_TO_KSEG132(a) ((a) + 0xE0000000ul)
|
||||||
|
|
||||||
|
/* 64-bit addresses */
|
||||||
|
|
||||||
|
#define KSEG0_TO_PHYS64(a) ((a) & 0xFFFFFFFF7FFFFFFFull)
|
||||||
|
#define KSEG1_TO_PHYS64(a) ((a) & 0xFFFFFFFF1FFFFFFFull)
|
||||||
|
|
||||||
|
#define PHYS_TO_KSEG064(a) ((a) + 0x0000000080000000ull)
|
||||||
|
#define PHYS_TO_KSEG164(a) ((a) + 0x00000000E0000000ull)
|
||||||
|
|
||||||
|
#endif /* _ADDR_H */
|
@ -0,0 +1,409 @@
|
|||||||
|
/*
|
||||||
|
* This file is subject to the terms and conditions of the GNU General Public
|
||||||
|
* License. See the file "COPYING" in the main directory of this archive
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1995, 1996, 1997, 1999, 2001 by Ralf Baechle
|
||||||
|
* Copyright (C) 1999 by Silicon Graphics, Inc.
|
||||||
|
* Copyright (C) 2001 MIPS Technologies, Inc.
|
||||||
|
* Copyright (C) 2002 Maciej W. Rozycki
|
||||||
|
*
|
||||||
|
* Some useful macros for MIPS assembler code
|
||||||
|
*
|
||||||
|
* Some of the routines below contain useless nops that will be optimized
|
||||||
|
* away by gas in -O mode. These nops are however required to fill delay
|
||||||
|
* slots in noreorder mode.
|
||||||
|
*/
|
||||||
|
#ifndef __ASM_ASM_H
|
||||||
|
#define __ASM_ASM_H
|
||||||
|
|
||||||
|
#include <asm/sgidefs.h>
|
||||||
|
|
||||||
|
#ifndef CAT
|
||||||
|
#ifdef __STDC__
|
||||||
|
#define __CAT(str1, str2) str1##str2
|
||||||
|
#else
|
||||||
|
#define __CAT(str1, str2) str1/**/str2
|
||||||
|
#endif
|
||||||
|
#define CAT(str1, str2) __CAT(str1, str2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PIC specific declarations
|
||||||
|
* Not used for the kernel but here seems to be the right place.
|
||||||
|
*/
|
||||||
|
#ifdef __PIC__
|
||||||
|
#define CPRESTORE(register) \
|
||||||
|
.cprestore register
|
||||||
|
#define CPADD(register) \
|
||||||
|
.cpadd register
|
||||||
|
#define CPLOAD(register) \
|
||||||
|
.cpload register
|
||||||
|
#else
|
||||||
|
#define CPRESTORE(register)
|
||||||
|
#define CPADD(register)
|
||||||
|
#define CPLOAD(register)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LEAF - declare leaf routine
|
||||||
|
*/
|
||||||
|
#define LEAF(symbol) \
|
||||||
|
.globl symbol; \
|
||||||
|
.align 2; \
|
||||||
|
.type symbol, @function; \
|
||||||
|
.ent symbol, 0; \
|
||||||
|
symbol: .frame sp, 0, ra
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NESTED - declare nested routine entry point
|
||||||
|
*/
|
||||||
|
#define NESTED(symbol, framesize, rpc) \
|
||||||
|
.globl symbol; \
|
||||||
|
.align 2; \
|
||||||
|
.type symbol, @function; \
|
||||||
|
.ent symbol, 0; \
|
||||||
|
symbol: .frame sp, framesize, rpc
|
||||||
|
|
||||||
|
/*
|
||||||
|
* END - mark end of function
|
||||||
|
*/
|
||||||
|
#define END(function) \
|
||||||
|
.end function; \
|
||||||
|
.size function, .-function
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EXPORT - export definition of symbol
|
||||||
|
*/
|
||||||
|
#define EXPORT(symbol) \
|
||||||
|
.globl symbol; \
|
||||||
|
symbol:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FEXPORT - export definition of a function symbol
|
||||||
|
*/
|
||||||
|
#define FEXPORT(symbol) \
|
||||||
|
.globl symbol; \
|
||||||
|
.type symbol, @function; \
|
||||||
|
symbol:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ABS - export absolute symbol
|
||||||
|
*/
|
||||||
|
#define ABS(symbol,value) \
|
||||||
|
.globl symbol; \
|
||||||
|
symbol = value
|
||||||
|
|
||||||
|
#define PANIC(msg) \
|
||||||
|
.set push; \
|
||||||
|
.set reorder; \
|
||||||
|
PTR_LA a0, 8f; \
|
||||||
|
jal panic; \
|
||||||
|
9: b 9b; \
|
||||||
|
.set pop; \
|
||||||
|
TEXT(msg)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print formatted string
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_PRINTK
|
||||||
|
#define PRINT(string) \
|
||||||
|
.set push; \
|
||||||
|
.set reorder; \
|
||||||
|
PTR_LA a0, 8f; \
|
||||||
|
jal printk; \
|
||||||
|
.set pop; \
|
||||||
|
TEXT(string)
|
||||||
|
#else
|
||||||
|
#define PRINT(string)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TEXT(msg) \
|
||||||
|
.pushsection .data; \
|
||||||
|
8: .asciiz msg; \
|
||||||
|
.popsection;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build text tables
|
||||||
|
*/
|
||||||
|
#define TTABLE(string) \
|
||||||
|
.pushsection .text; \
|
||||||
|
.word 1f; \
|
||||||
|
.popsection \
|
||||||
|
.pushsection .data; \
|
||||||
|
1: .asciiz string; \
|
||||||
|
.popsection
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MIPS IV pref instruction.
|
||||||
|
* Use with .set noreorder only!
|
||||||
|
*
|
||||||
|
* MIPS IV implementations are free to treat this as a nop. The R5000
|
||||||
|
* is one of them. So we should have an option not to use this instruction.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_CPU_HAS_PREFETCH
|
||||||
|
|
||||||
|
#define PREF(hint,addr) \
|
||||||
|
.set push; \
|
||||||
|
.set mips4; \
|
||||||
|
pref hint, addr; \
|
||||||
|
.set pop
|
||||||
|
|
||||||
|
#define PREFX(hint,addr) \
|
||||||
|
.set push; \
|
||||||
|
.set mips4; \
|
||||||
|
prefx hint, addr; \
|
||||||
|
.set pop
|
||||||
|
|
||||||
|
#else /* !CONFIG_CPU_HAS_PREFETCH */
|
||||||
|
|
||||||
|
#define PREF(hint, addr)
|
||||||
|
#define PREFX(hint, addr)
|
||||||
|
|
||||||
|
#endif /* !CONFIG_CPU_HAS_PREFETCH */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MIPS ISA IV/V movn/movz instructions and equivalents for older CPUs.
|
||||||
|
*/
|
||||||
|
#if (_MIPS_ISA == _MIPS_ISA_MIPS1)
|
||||||
|
#define MOVN(rd, rs, rt) \
|
||||||
|
.set push; \
|
||||||
|
.set reorder; \
|
||||||
|
beqz rt, 9f; \
|
||||||
|
move rd, rs; \
|
||||||
|
.set pop; \
|
||||||
|
9:
|
||||||
|
#define MOVZ(rd, rs, rt) \
|
||||||
|
.set push; \
|
||||||
|
.set reorder; \
|
||||||
|
bnez rt, 9f; \
|
||||||
|
move rd, rs; \
|
||||||
|
.set pop; \
|
||||||
|
9:
|
||||||
|
#endif /* _MIPS_ISA == _MIPS_ISA_MIPS1 */
|
||||||
|
#if (_MIPS_ISA == _MIPS_ISA_MIPS2) || (_MIPS_ISA == _MIPS_ISA_MIPS3)
|
||||||
|
#define MOVN(rd, rs, rt) \
|
||||||
|
.set push; \
|
||||||
|
.set noreorder; \
|
||||||
|
bnezl rt, 9f; \
|
||||||
|
move rd, rs; \
|
||||||
|
.set pop; \
|
||||||
|
9:
|
||||||
|
#define MOVZ(rd, rs, rt) \
|
||||||
|
.set push; \
|
||||||
|
.set noreorder; \
|
||||||
|
beqzl rt, 9f; \
|
||||||
|
move rd, rs; \
|
||||||
|
.set pop; \
|
||||||
|
9:
|
||||||
|
#endif /* (_MIPS_ISA == _MIPS_ISA_MIPS2) || (_MIPS_ISA == _MIPS_ISA_MIPS3) */
|
||||||
|
#if (_MIPS_ISA == _MIPS_ISA_MIPS4 ) || (_MIPS_ISA == _MIPS_ISA_MIPS5) || \
|
||||||
|
(_MIPS_ISA == _MIPS_ISA_MIPS32) || (_MIPS_ISA == _MIPS_ISA_MIPS64)
|
||||||
|
#define MOVN(rd, rs, rt) \
|
||||||
|
movn rd, rs, rt
|
||||||
|
#define MOVZ(rd, rs, rt) \
|
||||||
|
movz rd, rs, rt
|
||||||
|
#endif /* MIPS IV, MIPS V, MIPS32 or MIPS64 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stack alignment
|
||||||
|
*/
|
||||||
|
#if (_MIPS_SIM == _MIPS_SIM_ABI32)
|
||||||
|
#define ALSZ 7
|
||||||
|
#define ALMASK ~7
|
||||||
|
#endif
|
||||||
|
#if (_MIPS_SIM == _MIPS_SIM_NABI32) || (_MIPS_SIM == _MIPS_SIM_ABI64)
|
||||||
|
#define ALSZ 15
|
||||||
|
#define ALMASK ~15
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros to handle different pointer/register sizes for 32/64-bit code
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size of a register
|
||||||
|
*/
|
||||||
|
#ifdef __mips64
|
||||||
|
#define SZREG 8
|
||||||
|
#else
|
||||||
|
#define SZREG 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use the following macros in assemblercode to load/store registers,
|
||||||
|
* pointers etc.
|
||||||
|
*/
|
||||||
|
#if (_MIPS_SIM == _MIPS_SIM_ABI32)
|
||||||
|
#define REG_S sw
|
||||||
|
#define REG_L lw
|
||||||
|
#define REG_SUBU subu
|
||||||
|
#define REG_ADDU addu
|
||||||
|
#endif
|
||||||
|
#if (_MIPS_SIM == _MIPS_SIM_NABI32) || (_MIPS_SIM == _MIPS_SIM_ABI64)
|
||||||
|
#define REG_S sd
|
||||||
|
#define REG_L ld
|
||||||
|
#define REG_SUBU dsubu
|
||||||
|
#define REG_ADDU daddu
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How to add/sub/load/store/shift C int variables.
|
||||||
|
*/
|
||||||
|
#if (_MIPS_SZINT == 32)
|
||||||
|
#define INT_ADD add
|
||||||
|
#define INT_ADDU addu
|
||||||
|
#define INT_ADDI addi
|
||||||
|
#define INT_ADDIU addiu
|
||||||
|
#define INT_SUB sub
|
||||||
|
#define INT_SUBU subu
|
||||||
|
#define INT_L lw
|
||||||
|
#define INT_S sw
|
||||||
|
#define INT_SLL sll
|
||||||
|
#define INT_SLLV sllv
|
||||||
|
#define INT_SRL srl
|
||||||
|
#define INT_SRLV srlv
|
||||||
|
#define INT_SRA sra
|
||||||
|
#define INT_SRAV srav
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (_MIPS_SZINT == 64)
|
||||||
|
#define INT_ADD dadd
|
||||||
|
#define INT_ADDU daddu
|
||||||
|
#define INT_ADDI daddi
|
||||||
|
#define INT_ADDIU daddiu
|
||||||
|
#define INT_SUB dsub
|
||||||
|
#define INT_SUBU dsubu
|
||||||
|
#define INT_L ld
|
||||||
|
#define INT_S sd
|
||||||
|
#define INT_SLL dsll
|
||||||
|
#define INT_SLLV dsllv
|
||||||
|
#define INT_SRL dsrl
|
||||||
|
#define INT_SRLV dsrlv
|
||||||
|
#define INT_SRA dsra
|
||||||
|
#define INT_SRAV dsrav
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How to add/sub/load/store/shift C long variables.
|
||||||
|
*/
|
||||||
|
#if (_MIPS_SZLONG == 32)
|
||||||
|
#define LONG_ADD add
|
||||||
|
#define LONG_ADDU addu
|
||||||
|
#define LONG_ADDI addi
|
||||||
|
#define LONG_ADDIU addiu
|
||||||
|
#define LONG_SUB sub
|
||||||
|
#define LONG_SUBU subu
|
||||||
|
#define LONG_L lw
|
||||||
|
#define LONG_S sw
|
||||||
|
#define LONG_SLL sll
|
||||||
|
#define LONG_SLLV sllv
|
||||||
|
#define LONG_SRL srl
|
||||||
|
#define LONG_SRLV srlv
|
||||||
|
#define LONG_SRA sra
|
||||||
|
#define LONG_SRAV srav
|
||||||
|
|
||||||
|
#define LONG .word
|
||||||
|
#define LONGSIZE 4
|
||||||
|
#define LONGMASK 3
|
||||||
|
#define LONGLOG 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (_MIPS_SZLONG == 64)
|
||||||
|
#define LONG_ADD dadd
|
||||||
|
#define LONG_ADDU daddu
|
||||||
|
#define LONG_ADDI daddi
|
||||||
|
#define LONG_ADDIU daddiu
|
||||||
|
#define LONG_SUB dsub
|
||||||
|
#define LONG_SUBU dsubu
|
||||||
|
#define LONG_L ld
|
||||||
|
#define LONG_S sd
|
||||||
|
#define LONG_SLL dsll
|
||||||
|
#define LONG_SLLV dsllv
|
||||||
|
#define LONG_SRL dsrl
|
||||||
|
#define LONG_SRLV dsrlv
|
||||||
|
#define LONG_SRA dsra
|
||||||
|
#define LONG_SRAV dsrav
|
||||||
|
|
||||||
|
#define LONG .dword
|
||||||
|
#define LONGSIZE 8
|
||||||
|
#define LONGMASK 7
|
||||||
|
#define LONGLOG 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How to add/sub/load/store/shift pointers.
|
||||||
|
*/
|
||||||
|
#if (_MIPS_SZPTR == 32)
|
||||||
|
#define PTR_ADD add
|
||||||
|
#define PTR_ADDU addu
|
||||||
|
#define PTR_ADDI addi
|
||||||
|
#define PTR_ADDIU addiu
|
||||||
|
#define PTR_SUB sub
|
||||||
|
#define PTR_SUBU subu
|
||||||
|
#define PTR_L lw
|
||||||
|
#define PTR_S sw
|
||||||
|
#define PTR_LA la
|
||||||
|
#define PTR_LI li
|
||||||
|
#define PTR_SLL sll
|
||||||
|
#define PTR_SLLV sllv
|
||||||
|
#define PTR_SRL srl
|
||||||
|
#define PTR_SRLV srlv
|
||||||
|
#define PTR_SRA sra
|
||||||
|
#define PTR_SRAV srav
|
||||||
|
|
||||||
|
#define PTR_SCALESHIFT 2
|
||||||
|
|
||||||
|
#define PTR .word
|
||||||
|
#define PTRSIZE 4
|
||||||
|
#define PTRLOG 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (_MIPS_SZPTR == 64)
|
||||||
|
#define PTR_ADD dadd
|
||||||
|
#define PTR_ADDU daddu
|
||||||
|
#define PTR_ADDI daddi
|
||||||
|
#define PTR_ADDIU daddiu
|
||||||
|
#define PTR_SUB dsub
|
||||||
|
#define PTR_SUBU dsubu
|
||||||
|
#define PTR_L ld
|
||||||
|
#define PTR_S sd
|
||||||
|
#define PTR_LA dla
|
||||||
|
#define PTR_LI dli
|
||||||
|
#define PTR_SLL dsll
|
||||||
|
#define PTR_SLLV dsllv
|
||||||
|
#define PTR_SRL dsrl
|
||||||
|
#define PTR_SRLV dsrlv
|
||||||
|
#define PTR_SRA dsra
|
||||||
|
#define PTR_SRAV dsrav
|
||||||
|
|
||||||
|
#define PTR_SCALESHIFT 3
|
||||||
|
|
||||||
|
#define PTR .dword
|
||||||
|
#define PTRSIZE 8
|
||||||
|
#define PTRLOG 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some cp0 registers were extended to 64bit for MIPS III.
|
||||||
|
*/
|
||||||
|
#if (_MIPS_SIM == _MIPS_SIM_ABI32)
|
||||||
|
#define MFC0 mfc0
|
||||||
|
#define MTC0 mtc0
|
||||||
|
#endif
|
||||||
|
#if (_MIPS_SIM == _MIPS_SIM_NABI32) || (_MIPS_SIM == _MIPS_SIM_ABI64)
|
||||||
|
#define MFC0 dmfc0
|
||||||
|
#define MTC0 dmtc0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SSNOP sll zero, zero, 1
|
||||||
|
|
||||||
|
#ifdef CONFIG_SGI_IP28
|
||||||
|
/* Inhibit speculative stores to volatile (e.g.DMA) or invalid addresses. */
|
||||||
|
#include <asm/cacheops.h>
|
||||||
|
#define R10KCBARRIER(addr) cache Cache_Barrier, addr;
|
||||||
|
#else
|
||||||
|
#define R10KCBARRIER(addr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __ASM_ASM_H */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* This file is subject to the terms and conditions of the GNU General Public
|
||||||
|
* License. See the file "COPYING" in the main directory of this archive
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1985 MIPS Computer Systems, Inc.
|
||||||
|
* Copyright (C) 1994, 95, 99, 2003 by Ralf Baechle
|
||||||
|
* Copyright (C) 1990 - 1992, 1999 Silicon Graphics, Inc.
|
||||||
|
*/
|
||||||
|
#ifndef _ASM_REGDEF_H
|
||||||
|
#define _ASM_REGDEF_H
|
||||||
|
|
||||||
|
#include <asm/sgidefs.h>
|
||||||
|
|
||||||
|
#define _MIPS_SIM _MIPS_SIM_ABI32
|
||||||
|
|
||||||
|
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Symbolic register names for 32 bit ABI
|
||||||
|
*/
|
||||||
|
#define zero $0 /* wired zero */
|
||||||
|
#define AT $1 /* assembler temp - uppercase because of ".set at" */
|
||||||
|
#define v0 $2 /* return value */
|
||||||
|
#define v1 $3
|
||||||
|
#define a0 $4 /* argument registers */
|
||||||
|
#define a1 $5
|
||||||
|
#define a2 $6
|
||||||
|
#define a3 $7
|
||||||
|
#define t0 $8 /* caller saved */
|
||||||
|
#define t1 $9
|
||||||
|
#define t2 $10
|
||||||
|
#define t3 $11
|
||||||
|
#define t4 $12
|
||||||
|
#define t5 $13
|
||||||
|
#define t6 $14
|
||||||
|
#define t7 $15
|
||||||
|
#define s0 $16 /* callee saved */
|
||||||
|
#define s1 $17
|
||||||
|
#define s2 $18
|
||||||
|
#define s3 $19
|
||||||
|
#define s4 $20
|
||||||
|
#define s5 $21
|
||||||
|
#define s6 $22
|
||||||
|
#define s7 $23
|
||||||
|
#define t8 $24 /* caller saved */
|
||||||
|
#define t9 $25
|
||||||
|
#define jp $25 /* PIC jump register */
|
||||||
|
#define k0 $26 /* kernel scratch */
|
||||||
|
#define k1 $27
|
||||||
|
#define gp $28 /* global pointer */
|
||||||
|
#define sp $29 /* stack pointer */
|
||||||
|
#define fp $30 /* frame pointer */
|
||||||
|
#define s8 $30 /* same like fp! */
|
||||||
|
#define ra $31 /* return address */
|
||||||
|
|
||||||
|
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
|
||||||
|
|
||||||
|
#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
|
||||||
|
|
||||||
|
#define zero $0 /* wired zero */
|
||||||
|
#define AT $at /* assembler temp - uppercase because of ".set at" */
|
||||||
|
#define v0 $2 /* return value - caller saved */
|
||||||
|
#define v1 $3
|
||||||
|
#define a0 $4 /* argument registers */
|
||||||
|
#define a1 $5
|
||||||
|
#define a2 $6
|
||||||
|
#define a3 $7
|
||||||
|
#define a4 $8 /* arg reg 64 bit; caller saved in 32 bit */
|
||||||
|
#define ta0 $8
|
||||||
|
#define a5 $9
|
||||||
|
#define ta1 $9
|
||||||
|
#define a6 $10
|
||||||
|
#define ta2 $10
|
||||||
|
#define a7 $11
|
||||||
|
#define ta3 $11
|
||||||
|
#define t0 $12 /* caller saved */
|
||||||
|
#define t1 $13
|
||||||
|
#define t2 $14
|
||||||
|
#define t3 $15
|
||||||
|
#define s0 $16 /* callee saved */
|
||||||
|
#define s1 $17
|
||||||
|
#define s2 $18
|
||||||
|
#define s3 $19
|
||||||
|
#define s4 $20
|
||||||
|
#define s5 $21
|
||||||
|
#define s6 $22
|
||||||
|
#define s7 $23
|
||||||
|
#define t8 $24 /* caller saved */
|
||||||
|
#define t9 $25 /* callee address for PIC/temp */
|
||||||
|
#define jp $25 /* PIC jump register */
|
||||||
|
#define k0 $26 /* kernel temporary */
|
||||||
|
#define k1 $27
|
||||||
|
#define gp $28 /* global pointer - caller saved for PIC */
|
||||||
|
#define sp $29 /* stack pointer */
|
||||||
|
#define fp $30 /* frame pointer */
|
||||||
|
#define s8 $30 /* callee saved */
|
||||||
|
#define ra $31 /* return address */
|
||||||
|
|
||||||
|
#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 */
|
||||||
|
|
||||||
|
#endif /* _ASM_REGDEF_H */
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* This file is subject to the terms and conditions of the GNU General Public
|
||||||
|
* License. See the file "COPYING" in the main directory of this archive
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1996, 1999, 2001 Ralf Baechle
|
||||||
|
* Copyright (C) 1999 Silicon Graphics, Inc.
|
||||||
|
* Copyright (C) 2001 MIPS Technologies, Inc.
|
||||||
|
*/
|
||||||
|
#ifndef __ASM_SGIDEFS_H
|
||||||
|
#define __ASM_SGIDEFS_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for the ISA levels
|
||||||
|
*
|
||||||
|
* With the introduction of MIPS32 / MIPS64 instruction sets definitions
|
||||||
|
* MIPS ISAs are no longer subsets of each other. Therefore comparisons
|
||||||
|
* on these symbols except with == may result in unexpected results and
|
||||||
|
* are forbidden!
|
||||||
|
*/
|
||||||
|
#define _MIPS_ISA_MIPS1 1
|
||||||
|
#define _MIPS_ISA_MIPS2 2
|
||||||
|
#define _MIPS_ISA_MIPS3 3
|
||||||
|
#define _MIPS_ISA_MIPS4 4
|
||||||
|
#define _MIPS_ISA_MIPS5 5
|
||||||
|
#define _MIPS_ISA_MIPS32 6
|
||||||
|
#define _MIPS_ISA_MIPS64 7
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Subprogram calling convention
|
||||||
|
*/
|
||||||
|
#define _MIPS_SIM_ABI32 1
|
||||||
|
#define _MIPS_SIM_NABI32 2
|
||||||
|
#define _MIPS_SIM_ABI64 3
|
||||||
|
|
||||||
|
#endif /* __ASM_SGIDEFS_H */
|
@ -0,0 +1,209 @@
|
|||||||
|
#ifndef _ELF_H
|
||||||
|
#define _ELF_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structures, macros and defines for working with ELF files. This header
|
||||||
|
* is intended to be as generic as possible in order to enable future
|
||||||
|
* Cisco routers to be targetted using Ciscoboot.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
/* ELF object file types */
|
||||||
|
#define ELF_TYPE_NONE 0 /* no file type */
|
||||||
|
#define ELF_TYPE_REL 1 /* relocatable file */
|
||||||
|
#define ELF_TYPE_EXEC 2 /* executable file */
|
||||||
|
#define ELF_TYPE_DYN 3 /* shared object file */
|
||||||
|
#define ELF_TYPE_CORE 4 /* core file */
|
||||||
|
#define ELF_TYPE_LOPROC 0xff00 /* cpu specific */
|
||||||
|
#define ELF_TYPE_HIPROC 0xffff
|
||||||
|
|
||||||
|
/* ELF machine types */
|
||||||
|
#define ELF_MACH_NONE 0 /* no machine type */
|
||||||
|
#define ELF_MACH_M32 1 /* AT&T WE 32100 */
|
||||||
|
#define ELF_MACH_SPARC 2 /* Sun SPARC */
|
||||||
|
#define ELF_MACH_386 3 /* Intel i386 */
|
||||||
|
#define ELF_MACH_68K 4 /* Motorola 68000 */
|
||||||
|
#define ELF_MACH_88K 5 /* Motorola 88000 */
|
||||||
|
#define ELF_MACH_860 7 /* Intel 80860 */
|
||||||
|
#define ELF_MACH_MIPS 8 /* MIPS RS3000 Big-Endian */
|
||||||
|
#define ELF_MACH_MIPS_R4K_BE 10 /* MIPS RS4000 Big-Endian */
|
||||||
|
/* 11-16 are reserved */
|
||||||
|
|
||||||
|
/* ELF Version */
|
||||||
|
#define ELF_VER_NONE 0 /* invalid version */
|
||||||
|
#define ELF_VER_CURRENT 1 /* Current ELF version */
|
||||||
|
|
||||||
|
|
||||||
|
/* ELF Header Structure */
|
||||||
|
|
||||||
|
#define ELF_IDENT_COUNT 16
|
||||||
|
|
||||||
|
struct elf32_header {
|
||||||
|
uint8_t ident[ELF_IDENT_COUNT]; /* key fields */
|
||||||
|
uint16_t type; /* object file type */
|
||||||
|
uint16_t machine; /* architecture */
|
||||||
|
uint32_t version; /* object file version */
|
||||||
|
uint32_t entry; /* entry point */
|
||||||
|
uint32_t phoff; /* program header offset */
|
||||||
|
uint32_t shoff; /* section header offset */
|
||||||
|
uint32_t flags; /* ELF file flags */
|
||||||
|
uint16_t ehsize; /* ELF header size */
|
||||||
|
uint16_t phentsize; /* size of a program header entry */
|
||||||
|
uint16_t phnum; /* number of entries in the program header */
|
||||||
|
uint16_t shentsize; /* size of a section header entry */
|
||||||
|
uint16_t shnum; /* number of section header entries */
|
||||||
|
uint16_t shstrndx; /* index of string table entry in the section hdr */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ELF magic */
|
||||||
|
#define ELF_MAGIC_1 0x7f
|
||||||
|
#define ELF_MAGIC_2 0x45
|
||||||
|
#define ELF_MAGIC_3 0x4c
|
||||||
|
#define ELF_MAGIC_4 0x46
|
||||||
|
|
||||||
|
/* ELF class */
|
||||||
|
#define ELF_CLASS_NONE 0
|
||||||
|
#define ELF_CLASS_32 1
|
||||||
|
#define ELF_CLASS_64 2
|
||||||
|
|
||||||
|
/* ELF Data Encoding */
|
||||||
|
#define ELF_DATA_NONE 0 /* invalid */
|
||||||
|
#define ELF_DATA_LSB 1 /* Little endian */
|
||||||
|
#define ELF_DATA_MSB 2 /* big endian */
|
||||||
|
|
||||||
|
/* Offsets within the ident string */
|
||||||
|
#define ELF_INDEX_MAGIC0 0
|
||||||
|
#define ELF_INDEX_MAGIC1 1
|
||||||
|
#define ELF_INDEX_MAGIC2 2
|
||||||
|
#define ELF_INDEX_MAGIC3 3
|
||||||
|
#define ELF_INDEX_CLASS 4 /* file class */
|
||||||
|
#define ELF_INDEX_DATA 5 /* data encoding */
|
||||||
|
#define ELF_INDEX_VERSION 6 /* file version */
|
||||||
|
#define ELF_INDEX_PADDING 7 /* start of padding */
|
||||||
|
|
||||||
|
/* Special Section Header Indexes */
|
||||||
|
#define ELF_SH_UNDEF 0 /* no section header present */
|
||||||
|
#define ELF_SH_LORESERVE 0xff00 /* lower-bound of reserved indices */
|
||||||
|
#define ELF_SH_LOPROC 0xff00 /* processor-specifc semantics low bound */
|
||||||
|
#define ELF_SH_HIPROC 0xff1f /* processor-specific semantics high bound */
|
||||||
|
#define ELF_SH_ABS 0xfff1 /* abs values for symbols in this section */
|
||||||
|
#define ELF_SH_COMMON 0xfff2 /* Common Block/unallocated extern vars */
|
||||||
|
#define ELF_SH_HIRESERVE 0xffff /* high value for reserved indices */
|
||||||
|
|
||||||
|
/* Section Header Structure */
|
||||||
|
struct elf32_section_header {
|
||||||
|
uint32_t name; /* index of the string table entry for this section */
|
||||||
|
uint32_t type; /* section type */
|
||||||
|
uint32_t flags; /* section flags */
|
||||||
|
uint32_t addr; /* section address if in actual memory image */
|
||||||
|
uint32_t offset; /* byte offset from beginning of file to start of sect. */
|
||||||
|
uint32_t size; /* size of section in bytes */
|
||||||
|
uint32_t link; /* section header table index link */
|
||||||
|
uint32_t info; /* extra information */
|
||||||
|
uint32_t addralign; /* alignment constraints */
|
||||||
|
uint32_t entsize; /* per-entry size */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Section Types */
|
||||||
|
#define ELF_SHT_NULL 0 /* inactive/no associated section */
|
||||||
|
#define ELF_SHT_PROGBITS 1 /* program-specific information */
|
||||||
|
#define ELF_SHT_SYMTAB 2 /* Symbol table */
|
||||||
|
#define ELF_SHT_STRTAB 3 /* string table */
|
||||||
|
#define ELF_SHT_RELA 4 /* Relocation entries with explicit addends */
|
||||||
|
#define ELF_SHT_HASH 5 /* symbol hash table */
|
||||||
|
#define ELF_SHT_DYNAMIC 6 /* dynamic linking information */
|
||||||
|
#define ELF_SHT_NOTE 7 /* notational marking */
|
||||||
|
#define ELF_SHT_NOBITS 8 /* no space in file, looks like progbits */
|
||||||
|
#define ELF_SHT_REL 9 /* relocation entires without explicit addends */
|
||||||
|
#define ELF_SHT_SHLIB 10 /* reserved; non-ABI conformant code */
|
||||||
|
#define ELF_SHT_DYNSYM 11 /* symbol table */
|
||||||
|
#define ELF_SHT_LOPROC 0x70000000 /* region reserved for CPU-specific info */
|
||||||
|
#define ELF_SHT_HIPROC 0x7fffffff
|
||||||
|
#define ELF_SHT_LOUSER 0x80000000 /* section reseverd for prog. info */
|
||||||
|
#define ELF_SHT_HIUSER 0xffffffff
|
||||||
|
|
||||||
|
/* Section header flags */
|
||||||
|
#define ELF_SHF_WRITE 0x1 /* Contains writable data */
|
||||||
|
#define ELF_SHF_ALLOC 0x2 /* occupies memory during exec */
|
||||||
|
#define ELF_SHF_EXECINSTR 0x4 /* contains executable instructions */
|
||||||
|
#define ELF_SHF_MASKPROC 0xf0000000 /* Processor-specific mask bits */
|
||||||
|
|
||||||
|
#define ELF_SHF_WRITABLE(x) ((x) & ELF_SHF_WRITE)
|
||||||
|
#define ELF_SHF_ALLOCD(x) ((x) & ELF_SHF_ALLOC)
|
||||||
|
#define ELF_SHF_EXECUTABLE(x) ((x) & ELF_SHF_EXECINSTR)
|
||||||
|
|
||||||
|
/* Symbol Table */
|
||||||
|
#define ELF_STN_UNDEF 0
|
||||||
|
|
||||||
|
/* ELF Spec, p. 4-22 */
|
||||||
|
struct elf32_sym_table_entry {
|
||||||
|
uint32_t name; /* string table entry */
|
||||||
|
uint32_t value; /* value of the symbol */
|
||||||
|
uint32_t size; /* size of the symbol */
|
||||||
|
uint8_t info; /* symbol's type and binding attribs */
|
||||||
|
uint8_t other; /* no defined meaning */
|
||||||
|
uint16_t shndx; /* associated section header table index */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ELF_ST_BIND(i) ((i) >> 4)
|
||||||
|
#define ELF_ST_TYPE(i) ((i) & 0xf)
|
||||||
|
#define ELF_ST_INFO(b, t) (((b)<<4) + ((t) & 0xf))
|
||||||
|
|
||||||
|
/* symbol binding (use with ELF_ST_BIND */
|
||||||
|
#define ELF_STB_LOCAL 0 /* not visible outside of this object file */
|
||||||
|
#define ELF_STB_GLOBAL 1 /* visible to all object files being combined */
|
||||||
|
#define ELF_STB_WEAK 2 /* Weak bound symbols (lower precedence than glbl */
|
||||||
|
#define ELF_STB_LOPROC 13 /* Processor specific semantics range */
|
||||||
|
#define ELF_STB_HIPROC 15
|
||||||
|
|
||||||
|
/* symbol type (use with ELF_ST_TYPE macro) */
|
||||||
|
#define ELF_STT_NOTYPE 0 /* type is not specified */
|
||||||
|
#define ELF_STT_OBJECT 1 /* symbol is associated with a data object */
|
||||||
|
#define ELF_STT_FUNC 2 /* symbol is associated with executable code */
|
||||||
|
#define ELF_STT_SECTION 3 /* symbol is associated with a section */
|
||||||
|
#define ELF_STT_FILE 4 /* file symbol type */
|
||||||
|
#define ELF_STT_LOPROC 13 /* processor specific semantics range */
|
||||||
|
#define ELF_STT_HIPROC 15
|
||||||
|
|
||||||
|
/* Relocation Entries */
|
||||||
|
struct elf32_rel {
|
||||||
|
uint32_t offset; /* where to apply relocation action */
|
||||||
|
uint32_t info; /* information about the symbol */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct elf32_rel_add {
|
||||||
|
uint32_t offset; /* where to apply relocation action */
|
||||||
|
uint32_t info; /* information about the symbol */
|
||||||
|
uint32_t addend; /* constant addend */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Info helper macros: */
|
||||||
|
#define ELF_REL_SYM(i) ((i) >> 8)
|
||||||
|
#define ELF_REL_TYPE(i) ((uint8_t)(i))
|
||||||
|
#define ELF_REL_INFO(s, t) (((s) << 8) + (unsigned char)(t))
|
||||||
|
|
||||||
|
/* Program Header/Segments */
|
||||||
|
struct elf32_phdr {
|
||||||
|
uint32_t type; /* segment type */
|
||||||
|
uint32_t offset; /* offset from beginning of file */
|
||||||
|
uint32_t vaddr; /* virtual address of first byte of segment */
|
||||||
|
uint32_t paddr; /* physical address of first byte of segment */
|
||||||
|
uint32_t filesz; /* size in file of this segment */
|
||||||
|
uint32_t memsz; /* Size of segment in memory image */
|
||||||
|
uint32_t flags; /* segment flags */
|
||||||
|
uint32_t align; /* alignment requirements for loading */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Segment Types */
|
||||||
|
#define ELF_PT_NULL 0 /* unused */
|
||||||
|
#define ELF_PT_LOAD 1 /* loadable segment */
|
||||||
|
#define ELF_PT_DYNAMIC 2 /* dynamic section */
|
||||||
|
#define ELF_PT_INTERP 3 /* null-terminate path to an invokable interpreter */
|
||||||
|
#define ELF_PT_NOTE 4 /* Auxiliary information */
|
||||||
|
#define ELF_PT_SHLIB 5 /* Shared Library? No ABI conformity required */
|
||||||
|
#define ELF_PT_PHDR 6 /* Program header table size */
|
||||||
|
#define ELF_PT_LOPROC 0x70000000 /* processor-specific values */
|
||||||
|
#define ELF_PT_HIPROC 0x7fffffff
|
||||||
|
|
||||||
|
#endif /* _ELF_H */
|
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef _ELF_LOADER_H
|
||||||
|
#define _ELF_LOADER_H
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
void load_elf32_section(uint32_t base, uint32_t address, uint32_t file_offset,
|
||||||
|
uint32_t length);
|
||||||
|
void load_elf32_uninitialized_memory(uint32_t address, uint32_t length);
|
||||||
|
int load_elf32_file(uint32_t base, uint32_t loader_addr);
|
||||||
|
|
||||||
|
#endif /* _ELF_LOADER_H */
|
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef _ELF_MIPS_H
|
||||||
|
#define _ELF_MIPS_H
|
||||||
|
|
||||||
|
#include <elf.h>
|
||||||
|
|
||||||
|
/* Machine-specific defines */
|
||||||
|
#define ELF_MIPS_EMACHINE_ID 8 /* expected EMACHINE ID (Cisco breaks this) */
|
||||||
|
|
||||||
|
#endif /* _ELF_MIPS_H */
|
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef _PRINTF_H
|
||||||
|
#define _PRINTF_H
|
||||||
|
|
||||||
|
int printf(const char *fmt, ...);
|
||||||
|
int sprintf(char *buf, const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif /* _PRINTF_H */
|
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef _PROMLIB_H
|
||||||
|
#define _PROMLIB_H
|
||||||
|
|
||||||
|
/* Syscall numbers -- move into v0
|
||||||
|
* A lot of these revolve around "best guesses" based on some reverse
|
||||||
|
* engineering.
|
||||||
|
*/
|
||||||
|
#define PUTC 1
|
||||||
|
#define GETC 3
|
||||||
|
#define MEMSIZE 4
|
||||||
|
#define VERSION 10
|
||||||
|
|
||||||
|
#define TIMER 0
|
||||||
|
|
||||||
|
/* Promlib Calls */
|
||||||
|
void c_putc(const char c);
|
||||||
|
void c_puts(const char *s);
|
||||||
|
char c_getc(void);
|
||||||
|
int c_gets(char *b, int n);
|
||||||
|
int c_memsz(void);
|
||||||
|
long c_timer(void);
|
||||||
|
int c_strnlen(const char *c, int maxlen);
|
||||||
|
char *c_verstr(void);
|
||||||
|
|
||||||
|
#endif /* _PROMLIB_H */
|
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef _STORAGE_STORAGE_H
|
||||||
|
#define _STORAGE_STORAGE_H
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
struct storage_class {
|
||||||
|
uint32_t dev_id;
|
||||||
|
char dev_name[16];
|
||||||
|
uint32_t start_addr;
|
||||||
|
|
||||||
|
/* storage device manager stuff */
|
||||||
|
struct storage_class *next;
|
||||||
|
struct storage_class *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
void initialize_storage_manager();
|
||||||
|
void register_storage_class(struct storage_class *sto);
|
||||||
|
|
||||||
|
#endif /* _STORAGE_STORAGE_H */
|
@ -0,0 +1,91 @@
|
|||||||
|
#ifndef _STRING_H
|
||||||
|
#define _STRING_H
|
||||||
|
|
||||||
|
#define NULL 0
|
||||||
|
|
||||||
|
inline int strcmp(const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
while (*s1 == *s2 && *s1 != '\0' && *s2 != '\0') {
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*s1 != *s2) return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int strncmp(const char *s1, const char *s2, uint32_t n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (s1[i] != s2[i]) return -1;
|
||||||
|
if (s1[i] == s2[i] && s1[i] == '\0') break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char *strcpy(char *dest, const char *src)
|
||||||
|
{
|
||||||
|
if (!dest || !src) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*src != '\0') {
|
||||||
|
*dest++ = *src++;
|
||||||
|
}
|
||||||
|
*dest = '\0';
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char *strncpy(char *dest, const char *src, uint32_t n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int t = 0;
|
||||||
|
if (!dest || !src || n == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (!t) dest[i] = src[i];
|
||||||
|
else dest[i] = '\0';
|
||||||
|
|
||||||
|
if (dest[i] == '\0') t = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t strlen(char *s)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (*s != '\0') {
|
||||||
|
i++; s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy n bytes from src to dst
|
||||||
|
* @param dst destination buffer
|
||||||
|
* @param src source buffer
|
||||||
|
* @param n number of bytes to copy
|
||||||
|
* @return number of bytes copied or value < 0 on error
|
||||||
|
*/
|
||||||
|
inline int memcpy(void *dst, const void *src, int n)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
if (!dst || !src) return -1;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
((char *)dst)[i] = ((char *)src)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _STRING_H */
|
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef _TYPES_H
|
||||||
|
#define _TYPES_H
|
||||||
|
|
||||||
|
/* define some convenience types */
|
||||||
|
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef char int8_t;
|
||||||
|
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef short int16_t;
|
||||||
|
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef int int32_t;
|
||||||
|
|
||||||
|
typedef unsigned long uint64_t;
|
||||||
|
typedef long int64_t;
|
||||||
|
|
||||||
|
/* endianess changes */
|
||||||
|
#define SWAP_32(x) \
|
||||||
|
((uint32_t)( \
|
||||||
|
(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
|
||||||
|
(((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
|
||||||
|
(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
||||||
|
(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
|
||||||
|
|
||||||
|
#define SWAP_16(x) \
|
||||||
|
((uint16_t) (\
|
||||||
|
(((uint16_t)(x) & (uint16_t)0x00ff) << 8) | \
|
||||||
|
(((uint16_t)(x) & (uint16_t)0xff00) >> 8)))
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _TYPES_H */
|
@ -0,0 +1,193 @@
|
|||||||
|
/* CiscoLoad - Bootloader for Cisco Routers
|
||||||
|
* (c) 2008 Philippe Vachon <philippe@cowpig.ca>
|
||||||
|
* Licensed under the GNU General Public License v2
|
||||||
|
*/
|
||||||
|
#include <promlib.h>
|
||||||
|
#include <printf.h>
|
||||||
|
#include <addr.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <elf_loader.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Todo: Add these to platform-specific header
|
||||||
|
*/
|
||||||
|
#define FLASH_BASE 0x30000000
|
||||||
|
#define KERNEL_ENTRY_POINT 0x80008000
|
||||||
|
|
||||||
|
#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[48];
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
printf("\nEnter filename to boot:\n> ");
|
||||||
|
c_gets(buf, 48);
|
||||||
|
printf("\n\nAttempting to load file %s\n", buf);
|
||||||
|
|
||||||
|
uint32_t kernel_off = find_file(buf, 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", buf);
|
||||||
|
} else {
|
||||||
|
printf("Booting \"%s\" from flash at 0x%08x\n", buf,
|
||||||
|
FLASH_BASE + kernel_off);
|
||||||
|
if (load_elf32_file(FLASH_BASE + kernel_off, FLASH_BASE + loader_off)
|
||||||
|
< 0)
|
||||||
|
{
|
||||||
|
printf("Fatal error while loading kernel. Aborting.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return to ROMMON */
|
||||||
|
}
|
@ -0,0 +1,320 @@
|
|||||||
|
/* -*- linux-c -*- ------------------------------------------------------- *
|
||||||
|
*
|
||||||
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||||
|
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||||
|
* Copyright (c) 2008 Philippe Vachon. Borrowed from Kernel 2.6
|
||||||
|
*
|
||||||
|
* This file is part of the Linux kernel, and is made available under
|
||||||
|
* the terms of the GNU General Public License version 2.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Oh, it's a waste of space, but oh-so-yummy for debugging. This
|
||||||
|
* version of printf() does not include 64-bit support. "Live with
|
||||||
|
* it."
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <promlib.h>
|
||||||
|
|
||||||
|
#define NULL 0
|
||||||
|
|
||||||
|
inline static int isdigit(int c)
|
||||||
|
{
|
||||||
|
return (c >= 48 && c <= 57);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int skip_atoi(const char **s)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (isdigit(**s))
|
||||||
|
i = i * 10 + *((*s)++) - '0';
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ZEROPAD 1 /* pad with zero */
|
||||||
|
#define SIGN 2 /* unsigned/signed long */
|
||||||
|
#define PLUS 4 /* show plus */
|
||||||
|
#define SPACE 8 /* space if plus */
|
||||||
|
#define LEFT 16 /* left justified */
|
||||||
|
#define SMALL 32 /* Must be 32 == 0x20 */
|
||||||
|
#define SPECIAL 64 /* 0x */
|
||||||
|
|
||||||
|
#define do_div(n,base) ({ \
|
||||||
|
int __res; \
|
||||||
|
__res = ((unsigned long) n) % (unsigned) base; \
|
||||||
|
n = ((unsigned long) n) / (unsigned) base; \
|
||||||
|
__res; })
|
||||||
|
|
||||||
|
static char *number(char *str, long num, int base, int size, int precision,
|
||||||
|
int type)
|
||||||
|
{
|
||||||
|
/* we are called with base 8, 10 or 16, only, thus don't need "G..." */
|
||||||
|
static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
|
||||||
|
|
||||||
|
char tmp[66];
|
||||||
|
char c, sign, locase;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* locase = 0 or 0x20. ORing digits or letters with 'locase'
|
||||||
|
* produces same digits or (maybe lowercased) letters */
|
||||||
|
locase = (type & SMALL);
|
||||||
|
if (type & LEFT)
|
||||||
|
type &= ~ZEROPAD;
|
||||||
|
if (base < 2 || base > 36)
|
||||||
|
return NULL;
|
||||||
|
c = (type & ZEROPAD) ? '0' : ' ';
|
||||||
|
sign = 0;
|
||||||
|
if (type & SIGN) {
|
||||||
|
if (num < 0) {
|
||||||
|
sign = '-';
|
||||||
|
num = -num;
|
||||||
|
size--;
|
||||||
|
} else if (type & PLUS) {
|
||||||
|
sign = '+';
|
||||||
|
size--;
|
||||||
|
} else if (type & SPACE) {
|
||||||
|
sign = ' ';
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type & SPECIAL) {
|
||||||
|
if (base == 16)
|
||||||
|
size -= 2;
|
||||||
|
else if (base == 8)
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
if (num == 0)
|
||||||
|
tmp[i++] = '0';
|
||||||
|
else
|
||||||
|
while (num != 0)
|
||||||
|
tmp[i++] = (digits[do_div(num, base)] | locase);
|
||||||
|
if (i > precision)
|
||||||
|
precision = i;
|
||||||
|
size -= precision;
|
||||||
|
if (!(type & (ZEROPAD + LEFT)))
|
||||||
|
while (size-- > 0)
|
||||||
|
*str++ = ' ';
|
||||||
|
if (sign)
|
||||||
|
*str++ = sign;
|
||||||
|
if (type & SPECIAL) {
|
||||||
|
if (base == 8)
|
||||||
|
*str++ = '0';
|
||||||
|
else if (base == 16) {
|
||||||
|
*str++ = '0';
|
||||||
|
*str++ = ('X' | locase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(type & LEFT))
|
||||||
|
while (size-- > 0)
|
||||||
|
*str++ = c;
|
||||||
|
while (i < precision--)
|
||||||
|
*str++ = '0';
|
||||||
|
while (i-- > 0)
|
||||||
|
*str++ = tmp[i];
|
||||||
|
while (size-- > 0)
|
||||||
|
*str++ = ' ';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vsprintf(char *buf, const char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
unsigned long num;
|
||||||
|
int i, base;
|
||||||
|
char *str;
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
int flags; /* flags to number() */
|
||||||
|
|
||||||
|
int field_width; /* width of output field */
|
||||||
|
int precision; /* min. # of digits for integers; max
|
||||||
|
number of chars for from string */
|
||||||
|
int qualifier; /* 'h', 'l', or 'L' for integer fields */
|
||||||
|
|
||||||
|
for (str = buf; *fmt; ++fmt) {
|
||||||
|
if (*fmt != '%') {
|
||||||
|
*str++ = *fmt;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process flags */
|
||||||
|
flags = 0;
|
||||||
|
repeat:
|
||||||
|
++fmt; /* this also skips first '%' */
|
||||||
|
switch (*fmt) {
|
||||||
|
case '-':
|
||||||
|
flags |= LEFT;
|
||||||
|
goto repeat;
|
||||||
|
case '+':
|
||||||
|
flags |= PLUS;
|
||||||
|
goto repeat;
|
||||||
|
case ' ':
|
||||||
|
flags |= SPACE;
|
||||||
|
goto repeat;
|
||||||
|
case '#':
|
||||||
|
flags |= SPECIAL;
|
||||||
|
goto repeat;
|
||||||
|
case '0':
|
||||||
|
flags |= ZEROPAD;
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get field width */
|
||||||
|
field_width = -1;
|
||||||
|
if (isdigit(*fmt))
|
||||||
|
field_width = skip_atoi(&fmt);
|
||||||
|
else if (*fmt == '*') {
|
||||||
|
++fmt;
|
||||||
|
/* it's the next argument */
|
||||||
|
field_width = va_arg(args, int);
|
||||||
|
if (field_width < 0) {
|
||||||
|
field_width = -field_width;
|
||||||
|
flags |= LEFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the precision */
|
||||||
|
precision = -1;
|
||||||
|
if (*fmt == '.') {
|
||||||
|
++fmt;
|
||||||
|
if (isdigit(*fmt))
|
||||||
|
precision = skip_atoi(&fmt);
|
||||||
|
else if (*fmt == '*') {
|
||||||
|
++fmt;
|
||||||
|
/* it's the next argument */
|
||||||
|
precision = va_arg(args, int);
|
||||||
|
}
|
||||||
|
if (precision < 0)
|
||||||
|
precision = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the conversion qualifier */
|
||||||
|
qualifier = -1;
|
||||||
|
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
|
||||||
|
qualifier = *fmt;
|
||||||
|
++fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default base */
|
||||||
|
base = 10;
|
||||||
|
|
||||||
|
switch (*fmt) {
|
||||||
|
case 'c':
|
||||||
|
if (!(flags & LEFT))
|
||||||
|
while (--field_width > 0)
|
||||||
|
*str++ = ' ';
|
||||||
|
*str++ = (unsigned char)va_arg(args, int);
|
||||||
|
while (--field_width > 0)
|
||||||
|
*str++ = ' ';
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
s = va_arg(args, char *);
|
||||||
|
len = c_strnlen(s, precision);
|
||||||
|
|
||||||
|
if (!(flags & LEFT))
|
||||||
|
while (len < field_width--)
|
||||||
|
*str++ = ' ';
|
||||||
|
for (i = 0; i < len; ++i)
|
||||||
|
*str++ = *s++;
|
||||||
|
while (len < field_width--)
|
||||||
|
*str++ = ' ';
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
if (field_width == -1) {
|
||||||
|
field_width = 2 * sizeof(void *);
|
||||||
|
flags |= ZEROPAD;
|
||||||
|
}
|
||||||
|
str = number(str,
|
||||||
|
(unsigned long)va_arg(args, void *), 16,
|
||||||
|
field_width, precision, flags);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
if (qualifier == 'l') {
|
||||||
|
long *ip = va_arg(args, long *);
|
||||||
|
*ip = (str - buf);
|
||||||
|
} else {
|
||||||
|
int *ip = va_arg(args, int *);
|
||||||
|
*ip = (str - buf);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '%':
|
||||||
|
*str++ = '%';
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* integer number formats - set up the flags and "break" */
|
||||||
|
case 'o':
|
||||||
|
base = 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
flags |= SMALL;
|
||||||
|
case 'X':
|
||||||
|
base = 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
flags |= SIGN;
|
||||||
|
case 'u':
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
*str++ = '%';
|
||||||
|
if (*fmt)
|
||||||
|
*str++ = *fmt;
|
||||||
|
else
|
||||||
|
--fmt;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (qualifier == 'l')
|
||||||
|
num = va_arg(args, unsigned long);
|
||||||
|
else if (qualifier == 'h') {
|
||||||
|
num = (unsigned short)va_arg(args, int);
|
||||||
|
if (flags & SIGN)
|
||||||
|
num = (short)num;
|
||||||
|
} else if (flags & SIGN)
|
||||||
|
num = va_arg(args, int);
|
||||||
|
else
|
||||||
|
num = va_arg(args, unsigned int);
|
||||||
|
str = number(str, num, base, field_width, precision, flags);
|
||||||
|
}
|
||||||
|
*str = '\0';
|
||||||
|
return str - buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sprintf(char *buf, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
i = vsprintf(buf, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int printf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char printf_buf[1024];
|
||||||
|
va_list args;
|
||||||
|
int printed;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
printed = vsprintf(printf_buf, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
printf_buf[printed] = '\0';
|
||||||
|
|
||||||
|
c_puts(printf_buf);
|
||||||
|
|
||||||
|
return printed;
|
||||||
|
}
|
@ -0,0 +1,182 @@
|
|||||||
|
/**
|
||||||
|
* PROM Library for Cisco Systems 3600 Series Routers
|
||||||
|
* (C) 2008 Philippe Vachon <philippe@cowpig.ca>
|
||||||
|
* -----------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calling convention:
|
||||||
|
* a0 - syscall number
|
||||||
|
* a1 - arg1 ... etc
|
||||||
|
* v0 - returned value from syscall
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <promlib.h>
|
||||||
|
|
||||||
|
/* putc - Syscall 1
|
||||||
|
* output character c to console
|
||||||
|
* @param c ASCII number for character
|
||||||
|
*/
|
||||||
|
void c_putc(const char c)
|
||||||
|
{
|
||||||
|
asm ( ".set noreorder\n "
|
||||||
|
"li $a0, %[syscall]\n"
|
||||||
|
"lb $a1, (%[character])\n"
|
||||||
|
"syscall\n"
|
||||||
|
"nop\n"
|
||||||
|
".set reorder\n"
|
||||||
|
: /* no output */
|
||||||
|
: [character] "r"(&c), [syscall] "g"(PUTC)
|
||||||
|
: "a0", "a1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
asm ( ".set noreorder\n "
|
||||||
|
"li $a0, %[syscall]\n"
|
||||||
|
"syscall\n"
|
||||||
|
"nop\n"
|
||||||
|
"move %[charout], $v0 \n"
|
||||||
|
".set reorder\n"
|
||||||
|
: [charout] "=r" (c)
|
||||||
|
: [syscall] "g" (GETC)
|
||||||
|
: "a0","v0"
|
||||||
|
);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} while (i < n);
|
||||||
|
|
||||||
|
b[i - 1] = '\0';
|
||||||
|
|
||||||
|
return i;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* c_version - get version string
|
||||||
|
* @return pointer to version string
|
||||||
|
*/
|
||||||
|
char *c_verstr(void)
|
||||||
|
{
|
||||||
|
char *c;
|
||||||
|
|
||||||
|
asm ( ".set noreorder\n"
|
||||||
|
"li $a0, %[syscall]\n"
|
||||||
|
"syscall\n"
|
||||||
|
"nop\n"
|
||||||
|
"move %[result], $v0\n"
|
||||||
|
".set reorder\n"
|
||||||
|
: [result] "=r" (c)
|
||||||
|
: [syscall] "g" (VERSION)
|
||||||
|
: "a0", "v0"
|
||||||
|
);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* memsz - get total memory size (in bytes)
|
||||||
|
* @return the size of the memory installed in the router, in bytes
|
||||||
|
*/
|
||||||
|
int c_memsz(void)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
asm ( " .set noreorder \n"
|
||||||
|
"li $a0, %[syscall]\n"
|
||||||
|
"syscall\n"
|
||||||
|
"nop\n"
|
||||||
|
"move %[result], $v0\n"
|
||||||
|
".set reorder\n"
|
||||||
|
: [result] "=r" (r)
|
||||||
|
: [syscall] "g" (MEMSIZE)
|
||||||
|
: "a0","v0"
|
||||||
|
);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* timer - get number of ticks from timer
|
||||||
|
* @return the value in the timer
|
||||||
|
*/
|
||||||
|
long c_timer(void)
|
||||||
|
{
|
||||||
|
long t = 0;
|
||||||
|
|
||||||
|
asm (" .set noreorder\n"
|
||||||
|
"li $a0, %[syscall]\n"
|
||||||
|
"syscall\n"
|
||||||
|
"nop\n"
|
||||||
|
"move %[result], $a0\n"
|
||||||
|
".set reorder\n"
|
||||||
|
: [result]"=r"(t)
|
||||||
|
: [syscall]"g"(TIMER)
|
||||||
|
: "a0","v0"
|
||||||
|
);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
|
||||||
|
# Configuration for the Cisco 3620 Router
|
||||||
|
TARGET=c3620
|
||||||
|
MACHCODE=0x1e
|
||||||
|
TEXTADDR=0x80008000
|
||||||
|
|
||||||
|
# additional CFLAGS
|
||||||
|
CFLAGS=
|
||||||
|
|
||||||
|
# don't modify anything below here
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
PROG = ciscoload
|
||||||
|
|
||||||
|
# check if the CROSS_COMPILE export has been set
|
||||||
|
ifndef CROSS_COMPILE
|
||||||
|
CROSS_COMPILE = mips-elf-
|
||||||
|
endif
|
||||||
|
|
||||||
|
CC=$(CROSS_COMPILE)gcc
|
||||||
|
AR=$(CROSS_COMPILE)ar
|
||||||
|
LD=$(CROSS_COMPILE)ld
|
||||||
|
OBJCOPY=$(CROSS_COMPILE)objcopy
|
||||||
|
|
||||||
|
INCLUDE=-I../include
|
||||||
|
|
||||||
|
CFLAGS=$(INCLUDE) -fno-builtin -fomit-frame-pointer -fno-pic -mno-abicalls -Wall
|
||||||
|
|
||||||
|
ASFLAGS=-xassembler-with-cpp -traditional-cpp
|
||||||
|
|
||||||
|
LDFLAGS= -nostartfiles -nostdlib --discard-all --strip-all --omagic \
|
||||||
|
-Ttext ${TEXTADDR} --entry _start
|
||||||
|
|
||||||
|
OBJECTS = kcopy.o
|
||||||
|
|
||||||
|
all: ${OBJECTS} ${PROG}
|
||||||
|
|
||||||
|
${PROG}: ${OBJECTS}
|
||||||
|
${CC} ${LDFLAGS} ${OBJECTS} -o ${PROG}.elf
|
||||||
|
${OBJCOPY} -O binary ${PROG}.elf ${PROG}.two
|
||||||
|
|
||||||
|
.S.o:
|
||||||
|
${CC} ${CFLAGS} ${ASFLAGS} -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *.o
|
||||||
|
rm ${PROG}.elf
|
||||||
|
rm ${PROG}.two
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,33 @@
|
|||||||
|
/* Re-copy kernel image from given offset in a0 (length a1), and then
|
||||||
|
* jump to entry point contained in a2. Copies data to location pointed
|
||||||
|
* to in a3
|
||||||
|
* Very naive.
|
||||||
|
* ------------------------------------------------------------------
|
||||||
|
* (c) 2008 Philippe Vachon <philippe@cowpig.ca>
|
||||||
|
* Licensed under the GNU General Public License v3. See COPYING in the
|
||||||
|
* source distribution for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/regdef.h>
|
||||||
|
#include <asm/asm.h>
|
||||||
|
|
||||||
|
EXPORT(_start)
|
||||||
|
|
||||||
|
LEAF(_start)
|
||||||
|
.set noreorder
|
||||||
|
|
||||||
|
1: lw s0, 0(a0) # load byte from address pointed to in a0
|
||||||
|
sw s0, 0(a3) # copy byte to address pointed to in a3
|
||||||
|
|
||||||
|
addiu a0, 4 # next location to read from
|
||||||
|
addiu a3, 4 # next location to write to
|
||||||
|
|
||||||
|
bnez a1, 1b # continue copying
|
||||||
|
addi a1, -4 # subtract from remaining bytes to copy
|
||||||
|
|
||||||
|
nop
|
||||||
|
|
||||||
|
jr a2 # jump to kernel entry point
|
||||||
|
nop
|
||||||
|
|
||||||
|
END(_start)
|
Binary file not shown.
@ -0,0 +1,52 @@
|
|||||||
|
/* Initial entry point for ciscoboot. Sets up some stack at 0x80008000
|
||||||
|
* and jumps to main
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/regdef.h>
|
||||||
|
#include <asm/asm.h>
|
||||||
|
|
||||||
|
EXPORT(_start)
|
||||||
|
|
||||||
|
.extern start_bootloader
|
||||||
|
|
||||||
|
LEAF(_start)
|
||||||
|
.set noreorder
|
||||||
|
li sp, 0x80008000
|
||||||
|
|
||||||
|
/* Save return address */
|
||||||
|
sw ra, -4(sp)
|
||||||
|
|
||||||
|
/* print out a letter C */
|
||||||
|
li a0, 1
|
||||||
|
li a1, 67
|
||||||
|
syscall
|
||||||
|
nop
|
||||||
|
|
||||||
|
/* get the total amount of RAM */
|
||||||
|
li a0, 4
|
||||||
|
syscall
|
||||||
|
nop
|
||||||
|
|
||||||
|
/* set the stack at the top of RAM */
|
||||||
|
li sp, 0x80000000
|
||||||
|
add sp, sp, v0
|
||||||
|
|
||||||
|
/* save return address*/
|
||||||
|
/*sw ra, -4(sp)
|
||||||
|
|
||||||
|
addi sp, sp, -4 */
|
||||||
|
|
||||||
|
/* start bootloader */
|
||||||
|
jal start_bootloader
|
||||||
|
nop
|
||||||
|
|
||||||
|
/* bootloader failed for some reason: */
|
||||||
|
li sp, 0x80008000
|
||||||
|
|
||||||
|
/* re-load return address to ROM: */
|
||||||
|
ld ra, -4(sp)
|
||||||
|
|
||||||
|
jr ra
|
||||||
|
|
||||||
|
.set reorder
|
||||||
|
END(_start)
|
Loading…
Reference in New Issue