Back to home page

LXR

 
 

    


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