root/arch/x86/boot/tools/build.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. partial_crc32_one
  2. partial_crc32
  3. die
  4. usage
  5. update_pecoff_section_header_fields
  6. update_pecoff_section_header
  7. update_pecoff_setup_and_reloc
  8. update_pecoff_text
  9. update_pecoff_bss
  10. reserve_pecoff_reloc_section
  11. efi_stub_defaults
  12. efi_stub_entry_update
  13. update_pecoff_setup_and_reloc
  14. update_pecoff_text
  15. update_pecoff_bss
  16. efi_stub_defaults
  17. efi_stub_entry_update
  18. reserve_pecoff_reloc_section
  19. parse_zoffset
  20. main

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

/* [<][>][^][v][top][bottom][index][help] */