linux/Documentation/arm/SH-Mobile/vrl4.c
<<
>>
Prefs
   1/*
   2 * vrl4 format generator
   3 *
   4 * Copyright (C) 2010 Simon Horman
   5 *
   6 * This file is subject to the terms and conditions of the GNU General Public
   7 * License.  See the file "COPYING" in the main directory of this archive
   8 * for more details.
   9 */
  10
  11/*
  12 * usage: vrl4 < zImage > out
  13 *        dd if=out of=/dev/sdx bs=512 seek=1 # Write the image to sector 1
  14 *
  15 * Reads a zImage from stdin and writes a vrl4 image to stdout.
  16 * In practice this means writing a padded vrl4 header to stdout followed
  17 * by the zImage.
  18 *
  19 * The padding places the zImage at ALIGN bytes into the output.
  20 * The vrl4 uses ALIGN + START_BASE as the start_address.
  21 * This is where the mask ROM will jump to after verifying the header.
  22 *
  23 * The header sets copy_size to min(sizeof(zImage), MAX_BOOT_PROG_LEN) + ALIGN.
  24 * That is, the mask ROM will load the padded header (ALIGN bytes)
  25 * And then MAX_BOOT_PROG_LEN bytes of the image, or the entire image,
  26 * whichever is smaller.
  27 *
  28 * The zImage is not modified in any way.
  29 */
  30
  31#define _BSD_SOURCE
  32#include <endian.h>
  33#include <unistd.h>
  34#include <stdint.h>
  35#include <stdio.h>
  36#include <errno.h>
  37
  38struct hdr {
  39        uint32_t magic1;
  40        uint32_t reserved1;
  41        uint32_t magic2;
  42        uint32_t reserved2;
  43        uint16_t copy_size;
  44        uint16_t boot_options;
  45        uint32_t reserved3;
  46        uint32_t start_address;
  47        uint32_t reserved4;
  48        uint32_t reserved5;
  49        char     reserved6[308];
  50};
  51
  52#define DECLARE_HDR(h)                                  \
  53        struct hdr (h) = {                              \
  54                .magic1 =       htole32(0xea000000),    \
  55                .reserved1 =    htole32(0x56),          \
  56                .magic2 =       htole32(0xe59ff008),    \
  57                .reserved3 =    htole16(0x1) }
  58
  59/* Align to 512 bytes, the MMCIF sector size */
  60#define ALIGN_BITS      9
  61#define ALIGN           (1 << ALIGN_BITS)
  62
  63#define START_BASE      0xe55b0000
  64
  65/*
  66 * With an alignment of 512 the header uses the first sector.
  67 * There is a 128 sector (64kbyte) limit on the data loaded by the mask ROM.
  68 * So there are 127 sectors left for the boot programme. But in practice
  69 * Only a small portion of a zImage is needed, 16 sectors should be more
  70 * than enough.
  71 *
  72 * Note that this sets how much of the zImage is copied by the mask ROM.
  73 * The entire zImage is present after the header and is loaded
  74 * by the code in the boot program (which is the first portion of the zImage).
  75 */
  76#define MAX_BOOT_PROG_LEN (16 * 512)
  77
  78#define ROUND_UP(x)     ((x + ALIGN - 1) & ~(ALIGN - 1))
  79
  80ssize_t do_read(int fd, void *buf, size_t count)
  81{
  82        size_t offset = 0;
  83        ssize_t l;
  84
  85        while (offset < count) {
  86                l = read(fd, buf + offset, count - offset);
  87                if (!l)
  88                        break;
  89                if (l < 0) {
  90                        if (errno == EAGAIN || errno == EWOULDBLOCK)
  91                                continue;
  92                        perror("read");
  93                        return -1;
  94                }
  95                offset += l;
  96        }
  97
  98        return offset;
  99}
 100
 101ssize_t do_write(int fd, const void *buf, size_t count)
 102{
 103        size_t offset = 0;
 104        ssize_t l;
 105
 106        while (offset < count) {
 107                l = write(fd, buf + offset, count - offset);
 108                if (l < 0) {
 109                        if (errno == EAGAIN || errno == EWOULDBLOCK)
 110                                continue;
 111                        perror("write");
 112                        return -1;
 113                }
 114                offset += l;
 115        }
 116
 117        return offset;
 118}
 119
 120ssize_t write_zero(int fd, size_t len)
 121{
 122        size_t i = len;
 123
 124        while (i--) {
 125                const char x = 0;
 126                if (do_write(fd, &x, 1) < 0)
 127                        return -1;
 128        }
 129
 130        return len;
 131}
 132
 133int main(void)
 134{
 135        DECLARE_HDR(hdr);
 136        char boot_program[MAX_BOOT_PROG_LEN];
 137        size_t aligned_hdr_len, alligned_prog_len;
 138        ssize_t prog_len;
 139
 140        prog_len = do_read(0, boot_program, sizeof(boot_program));
 141        if (prog_len <= 0)
 142                return -1;
 143
 144        aligned_hdr_len = ROUND_UP(sizeof(hdr));
 145        hdr.start_address = htole32(START_BASE + aligned_hdr_len);
 146        alligned_prog_len = ROUND_UP(prog_len);
 147        hdr.copy_size = htole16(aligned_hdr_len + alligned_prog_len);
 148
 149        if (do_write(1, &hdr, sizeof(hdr)) < 0)
 150                return -1;
 151        if (write_zero(1, aligned_hdr_len - sizeof(hdr)) < 0)
 152                return -1;
 153
 154        if (do_write(1, boot_program, prog_len) < 0)
 155                return 1;
 156
 157        /* Write out the rest of the kernel */
 158        while (1) {
 159                prog_len = do_read(0, boot_program, sizeof(boot_program));
 160                if (prog_len < 0)
 161                        return 1;
 162                if (prog_len == 0)
 163                        break;
 164                if (do_write(1, boot_program, prog_len) < 0)
 165                        return 1;
 166        }
 167
 168        return 0;
 169}
 170