1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
219d8d79cSThomas Gleixner /*
319d8d79cSThomas Gleixner * Copyright (C) 1991, 1992 Linus Torvalds
419d8d79cSThomas Gleixner * Copyright (C) 1997 Martin Mares
519d8d79cSThomas Gleixner * Copyright (C) 2007 H. Peter Anvin
619d8d79cSThomas Gleixner */
719d8d79cSThomas Gleixner
819d8d79cSThomas Gleixner /*
9809373e2SKees Cook * This file builds a disk-image from three different files:
1019d8d79cSThomas Gleixner *
1119d8d79cSThomas Gleixner * - setup: 8086 machine code, sets up system parm
1219d8d79cSThomas Gleixner * - system: 80386 code for actual system
13809373e2SKees Cook * - zoffset.h: header with ZO_* defines
1419d8d79cSThomas Gleixner *
15809373e2SKees Cook * It does some checking that all files are of the correct type, and writes
16809373e2SKees Cook * the result to the specified destination, removing headers and padding to
17809373e2SKees Cook * the right amount. It also writes some system data to stdout.
1819d8d79cSThomas Gleixner */
1919d8d79cSThomas Gleixner
2019d8d79cSThomas Gleixner /*
2119d8d79cSThomas Gleixner * Changes by tytso to allow root device specification
2219d8d79cSThomas Gleixner * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
2319d8d79cSThomas Gleixner * Cross compiling fixes by Gertjan van Wingerde, July 1996
2419d8d79cSThomas Gleixner * Rewritten by Martin Mares, April 1997
2519d8d79cSThomas Gleixner * Substantially overhauled by H. Peter Anvin, April 2007
2619d8d79cSThomas Gleixner */
2719d8d79cSThomas Gleixner
2819d8d79cSThomas Gleixner #include <stdio.h>
2919d8d79cSThomas Gleixner #include <string.h>
3019d8d79cSThomas Gleixner #include <stdlib.h>
3119d8d79cSThomas Gleixner #include <stdarg.h>
3219d8d79cSThomas Gleixner #include <sys/types.h>
3319d8d79cSThomas Gleixner #include <sys/stat.h>
3419d8d79cSThomas Gleixner #include <unistd.h>
3519d8d79cSThomas Gleixner #include <fcntl.h>
3619d8d79cSThomas Gleixner #include <sys/mman.h>
3792f42c50SMatt Fleming #include <tools/le_byteshift.h>
3819d8d79cSThomas Gleixner
3919d8d79cSThomas Gleixner typedef unsigned char u8;
4019d8d79cSThomas Gleixner typedef unsigned short u16;
41a51f4047SH. Peter Anvin typedef unsigned int u32;
4219d8d79cSThomas Gleixner
4319d8d79cSThomas Gleixner /* Minimal number of setup sectors */
4419d8d79cSThomas Gleixner #define SETUP_SECT_MIN 5
4519d8d79cSThomas Gleixner #define SETUP_SECT_MAX 64
4619d8d79cSThomas Gleixner
4719d8d79cSThomas Gleixner /* This must be large enough to hold the entire setup */
4819d8d79cSThomas Gleixner u8 buf[SETUP_SECT_MAX*512];
4919d8d79cSThomas Gleixner
50aeb92067SArd Biesheuvel static unsigned long _edata;
5199f857dbSDavid Woodhouse
527d6e737cSIan Campbell /*----------------------------------------------------------------------*/
537d6e737cSIan Campbell
547d6e737cSIan Campbell static const u32 crctab32[] = {
557d6e737cSIan Campbell 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
567d6e737cSIan Campbell 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
577d6e737cSIan Campbell 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
587d6e737cSIan Campbell 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
597d6e737cSIan Campbell 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
607d6e737cSIan Campbell 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
617d6e737cSIan Campbell 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
627d6e737cSIan Campbell 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
637d6e737cSIan Campbell 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
647d6e737cSIan Campbell 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
657d6e737cSIan Campbell 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
667d6e737cSIan Campbell 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
677d6e737cSIan Campbell 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
687d6e737cSIan Campbell 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
697d6e737cSIan Campbell 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
707d6e737cSIan Campbell 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
717d6e737cSIan Campbell 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
727d6e737cSIan Campbell 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
737d6e737cSIan Campbell 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
747d6e737cSIan Campbell 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
757d6e737cSIan Campbell 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
767d6e737cSIan Campbell 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
777d6e737cSIan Campbell 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
787d6e737cSIan Campbell 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
797d6e737cSIan Campbell 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
807d6e737cSIan Campbell 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
817d6e737cSIan Campbell 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
827d6e737cSIan Campbell 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
837d6e737cSIan Campbell 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
847d6e737cSIan Campbell 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
857d6e737cSIan Campbell 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
867d6e737cSIan Campbell 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
877d6e737cSIan Campbell 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
887d6e737cSIan Campbell 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
897d6e737cSIan Campbell 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
907d6e737cSIan Campbell 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
917d6e737cSIan Campbell 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
927d6e737cSIan Campbell 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
937d6e737cSIan Campbell 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
947d6e737cSIan Campbell 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
957d6e737cSIan Campbell 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
967d6e737cSIan Campbell 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
977d6e737cSIan Campbell 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
987d6e737cSIan Campbell 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
997d6e737cSIan Campbell 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1007d6e737cSIan Campbell 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
1017d6e737cSIan Campbell 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
1027d6e737cSIan Campbell 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1037d6e737cSIan Campbell 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
1047d6e737cSIan Campbell 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
1057d6e737cSIan Campbell 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
1067d6e737cSIan Campbell 0x2d02ef8d
1077d6e737cSIan Campbell };
1087d6e737cSIan Campbell
partial_crc32_one(u8 c,u32 crc)1097d6e737cSIan Campbell static u32 partial_crc32_one(u8 c, u32 crc)
1107d6e737cSIan Campbell {
1117d6e737cSIan Campbell return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
1127d6e737cSIan Campbell }
1137d6e737cSIan Campbell
partial_crc32(const u8 * s,int len,u32 crc)1147d6e737cSIan Campbell static u32 partial_crc32(const u8 *s, int len, u32 crc)
1157d6e737cSIan Campbell {
1167d6e737cSIan Campbell while (len--)
1177d6e737cSIan Campbell crc = partial_crc32_one(*s++, crc);
1187d6e737cSIan Campbell return crc;
1197d6e737cSIan Campbell }
1207d6e737cSIan Campbell
die(const char * str,...)12119d8d79cSThomas Gleixner static void die(const char * str, ...)
12219d8d79cSThomas Gleixner {
12319d8d79cSThomas Gleixner va_list args;
12419d8d79cSThomas Gleixner va_start(args, str);
12519d8d79cSThomas Gleixner vfprintf(stderr, str, args);
12669be4efeSMattias Jacobsson va_end(args);
12719d8d79cSThomas Gleixner fputc('\n', stderr);
12819d8d79cSThomas Gleixner exit(1);
12919d8d79cSThomas Gleixner }
13019d8d79cSThomas Gleixner
usage(void)13119d8d79cSThomas Gleixner static void usage(void)
13219d8d79cSThomas Gleixner {
133809373e2SKees Cook die("Usage: build setup system zoffset.h image");
13419d8d79cSThomas Gleixner }
13519d8d79cSThomas Gleixner
13699f857dbSDavid Woodhouse /*
13799f857dbSDavid Woodhouse * Parse zoffset.h and find the entry points. We could just #include zoffset.h
13899f857dbSDavid Woodhouse * but that would mean tools/build would have to be rebuilt every time. It's
13999f857dbSDavid Woodhouse * not as if parsing it is hard...
14099f857dbSDavid Woodhouse */
14199f857dbSDavid Woodhouse #define PARSE_ZOFS(p, sym) do { \
14299f857dbSDavid Woodhouse if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym))) \
14399f857dbSDavid Woodhouse sym = strtoul(p + 11 + sizeof(#sym), NULL, 16); \
14499f857dbSDavid Woodhouse } while (0)
14599f857dbSDavid Woodhouse
parse_zoffset(char * fname)14699f857dbSDavid Woodhouse static void parse_zoffset(char *fname)
14799f857dbSDavid Woodhouse {
14899f857dbSDavid Woodhouse FILE *file;
14999f857dbSDavid Woodhouse char *p;
15099f857dbSDavid Woodhouse int c;
15199f857dbSDavid Woodhouse
15299f857dbSDavid Woodhouse file = fopen(fname, "r");
15399f857dbSDavid Woodhouse if (!file)
15499f857dbSDavid Woodhouse die("Unable to open `%s': %m", fname);
15599f857dbSDavid Woodhouse c = fread(buf, 1, sizeof(buf) - 1, file);
15699f857dbSDavid Woodhouse if (ferror(file))
15799f857dbSDavid Woodhouse die("read-error on `zoffset.h'");
158062f4871SJiri Slaby fclose(file);
15999f857dbSDavid Woodhouse buf[c] = 0;
16099f857dbSDavid Woodhouse
16199f857dbSDavid Woodhouse p = (char *)buf;
16299f857dbSDavid Woodhouse
16399f857dbSDavid Woodhouse while (p && *p) {
164aeb92067SArd Biesheuvel PARSE_ZOFS(p, _edata);
16599f857dbSDavid Woodhouse
16699f857dbSDavid Woodhouse p = strchr(p, '\n');
16799f857dbSDavid Woodhouse while (p && (*p == '\r' || *p == '\n'))
16899f857dbSDavid Woodhouse p++;
16999f857dbSDavid Woodhouse }
17099f857dbSDavid Woodhouse }
17199f857dbSDavid Woodhouse
main(int argc,char ** argv)17219d8d79cSThomas Gleixner int main(int argc, char ** argv)
17319d8d79cSThomas Gleixner {
1748eace5b3SArd Biesheuvel unsigned int i, sz, setup_sectors;
17519d8d79cSThomas Gleixner int c;
17619d8d79cSThomas Gleixner struct stat sb;
177809373e2SKees Cook FILE *file, *dest;
17819d8d79cSThomas Gleixner int fd;
17919d8d79cSThomas Gleixner void *kernel;
1807d6e737cSIan Campbell u32 crc = 0xffffffffUL;
18119d8d79cSThomas Gleixner
182809373e2SKees Cook if (argc != 5)
18319d8d79cSThomas Gleixner usage();
184809373e2SKees Cook parse_zoffset(argv[3]);
185809373e2SKees Cook
186809373e2SKees Cook dest = fopen(argv[4], "w");
187809373e2SKees Cook if (!dest)
188809373e2SKees Cook die("Unable to write `%s': %m", argv[4]);
18919d8d79cSThomas Gleixner
19019d8d79cSThomas Gleixner /* Copy the setup code */
19119d8d79cSThomas Gleixner file = fopen(argv[1], "r");
19219d8d79cSThomas Gleixner if (!file)
19319d8d79cSThomas Gleixner die("Unable to open `%s': %m", argv[1]);
19419d8d79cSThomas Gleixner c = fread(buf, 1, sizeof(buf), file);
19519d8d79cSThomas Gleixner if (ferror(file))
19619d8d79cSThomas Gleixner die("read-error on `setup'");
19719d8d79cSThomas Gleixner if (c < 1024)
19819d8d79cSThomas Gleixner die("The setup must be at least 1024 bytes");
19992f42c50SMatt Fleming if (get_unaligned_le16(&buf[510]) != 0xAA55)
20019d8d79cSThomas Gleixner die("Boot block hasn't got boot flag (0xAA55)");
20119d8d79cSThomas Gleixner fclose(file);
20219d8d79cSThomas Gleixner
20319d8d79cSThomas Gleixner /* Pad unused space with zeros */
204*3e3eabe2SArd Biesheuvel setup_sectors = (c + 4095) / 4096;
205*3e3eabe2SArd Biesheuvel setup_sectors *= 8;
20619d8d79cSThomas Gleixner if (setup_sectors < SETUP_SECT_MIN)
20719d8d79cSThomas Gleixner setup_sectors = SETUP_SECT_MIN;
20819d8d79cSThomas Gleixner i = setup_sectors*512;
20919d8d79cSThomas Gleixner memset(buf+c, 0, i-c);
21019d8d79cSThomas Gleixner
21119d8d79cSThomas Gleixner /* Open and stat the kernel file */
21219d8d79cSThomas Gleixner fd = open(argv[2], O_RDONLY);
21319d8d79cSThomas Gleixner if (fd < 0)
21419d8d79cSThomas Gleixner die("Unable to open `%s': %m", argv[2]);
21519d8d79cSThomas Gleixner if (fstat(fd, &sb))
21619d8d79cSThomas Gleixner die("Unable to stat `%s': %m", argv[2]);
217aeb92067SArd Biesheuvel if (_edata != sb.st_size)
218aeb92067SArd Biesheuvel die("Unexpected file size `%s': %u != %u", argv[2], _edata,
219aeb92067SArd Biesheuvel sb.st_size);
220aeb92067SArd Biesheuvel sz = _edata - 4;
22119d8d79cSThomas Gleixner kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
22219d8d79cSThomas Gleixner if (kernel == MAP_FAILED)
22319d8d79cSThomas Gleixner die("Unable to mmap '%s': %m", argv[2]);
2242c33c27fSDaniel Kiper
2257d6e737cSIan Campbell crc = partial_crc32(buf, i, crc);
226809373e2SKees Cook if (fwrite(buf, 1, i, dest) != i)
22719d8d79cSThomas Gleixner die("Writing setup failed");
22819d8d79cSThomas Gleixner
22919d8d79cSThomas Gleixner /* Copy the kernel code */
2307d6e737cSIan Campbell crc = partial_crc32(kernel, sz, crc);
231809373e2SKees Cook if (fwrite(kernel, 1, sz, dest) != sz)
23219d8d79cSThomas Gleixner die("Writing kernel failed");
2337d6e737cSIan Campbell
2347d6e737cSIan Campbell /* Write the CRC */
235a51f4047SH. Peter Anvin put_unaligned_le32(crc, buf);
236809373e2SKees Cook if (fwrite(buf, 1, 4, dest) != 4)
2377d6e737cSIan Campbell die("Writing CRC failed");
2387d6e737cSIan Campbell
239809373e2SKees Cook /* Catch any delayed write failures */
240809373e2SKees Cook if (fclose(dest))
241809373e2SKees Cook die("Writing image failed");
242809373e2SKees Cook
24319d8d79cSThomas Gleixner close(fd);
24419d8d79cSThomas Gleixner
24519d8d79cSThomas Gleixner /* Everything is OK */
24619d8d79cSThomas Gleixner return 0;
24719d8d79cSThomas Gleixner }
248