| /* |
| * 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) Hewlett-Packard (Paul Bame) paul_bame@hp.com |
| */ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <assert.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <assert.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <sys/mman.h> |
| #include "load.h" |
| #include "palo.h" |
| |
| #define B32(x) __be32_to_cpu((x)) |
| |
| /* compute the sum of words in an 4-byte aligned region */ |
| int |
| checksum(void *p, size_t len) |
| { |
| int xsum = 0; |
| int *x = (int *)p; |
| int i; |
| |
| if (0) printf("checksum(%p, %u) = ", p, len); |
| len /= 4; |
| |
| for (i = 0; i < len; i++) |
| { |
| xsum += B32(x[i]); |
| } |
| |
| if (0) printf("0x%08x\n", xsum); |
| |
| return (xsum); |
| } |
| |
| /* maximum allowed HP boot loader (IPL) size */ |
| #define MAXBLSIZE (256 * 1024) |
| |
| void |
| fix_bootloader(int out, int bootloader) |
| { |
| size_t rblsize; /* sector-rounded boot loader size */ |
| struct loadable loadable; |
| int xsum1; |
| void *blimage; |
| int r; |
| int wide; |
| |
| memset(&loadable, 0, sizeof loadable); |
| |
| r = prepare_loadable(bootloader, &loadable, &wide); |
| if (!r) |
| { |
| fprintf(stderr, "Can't grok your bootloader executable format\n"); |
| exit(2); |
| } |
| |
| rblsize = loadable.size; |
| printf("entry 0x%08x size %d\n", loadable.entry, rblsize); |
| rblsize += (FW_BLOCKSIZE - 1); |
| rblsize &= ~(FW_BLOCKSIZE - 1); |
| |
| if (loadable.entry != loadable.first) |
| { |
| fprintf(stderr, "Entry point addres 0x%08x must be the same as the lowest" |
| "address 0x%08x\n", loadable.entry, loadable.first); |
| exit(2); |
| } |
| |
| /* IPL max size is 256k */ |
| if (rblsize > MAXBLSIZE) |
| error(5, loadable.size); |
| |
| /* load the boot loader into RAM */ |
| /* WORKAROUND: since the ELF32 value of p_memsz of the iplelf binary |
| * is wrong, just use 5 times more memory here to avoid a segfault. */ |
| blimage = (void *)malloc(5*MAXBLSIZE); |
| assert(blimage != NULL); |
| if (!load_loadable(blimage, bootloader, &loadable)) |
| error(13); |
| |
| /* checksum it */ |
| xsum1 = checksum(blimage, rblsize); |
| |
| /* write checksum into RAM -- see ipl/crt0.S!!! */ |
| ((int *)blimage)[1] = B32(-xsum1); |
| |
| /* write it out */ |
| seekwrite(out, blimage, rblsize, 0); |
| close(bootloader); |
| |
| free(blimage); |
| } |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| int bootloader = -1; |
| int out = -1; |
| |
| switch(argc) |
| { |
| case 1: |
| bootloader = fileno(stdin); |
| out = fileno(stdout); |
| break; |
| case 2: |
| if ((bootloader = open(argv[1], O_RDONLY)) == -1) |
| { |
| perror(argv[1]); |
| return 2; |
| } |
| out = fileno(stdout); |
| break; |
| case 3: |
| if ((bootloader = open(argv[1], O_RDONLY)) == -1) |
| { |
| perror(argv[1]); |
| return 2; |
| } |
| if ((out = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, 0666)) == -1) |
| { |
| perror(argv[2]); |
| return 2; |
| } |
| break; |
| default: |
| fprintf(stderr, "Usage: %s [ipl [bootable_ipl]]\n", argv[0]); |
| return 3; |
| } |
| |
| fix_bootloader(out, bootloader); |
| |
| fsync(out); |
| |
| return 0; |
| } |