summaryrefslogtreecommitdiffstats
path: root/arch/ppc/boot/mkprep.c
blob: 4173346703a5583eea904153abfd4a05679171ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/*
 * Makes a prep bootable image which can be dd'd onto
 * a disk device to make a bootdisk.  Will take
 * as input a elf executable, strip off the header
 * and write out a boot image as:
 * 1) default - strips elf header
 *      suitable as a network boot image
 * 2) -pbp - strips elf header and writes out prep boot partition image
 *      cat or dd onto disk for booting
 * 3) -asm - strips elf header and writes out as asm data
 *      useful for generating data for a compressed image
 *                  -- Cort
 */

#ifdef linux
#include <linux/types.h>
#include <asm/stat.h>
/*#include <asm/byteorder.h>*/ /* the byte swap funcs don't work here -- Cort */
#else
#include <unistd.h>
#include <sys/stat.h>
#endif

#include <stdio.h>
#include <errno.h>

#define cpu_to_le32(x) le32_to_cpu((x))
unsigned long le32_to_cpu(unsigned long x)
{
     	return (((x & 0x000000ffU) << 24) |
		((x & 0x0000ff00U) <<  8) |
		((x & 0x00ff0000U) >>  8) |
		((x & 0xff000000U) >> 24));
}


#define cpu_to_le16(x) le16_to_cpu((x))
unsigned short le16_to_cpu(unsigned short x)
{
	return (((x & 0x00ff) << 8) |
		((x & 0xff00) >> 8));
}

#define cpu_to_be32(x) (x)
#define be32_to_cpu(x) (x)
#define cpu_to_be16(x) (x)
#define be16_to_cpu(x) (x)

/* size of read buffer */
#define SIZE 0x1000


typedef unsigned long dword_t;
typedef unsigned short word_t;
typedef unsigned char byte_t;
typedef byte_t block_t[512];
typedef byte_t page_t[4096];


/*
 * Partition table entry
 *  - from the PReP spec
 */
typedef struct partition_entry {
  byte_t	boot_indicator;
  byte_t	starting_head;
  byte_t	starting_sector;
  byte_t	starting_cylinder;

  byte_t	system_indicator;
  byte_t	ending_head;
  byte_t	ending_sector;
  byte_t	ending_cylinder;

  dword_t	beginning_sector;
  dword_t	number_of_sectors;
} partition_entry_t;

#define BootActive	0x80
#define SystemPrep	0x41

void copy_image(int , int);
void write_prep_partition(int , int );
void write_asm_data( int in, int out );

unsigned int elfhdr_size = 65536;

int main(int argc, char *argv[])
{
  int in_fd, out_fd;
  int argptr = 1;
  unsigned int prep = 0;
  unsigned int asmoutput = 0;

  if ( (argc < 3) || (argc > 4) )
  {
    fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",argv[0]);
    exit(-1);
  }

  /* needs to handle args more elegantly -- but this is a small/simple program */
  
  /* check for -pbp */
  if ( !strcmp( argv[argptr], "-pbp" ) )
  {
    prep = 1;
    argptr++;
  }
  
  /* check for -asm */
  if ( !strcmp( argv[argptr], "-asm" ) )
  {
    asmoutput = 1;
    argptr++;
  }

  /* input file */
  if ( !strcmp( argv[argptr], "-" ) )
    in_fd = 0;			/* stdin */
  else
    if ((in_fd = open( argv[argptr] , 0)) < 0)
      exit(-1);
  argptr++;

  /* output file */
  if ( !strcmp( argv[argptr], "-" ) )
    out_fd = 1;			/* stdout */
  else
    if ((out_fd = creat( argv[argptr] , 0755)) < 0)
      exit(-1);
  argptr++;

  /* skip elf header in input file */
  lseek(in_fd, elfhdr_size, SEEK_SET);
  
  /* write prep partition if necessary */
  if ( prep )
    write_prep_partition( in_fd, out_fd );

  /* write input image to bootimage */
  if ( asmoutput )
    write_asm_data( in_fd, out_fd );
  else
    copy_image(in_fd, out_fd);
  
  return 0;
}

