Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  Copyright (C) 1991, 1992  Linus Torvalds
0004  *  Copyright (C) 1997 Martin Mares
0005  *  Copyright (C) 2007 H. Peter Anvin
0006  */
0007 
0008 /*
0009  * This file builds a disk-image from three different files:
0010  *
0011  * - setup: 8086 machine code, sets up system parm
0012  * - system: 80386 code for actual system
0013  * - zoffset.h: header with ZO_* defines
0014  *
0015  * It does some checking that all files are of the correct type, and writes
0016  * the result to the specified destination, removing headers and padding to
0017  * the right amount. It also writes some system data to stdout.
0018  */
0019 
0020 /*
0021  * Changes by tytso to allow root device specification
0022  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
0023  * Cross compiling fixes by Gertjan van Wingerde, July 1996
0024  * Rewritten by Martin Mares, April 1997
0025  * Substantially overhauled by H. Peter Anvin, April 2007
0026  */
0027 
0028 #include <stdio.h>
0029 #include <string.h>
0030 #include <stdlib.h>
0031 #include <stdarg.h>
0032 #include <sys/types.h>
0033 #include <sys/stat.h>
0034 #include <unistd.h>
0035 #include <fcntl.h>
0036 #include <sys/mman.h>
0037 #include <tools/le_byteshift.h>
0038 
0039 typedef unsigned char  u8;
0040 typedef unsigned short u16;
0041 typedef unsigned int   u32;
0042 
0043 #define DEFAULT_MAJOR_ROOT 0
0044 #define DEFAULT_MINOR_ROOT 0
0045 #define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT)
0046 
0047 /* Minimal number of setup sectors */
0048 #define SETUP_SECT_MIN 5
0049 #define SETUP_SECT_MAX 64
0050 
0051 /* This must be large enough to hold the entire setup */
0052 u8 buf[SETUP_SECT_MAX*512];
0053 
0054 #define PECOFF_RELOC_RESERVE 0x20
0055 
0056 #ifdef CONFIG_EFI_MIXED
0057 #define PECOFF_COMPAT_RESERVE 0x20
0058 #else
0059 #define PECOFF_COMPAT_RESERVE 0x0
0060 #endif
0061 
0062 static unsigned long efi32_stub_entry;
0063 static unsigned long efi64_stub_entry;
0064 static unsigned long efi_pe_entry;
0065 static unsigned long efi32_pe_entry;
0066 static unsigned long kernel_info;
0067 static unsigned long startup_64;
0068 static unsigned long _ehead;
0069 static unsigned long _end;
0070 
0071 /*----------------------------------------------------------------------*/
0072 
0073 static const u32 crctab32[] = {
0074     0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
0075     0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
0076     0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
0077     0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0078     0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
0079     0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0080     0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0081     0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0082     0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
0083     0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
0084     0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
0085     0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0086     0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
0087     0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0088     0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
0089     0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0090     0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
0091     0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0092     0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
0093     0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0094     0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0095     0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
0096     0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
0097     0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0098     0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
0099     0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
0100     0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
0101     0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0102     0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
0103     0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0104     0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
0105     0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0106     0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
0107     0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
0108     0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0109     0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0110     0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
0111     0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
0112     0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
0113     0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0114     0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
0115     0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0116     0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
0117     0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0118     0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
0119     0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
0120     0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
0121     0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0122     0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0123     0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
0124     0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
0125     0x2d02ef8d
0126 };
0127 
0128 static u32 partial_crc32_one(u8 c, u32 crc)
0129 {
0130     return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
0131 }
0132 
0133 static u32 partial_crc32(const u8 *s, int len, u32 crc)
0134 {
0135     while (len--)
0136         crc = partial_crc32_one(*s++, crc);
0137     return crc;
0138 }
0139 
0140 static void die(const char * str, ...)
0141 {
0142     va_list args;
0143     va_start(args, str);
0144     vfprintf(stderr, str, args);
0145     va_end(args);
0146     fputc('\n', stderr);
0147     exit(1);
0148 }
0149 
0150 static void usage(void)
0151 {
0152     die("Usage: build setup system zoffset.h image");
0153 }
0154 
0155 #ifdef CONFIG_EFI_STUB
0156 
0157 static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset)
0158 {
0159     unsigned int pe_header;
0160     unsigned short num_sections;
0161     u8 *section;
0162 
0163     pe_header = get_unaligned_le32(&buf[0x3c]);
0164     num_sections = get_unaligned_le16(&buf[pe_header + 6]);
0165 
0166 #ifdef CONFIG_X86_32
0167     section = &buf[pe_header + 0xa8];
0168 #else
0169     section = &buf[pe_header + 0xb8];
0170 #endif
0171 
0172     while (num_sections > 0) {
0173         if (strncmp((char*)section, section_name, 8) == 0) {
0174             /* section header size field */
0175             put_unaligned_le32(size, section + 0x8);
0176 
0177             /* section header vma field */
0178             put_unaligned_le32(vma, section + 0xc);
0179 
0180             /* section header 'size of initialised data' field */
0181             put_unaligned_le32(datasz, section + 0x10);
0182 
0183             /* section header 'file offset' field */
0184             put_unaligned_le32(offset, section + 0x14);
0185 
0186             break;
0187         }
0188         section += 0x28;
0189         num_sections--;
0190     }
0191 }
0192 
0193 static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
0194 {
0195     update_pecoff_section_header_fields(section_name, offset, size, size, offset);
0196 }
0197 
0198 static void update_pecoff_setup_and_reloc(unsigned int size)
0199 {
0200     u32 setup_offset = 0x200;
0201     u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE;
0202 #ifdef CONFIG_EFI_MIXED
0203     u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE;
0204 #endif
0205     u32 setup_size = reloc_offset - setup_offset;
0206 
0207     update_pecoff_section_header(".setup", setup_offset, setup_size);
0208     update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
0209 
0210     /*
0211      * Modify .reloc section contents with a single entry. The
0212      * relocation is applied to offset 10 of the relocation section.
0213      */
0214     put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
0215     put_unaligned_le32(10, &buf[reloc_offset + 4]);
0216 
0217 #ifdef CONFIG_EFI_MIXED
0218     update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE);
0219 
0220     /*
0221      * Put the IA-32 machine type (0x14c) and the associated entry point
0222      * address in the .compat section, so loaders can figure out which other
0223      * execution modes this image supports.
0224      */
0225     buf[compat_offset] = 0x1;
0226     buf[compat_offset + 1] = 0x8;
0227     put_unaligned_le16(0x14c, &buf[compat_offset + 2]);
0228     put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]);
0229 #endif
0230 }
0231 
0232 static void update_pecoff_text(unsigned int text_start, unsigned int file_sz,
0233                    unsigned int init_sz)
0234 {
0235     unsigned int pe_header;
0236     unsigned int text_sz = file_sz - text_start;
0237     unsigned int bss_sz = init_sz - file_sz;
0238 
0239     pe_header = get_unaligned_le32(&buf[0x3c]);
0240 
0241     /*
0242      * The PE/COFF loader may load the image at an address which is
0243      * misaligned with respect to the kernel_alignment field in the setup
0244      * header.
0245      *
0246      * In order to avoid relocating the kernel to correct the misalignment,
0247      * add slack to allow the buffer to be aligned within the declared size
0248      * of the image.
0249      */
0250     bss_sz  += CONFIG_PHYSICAL_ALIGN;
0251     init_sz += CONFIG_PHYSICAL_ALIGN;
0252 
0253     /*
0254      * Size of code: Subtract the size of the first sector (512 bytes)
0255      * which includes the header.
0256      */
0257     put_unaligned_le32(file_sz - 512 + bss_sz, &buf[pe_header + 0x1c]);
0258 
0259     /* Size of image */
0260     put_unaligned_le32(init_sz, &buf[pe_header + 0x50]);
0261 
0262     /*
0263      * Address of entry point for PE/COFF executable
0264      */
0265     put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
0266 
0267     update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz,
0268                         text_sz, text_start);
0269 }
0270 
0271 static int reserve_pecoff_reloc_section(int c)
0272 {
0273     /* Reserve 0x20 bytes for .reloc section */
0274     memset(buf+c, 0, PECOFF_RELOC_RESERVE);
0275     return PECOFF_RELOC_RESERVE;
0276 }
0277 
0278 static void efi_stub_defaults(void)
0279 {
0280     /* Defaults for old kernel */
0281 #ifdef CONFIG_X86_32
0282     efi_pe_entry = 0x10;
0283 #else
0284     efi_pe_entry = 0x210;
0285     startup_64 = 0x200;
0286 #endif
0287 }
0288 
0289 static void efi_stub_entry_update(void)
0290 {
0291     unsigned long addr = efi32_stub_entry;
0292 
0293 #ifdef CONFIG_X86_64
0294     /* Yes, this is really how we defined it :( */
0295     addr = efi64_stub_entry - 0x200;
0296 #endif
0297 
0298 #ifdef CONFIG_EFI_MIXED
0299     if (efi32_stub_entry != addr)
0300         die("32-bit and 64-bit EFI entry points do not match\n");
0301 #endif
0302     put_unaligned_le32(addr, &buf[0x264]);
0303 }
0304 
0305 #else
0306 
0307 static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
0308 static inline void update_pecoff_text(unsigned int text_start,
0309                       unsigned int file_sz,
0310                       unsigned int init_sz) {}
0311 static inline void efi_stub_defaults(void) {}
0312 static inline void efi_stub_entry_update(void) {}
0313 
0314 static inline int reserve_pecoff_reloc_section(int c)
0315 {
0316     return 0;
0317 }
0318 #endif /* CONFIG_EFI_STUB */
0319 
0320 static int reserve_pecoff_compat_section(int c)
0321 {
0322     /* Reserve 0x20 bytes for .compat section */
0323     memset(buf+c, 0, PECOFF_COMPAT_RESERVE);
0324     return PECOFF_COMPAT_RESERVE;
0325 }
0326 
0327 /*
0328  * Parse zoffset.h and find the entry points. We could just #include zoffset.h
0329  * but that would mean tools/build would have to be rebuilt every time. It's
0330  * not as if parsing it is hard...
0331  */
0332 #define PARSE_ZOFS(p, sym) do { \
0333     if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym)))   \
0334         sym = strtoul(p + 11 + sizeof(#sym), NULL, 16);     \
0335 } while (0)
0336 
0337 static void parse_zoffset(char *fname)
0338 {
0339     FILE *file;
0340     char *p;
0341     int c;
0342 
0343     file = fopen(fname, "r");
0344     if (!file)
0345         die("Unable to open `%s': %m", fname);
0346     c = fread(buf, 1, sizeof(buf) - 1, file);
0347     if (ferror(file))
0348         die("read-error on `zoffset.h'");
0349     fclose(file);
0350     buf[c] = 0;
0351 
0352     p = (char *)buf;
0353 
0354     while (p && *p) {
0355         PARSE_ZOFS(p, efi32_stub_entry);
0356         PARSE_ZOFS(p, efi64_stub_entry);
0357         PARSE_ZOFS(p, efi_pe_entry);
0358         PARSE_ZOFS(p, efi32_pe_entry);
0359         PARSE_ZOFS(p, kernel_info);
0360         PARSE_ZOFS(p, startup_64);
0361         PARSE_ZOFS(p, _ehead);
0362         PARSE_ZOFS(p, _end);
0363 
0364         p = strchr(p, '\n');
0365         while (p && (*p == '\r' || *p == '\n'))
0366             p++;
0367     }
0368 }
0369 
0370 int main(int argc, char ** argv)
0371 {
0372     unsigned int i, sz, setup_sectors, init_sz;
0373     int c;
0374     u32 sys_size;
0375     struct stat sb;
0376     FILE *file, *dest;
0377     int fd;
0378     void *kernel;
0379     u32 crc = 0xffffffffUL;
0380 
0381     efi_stub_defaults();
0382 
0383     if (argc != 5)
0384         usage();
0385     parse_zoffset(argv[3]);
0386 
0387     dest = fopen(argv[4], "w");
0388     if (!dest)
0389         die("Unable to write `%s': %m", argv[4]);
0390 
0391     /* Copy the setup code */
0392     file = fopen(argv[1], "r");
0393     if (!file)
0394         die("Unable to open `%s': %m", argv[1]);
0395     c = fread(buf, 1, sizeof(buf), file);
0396     if (ferror(file))
0397         die("read-error on `setup'");
0398     if (c < 1024)
0399         die("The setup must be at least 1024 bytes");
0400     if (get_unaligned_le16(&buf[510]) != 0xAA55)
0401         die("Boot block hasn't got boot flag (0xAA55)");
0402     fclose(file);
0403 
0404     c += reserve_pecoff_compat_section(c);
0405     c += reserve_pecoff_reloc_section(c);
0406 
0407     /* Pad unused space with zeros */
0408     setup_sectors = (c + 511) / 512;
0409     if (setup_sectors < SETUP_SECT_MIN)
0410         setup_sectors = SETUP_SECT_MIN;
0411     i = setup_sectors*512;
0412     memset(buf+c, 0, i-c);
0413 
0414     update_pecoff_setup_and_reloc(i);
0415 
0416     /* Set the default root device */
0417     put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
0418 
0419     /* Open and stat the kernel file */
0420     fd = open(argv[2], O_RDONLY);
0421     if (fd < 0)
0422         die("Unable to open `%s': %m", argv[2]);
0423     if (fstat(fd, &sb))
0424         die("Unable to stat `%s': %m", argv[2]);
0425     sz = sb.st_size;
0426     kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
0427     if (kernel == MAP_FAILED)
0428         die("Unable to mmap '%s': %m", argv[2]);
0429     /* Number of 16-byte paragraphs, including space for a 4-byte CRC */
0430     sys_size = (sz + 15 + 4) / 16;
0431 #ifdef CONFIG_EFI_STUB
0432     /*
0433      * COFF requires minimum 32-byte alignment of sections, and
0434      * adding a signature is problematic without that alignment.
0435      */
0436     sys_size = (sys_size + 1) & ~1;
0437 #endif
0438 
0439     /* Patch the setup code with the appropriate size parameters */
0440     buf[0x1f1] = setup_sectors-1;
0441     put_unaligned_le32(sys_size, &buf[0x1f4]);
0442 
0443     init_sz = get_unaligned_le32(&buf[0x260]);
0444 #ifdef CONFIG_EFI_STUB
0445     /*
0446      * The decompression buffer will start at ImageBase. When relocating
0447      * the compressed kernel to its end, we must ensure that the head
0448      * section does not get overwritten.  The head section occupies
0449      * [i, i + _ehead), and the destination is [init_sz - _end, init_sz).
0450      *
0451      * At present these should never overlap, because 'i' is at most 32k
0452      * because of SETUP_SECT_MAX, '_ehead' is less than 1k, and the
0453      * calculation of INIT_SIZE in boot/header.S ensures that
0454      * 'init_sz - _end' is at least 64k.
0455      *
0456      * For future-proofing, increase init_sz if necessary.
0457      */
0458 
0459     if (init_sz - _end < i + _ehead) {
0460         init_sz = (i + _ehead + _end + 4095) & ~4095;
0461         put_unaligned_le32(init_sz, &buf[0x260]);
0462     }
0463 #endif
0464     update_pecoff_text(setup_sectors * 512, i + (sys_size * 16), init_sz);
0465 
0466     efi_stub_entry_update();
0467 
0468     /* Update kernel_info offset. */
0469     put_unaligned_le32(kernel_info, &buf[0x268]);
0470 
0471     crc = partial_crc32(buf, i, crc);
0472     if (fwrite(buf, 1, i, dest) != i)
0473         die("Writing setup failed");
0474 
0475     /* Copy the kernel code */
0476     crc = partial_crc32(kernel, sz, crc);
0477     if (fwrite(kernel, 1, sz, dest) != sz)
0478         die("Writing kernel failed");
0479 
0480     /* Add padding leaving 4 bytes for the checksum */
0481     while (sz++ < (sys_size*16) - 4) {
0482         crc = partial_crc32_one('\0', crc);
0483         if (fwrite("\0", 1, 1, dest) != 1)
0484             die("Writing padding failed");
0485     }
0486 
0487     /* Write the CRC */
0488     put_unaligned_le32(crc, buf);
0489     if (fwrite(buf, 1, 4, dest) != 4)
0490         die("Writing CRC failed");
0491 
0492     /* Catch any delayed write failures */
0493     if (fclose(dest))
0494         die("Writing image failed");
0495 
0496     close(fd);
0497 
0498     /* Everything is OK */
0499     return 0;
0500 }