/*- * Copyright (c) 1997 Causality Limited. * All rights reserved. * * This code was written by Mark Brinicombe * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Causality Limited. * 4. The name of Causality Limited may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Angel communication code * * Copyright 1997 Perihelion Software Ltd. * All Rights Reserved. */ /* Modified by Deborah A. Wallach (kerr@pa.dec.com) 12/22/97 */ #include #include #include #include #include #include "options.h" #define QUIET 1 #define swap(x) x; int verbose = 0; struct bootoptions boot_options = { DEFAULT_SERIAL_DEVICE, DEFAULT_SERIAL_OPTIONS, NULL, 0, 0, DEFAULT_BASE_ADDRESS, DEFAULT_ENTRY_ADDRESS, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, NULL, DEFAULT_BAUD_RATE, NULL, 0, 0 }; void usage(void); int boot(int serial_fd, int image_fd, int o_image_fd, struct bootoptions *boot_options); int parse_options_file(char *file, struct bootoptions *boot_options, int flags); void dump_options(struct bootoptions *boot_options); extern int Angel_SendMessage(int serial_fd, unsigned char *buf, unsigned int count); extern int Angel_DumpPacket(int serial_fd); extern int Angel_SetBaudrate(int serial_fd, int rate, int fifoon); int main(int argc, char *argv[]) { char *image; int serial_fd; int image_fd, o_image_fd = 0; int ch; parse_options_file(".angelrc", &boot_options, QUIET); while ((ch = getopt(argc, argv, "d:c:b:s:o:e:f:0:1:2:3:x:vhS:O:B:")) != -1) { switch(ch) { case 'v': verbose = 1; break; case 'd': boot_options.serial_device = optarg; break; case 'c': boot_options.serial_options = optarg; break; case 'f': parse_options_file(optarg, &boot_options, 0); break; case 'b': boot_options.base_address = strtoul(optarg, NULL, 16); break; case 'e': boot_options.entry_address = strtoul(optarg, NULL, 16); break; case 's': boot_options.image_size = strtoul(optarg, NULL, 16); break; case 'o': boot_options.image_offset = strtoul(optarg, NULL, 16); break; case '0': boot_options.regs[0] = strtoul(optarg, NULL, 16); break; case '1': boot_options.regs[1] = strtoul(optarg, NULL, 16); break; case '2': boot_options.regs[2] = strtoul(optarg, NULL, 16); break; case '3': boot_options.regs[3] = strtoul(optarg, NULL, 16); break; case 'x': boot_options.exec = optarg; break; case 'h': usage(); break; case 'S': boot_options.baud_rate = strtoul(optarg, NULL, 10); break; case 'O': boot_options.o_image_file = optarg; break; case 'B': boot_options.o_base_address = strtoul(optarg, NULL, 16); break; } } argc -= optind; argv += optind; if (argc == 0 && boot_options.image_file == NULL) usage(); if (argc > 0) { boot_options.image_file = argv[0]; ++argv; --argc; } if (verbose) dump_options(&boot_options); serial_fd = serial_open(boot_options.serial_device, boot_options.serial_options); if (serial_fd == -1) exit(1); image_fd = open(boot_options.image_file, O_RDONLY); if (image_fd == -1) { fprintf(stderr, "Cannot read image file\n"); return(1); } if (boot_options.image_size == 0) { off_t size; size = lseek(image_fd, 0, SEEK_END); if (size > 0xffffffffL) { fprintf(stderr, "Image file is too big\n"); return(1); } boot_options.image_size = (unsigned int)size; } if (lseek(image_fd, (off_t)boot_options.image_offset, SEEK_SET) != (off_t)boot_options.image_offset) { fprintf(stderr, "Cannot seek to requested image offset\n"); return(1); } if (boot_options.o_image_file) { o_image_fd = open(boot_options.o_image_file, O_RDONLY); if (o_image_fd == -1) { fprintf(stderr, "Cannot read other image file\n"); return(1); } if (boot_options.o_image_size == 0) { off_t size; size = lseek(o_image_fd, 0, SEEK_END); if (size > 0xffffffffL) { fprintf(stderr, "Image file is too big\n"); return(1); } boot_options.o_image_size = (unsigned int)size; } if (lseek(o_image_fd, (off_t)0, SEEK_SET) != (off_t)0) { fprintf(stderr, "Cannot seek to requested image offset\n"); return(1); } } boot(serial_fd, image_fd, o_image_fd, &boot_options); close(image_fd); if (boot_options.o_image_file) close(o_image_fd); serial_close(serial_fd); if (boot_options.exec) execlp(boot_options.exec, boot_options.exec, NULL); } void usage(void) { fprintf(stderr, "Usage:\tangelboot [-v] [-h] [-f options file] [-d device] [-c options] [-b base] [-s size] [-o offset] [-e entry] [-S baudrate] [-O otherimage] [-B other base] image\n"); exit(0); } int boot(int serial_fd, int image_fd, int o_image_fd, struct bootoptions *boot_options) { unsigned char Home, Oppo; unsigned char AngelMsg[4096]; unsigned char *p, *r; int l, i, reply, Size; unsigned int regs[6]; if (verbose) printf("Negotiating..."); p = AngelMsg; /******* LEN *******/ *p++ = 0x00; *p++ = 0x00; *p++ = 0x24; /* Chan */ /* Home */ /* Opp */ /* Flags */ *p++ = 0x03; *p++ = 0x01; *p++ = 0x00; *p++ = 0x01; /*---- REASON ---------*/ /* Channel */ /* Direct */ *p++ = 0x05; *p++ = 0x00; *p++ = 0x03; *p++ = 0x00; /* Param negotiate */ *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* ID */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo1 */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo2 */ *p++ = 0x01; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* # parameter blks */ *p++ = 0x00; *p++ = 0xc0; *p++ = 0x00; *p++ = 0x00; /* Baudrate */ *p++ = 0x01; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* # options */ { int baud = htonl(boot_options->baud_rate); *p++ = (unsigned char)((0xff000000&baud)>>24); *p++ = (unsigned char)((0x00ff0000&baud)>>16); *p++ = (unsigned char)((0x0000ff00&baud)>> 8); *p++ = (unsigned char)((0x000000ff&baud)>> 0); } Angel_SendMessage(serial_fd, AngelMsg, 39); /* Right now I don't care, just consume the packet. Of course if you ask for * a baud rate you can't have then you'll die soon. */ Angel_DumpPacket(serial_fd); Angel_SetBaudrate(serial_fd, boot_options->baud_rate, 0); /* After issue of Param Neg, need to wait while target switches */ sleep(1); /* Now check all is well */ if (verbose) printf("Issuing 'ping'..."); p = AngelMsg; *p++ = 0x00; *p++ = 0x00; *p++ = 0x14; *p++ = 0x03; *p++ = 0x02; *p++ = 0x00; *p++ = 0x01; *p++ = 0x06; *p++ = 0x00; *p++ = 0x03; *p++ = 0x00; /* Ping */ *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* ID */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo1 */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo2 */ Angel_SendMessage(serial_fd, AngelMsg, 23); Angel_DumpPacket(serial_fd); if (verbose) printf("Issue reset..."); p = AngelMsg; *p++ = 0x00; *p++ = 0x00; *p++ = 0x18; *p++ = 0x03; *p++ = 0x01; *p++ = 0x00; *p++ = 0x01; *p++ = 0x03; *p++ = 0x00; *p++ = 0x03; *p++ = 0x00; /* Reset */ *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* ID */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo1 */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo2 */ *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* ID */ Angel_SendMessage(serial_fd, AngelMsg, 27); Angel_DumpPacket(serial_fd); /* ADP_Booted reply */ Angel_DumpPacket(serial_fd); printf("Initialising execution environment.\n"); /* Setup register contents required for kernel startup */ regs[0] = boot_options->regs[0]; /* r0 */ regs[1] = boot_options->regs[1]; /* r1 */ regs[2] = boot_options->regs[2]; /* r2 */ regs[3] = boot_options->regs[3]; /* r3 */ regs[4] = swap(boot_options->entry_address); /* pc = kernel start address */ regs[5] = swap(0xD3L); /* cpsr = SVC32 mode FIQ/IRQ disabled */ p = AngelMsg; *p++ = 0x00; *p++ = 0x00; *p++ = 0x18; *p++ = 0x04; *p++ = 0x02; *p++ = 0x00; *p++ = 0x01; *p++ = 0x00; *p++ = 0x00; *p++ = 0x04; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; Angel_SendMessage(serial_fd, AngelMsg, (7 + 16 + 4)); /* Okay we're off the boot channel and onto ADP proper now */ Home = 0x01; Oppo = 0x00; p = AngelMsg; r = (unsigned char *) regs; *p++ = 0x00; *p++ = 0x00; *p++ = 0x31; *p++ = 0x01; *p++ = Home; *p++ = Oppo; *p++ = 0x01; /* CHANNEL */ *p++ = 0x06; *p++ = 0x00; *p++ = 0x01; *p++ = 0x00; /* CPUWrite, HADP */ *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* ID */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo1 */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo2 */ *p++ = 0xff; /* current mode */ *p++ = 0x0F; *p++ = 0x00; *p++ = 0x03; *p++ = 0x00; /* Write a0 - a3, pc, cpsr */ /* Transfer register data */ for(i = 0; i < 6 * sizeof(int); i++) *p++ = *r++; Angel_SendMessage(serial_fd, AngelMsg, (7 + 16 + 1 + 4 + 24)); Angel_DumpPacket(serial_fd); Home += 1; Oppo += 1; /* Send that them there nucleus down */ printf("Downloading image size 0x%lx to 0x%x\n", boot_options->image_size, boot_options->base_address); l = boot_options->base_address; i = 0; while (boot_options->image_size > 0) { p = AngelMsg; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x01; *p++ = Home; *p++ = Oppo; *p++ = 0x01; *p++ = 0x04; *p++ = 0x00; *p++ = 0x01; *p++ = 0x00; /* ADP_Write, HADP */ *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* ID */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo1 */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo2 */ /* Address */ *p++ = (char) (l & 0xff); *p++ = (char) ((l >> 8) & 0xff); *p++ = (char) ((l >> 16) & 0xff); *p++ = (char) ((l >> 24) & 0xff); if ((Size = read(image_fd, (p + 4), 2016)) == 0) { fprintf(stderr, "Failed to read image data\n"); return(1); } /* Num bytes */ *p++ = (char) (Size & 0xff); *p++ = (char) ((Size >> 8) & 0xff); *p++ = (char) ((Size >> 16) & 0xff); *p++ = (char) ((Size >> 24) & 0xff); /* Fill in size */ p = &AngelMsg[1]; *p++ = (char)(((Size + 4 + 16 + 8) >> 8) & 0xff); *p++ = (char)((Size + 4 + 16 + 8) & 0xff); Angel_SendMessage(serial_fd, AngelMsg, (7 + 16 + 8 + Size)); reply = Angel_DumpPacket(serial_fd); putchar('.');fflush(stdout); /* What does this mean ? failure ? */ if (reply == 11) return(1); Home += 1; Oppo += 1; l += Size; boot_options->image_size -= Size; i++; } printf("\n\r"); /* ------------------------------------------------------------------------- */ if(boot_options->o_image_file) { /* Send the other file down */ printf("Downloading other image size 0x%lx to 0x%x\n", boot_options->o_image_size, boot_options->o_base_address); l = boot_options->o_base_address; i = 0; while (boot_options->o_image_size > 0) { p = AngelMsg; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x01; *p++ = Home; *p++ = Oppo; *p++ = 0x01; *p++ = 0x04; *p++ = 0x00; *p++ = 0x01; *p++ = 0x00; /* ADP_Write, HADP */ *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* ID */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo1 */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo2 */ /* Address */ *p++ = (char) (l & 0xff); *p++ = (char) ((l >> 8) & 0xff); *p++ = (char) ((l >> 16) & 0xff); *p++ = (char) ((l >> 24) & 0xff); if ((Size = read(o_image_fd, (p + 4), 2016)) == 0) { fprintf(stderr, "Failed to read image data\n"); return(1); } /* Num bytes */ *p++ = (char) (Size & 0xff); *p++ = (char) ((Size >> 8) & 0xff); *p++ = (char) ((Size >> 16) & 0xff); *p++ = (char) ((Size >> 24) & 0xff); /* Fill in size */ p = &AngelMsg[1]; *p++ = (char)(((Size + 4 + 16 + 8) >> 8) & 0xff); *p++ = (char)((Size + 4 + 16 + 8) & 0xff); Angel_SendMessage(serial_fd, AngelMsg, (7 + 16 + 8 + Size)); reply = Angel_DumpPacket(serial_fd); putchar('.');fflush(stdout); /* What does this mean ? failure ? */ if (reply == 11) return(1); Home += 1; Oppo += 1; l += Size; boot_options->o_image_size -= Size; i++; } printf("\n\r"); } /* ------------------------------------------------------------------------- */ if (verbose) printf("Starting ..."); p = AngelMsg; *p++ = 0x00; *p++ = 0x00; *p++ = 0x14; *p++ = 0x01; *p++ = Home; *p++ = Oppo; *p++ = 0x01; /* CHANNEL */ *p++ = 0x0d; *p++ = 0x00; *p++ = 0x01; *p++ = 0x00; /* EXECUTE, HADP */ *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* ID */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo1 */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; /* OSInfo2 */ Angel_SendMessage(serial_fd, AngelMsg, (7 + 16)); Angel_DumpPacket(serial_fd); Home += 1; Oppo += 1; return(0); } int parse_options_file(char *file, struct bootoptions *boot_options, int flags) { if (firstfile(file) == -1) { if (! (flags & QUIET)) fprintf(stderr, "Cannot open options file %s\n", file); return(1); } yyparse(); } void dump_options(struct bootoptions *boot_options) { printf("serial device\t= %s\n", boot_options->serial_device); printf("serial options\t= %s\n", boot_options->serial_options); printf("baud rate\t= %d\n", boot_options->baud_rate); printf("image file\t= %s\n", boot_options->image_file); printf("image size\t= 0x%08x\n", boot_options->image_size); printf("image offset\t= 0x%08x\n", boot_options->image_offset); printf("base address\t= 0x%08x\n", boot_options->base_address); printf("entry address\t= 0x%08x\n", boot_options->entry_address); printf("r0\t\t= %08x\n", boot_options->regs[0]); printf("r1\t\t= %08x\n", boot_options->regs[1]); printf("r2\t\t= %08x\n", boot_options->regs[2]); printf("r3\t\t= %08x\n", boot_options->regs[3]); printf("other image file\t= %s\n", boot_options->o_image_file); printf("other image size\t= 0x%08x\n", boot_options->o_image_size); printf("other base address\t= 0x%08x\n", boot_options->o_base_address); }