commit 6d598a23e07cb96d46acf1c94ef032c332354ca2 Author: Philippe Vachon Date: Sat Nov 15 17:56:43 2008 -0500 Initial commit. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..3912109 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/DEVELOPMENT b/DEVELOPMENT new file mode 100644 index 0000000..ab3085f --- /dev/null +++ b/DEVELOPMENT @@ -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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a35b542 --- /dev/null +++ b/Makefile @@ -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 diff --git a/README b/README new file mode 100644 index 0000000..7145662 --- /dev/null +++ b/README @@ -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. diff --git a/TODO b/TODO new file mode 100644 index 0000000..eef5ccd --- /dev/null +++ b/TODO @@ -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 diff --git a/elf_loader.c b/elf_loader.c new file mode 100644 index 0000000..7ff8858 --- /dev/null +++ b/elf_loader.c @@ -0,0 +1,242 @@ +#include +#include +#include + + +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 */ +} diff --git a/elftool/Makefile b/elftool/Makefile new file mode 100644 index 0000000..798e137 --- /dev/null +++ b/elftool/Makefile @@ -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) diff --git a/elftool/elftool.c b/elftool/elftool.c new file mode 100644 index 0000000..b6f824a --- /dev/null +++ b/elftool/elftool.c @@ -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 + * + * Licensed under the GNU General Public License v2 + * See COPYING in the root directory of the CiscoLoad source distribution for + * more information + */ +#include +#include + +/** + * 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 \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; +} diff --git a/include/addr.h b/include/addr.h new file mode 100644 index 0000000..d7d3e48 --- /dev/null +++ b/include/addr.h @@ -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 */ diff --git a/include/asm/asm.h b/include/asm/asm.h new file mode 100644 index 0000000..608cfcf --- /dev/null +++ b/include/asm/asm.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 + +#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 +#define R10KCBARRIER(addr) cache Cache_Barrier, addr; +#else +#define R10KCBARRIER(addr) +#endif + +#endif /* __ASM_ASM_H */ diff --git a/include/asm/mipsregs.h b/include/asm/mipsregs.h new file mode 100644 index 0000000..b3e2a7b --- /dev/null +++ b/include/asm/mipsregs.h @@ -0,0 +1,1511 @@ +/* + * 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) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle + * Copyright (C) 2000 Silicon Graphics, Inc. + * Modified for further R[236]000 support by Paul M. Antoine, 1996. + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000, 07 MIPS Technologies, Inc. + * Copyright (C) 2003, 2004 Maciej W. Rozycki + */ +#ifndef _ASM_MIPSREGS_H +#define _ASM_MIPSREGS_H + +/* + * Configure language + */ +#ifdef __ASSEMBLY__ +#define _ULCAST_ +#else +#define _ULCAST_ (unsigned long) +#endif + +/* + * Coprocessor 0 register names + */ +#define CP0_INDEX $0 +#define CP0_RANDOM $1 +#define CP0_ENTRYLO0 $2 +#define CP0_ENTRYLO1 $3 +#define CP0_CONF $3 +#define CP0_CONTEXT $4 +#define CP0_PAGEMASK $5 +#define CP0_WIRED $6 +#define CP0_INFO $7 +#define CP0_BADVADDR $8 +#define CP0_COUNT $9 +#define CP0_ENTRYHI $10 +#define CP0_COMPARE $11 +#define CP0_STATUS $12 +#define CP0_CAUSE $13 +#define CP0_EPC $14 +#define CP0_PRID $15 +#define CP0_CONFIG $16 +#define CP0_LLADDR $17 +#define CP0_WATCHLO $18 +#define CP0_WATCHHI $19 +#define CP0_XCONTEXT $20 +#define CP0_FRAMEMASK $21 +#define CP0_DIAGNOSTIC $22 +#define CP0_DEBUG $23 +#define CP0_DEPC $24 +#define CP0_PERFORMANCE $25 +#define CP0_ECC $26 +#define CP0_CACHEERR $27 +#define CP0_TAGLO $28 +#define CP0_TAGHI $29 +#define CP0_ERROREPC $30 +#define CP0_DESAVE $31 + +/* + * R4640/R4650 cp0 register names. These registers are listed + * here only for completeness; without MMU these CPUs are not useable + * by Linux. A future ELKS port might take make Linux run on them + * though ... + */ +#define CP0_IBASE $0 +#define CP0_IBOUND $1 +#define CP0_DBASE $2 +#define CP0_DBOUND $3 +#define CP0_CALG $17 +#define CP0_IWATCH $18 +#define CP0_DWATCH $19 + +/* + * Coprocessor 0 Set 1 register names + */ +#define CP0_S1_DERRADDR0 $26 +#define CP0_S1_DERRADDR1 $27 +#define CP0_S1_INTCONTROL $20 + +/* + * Coprocessor 0 Set 2 register names + */ +#define CP0_S2_SRSCTL $12 /* MIPSR2 */ + +/* + * Coprocessor 0 Set 3 register names + */ +#define CP0_S3_SRSMAP $12 /* MIPSR2 */ + +/* + * TX39 Series + */ +#define CP0_TX39_CACHE $7 + +/* + * Coprocessor 1 (FPU) register names + */ +#define CP1_REVISION $0 +#define CP1_STATUS $31 + +/* + * FPU Status Register Values + */ +/* + * Status Register Values + */ + +#define FPU_CSR_FLUSH 0x01000000 /* flush denormalised results to 0 */ +#define FPU_CSR_COND 0x00800000 /* $fcc0 */ +#define FPU_CSR_COND0 0x00800000 /* $fcc0 */ +#define FPU_CSR_COND1 0x02000000 /* $fcc1 */ +#define FPU_CSR_COND2 0x04000000 /* $fcc2 */ +#define FPU_CSR_COND3 0x08000000 /* $fcc3 */ +#define FPU_CSR_COND4 0x10000000 /* $fcc4 */ +#define FPU_CSR_COND5 0x20000000 /* $fcc5 */ +#define FPU_CSR_COND6 0x40000000 /* $fcc6 */ +#define FPU_CSR_COND7 0x80000000 /* $fcc7 */ + +/* + * X the exception cause indicator + * E the exception enable + * S the sticky/flag bit +*/ +#define FPU_CSR_ALL_X 0x0003f000 +#define FPU_CSR_UNI_X 0x00020000 +#define FPU_CSR_INV_X 0x00010000 +#define FPU_CSR_DIV_X 0x00008000 +#define FPU_CSR_OVF_X 0x00004000 +#define FPU_CSR_UDF_X 0x00002000 +#define FPU_CSR_INE_X 0x00001000 + +#define FPU_CSR_ALL_E 0x00000f80 +#define FPU_CSR_INV_E 0x00000800 +#define FPU_CSR_DIV_E 0x00000400 +#define FPU_CSR_OVF_E 0x00000200 +#define FPU_CSR_UDF_E 0x00000100 +#define FPU_CSR_INE_E 0x00000080 + +#define FPU_CSR_ALL_S 0x0000007c +#define FPU_CSR_INV_S 0x00000040 +#define FPU_CSR_DIV_S 0x00000020 +#define FPU_CSR_OVF_S 0x00000010 +#define FPU_CSR_UDF_S 0x00000008 +#define FPU_CSR_INE_S 0x00000004 + +/* rounding mode */ +#define FPU_CSR_RN 0x0 /* nearest */ +#define FPU_CSR_RZ 0x1 /* towards zero */ +#define FPU_CSR_RU 0x2 /* towards +Infinity */ +#define FPU_CSR_RD 0x3 /* towards -Infinity */ + + +/* + * Values for PageMask register + */ +#ifdef CONFIG_CPU_VR41XX + +/* Why doesn't stupidity hurt ... */ + +#define PM_1K 0x00000000 +#define PM_4K 0x00001800 +#define PM_16K 0x00007800 +#define PM_64K 0x0001f800 +#define PM_256K 0x0007f800 + +#else + +#define PM_4K 0x00000000 +#define PM_16K 0x00006000 +#define PM_64K 0x0001e000 +#define PM_256K 0x0007e000 +#define PM_1M 0x001fe000 +#define PM_4M 0x007fe000 +#define PM_16M 0x01ffe000 +#define PM_64M 0x07ffe000 +#define PM_256M 0x1fffe000 + +#endif + +/* + * Default page size for a given kernel configuration + */ +#ifdef CONFIG_PAGE_SIZE_4KB +#define PM_DEFAULT_MASK PM_4K +#elif defined(CONFIG_PAGE_SIZE_16KB) +#define PM_DEFAULT_MASK PM_16K +#elif defined(CONFIG_PAGE_SIZE_64KB) +#define PM_DEFAULT_MASK PM_64K +#else +#error Bad page size configuration! +#endif + + +/* + * Values used for computation of new tlb entries + */ +#define PL_4K 12 +#define PL_16K 14 +#define PL_64K 16 +#define PL_256K 18 +#define PL_1M 20 +#define PL_4M 22 +#define PL_16M 24 +#define PL_64M 26 +#define PL_256M 28 + +/* + * R4x00 interrupt enable / cause bits + */ +#define IE_SW0 (_ULCAST_(1) << 8) +#define IE_SW1 (_ULCAST_(1) << 9) +#define IE_IRQ0 (_ULCAST_(1) << 10) +#define IE_IRQ1 (_ULCAST_(1) << 11) +#define IE_IRQ2 (_ULCAST_(1) << 12) +#define IE_IRQ3 (_ULCAST_(1) << 13) +#define IE_IRQ4 (_ULCAST_(1) << 14) +#define IE_IRQ5 (_ULCAST_(1) << 15) + +/* + * R4x00 interrupt cause bits + */ +#define C_SW0 (_ULCAST_(1) << 8) +#define C_SW1 (_ULCAST_(1) << 9) +#define C_IRQ0 (_ULCAST_(1) << 10) +#define C_IRQ1 (_ULCAST_(1) << 11) +#define C_IRQ2 (_ULCAST_(1) << 12) +#define C_IRQ3 (_ULCAST_(1) << 13) +#define C_IRQ4 (_ULCAST_(1) << 14) +#define C_IRQ5 (_ULCAST_(1) << 15) + +/* + * Bitfields in the R4xx0 cp0 status register + */ +#define ST0_IE 0x00000001 +#define ST0_EXL 0x00000002 +#define ST0_ERL 0x00000004 +#define ST0_KSU 0x00000018 +# define KSU_USER 0x00000010 +# define KSU_SUPERVISOR 0x00000008 +# define KSU_KERNEL 0x00000000 +#define ST0_UX 0x00000020 +#define ST0_SX 0x00000040 +#define ST0_KX 0x00000080 +#define ST0_DE 0x00010000 +#define ST0_CE 0x00020000 + +/* + * Setting c0_status.co enables Hit_Writeback and Hit_Writeback_Invalidate + * cacheops in userspace. This bit exists only on RM7000 and RM9000 + * processors. + */ +#define ST0_CO 0x08000000 + +/* + * Bitfields in the R[23]000 cp0 status register. + */ +#define ST0_IEC 0x00000001 +#define ST0_KUC 0x00000002 +#define ST0_IEP 0x00000004 +#define ST0_KUP 0x00000008 +#define ST0_IEO 0x00000010 +#define ST0_KUO 0x00000020 +/* bits 6 & 7 are reserved on R[23]000 */ +#define ST0_ISC 0x00010000 +#define ST0_SWC 0x00020000 +#define ST0_CM 0x00080000 + +/* + * Bits specific to the R4640/R4650 + */ +#define ST0_UM (_ULCAST_(1) << 4) +#define ST0_IL (_ULCAST_(1) << 23) +#define ST0_DL (_ULCAST_(1) << 24) + +/* + * Enable the MIPS MDMX and DSP ASEs + */ +#define ST0_MX 0x01000000 + +/* + * Bitfields in the TX39 family CP0 Configuration Register 3 + */ +#define TX39_CONF_ICS_SHIFT 19 +#define TX39_CONF_ICS_MASK 0x00380000 +#define TX39_CONF_ICS_1KB 0x00000000 +#define TX39_CONF_ICS_2KB 0x00080000 +#define TX39_CONF_ICS_4KB 0x00100000 +#define TX39_CONF_ICS_8KB 0x00180000 +#define TX39_CONF_ICS_16KB 0x00200000 + +#define TX39_CONF_DCS_SHIFT 16 +#define TX39_CONF_DCS_MASK 0x00070000 +#define TX39_CONF_DCS_1KB 0x00000000 +#define TX39_CONF_DCS_2KB 0x00010000 +#define TX39_CONF_DCS_4KB 0x00020000 +#define TX39_CONF_DCS_8KB 0x00030000 +#define TX39_CONF_DCS_16KB 0x00040000 + +#define TX39_CONF_CWFON 0x00004000 +#define TX39_CONF_WBON 0x00002000 +#define TX39_CONF_RF_SHIFT 10 +#define TX39_CONF_RF_MASK 0x00000c00 +#define TX39_CONF_DOZE 0x00000200 +#define TX39_CONF_HALT 0x00000100 +#define TX39_CONF_LOCK 0x00000080 +#define TX39_CONF_ICE 0x00000020 +#define TX39_CONF_DCE 0x00000010 +#define TX39_CONF_IRSIZE_SHIFT 2 +#define TX39_CONF_IRSIZE_MASK 0x0000000c +#define TX39_CONF_DRSIZE_SHIFT 0 +#define TX39_CONF_DRSIZE_MASK 0x00000003 + +/* + * Status register bits available in all MIPS CPUs. + */ +#define ST0_IM 0x0000ff00 +#define STATUSB_IP0 8 +#define STATUSF_IP0 (_ULCAST_(1) << 8) +#define STATUSB_IP1 9 +#define STATUSF_IP1 (_ULCAST_(1) << 9) +#define STATUSB_IP2 10 +#define STATUSF_IP2 (_ULCAST_(1) << 10) +#define STATUSB_IP3 11 +#define STATUSF_IP3 (_ULCAST_(1) << 11) +#define STATUSB_IP4 12 +#define STATUSF_IP4 (_ULCAST_(1) << 12) +#define STATUSB_IP5 13 +#define STATUSF_IP5 (_ULCAST_(1) << 13) +#define STATUSB_IP6 14 +#define STATUSF_IP6 (_ULCAST_(1) << 14) +#define STATUSB_IP7 15 +#define STATUSF_IP7 (_ULCAST_(1) << 15) +#define STATUSB_IP8 0 +#define STATUSF_IP8 (_ULCAST_(1) << 0) +#define STATUSB_IP9 1 +#define STATUSF_IP9 (_ULCAST_(1) << 1) +#define STATUSB_IP10 2 +#define STATUSF_IP10 (_ULCAST_(1) << 2) +#define STATUSB_IP11 3 +#define STATUSF_IP11 (_ULCAST_(1) << 3) +#define STATUSB_IP12 4 +#define STATUSF_IP12 (_ULCAST_(1) << 4) +#define STATUSB_IP13 5 +#define STATUSF_IP13 (_ULCAST_(1) << 5) +#define STATUSB_IP14 6 +#define STATUSF_IP14 (_ULCAST_(1) << 6) +#define STATUSB_IP15 7 +#define STATUSF_IP15 (_ULCAST_(1) << 7) +#define ST0_CH 0x00040000 +#define ST0_SR 0x00100000 +#define ST0_TS 0x00200000 +#define ST0_BEV 0x00400000 +#define ST0_RE 0x02000000 +#define ST0_FR 0x04000000 +#define ST0_CU 0xf0000000 +#define ST0_CU0 0x10000000 +#define ST0_CU1 0x20000000 +#define ST0_CU2 0x40000000 +#define ST0_CU3 0x80000000 +#define ST0_XX 0x80000000 /* MIPS IV naming */ + +/* + * Bitfields and bit numbers in the coprocessor 0 cause register. + * + * Refer to your MIPS R4xx0 manual, chapter 5 for explanation. + */ +#define CAUSEB_EXCCODE 2 +#define CAUSEF_EXCCODE (_ULCAST_(31) << 2) +#define CAUSEB_IP 8 +#define CAUSEF_IP (_ULCAST_(255) << 8) +#define CAUSEB_IP0 8 +#define CAUSEF_IP0 (_ULCAST_(1) << 8) +#define CAUSEB_IP1 9 +#define CAUSEF_IP1 (_ULCAST_(1) << 9) +#define CAUSEB_IP2 10 +#define CAUSEF_IP2 (_ULCAST_(1) << 10) +#define CAUSEB_IP3 11 +#define CAUSEF_IP3 (_ULCAST_(1) << 11) +#define CAUSEB_IP4 12 +#define CAUSEF_IP4 (_ULCAST_(1) << 12) +#define CAUSEB_IP5 13 +#define CAUSEF_IP5 (_ULCAST_(1) << 13) +#define CAUSEB_IP6 14 +#define CAUSEF_IP6 (_ULCAST_(1) << 14) +#define CAUSEB_IP7 15 +#define CAUSEF_IP7 (_ULCAST_(1) << 15) +#define CAUSEB_IV 23 +#define CAUSEF_IV (_ULCAST_(1) << 23) +#define CAUSEB_CE 28 +#define CAUSEF_CE (_ULCAST_(3) << 28) +#define CAUSEB_BD 31 +#define CAUSEF_BD (_ULCAST_(1) << 31) + +/* + * Bits in the coprocessor 0 config register. + */ +/* Generic bits. */ +#define CONF_CM_CACHABLE_NO_WA 0 +#define CONF_CM_CACHABLE_WA 1 +#define CONF_CM_UNCACHED 2 +#define CONF_CM_CACHABLE_NONCOHERENT 3 +#define CONF_CM_CACHABLE_CE 4 +#define CONF_CM_CACHABLE_COW 5 +#define CONF_CM_CACHABLE_CUW 6 +#define CONF_CM_CACHABLE_ACCELERATED 7 +#define CONF_CM_CMASK 7 +#define CONF_BE (_ULCAST_(1) << 15) + +/* Bits common to various processors. */ +#define CONF_CU (_ULCAST_(1) << 3) +#define CONF_DB (_ULCAST_(1) << 4) +#define CONF_IB (_ULCAST_(1) << 5) +#define CONF_DC (_ULCAST_(7) << 6) +#define CONF_IC (_ULCAST_(7) << 9) +#define CONF_EB (_ULCAST_(1) << 13) +#define CONF_EM (_ULCAST_(1) << 14) +#define CONF_SM (_ULCAST_(1) << 16) +#define CONF_SC (_ULCAST_(1) << 17) +#define CONF_EW (_ULCAST_(3) << 18) +#define CONF_EP (_ULCAST_(15)<< 24) +#define CONF_EC (_ULCAST_(7) << 28) +#define CONF_CM (_ULCAST_(1) << 31) + +/* Bits specific to the R4xx0. */ +#define R4K_CONF_SW (_ULCAST_(1) << 20) +#define R4K_CONF_SS (_ULCAST_(1) << 21) +#define R4K_CONF_SB (_ULCAST_(3) << 22) + +/* Bits specific to the R5000. */ +#define R5K_CONF_SE (_ULCAST_(1) << 12) +#define R5K_CONF_SS (_ULCAST_(3) << 20) + +/* Bits specific to the RM7000. */ +#define RM7K_CONF_SE (_ULCAST_(1) << 3) +#define RM7K_CONF_TE (_ULCAST_(1) << 12) +#define RM7K_CONF_CLK (_ULCAST_(1) << 16) +#define RM7K_CONF_TC (_ULCAST_(1) << 17) +#define RM7K_CONF_SI (_ULCAST_(3) << 20) +#define RM7K_CONF_SC (_ULCAST_(1) << 31) + +/* Bits specific to the R10000. */ +#define R10K_CONF_DN (_ULCAST_(3) << 3) +#define R10K_CONF_CT (_ULCAST_(1) << 5) +#define R10K_CONF_PE (_ULCAST_(1) << 6) +#define R10K_CONF_PM (_ULCAST_(3) << 7) +#define R10K_CONF_EC (_ULCAST_(15)<< 9) +#define R10K_CONF_SB (_ULCAST_(1) << 13) +#define R10K_CONF_SK (_ULCAST_(1) << 14) +#define R10K_CONF_SS (_ULCAST_(7) << 16) +#define R10K_CONF_SC (_ULCAST_(7) << 19) +#define R10K_CONF_DC (_ULCAST_(7) << 26) +#define R10K_CONF_IC (_ULCAST_(7) << 29) + +/* Bits specific to the VR41xx. */ +#define VR41_CONF_CS (_ULCAST_(1) << 12) +#define VR41_CONF_P4K (_ULCAST_(1) << 13) +#define VR41_CONF_BP (_ULCAST_(1) << 16) +#define VR41_CONF_M16 (_ULCAST_(1) << 20) +#define VR41_CONF_AD (_ULCAST_(1) << 23) + +/* Bits specific to the R30xx. */ +#define R30XX_CONF_FDM (_ULCAST_(1) << 19) +#define R30XX_CONF_REV (_ULCAST_(1) << 22) +#define R30XX_CONF_AC (_ULCAST_(1) << 23) +#define R30XX_CONF_RF (_ULCAST_(1) << 24) +#define R30XX_CONF_HALT (_ULCAST_(1) << 25) +#define R30XX_CONF_FPINT (_ULCAST_(7) << 26) +#define R30XX_CONF_DBR (_ULCAST_(1) << 29) +#define R30XX_CONF_SB (_ULCAST_(1) << 30) +#define R30XX_CONF_LOCK (_ULCAST_(1) << 31) + +/* Bits specific to the TX49. */ +#define TX49_CONF_DC (_ULCAST_(1) << 16) +#define TX49_CONF_IC (_ULCAST_(1) << 17) /* conflict with CONF_SC */ +#define TX49_CONF_HALT (_ULCAST_(1) << 18) +#define TX49_CONF_CWFON (_ULCAST_(1) << 27) + +/* Bits specific to the MIPS32/64 PRA. */ +#define MIPS_CONF_MT (_ULCAST_(7) << 7) +#define MIPS_CONF_AR (_ULCAST_(7) << 10) +#define MIPS_CONF_AT (_ULCAST_(3) << 13) +#define MIPS_CONF_M (_ULCAST_(1) << 31) + +/* + * Bits in the MIPS32/64 PRA coprocessor 0 config registers 1 and above. + */ +#define MIPS_CONF1_FP (_ULCAST_(1) << 0) +#define MIPS_CONF1_EP (_ULCAST_(1) << 1) +#define MIPS_CONF1_CA (_ULCAST_(1) << 2) +#define MIPS_CONF1_WR (_ULCAST_(1) << 3) +#define MIPS_CONF1_PC (_ULCAST_(1) << 4) +#define MIPS_CONF1_MD (_ULCAST_(1) << 5) +#define MIPS_CONF1_C2 (_ULCAST_(1) << 6) +#define MIPS_CONF1_DA (_ULCAST_(7) << 7) +#define MIPS_CONF1_DL (_ULCAST_(7) << 10) +#define MIPS_CONF1_DS (_ULCAST_(7) << 13) +#define MIPS_CONF1_IA (_ULCAST_(7) << 16) +#define MIPS_CONF1_IL (_ULCAST_(7) << 19) +#define MIPS_CONF1_IS (_ULCAST_(7) << 22) +#define MIPS_CONF1_TLBS (_ULCAST_(63)<< 25) + +#define MIPS_CONF2_SA (_ULCAST_(15)<< 0) +#define MIPS_CONF2_SL (_ULCAST_(15)<< 4) +#define MIPS_CONF2_SS (_ULCAST_(15)<< 8) +#define MIPS_CONF2_SU (_ULCAST_(15)<< 12) +#define MIPS_CONF2_TA (_ULCAST_(15)<< 16) +#define MIPS_CONF2_TL (_ULCAST_(15)<< 20) +#define MIPS_CONF2_TS (_ULCAST_(15)<< 24) +#define MIPS_CONF2_TU (_ULCAST_(7) << 28) + +#define MIPS_CONF3_TL (_ULCAST_(1) << 0) +#define MIPS_CONF3_SM (_ULCAST_(1) << 1) +#define MIPS_CONF3_MT (_ULCAST_(1) << 2) +#define MIPS_CONF3_SP (_ULCAST_(1) << 4) +#define MIPS_CONF3_VINT (_ULCAST_(1) << 5) +#define MIPS_CONF3_VEIC (_ULCAST_(1) << 6) +#define MIPS_CONF3_LPA (_ULCAST_(1) << 7) +#define MIPS_CONF3_DSP (_ULCAST_(1) << 10) +#define MIPS_CONF3_ULRI (_ULCAST_(1) << 13) + +#define MIPS_CONF7_WII (_ULCAST_(1) << 31) + +#define MIPS_CONF7_RPS (_ULCAST_(1) << 2) + + +/* + * Bits in the MIPS32/64 coprocessor 1 (FPU) revision register. + */ +#define MIPS_FPIR_S (_ULCAST_(1) << 16) +#define MIPS_FPIR_D (_ULCAST_(1) << 17) +#define MIPS_FPIR_PS (_ULCAST_(1) << 18) +#define MIPS_FPIR_3D (_ULCAST_(1) << 19) +#define MIPS_FPIR_W (_ULCAST_(1) << 20) +#define MIPS_FPIR_L (_ULCAST_(1) << 21) +#define MIPS_FPIR_F64 (_ULCAST_(1) << 22) + +#ifndef __ASSEMBLY__ + +/* + * Functions to access the R10000 performance counters. These are basically + * mfc0 and mtc0 instructions from and to coprocessor register with a 5-bit + * performance counter number encoded into bits 1 ... 5 of the instruction. + * Only performance counters 0 to 1 actually exist, so for a non-R10000 aware + * disassembler these will look like an access to sel 0 or 1. + */ +#define read_r10k_perf_cntr(counter) \ +({ \ + unsigned int __res; \ + __asm__ __volatile__( \ + "mfpc\t%0, %1" \ + : "=r" (__res) \ + : "i" (counter)); \ + \ + __res; \ +}) + +#define write_r10k_perf_cntr(counter,val) \ +do { \ + __asm__ __volatile__( \ + "mtpc\t%0, %1" \ + : \ + : "r" (val), "i" (counter)); \ +} while (0) + +#define read_r10k_perf_event(counter) \ +({ \ + unsigned int __res; \ + __asm__ __volatile__( \ + "mfps\t%0, %1" \ + : "=r" (__res) \ + : "i" (counter)); \ + \ + __res; \ +}) + +#define write_r10k_perf_cntl(counter,val) \ +do { \ + __asm__ __volatile__( \ + "mtps\t%0, %1" \ + : \ + : "r" (val), "i" (counter)); \ +} while (0) + + +/* + * Macros to access the system control coprocessor + */ + +#define __read_32bit_c0_register(source, sel) \ +({ int __res; \ + if (sel == 0) \ + __asm__ __volatile__( \ + "mfc0\t%0, " #source "\n\t" \ + : "=r" (__res)); \ + else \ + __asm__ __volatile__( \ + ".set\tmips32\n\t" \ + "mfc0\t%0, " #source ", " #sel "\n\t" \ + ".set\tmips0\n\t" \ + : "=r" (__res)); \ + __res; \ +}) + +#define __read_64bit_c0_register(source, sel) \ +({ unsigned long long __res; \ + if (sizeof(unsigned long) == 4) \ + __res = __read_64bit_c0_split(source, sel); \ + else if (sel == 0) \ + __asm__ __volatile__( \ + ".set\tmips3\n\t" \ + "dmfc0\t%0, " #source "\n\t" \ + ".set\tmips0" \ + : "=r" (__res)); \ + else \ + __asm__ __volatile__( \ + ".set\tmips64\n\t" \ + "dmfc0\t%0, " #source ", " #sel "\n\t" \ + ".set\tmips0" \ + : "=r" (__res)); \ + __res; \ +}) + +#define __write_32bit_c0_register(register, sel, value) \ +do { \ + if (sel == 0) \ + __asm__ __volatile__( \ + "mtc0\t%z0, " #register "\n\t" \ + : : "Jr" ((unsigned int)(value))); \ + else \ + __asm__ __volatile__( \ + ".set\tmips32\n\t" \ + "mtc0\t%z0, " #register ", " #sel "\n\t" \ + ".set\tmips0" \ + : : "Jr" ((unsigned int)(value))); \ +} while (0) + +#define __write_64bit_c0_register(register, sel, value) \ +do { \ + if (sizeof(unsigned long) == 4) \ + __write_64bit_c0_split(register, sel, value); \ + else if (sel == 0) \ + __asm__ __volatile__( \ + ".set\tmips3\n\t" \ + "dmtc0\t%z0, " #register "\n\t" \ + ".set\tmips0" \ + : : "Jr" (value)); \ + else \ + __asm__ __volatile__( \ + ".set\tmips64\n\t" \ + "dmtc0\t%z0, " #register ", " #sel "\n\t" \ + ".set\tmips0" \ + : : "Jr" (value)); \ +} while (0) + +#define __read_ulong_c0_register(reg, sel) \ + ((sizeof(unsigned long) == 4) ? \ + (unsigned long) __read_32bit_c0_register(reg, sel) : \ + (unsigned long) __read_64bit_c0_register(reg, sel)) + +#define __write_ulong_c0_register(reg, sel, val) \ +do { \ + if (sizeof(unsigned long) == 4) \ + __write_32bit_c0_register(reg, sel, val); \ + else \ + __write_64bit_c0_register(reg, sel, val); \ +} while (0) + +/* + * On RM7000/RM9000 these are uses to access cop0 set 1 registers + */ +#define __read_32bit_c0_ctrl_register(source) \ +({ int __res; \ + __asm__ __volatile__( \ + "cfc0\t%0, " #source "\n\t" \ + : "=r" (__res)); \ + __res; \ +}) + +#define __write_32bit_c0_ctrl_register(register, value) \ +do { \ + __asm__ __volatile__( \ + "ctc0\t%z0, " #register "\n\t" \ + : : "Jr" ((unsigned int)(value))); \ +} while (0) + +/* + * These versions are only needed for systems with more than 38 bits of + * physical address space running the 32-bit kernel. That's none atm :-) + */ +#define __read_64bit_c0_split(source, sel) \ +({ \ + unsigned long long __val; \ + unsigned long __flags; \ + \ + local_irq_save(__flags); \ + if (sel == 0) \ + __asm__ __volatile__( \ + ".set\tmips64\n\t" \ + "dmfc0\t%M0, " #source "\n\t" \ + "dsll\t%L0, %M0, 32\n\t" \ + "dsrl\t%M0, %M0, 32\n\t" \ + "dsrl\t%L0, %L0, 32\n\t" \ + ".set\tmips0" \ + : "=r" (__val)); \ + else \ + __asm__ __volatile__( \ + ".set\tmips64\n\t" \ + "dmfc0\t%M0, " #source ", " #sel "\n\t" \ + "dsll\t%L0, %M0, 32\n\t" \ + "dsrl\t%M0, %M0, 32\n\t" \ + "dsrl\t%L0, %L0, 32\n\t" \ + ".set\tmips0" \ + : "=r" (__val)); \ + local_irq_restore(__flags); \ + \ + __val; \ +}) + +#define __write_64bit_c0_split(source, sel, val) \ +do { \ + unsigned long __flags; \ + \ + local_irq_save(__flags); \ + if (sel == 0) \ + __asm__ __volatile__( \ + ".set\tmips64\n\t" \ + "dsll\t%L0, %L0, 32\n\t" \ + "dsrl\t%L0, %L0, 32\n\t" \ + "dsll\t%M0, %M0, 32\n\t" \ + "or\t%L0, %L0, %M0\n\t" \ + "dmtc0\t%L0, " #source "\n\t" \ + ".set\tmips0" \ + : : "r" (val)); \ + else \ + __asm__ __volatile__( \ + ".set\tmips64\n\t" \ + "dsll\t%L0, %L0, 32\n\t" \ + "dsrl\t%L0, %L0, 32\n\t" \ + "dsll\t%M0, %M0, 32\n\t" \ + "or\t%L0, %L0, %M0\n\t" \ + "dmtc0\t%L0, " #source ", " #sel "\n\t" \ + ".set\tmips0" \ + : : "r" (val)); \ + local_irq_restore(__flags); \ +} while (0) + +#define read_c0_index() __read_32bit_c0_register($0, 0) +#define write_c0_index(val) __write_32bit_c0_register($0, 0, val) + +#define read_c0_random() __read_32bit_c0_register($1, 0) +#define write_c0_random(val) __write_32bit_c0_register($1, 0, val) + +#define read_c0_entrylo0() __read_ulong_c0_register($2, 0) +#define write_c0_entrylo0(val) __write_ulong_c0_register($2, 0, val) + +#define read_c0_entrylo1() __read_ulong_c0_register($3, 0) +#define write_c0_entrylo1(val) __write_ulong_c0_register($3, 0, val) + +#define read_c0_conf() __read_32bit_c0_register($3, 0) +#define write_c0_conf(val) __write_32bit_c0_register($3, 0, val) + +#define read_c0_context() __read_ulong_c0_register($4, 0) +#define write_c0_context(val) __write_ulong_c0_register($4, 0, val) + +#define read_c0_userlocal() __read_ulong_c0_register($4, 2) +#define write_c0_userlocal(val) __write_ulong_c0_register($4, 2, val) + +#define read_c0_pagemask() __read_32bit_c0_register($5, 0) +#define write_c0_pagemask(val) __write_32bit_c0_register($5, 0, val) + +#define read_c0_wired() __read_32bit_c0_register($6, 0) +#define write_c0_wired(val) __write_32bit_c0_register($6, 0, val) + +#define read_c0_info() __read_32bit_c0_register($7, 0) + +#define read_c0_cache() __read_32bit_c0_register($7, 0) /* TX39xx */ +#define write_c0_cache(val) __write_32bit_c0_register($7, 0, val) + +#define read_c0_badvaddr() __read_ulong_c0_register($8, 0) +#define write_c0_badvaddr(val) __write_ulong_c0_register($8, 0, val) + +#define read_c0_count() __read_32bit_c0_register($9, 0) +#define write_c0_count(val) __write_32bit_c0_register($9, 0, val) + +#define read_c0_count2() __read_32bit_c0_register($9, 6) /* pnx8550 */ +#define write_c0_count2(val) __write_32bit_c0_register($9, 6, val) + +#define read_c0_count3() __read_32bit_c0_register($9, 7) /* pnx8550 */ +#define write_c0_count3(val) __write_32bit_c0_register($9, 7, val) + +#define read_c0_entryhi() __read_ulong_c0_register($10, 0) +#define write_c0_entryhi(val) __write_ulong_c0_register($10, 0, val) + +#define read_c0_compare() __read_32bit_c0_register($11, 0) +#define write_c0_compare(val) __write_32bit_c0_register($11, 0, val) + +#define read_c0_compare2() __read_32bit_c0_register($11, 6) /* pnx8550 */ +#define write_c0_compare2(val) __write_32bit_c0_register($11, 6, val) + +#define read_c0_compare3() __read_32bit_c0_register($11, 7) /* pnx8550 */ +#define write_c0_compare3(val) __write_32bit_c0_register($11, 7, val) + +#define read_c0_status() __read_32bit_c0_register($12, 0) +#ifdef CONFIG_MIPS_MT_SMTC +#define write_c0_status(val) \ +do { \ + __write_32bit_c0_register($12, 0, val); \ + __ehb(); \ +} while (0) +#else +/* + * Legacy non-SMTC code, which may be hazardous + * but which might not support EHB + */ +#define write_c0_status(val) __write_32bit_c0_register($12, 0, val) +#endif /* CONFIG_MIPS_MT_SMTC */ + +#define read_c0_cause() __read_32bit_c0_register($13, 0) +#define write_c0_cause(val) __write_32bit_c0_register($13, 0, val) + +#define read_c0_epc() __read_ulong_c0_register($14, 0) +#define write_c0_epc(val) __write_ulong_c0_register($14, 0, val) + +#define read_c0_prid() __read_32bit_c0_register($15, 0) + +#define read_c0_config() __read_32bit_c0_register($16, 0) +#define read_c0_config1() __read_32bit_c0_register($16, 1) +#define read_c0_config2() __read_32bit_c0_register($16, 2) +#define read_c0_config3() __read_32bit_c0_register($16, 3) +#define read_c0_config4() __read_32bit_c0_register($16, 4) +#define read_c0_config5() __read_32bit_c0_register($16, 5) +#define read_c0_config6() __read_32bit_c0_register($16, 6) +#define read_c0_config7() __read_32bit_c0_register($16, 7) +#define write_c0_config(val) __write_32bit_c0_register($16, 0, val) +#define write_c0_config1(val) __write_32bit_c0_register($16, 1, val) +#define write_c0_config2(val) __write_32bit_c0_register($16, 2, val) +#define write_c0_config3(val) __write_32bit_c0_register($16, 3, val) +#define write_c0_config4(val) __write_32bit_c0_register($16, 4, val) +#define write_c0_config5(val) __write_32bit_c0_register($16, 5, val) +#define write_c0_config6(val) __write_32bit_c0_register($16, 6, val) +#define write_c0_config7(val) __write_32bit_c0_register($16, 7, val) + +/* + * The WatchLo register. There may be upto 8 of them. + */ +#define read_c0_watchlo0() __read_ulong_c0_register($18, 0) +#define read_c0_watchlo1() __read_ulong_c0_register($18, 1) +#define read_c0_watchlo2() __read_ulong_c0_register($18, 2) +#define read_c0_watchlo3() __read_ulong_c0_register($18, 3) +#define read_c0_watchlo4() __read_ulong_c0_register($18, 4) +#define read_c0_watchlo5() __read_ulong_c0_register($18, 5) +#define read_c0_watchlo6() __read_ulong_c0_register($18, 6) +#define read_c0_watchlo7() __read_ulong_c0_register($18, 7) +#define write_c0_watchlo0(val) __write_ulong_c0_register($18, 0, val) +#define write_c0_watchlo1(val) __write_ulong_c0_register($18, 1, val) +#define write_c0_watchlo2(val) __write_ulong_c0_register($18, 2, val) +#define write_c0_watchlo3(val) __write_ulong_c0_register($18, 3, val) +#define write_c0_watchlo4(val) __write_ulong_c0_register($18, 4, val) +#define write_c0_watchlo5(val) __write_ulong_c0_register($18, 5, val) +#define write_c0_watchlo6(val) __write_ulong_c0_register($18, 6, val) +#define write_c0_watchlo7(val) __write_ulong_c0_register($18, 7, val) + +/* + * The WatchHi register. There may be upto 8 of them. + */ +#define read_c0_watchhi0() __read_32bit_c0_register($19, 0) +#define read_c0_watchhi1() __read_32bit_c0_register($19, 1) +#define read_c0_watchhi2() __read_32bit_c0_register($19, 2) +#define read_c0_watchhi3() __read_32bit_c0_register($19, 3) +#define read_c0_watchhi4() __read_32bit_c0_register($19, 4) +#define read_c0_watchhi5() __read_32bit_c0_register($19, 5) +#define read_c0_watchhi6() __read_32bit_c0_register($19, 6) +#define read_c0_watchhi7() __read_32bit_c0_register($19, 7) + +#define write_c0_watchhi0(val) __write_32bit_c0_register($19, 0, val) +#define write_c0_watchhi1(val) __write_32bit_c0_register($19, 1, val) +#define write_c0_watchhi2(val) __write_32bit_c0_register($19, 2, val) +#define write_c0_watchhi3(val) __write_32bit_c0_register($19, 3, val) +#define write_c0_watchhi4(val) __write_32bit_c0_register($19, 4, val) +#define write_c0_watchhi5(val) __write_32bit_c0_register($19, 5, val) +#define write_c0_watchhi6(val) __write_32bit_c0_register($19, 6, val) +#define write_c0_watchhi7(val) __write_32bit_c0_register($19, 7, val) + +#define read_c0_xcontext() __read_ulong_c0_register($20, 0) +#define write_c0_xcontext(val) __write_ulong_c0_register($20, 0, val) + +#define read_c0_intcontrol() __read_32bit_c0_ctrl_register($20) +#define write_c0_intcontrol(val) __write_32bit_c0_ctrl_register($20, val) + +#define read_c0_framemask() __read_32bit_c0_register($21, 0) +#define write_c0_framemask(val) __write_32bit_c0_register($21, 0, val) + +/* RM9000 PerfControl performance counter control register */ +#define read_c0_perfcontrol() __read_32bit_c0_register($22, 0) +#define write_c0_perfcontrol(val) __write_32bit_c0_register($22, 0, val) + +#define read_c0_diag() __read_32bit_c0_register($22, 0) +#define write_c0_diag(val) __write_32bit_c0_register($22, 0, val) + +#define read_c0_diag1() __read_32bit_c0_register($22, 1) +#define write_c0_diag1(val) __write_32bit_c0_register($22, 1, val) + +#define read_c0_diag2() __read_32bit_c0_register($22, 2) +#define write_c0_diag2(val) __write_32bit_c0_register($22, 2, val) + +#define read_c0_diag3() __read_32bit_c0_register($22, 3) +#define write_c0_diag3(val) __write_32bit_c0_register($22, 3, val) + +#define read_c0_diag4() __read_32bit_c0_register($22, 4) +#define write_c0_diag4(val) __write_32bit_c0_register($22, 4, val) + +#define read_c0_diag5() __read_32bit_c0_register($22, 5) +#define write_c0_diag5(val) __write_32bit_c0_register($22, 5, val) + +#define read_c0_debug() __read_32bit_c0_register($23, 0) +#define write_c0_debug(val) __write_32bit_c0_register($23, 0, val) + +#define read_c0_depc() __read_ulong_c0_register($24, 0) +#define write_c0_depc(val) __write_ulong_c0_register($24, 0, val) + +/* + * MIPS32 / MIPS64 performance counters + */ +#define read_c0_perfctrl0() __read_32bit_c0_register($25, 0) +#define write_c0_perfctrl0(val) __write_32bit_c0_register($25, 0, val) +#define read_c0_perfcntr0() __read_32bit_c0_register($25, 1) +#define write_c0_perfcntr0(val) __write_32bit_c0_register($25, 1, val) +#define read_c0_perfctrl1() __read_32bit_c0_register($25, 2) +#define write_c0_perfctrl1(val) __write_32bit_c0_register($25, 2, val) +#define read_c0_perfcntr1() __read_32bit_c0_register($25, 3) +#define write_c0_perfcntr1(val) __write_32bit_c0_register($25, 3, val) +#define read_c0_perfctrl2() __read_32bit_c0_register($25, 4) +#define write_c0_perfctrl2(val) __write_32bit_c0_register($25, 4, val) +#define read_c0_perfcntr2() __read_32bit_c0_register($25, 5) +#define write_c0_perfcntr2(val) __write_32bit_c0_register($25, 5, val) +#define read_c0_perfctrl3() __read_32bit_c0_register($25, 6) +#define write_c0_perfctrl3(val) __write_32bit_c0_register($25, 6, val) +#define read_c0_perfcntr3() __read_32bit_c0_register($25, 7) +#define write_c0_perfcntr3(val) __write_32bit_c0_register($25, 7, val) + +/* RM9000 PerfCount performance counter register */ +#define read_c0_perfcount() __read_64bit_c0_register($25, 0) +#define write_c0_perfcount(val) __write_64bit_c0_register($25, 0, val) + +#define read_c0_ecc() __read_32bit_c0_register($26, 0) +#define write_c0_ecc(val) __write_32bit_c0_register($26, 0, val) + +#define read_c0_derraddr0() __read_ulong_c0_register($26, 1) +#define write_c0_derraddr0(val) __write_ulong_c0_register($26, 1, val) + +#define read_c0_cacheerr() __read_32bit_c0_register($27, 0) + +#define read_c0_derraddr1() __read_ulong_c0_register($27, 1) +#define write_c0_derraddr1(val) __write_ulong_c0_register($27, 1, val) + +#define read_c0_taglo() __read_32bit_c0_register($28, 0) +#define write_c0_taglo(val) __write_32bit_c0_register($28, 0, val) + +#define read_c0_dtaglo() __read_32bit_c0_register($28, 2) +#define write_c0_dtaglo(val) __write_32bit_c0_register($28, 2, val) + +#define read_c0_taghi() __read_32bit_c0_register($29, 0) +#define write_c0_taghi(val) __write_32bit_c0_register($29, 0, val) + +#define read_c0_errorepc() __read_ulong_c0_register($30, 0) +#define write_c0_errorepc(val) __write_ulong_c0_register($30, 0, val) + +/* MIPSR2 */ +#define read_c0_hwrena() __read_32bit_c0_register($7, 0) +#define write_c0_hwrena(val) __write_32bit_c0_register($7, 0, val) + +#define read_c0_intctl() __read_32bit_c0_register($12, 1) +#define write_c0_intctl(val) __write_32bit_c0_register($12, 1, val) + +#define read_c0_srsctl() __read_32bit_c0_register($12, 2) +#define write_c0_srsctl(val) __write_32bit_c0_register($12, 2, val) + +#define read_c0_srsmap() __read_32bit_c0_register($12, 3) +#define write_c0_srsmap(val) __write_32bit_c0_register($12, 3, val) + +#define read_c0_ebase() __read_32bit_c0_register($15, 1) +#define write_c0_ebase(val) __write_32bit_c0_register($15, 1, val) + +/* + * Macros to access the floating point coprocessor control registers + */ +#define read_32bit_cp1_register(source) \ +({ int __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\treorder\n\t" \ + "cfc1\t%0,"STR(source)"\n\t" \ + ".set\tpop" \ + : "=r" (__res)); \ + __res;}) + +#define rddsp(mask) \ +({ \ + unsigned int __res; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " # rddsp $1, %x1 \n" \ + " .word 0x7c000cb8 | (%x1 << 16) \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__res) \ + : "i" (mask)); \ + __res; \ +}) + +#define wrdsp(val, mask) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " # wrdsp $1, %x1 \n" \ + " .word 0x7c2004f8 | (%x1 << 11) \n" \ + " .set pop \n" \ + : \ + : "r" (val), "i" (mask)); \ +} while (0) + +#if 0 /* Need DSP ASE capable assembler ... */ +#define mflo0() ({ long mflo0; __asm__("mflo %0, $ac0" : "=r" (mflo0)); mflo0;}) +#define mflo1() ({ long mflo1; __asm__("mflo %0, $ac1" : "=r" (mflo1)); mflo1;}) +#define mflo2() ({ long mflo2; __asm__("mflo %0, $ac2" : "=r" (mflo2)); mflo2;}) +#define mflo3() ({ long mflo3; __asm__("mflo %0, $ac3" : "=r" (mflo3)); mflo3;}) + +#define mfhi0() ({ long mfhi0; __asm__("mfhi %0, $ac0" : "=r" (mfhi0)); mfhi0;}) +#define mfhi1() ({ long mfhi1; __asm__("mfhi %0, $ac1" : "=r" (mfhi1)); mfhi1;}) +#define mfhi2() ({ long mfhi2; __asm__("mfhi %0, $ac2" : "=r" (mfhi2)); mfhi2;}) +#define mfhi3() ({ long mfhi3; __asm__("mfhi %0, $ac3" : "=r" (mfhi3)); mfhi3;}) + +#define mtlo0(x) __asm__("mtlo %0, $ac0" ::"r" (x)) +#define mtlo1(x) __asm__("mtlo %0, $ac1" ::"r" (x)) +#define mtlo2(x) __asm__("mtlo %0, $ac2" ::"r" (x)) +#define mtlo3(x) __asm__("mtlo %0, $ac3" ::"r" (x)) + +#define mthi0(x) __asm__("mthi %0, $ac0" ::"r" (x)) +#define mthi1(x) __asm__("mthi %0, $ac1" ::"r" (x)) +#define mthi2(x) __asm__("mthi %0, $ac2" ::"r" (x)) +#define mthi3(x) __asm__("mthi %0, $ac3" ::"r" (x)) + +#else + +#define mfhi0() \ +({ \ + unsigned long __treg; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " # mfhi %0, $ac0 \n" \ + " .word 0x00000810 \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__treg)); \ + __treg; \ +}) + +#define mfhi1() \ +({ \ + unsigned long __treg; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " # mfhi %0, $ac1 \n" \ + " .word 0x00200810 \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__treg)); \ + __treg; \ +}) + +#define mfhi2() \ +({ \ + unsigned long __treg; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " # mfhi %0, $ac2 \n" \ + " .word 0x00400810 \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__treg)); \ + __treg; \ +}) + +#define mfhi3() \ +({ \ + unsigned long __treg; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " # mfhi %0, $ac3 \n" \ + " .word 0x00600810 \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__treg)); \ + __treg; \ +}) + +#define mflo0() \ +({ \ + unsigned long __treg; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " # mflo %0, $ac0 \n" \ + " .word 0x00000812 \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__treg)); \ + __treg; \ +}) + +#define mflo1() \ +({ \ + unsigned long __treg; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " # mflo %0, $ac1 \n" \ + " .word 0x00200812 \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__treg)); \ + __treg; \ +}) + +#define mflo2() \ +({ \ + unsigned long __treg; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " # mflo %0, $ac2 \n" \ + " .word 0x00400812 \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__treg)); \ + __treg; \ +}) + +#define mflo3() \ +({ \ + unsigned long __treg; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " # mflo %0, $ac3 \n" \ + " .word 0x00600812 \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__treg)); \ + __treg; \ +}) + +#define mthi0(x) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " # mthi $1, $ac0 \n" \ + " .word 0x00200011 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +} while (0) + +#define mthi1(x) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " # mthi $1, $ac1 \n" \ + " .word 0x00200811 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +} while (0) + +#define mthi2(x) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " # mthi $1, $ac2 \n" \ + " .word 0x00201011 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +} while (0) + +#define mthi3(x) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " # mthi $1, $ac3 \n" \ + " .word 0x00201811 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +} while (0) + +#define mtlo0(x) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " # mtlo $1, $ac0 \n" \ + " .word 0x00200013 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +} while (0) + +#define mtlo1(x) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " # mtlo $1, $ac1 \n" \ + " .word 0x00200813 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +} while (0) + +#define mtlo2(x) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " # mtlo $1, $ac2 \n" \ + " .word 0x00201013 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +} while (0) + +#define mtlo3(x) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " # mtlo $1, $ac3 \n" \ + " .word 0x00201813 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +} while (0) + +#endif + +/* + * TLB operations. + * + * It is responsibility of the caller to take care of any TLB hazards. + */ +static inline void tlb_probe(void) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + "tlbp\n\t" + ".set reorder"); +} + +static inline void tlb_read(void) +{ +#if MIPS34K_MISSED_ITLB_WAR + int res = 0; + + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " .set noat \n" + " .set mips32r2 \n" + " .word 0x41610001 # dvpe $1 \n" + " move %0, $1 \n" + " ehb \n" + " .set pop \n" + : "=r" (res)); + + instruction_hazard(); +#endif + + __asm__ __volatile__( + ".set noreorder\n\t" + "tlbr\n\t" + ".set reorder"); + +#if MIPS34K_MISSED_ITLB_WAR + if ((res & _ULCAST_(1))) + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " .set noat \n" + " .set mips32r2 \n" + " .word 0x41600021 # evpe \n" + " ehb \n" + " .set pop \n"); +#endif +} + +static inline void tlb_write_indexed(void) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + "tlbwi\n\t" + ".set reorder"); +} + +static inline void tlb_write_random(void) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + "tlbwr\n\t" + ".set reorder"); +} + +/* + * Manipulate bits in a c0 register. + */ +#ifndef CONFIG_MIPS_MT_SMTC +/* + * SMTC Linux requires shutting-down microthread scheduling + * during CP0 register read-modify-write sequences. + */ +#define __BUILD_SET_C0(name) \ +static inline unsigned int \ +set_c0_##name(unsigned int set) \ +{ \ + unsigned int res; \ + \ + res = read_c0_##name(); \ + res |= set; \ + write_c0_##name(res); \ + \ + return res; \ +} \ + \ +static inline unsigned int \ +clear_c0_##name(unsigned int clear) \ +{ \ + unsigned int res; \ + \ + res = read_c0_##name(); \ + res &= ~clear; \ + write_c0_##name(res); \ + \ + return res; \ +} \ + \ +static inline unsigned int \ +change_c0_##name(unsigned int change, unsigned int new) \ +{ \ + unsigned int res; \ + \ + res = read_c0_##name(); \ + res &= ~change; \ + res |= (new & change); \ + write_c0_##name(res); \ + \ + return res; \ +} + +#else /* SMTC versions that manage MT scheduling */ + +#include + +/* + * This is a duplicate of dmt() in mipsmtregs.h to avoid problems with + * header file recursion. + */ +static inline unsigned int __dmt(void) +{ + int res; + + __asm__ __volatile__( + " .set push \n" + " .set mips32r2 \n" + " .set noat \n" + " .word 0x41610BC1 # dmt $1 \n" + " ehb \n" + " move %0, $1 \n" + " .set pop \n" + : "=r" (res)); + + instruction_hazard(); + + return res; +} + +#define __VPECONTROL_TE_SHIFT 15 +#define __VPECONTROL_TE (1UL << __VPECONTROL_TE_SHIFT) + +#define __EMT_ENABLE __VPECONTROL_TE + +static inline void __emt(unsigned int previous) +{ + if ((previous & __EMT_ENABLE)) + __asm__ __volatile__( + " .set mips32r2 \n" + " .word 0x41600be1 # emt \n" + " ehb \n" + " .set mips0 \n"); +} + +static inline void __ehb(void) +{ + __asm__ __volatile__( + " .set mips32r2 \n" + " ehb \n" " .set mips0 \n"); +} + +/* + * Note that local_irq_save/restore affect TC-specific IXMT state, + * not Status.IE as in non-SMTC kernel. + */ + +#define __BUILD_SET_C0(name) \ +static inline unsigned int \ +set_c0_##name(unsigned int set) \ +{ \ + unsigned int res; \ + unsigned int omt; \ + unsigned long flags; \ + \ + local_irq_save(flags); \ + omt = __dmt(); \ + res = read_c0_##name(); \ + res |= set; \ + write_c0_##name(res); \ + __emt(omt); \ + local_irq_restore(flags); \ + \ + return res; \ +} \ + \ +static inline unsigned int \ +clear_c0_##name(unsigned int clear) \ +{ \ + unsigned int res; \ + unsigned int omt; \ + unsigned long flags; \ + \ + local_irq_save(flags); \ + omt = __dmt(); \ + res = read_c0_##name(); \ + res &= ~clear; \ + write_c0_##name(res); \ + __emt(omt); \ + local_irq_restore(flags); \ + \ + return res; \ +} \ + \ +static inline unsigned int \ +change_c0_##name(unsigned int change, unsigned int new) \ +{ \ + unsigned int res; \ + unsigned int omt; \ + unsigned long flags; \ + \ + local_irq_save(flags); \ + \ + omt = __dmt(); \ + res = read_c0_##name(); \ + res &= ~change; \ + res |= (new & change); \ + write_c0_##name(res); \ + __emt(omt); \ + local_irq_restore(flags); \ + \ + return res; \ +} +#endif + +__BUILD_SET_C0(status) +__BUILD_SET_C0(cause) +__BUILD_SET_C0(config) +__BUILD_SET_C0(intcontrol) +__BUILD_SET_C0(intctl) +__BUILD_SET_C0(srsmap) + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASM_MIPSREGS_H */ diff --git a/include/asm/regdef.h b/include/asm/regdef.h new file mode 100644 index 0000000..af2e6ea --- /dev/null +++ b/include/asm/regdef.h @@ -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 + +#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 */ diff --git a/include/asm/sgidefs.h b/include/asm/sgidefs.h new file mode 100644 index 0000000..5be81f8 --- /dev/null +++ b/include/asm/sgidefs.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 */ diff --git a/include/elf.h b/include/elf.h new file mode 100644 index 0000000..74752cc --- /dev/null +++ b/include/elf.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 + +/* 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 */ diff --git a/include/elf_loader.h b/include/elf_loader.h new file mode 100644 index 0000000..85e651c --- /dev/null +++ b/include/elf_loader.h @@ -0,0 +1,11 @@ +#ifndef _ELF_LOADER_H +#define _ELF_LOADER_H + +#include + +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 */ diff --git a/include/elf_mips.h b/include/elf_mips.h new file mode 100644 index 0000000..cf52526 --- /dev/null +++ b/include/elf_mips.h @@ -0,0 +1,9 @@ +#ifndef _ELF_MIPS_H +#define _ELF_MIPS_H + +#include + +/* Machine-specific defines */ +#define ELF_MIPS_EMACHINE_ID 8 /* expected EMACHINE ID (Cisco breaks this) */ + +#endif /* _ELF_MIPS_H */ diff --git a/include/printf.h b/include/printf.h new file mode 100644 index 0000000..cb4e707 --- /dev/null +++ b/include/printf.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 */ diff --git a/include/promlib.h b/include/promlib.h new file mode 100644 index 0000000..9a61951 --- /dev/null +++ b/include/promlib.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 */ diff --git a/include/storage/storage.h b/include/storage/storage.h new file mode 100644 index 0000000..41a6bea --- /dev/null +++ b/include/storage/storage.h @@ -0,0 +1,19 @@ +#ifndef _STORAGE_STORAGE_H +#define _STORAGE_STORAGE_H + +#include + +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 */ diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..33bc707 --- /dev/null +++ b/include/string.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 */ diff --git a/include/types.h b/include/types.h new file mode 100644 index 0000000..49fe143 --- /dev/null +++ b/include/types.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 */ diff --git a/main.c b/main.c new file mode 100644 index 0000000..837b41f --- /dev/null +++ b/main.c @@ -0,0 +1,193 @@ +/* CiscoLoad - Bootloader for Cisco Routers + * (c) 2008 Philippe Vachon + * Licensed under the GNU General Public License v2 + */ +#include +#include +#include +#include +#include +#include + +/** + * 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 */ +} diff --git a/printf.c b/printf.c new file mode 100644 index 0000000..6661a41 --- /dev/null +++ b/printf.c @@ -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 +#include + +#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; +} diff --git a/promlib.c b/promlib.c new file mode 100644 index 0000000..8e44e4d --- /dev/null +++ b/promlib.c @@ -0,0 +1,182 @@ +/** + * PROM Library for Cisco Systems 3600 Series Routers + * (C) 2008 Philippe Vachon + * ----------------------------------------------------------- + */ + +/** + * Calling convention: + * a0 - syscall number + * a1 - arg1 ... etc + * v0 - returned value from syscall + */ + +#include + +/* 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; +} diff --git a/second/Makefile b/second/Makefile new file mode 100644 index 0000000..dee8ecd --- /dev/null +++ b/second/Makefile @@ -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 diff --git a/second/ciscoload.elf b/second/ciscoload.elf new file mode 100755 index 0000000..568cba9 Binary files /dev/null and b/second/ciscoload.elf differ diff --git a/second/ciscoload.two b/second/ciscoload.two new file mode 100755 index 0000000..5053c7f Binary files /dev/null and b/second/ciscoload.two differ diff --git a/second/kcopy.S b/second/kcopy.S new file mode 100644 index 0000000..d49481d --- /dev/null +++ b/second/kcopy.S @@ -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 + * Licensed under the GNU General Public License v3. See COPYING in the + * source distribution for more details. + */ + +#include +#include + +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) diff --git a/second/kcopy.o b/second/kcopy.o new file mode 100644 index 0000000..90aa5a3 Binary files /dev/null and b/second/kcopy.o differ diff --git a/start.S b/start.S new file mode 100644 index 0000000..1409c3c --- /dev/null +++ b/start.S @@ -0,0 +1,52 @@ +/* Initial entry point for ciscoboot. Sets up some stack at 0x80008000 + * and jumps to main + */ + +#include +#include + +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)