diff options
Diffstat (limited to 'arch/ppc/boot/utils/mkprep.c')
-rw-r--r-- | arch/ppc/boot/utils/mkprep.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/arch/ppc/boot/utils/mkprep.c b/arch/ppc/boot/utils/mkprep.c new file mode 100644 index 000000000000..f6d5a2f2fcf6 --- /dev/null +++ b/arch/ppc/boot/utils/mkprep.c | |||
@@ -0,0 +1,293 @@ | |||
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)) | ||
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)) | ||
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 | |||
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 | |||
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 | ||
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 | ||
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 | } | ||