void write_prep_partition(int in, int out)
{
  unsigned char block[512];
  partition_entry_t *pe = (partition_entry_t *)&block[0x1BE];
  dword_t *entry  = (dword_t *)&block[0];
  dword_t *length = (dword_t *)&block[sizeof(long)];
  struct stat info;
  
  if (fstat(in, &info) < 0)
  {
    fprintf(stderr,"info failed\n");
    exit(-1);
  }
  
  bzero( block, sizeof block );

 
  /* set entry point and boot image size */
  *entry = cpu_to_le32(0x400);
  /* need use size - elfheader? */
  *length = cpu_to_le32(info.st_size+0x400);

  /*
   * Writes the "boot record", which contains the partition table, to the
   * diskette, followed by the dummy PC boot block and load image descriptor
   * block.  It returns the number of bytes it has written to the load
   * image.
   *
   * The boot record is the first block of the diskette and identifies the
   * "PReP" partition.  The "PReP" partition contains the "load image" starting
   * at offset zero within the partition.  The first block of the load image is
   * a dummy PC boot block.  The second block is the "load image descriptor"
   * which contains the size of the load image and the entry point into the
   * image.  The actual boot image starts at offset 1024 bytes (third sector)
   * in the partition.
   */
  
  /* sets magic number for msdos partition (used by linux) */
  block[510] = 0x55;
  block[511] = 0xAA;
  
  /*
   * Build a "PReP" partition table entry in the boot record
   *  - "PReP" may only look at the system_indicator
   */
  pe->boot_indicator   = BootActive;
  pe->system_indicator = SystemPrep;
  /*
   * The first block of the diskette is used by this "boot record" which
   * actually contains the partition table. (The first block of the
   * partition contains the boot image, but I digress...)  We'll set up
   * one partition on the diskette and it shall contain the rest of the
   * diskette.
   */
  pe->starting_head     = 0;	/* zero-based			     */
  pe->starting_sector   = 2;	/* one-based			     */
  pe->starting_cylinder = 0;	/* zero-based			     */
  pe->ending_head       = 1;	/* assumes two heads		     */
  pe->ending_sector     = 18;	/* assumes 18 sectors/track	     */
  pe->ending_cylinder   = 79;	/* assumes 80 cylinders/diskette     */

  /*
   * The "PReP" software ignores the above fields and just looks at
   * the next two.
   *   - size of the diskette is (assumed to be)
   *     (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
   *   - unlike the above sector numbers, the beginning sector is zero-based!
   */
#if 0
  pe->beginning_sector  = cpu_to_le32(1);
#else
  /* This has to be 0 on the PowerStack? */   
  pe->beginning_sector  = cpu_to_le32(0);
#endif    
/*pe->number_of_sectors = cpu_to_le32(2*18*80-1);*/

  write( out, block, sizeof(block) );
  write( out, entry, sizeof(*entry) );
  write( out, length, sizeof(*length) );  
  /* set file position to 2nd sector where image will be written */
  lseek( out, 0x400, SEEK_SET );
}



void
copy_image(int in, int out)
{
  char buf[SIZE];
  int n;

  while ( (n = read(in, buf, SIZE)) > 0 )
    write(out, buf, n);
}


void
write_asm_data( int in, int out )
{
  int i, cnt, pos, len;
  unsigned int cksum, val;
  unsigned char *lp;
  unsigned char buf[SIZE];
  unsigned char str[256];
  
  write( out, "\t.data\n\t.globl input_data\ninput_data:\n",
	 strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) );
  pos = 0;
  cksum = 0;
  while ((len = read(in, buf, sizeof(buf))) > 0)
  {
    cnt = 0;
    lp = (unsigned char *)buf;
    len = (len + 3) & ~3;  /* Round up to longwords */
    for (i = 0;  i < len;  i += 4)
    {
      if (cnt == 0)
      {
	write( out, "\t.long\t", strlen( "\t.long\t" ) );
      }
      sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
      write( out, str, strlen(str) );
      val = *(unsigned long *)lp;
      cksum ^= val;
      lp += 4;
      if (++cnt == 4)
      {
	cnt = 0;
	sprintf( str, " # %x \n", pos+i-12);
	write( out, str, strlen(str) );
      } else
      {
	write( out, ",", 1 );
      }
    }
    if (cnt)
    {
      write( out, "0\n", 2 );
    }
    pos += len;
  }
  sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
  write( out, str, strlen(str) );

  fprintf(stderr, "cksum = %x\n", cksum);
}