linux/arch/x86/boot/tools/build.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 1991, 1992  Linus Torvalds
   3 *  Copyright (C) 1997 Martin Mares
   4 *  Copyright (C) 2007 H. Peter Anvin
   5 */
   6
   7/*
   8 * This file builds a disk-image from two different files:
   9 *
  10 * - setup: 8086 machine code, sets up system parm
  11 * - system: 80386 code for actual system
  12 *
  13 * It does some checking that all files are of the correct type, and
  14 * just writes the result to stdout, removing headers and padding to
  15 * the right amount. It also writes some system data to stderr.
  16 */
  17
  18/*
  19 * Changes by tytso to allow root device specification
  20 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  21 * Cross compiling fixes by Gertjan van Wingerde, July 1996
  22 * Rewritten by Martin Mares, April 1997
  23 * Substantially overhauled by H. Peter Anvin, April 2007
  24 */
  25
  26#include <stdio.h>
  27#include <string.h>
  28#include <stdlib.h>
  29#include <stdarg.h>
  30#include <sys/types.h>
  31#include <sys/stat.h>
  32#include <unistd.h>
  33#include <fcntl.h>
  34#include <sys/mman.h>
  35#include <tools/le_byteshift.h>
  36
  37typedef unsigned char  u8;
  38typedef unsigned short u16;
  39typedef unsigned int   u32;
  40
  41#define DEFAULT_MAJOR_ROOT 0
  42#define DEFAULT_MINOR_ROOT 0
  43#define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT)
  44
  45/* Minimal number of setup sectors */
  46#define SETUP_SECT_MIN 5
  47#define SETUP_SECT_MAX 64
  48
  49/* This must be large enough to hold the entire setup */
  50u8 buf[SETUP_SECT_MAX*512];
  51int is_big_kernel;
  52
  53#define PECOFF_RELOC_RESERVE 0x20
  54
  55/*----------------------------------------------------------------------*/
  56
  57static const u32 crctab32[] = {
  58        0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
  59        0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
  60        0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
  61        0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
  62        0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
  63        0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
  64        0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
  65        0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
  66        0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
  67        0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
  68        0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
  69        0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
  70        0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
  71        0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
  72        0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
  73        0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
  74        0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
  75        0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
  76        0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
  77        0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
  78        0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
  79        0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
  80        0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
  81        0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
  82        0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
  83        0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
  84        0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
  85        0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
  86        0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
  87        0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
  88        0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
  89        0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
  90        0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
  91        0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
  92        0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
  93        0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
  94        0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
  95        0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
  96        0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
  97        0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
  98        0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
  99        0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
 100        0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
 101        0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
 102        0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
 103        0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
 104        0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
 105        0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
 106        0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
 107        0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
 108        0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
 109        0x2d02ef8d
 110};
 111
 112static u32 partial_crc32_one(u8 c, u32 crc)
 113{
 114        return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
 115}
 116
 117static u32 partial_crc32(const u8 *s, int len, u32 crc)
 118{
 119        while (len--)
 120                crc = partial_crc32_one(*s++, crc);
 121        return crc;
 122}
 123
 124static void die(const char * str, ...)
 125{
 126        va_list args;
 127        va_start(args, str);
 128        vfprintf(stderr, str, args);
 129        fputc('\n', stderr);
 130        exit(1);
 131}
 132
 133static void usage(void)
 134{
 135        die("Usage: build setup system [> image]");
 136}
 137
 138#ifdef CONFIG_EFI_STUB
 139
 140static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
 141{
 142        unsigned int pe_header;
 143        unsigned short num_sections;
 144        u8 *section;
 145
 146        pe_header = get_unaligned_le32(&buf[0x3c]);
 147        num_sections = get_unaligned_le16(&buf[pe_header + 6]);
 148
 149#ifdef CONFIG_X86_32
 150        section = &buf[pe_header + 0xa8];
 151#else
 152        section = &buf[pe_header + 0xb8];
 153#endif
 154
 155        while (num_sections > 0) {
 156                if (strncmp((char*)section, section_name, 8) == 0) {
 157                        /* section header size field */
 158                        put_unaligned_le32(size, section + 0x8);
 159
 160                        /* section header vma field */
 161                        put_unaligned_le32(offset, section + 0xc);
 162
 163                        /* section header 'size of initialised data' field */
 164                        put_unaligned_le32(size, section + 0x10);
 165
 166                        /* section header 'file offset' field */
 167                        put_unaligned_le32(offset, section + 0x14);
 168
 169                        break;
 170                }
 171                section += 0x28;
 172                num_sections--;
 173        }
 174}
 175
 176static void update_pecoff_setup_and_reloc(unsigned int size)
 177{
 178        u32 setup_offset = 0x200;
 179        u32 reloc_offset = size - PECOFF_RELOC_RESERVE;
 180        u32 setup_size = reloc_offset - setup_offset;
 181
 182        update_pecoff_section_header(".setup", setup_offset, setup_size);
 183        update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
 184
 185        /*
 186         * Modify .reloc section contents with a single entry. The
 187         * relocation is applied to offset 10 of the relocation section.
 188         */
 189        put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
 190        put_unaligned_le32(10, &buf[reloc_offset + 4]);
 191}
 192
 193static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
 194{
 195        unsigned int pe_header;
 196        unsigned int text_sz = file_sz - text_start;
 197
 198        pe_header = get_unaligned_le32(&buf[0x3c]);
 199
 200        /* Size of image */
 201        put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);
 202
 203        /*
 204         * Size of code: Subtract the size of the first sector (512 bytes)
 205         * which includes the header.
 206         */
 207        put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]);
 208
 209#ifdef CONFIG_X86_32
 210        /*
 211         * Address of entry point.
 212         *
 213         * The EFI stub entry point is +16 bytes from the start of
 214         * the .text section.
 215         */
 216        put_unaligned_le32(text_start + 16, &buf[pe_header + 0x28]);
 217#else
 218        /*
 219         * Address of entry point. startup_32 is at the beginning and
 220         * the 64-bit entry point (startup_64) is always 512 bytes
 221         * after. The EFI stub entry point is 16 bytes after that, as
 222         * the first instruction allows legacy loaders to jump over
 223         * the EFI stub initialisation
 224         */
 225        put_unaligned_le32(text_start + 528, &buf[pe_header + 0x28]);
 226#endif /* CONFIG_X86_32 */
 227
 228        update_pecoff_section_header(".text", text_start, text_sz);
 229}
 230
 231#endif /* CONFIG_EFI_STUB */
 232
 233int main(int argc, char ** argv)
 234{
 235        unsigned int i, sz, setup_sectors;
 236        int c;
 237        u32 sys_size;
 238        struct stat sb;
 239        FILE *file;
 240        int fd;
 241        void *kernel;
 242        u32 crc = 0xffffffffUL;
 243
 244        if (argc != 3)
 245                usage();
 246
 247        /* Copy the setup code */
 248        file = fopen(argv[1], "r");
 249        if (!file)
 250                die("Unable to open `%s': %m", argv[1]);
 251        c = fread(buf, 1, sizeof(buf), file);
 252        if (ferror(file))
 253                die("read-error on `setup'");
 254        if (c < 1024)
 255                die("The setup must be at least 1024 bytes");
 256        if (get_unaligned_le16(&buf[510]) != 0xAA55)
 257                die("Boot block hasn't got boot flag (0xAA55)");
 258        fclose(file);
 259
 260#ifdef CONFIG_EFI_STUB
 261        /* Reserve 0x20 bytes for .reloc section */
 262        memset(buf+c, 0, PECOFF_RELOC_RESERVE);
 263        c += PECOFF_RELOC_RESERVE;
 264#endif
 265
 266        /* Pad unused space with zeros */
 267        setup_sectors = (c + 511) / 512;
 268        if (setup_sectors < SETUP_SECT_MIN)
 269                setup_sectors = SETUP_SECT_MIN;
 270        i = setup_sectors*512;
 271        memset(buf+c, 0, i-c);
 272
 273#ifdef CONFIG_EFI_STUB
 274        update_pecoff_setup_and_reloc(i);
 275#endif
 276
 277        /* Set the default root device */
 278        put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
 279
 280        fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
 281
 282        /* Open and stat the kernel file */
 283        fd = open(argv[2], O_RDONLY);
 284        if (fd < 0)
 285                die("Unable to open `%s': %m", argv[2]);
 286        if (fstat(fd, &sb))
 287                die("Unable to stat `%s': %m", argv[2]);
 288        sz = sb.st_size;
 289        fprintf (stderr, "System is %d kB\n", (sz+1023)/1024);
 290        kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
 291        if (kernel == MAP_FAILED)
 292                die("Unable to mmap '%s': %m", argv[2]);
 293        /* Number of 16-byte paragraphs, including space for a 4-byte CRC */
 294        sys_size = (sz + 15 + 4) / 16;
 295
 296        /* Patch the setup code with the appropriate size parameters */
 297        buf[0x1f1] = setup_sectors-1;
 298        put_unaligned_le32(sys_size, &buf[0x1f4]);
 299
 300#ifdef CONFIG_EFI_STUB
 301        update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz));
 302#endif
 303
 304        crc = partial_crc32(buf, i, crc);
 305        if (fwrite(buf, 1, i, stdout) != i)
 306                die("Writing setup failed");
 307
 308        /* Copy the kernel code */
 309        crc = partial_crc32(kernel, sz, crc);
 310        if (fwrite(kernel, 1, sz, stdout) != sz)
 311                die("Writing kernel failed");
 312
 313        /* Add padding leaving 4 bytes for the checksum */
 314        while (sz++ < (sys_size*16) - 4) {
 315                crc = partial_crc32_one('\0', crc);
 316                if (fwrite("\0", 1, 1, stdout) != 1)
 317                        die("Writing padding failed");
 318        }
 319
 320        /* Write the CRC */
 321        fprintf(stderr, "CRC %x\n", crc);
 322        put_unaligned_le32(crc, buf);
 323        if (fwrite(buf, 1, 4, stdout) != 4)
 324                die("Writing CRC failed");
 325
 326        close(fd);
 327
 328        /* Everything is OK */
 329        return 0;
 330}
 331