1 /*
2  * Makes a prep bootable image which can be dd'd onto
3  * a disk device to make a bootdisk.  Will take
4  * as input a elf executable, strip off the header
5  * and write out a boot image as:
6  * 1) default - strips elf header
7  *      suitable as a network boot image
8  * 2) -pbp - strips elf header and writes out prep boot partition image
9  *      cat or dd onto disk for booting
10  * 3) -asm - strips elf header and writes out as asm data
11  *      useful for generating data for a compressed image
12  *                  -- Cort
13  *
14  * Modified for x86 hosted builds by Matt Porter <porter@neta.com>
15  * Modified for Sparc hosted builds by Peter Wahl <PeterWahl@web.de>
16  */
17 
18 #include <fcntl.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <strings.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 
26 #define cpu_to_le32(x) le32_to_cpu((x))
le32_to_cpu(unsigned long x)27 unsigned long le32_to_cpu(unsigned long x)
28 {
29      	return (((x & 0x000000ffU) << 24) |
30 		((x & 0x0000ff00U) <<  8) |
31 		((x & 0x00ff0000U) >>  8) |
32 		((x & 0xff000000U) >> 24));
33 }
34 
35 
36 #define cpu_to_le16(x) le16_to_cpu((x))
le16_to_cpu(unsigned short x)37 unsigned short le16_to_cpu(unsigned short x)
38 {
39 	return (((x & 0x00ff) << 8) |
40 		((x & 0xff00) >> 8));
41 }
42 
43 #define cpu_to_be32(x) (x)
44 #define be32_to_cpu(x) (x)
45 #define cpu_to_be16(x) (x)
46 #define be16_to_cpu(x) (x)
47 
48 /* size of read buffer */
49 #define SIZE 0x1000
50 
51 
52 typedef unsigned long dword_t;
53 typedef unsigned short word_t;
54 typedef unsigned char byte_t;
55 typedef byte_t block_t[512];
56 typedef byte_t page_t[4096];
57 
58 
59 /*
60  * Partition table entry
61  *  - from the PReP spec
62  */
63 typedef struct partition_entry {
64   byte_t	boot_indicator;
65   byte_t	starting_head;
66   byte_t	starting_sector;
67   byte_t	starting_cylinder;
68 
69   byte_t	system_indicator;
70   byte_t	ending_head;
71   byte_t	ending_sector;
72   byte_t	ending_cylinder;
73 
74   dword_t	beginning_sector;
75   dword_t	number_of_sectors;
76 } partition_entry_t;
77 
78 #define BootActive	0x80
79 #define SystemPrep	0x41
80 
81 void copy_image(int , int);
82 void write_prep_partition(int , int );
83 void write_asm_data( int in, int out );
84 
85 unsigned int elfhdr_size = 65536;
86 
main(int argc,char * argv[])87 int main(int argc, char *argv[])
88 {
89   int in_fd, out_fd;
90   int argptr = 1;
91   unsigned int prep = 0;
92   unsigned int asmoutput = 0;
93 
94   if ( (argc < 3) || (argc > 4) )
95   {
96     fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",argv[0]);
97     exit(-1);
98   }
99 
100   /* needs to handle args more elegantly -- but this is a small/simple program */
101 
102   /* check for -pbp */
103   if ( !strcmp( argv[argptr], "-pbp" ) )
104   {
105     prep = 1;
106     argptr++;
107   }
108 
109   /* check for -asm */
110   if ( !strcmp( argv[argptr], "-asm" ) )
111   {
112     asmoutput = 1;
113     argptr++;
114   }
115 
116   /* input file */
117   if ( !strcmp( argv[argptr], "-" ) )
118     in_fd = 0;			/* stdin */
119   else
120     if ((in_fd = open( argv[argptr] , 0)) < 0)
121       exit(-1);
122   argptr++;
123 
124   /* output file */
125   if ( !strcmp( argv[argptr], "-" ) )
126     out_fd = 1;			/* stdout */
127   else
128     if ((out_fd = creat( argv[argptr] , 0755)) < 0)
129       exit(-1);
130   argptr++;
131 
132   /* skip elf header in input file */
133   /*if ( !prep )*/
134   lseek(in_fd, elfhdr_size, SEEK_SET);
135 
136   /* write prep partition if necessary */
137   if ( prep )
138 	  write_prep_partition( in_fd, out_fd );
139 
140   /* write input image to bootimage */
141   if ( asmoutput )
142 	  write_asm_data( in_fd, out_fd );
143   else
144 	  copy_image(in_fd, out_fd);
145 
146   return 0;
147 }
148 
write_prep_partition(int in,int out)149 void write_prep_partition(int in, int out)
150 {
151   unsigned char block[512];
152   partition_entry_t pe;
153   dword_t *entry  = (dword_t *)&block[0];
154   dword_t *length = (dword_t *)&block[sizeof(long)];
155   struct stat info;
156 
157   if (fstat(in, &info) < 0)
158   {
159     fprintf(stderr,"info failed\n");
160     exit(-1);
161   }
162 
163   bzero( block, sizeof block );
164 
165   /* set entry point and boot image size skipping over elf header */
166 #ifdef __i386__
167   *entry = 0x400/*+65536*/;
168   *length = info.st_size-elfhdr_size+0x400;
169 #else
170   *entry = cpu_to_le32(0x400/*+65536*/);
171   *length = cpu_to_le32(info.st_size-elfhdr_size+0x400);
172 #endif /* __i386__ */
173 
174   /* sets magic number for msdos partition (used by linux) */
175   block[510] = 0x55;
176   block[511] = 0xAA;
177 
178   /*
179    * Build a "PReP" partition table entry in the boot record
180    *  - "PReP" may only look at the system_indicator
181    */
182   pe.boot_indicator   = BootActive;
183   pe.system_indicator = SystemPrep;
184   /*
185    * The first block of the diskette is used by this "boot record" which
186    * actually contains the partition table. (The first block of the
187    * partition contains the boot image, but I digress...)  We'll set up
188    * one partition on the diskette and it shall contain the rest of the
189    * diskette.
190    */
191   pe.starting_head     = 0;	/* zero-based			     */
192   pe.starting_sector   = 2;	/* one-based			     */
193   pe.starting_cylinder = 0;	/* zero-based			     */
194   pe.ending_head       = 1;	/* assumes two heads		     */
195   pe.ending_sector     = 18;	/* assumes 18 sectors/track	     */
196   pe.ending_cylinder   = 79;	/* assumes 80 cylinders/diskette     */
197 
198   /*
199    * The "PReP" software ignores the above fields and just looks at
200    * the next two.
201    *   - size of the diskette is (assumed to be)
202    *     (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
203    *   - unlike the above sector numbers, the beginning sector is zero-based!
204    */
205 #if 0
206   pe.beginning_sector  = cpu_to_le32(1);
207 #else
208   /* This has to be 0 on the PowerStack? */
209 #ifdef __i386__
210   pe.beginning_sector  = 0;
211 #else
212   pe.beginning_sector  = cpu_to_le32(0);
213 #endif /* __i386__ */
214 #endif
215 
216 #ifdef __i386__
217   pe.number_of_sectors = 2*18*80-1;
218 #else
219   pe.number_of_sectors = cpu_to_le32(2*18*80-1);
220 #endif /* __i386__ */
221 
222   memcpy(&block[0x1BE],&pe,sizeof(pe));
223 
224   write( out, block, sizeof(block) );
225   write( out, entry, sizeof(*entry) );
226   write( out, length, sizeof(*length) );
227   /* set file position to 2nd sector where image will be written */
228   lseek( out, 0x400, SEEK_SET );
229 }
230 
231 
232 
233 void
copy_image(int in,int out)234 copy_image(int in, int out)
235 {
236   char buf[SIZE];
237   int n;
238 
239   while ( (n = read(in, buf, SIZE)) > 0 )
240     write(out, buf, n);
241 }
242 
243 
244 void
write_asm_data(int in,int out)245 write_asm_data( int in, int out )
246 {
247   int i, cnt, pos, len;
248   unsigned int cksum, val;
249   unsigned char *lp;
250   unsigned char buf[SIZE];
251   unsigned char str[256];
252 
253   write( out, "\t.data\n\t.globl input_data\ninput_data:\n",
254 	 strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) );
255   pos = 0;
256   cksum = 0;
257   while ((len = read(in, buf, sizeof(buf))) > 0)
258   {
259     cnt = 0;
260     lp = (unsigned char *)buf;
261     len = (len + 3) & ~3;  /* Round up to longwords */
262     for (i = 0;  i < len;  i += 4)
263     {
264       if (cnt == 0)
265       {
266 	write( out, "\t.long\t", strlen( "\t.long\t" ) );
267       }
268       sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
269       write( out, str, strlen(str) );
270       val = *(unsigned long *)lp;
271       cksum ^= val;
272       lp += 4;
273       if (++cnt == 4)
274       {
275 	cnt = 0;
276 	sprintf( str, " # %x \n", pos+i-12);
277 	write( out, str, strlen(str) );
278       } else
279       {
280 	write( out, ",", 1 );
281       }
282     }
283     if (cnt)
284     {
285       write( out, "0\n", 2 );
286     }
287     pos += len;
288   }
289   sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
290   write( out, str, strlen(str) );
291 
292   fprintf(stderr, "cksum = %x\n", cksum);
293 }
294