aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc/boot/utils
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/boot/utils')
-rw-r--r--arch/ppc/boot/utils/addRamDisk.c203
-rw-r--r--arch/ppc/boot/utils/addSystemMap.c186
-rw-r--r--arch/ppc/boot/utils/addnote.c175
-rw-r--r--arch/ppc/boot/utils/elf.pl33
-rw-r--r--arch/ppc/boot/utils/hack-coff.c84
-rw-r--r--arch/ppc/boot/utils/mkbugboot.c187
-rw-r--r--arch/ppc/boot/utils/mknote.c44
-rw-r--r--arch/ppc/boot/utils/mkprep.c293
-rw-r--r--arch/ppc/boot/utils/mktree.c152
9 files changed, 1357 insertions, 0 deletions
diff --git a/arch/ppc/boot/utils/addRamDisk.c b/arch/ppc/boot/utils/addRamDisk.c
new file mode 100644
index 000000000000..93400dfcce7f
--- /dev/null
+++ b/arch/ppc/boot/utils/addRamDisk.c
@@ -0,0 +1,203 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <netinet/in.h>
4#include <unistd.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <string.h>
8
9#define ElfHeaderSize (64 * 1024)
10#define ElfPages (ElfHeaderSize / 4096)
11#define KERNELBASE (0xc0000000)
12
13void get4k(FILE *file, char *buf )
14{
15 unsigned j;
16 unsigned num = fread(buf, 1, 4096, file);
17 for ( j=num; j<4096; ++j )
18 buf[j] = 0;
19}
20
21void put4k(FILE *file, char *buf )
22{
23 fwrite(buf, 1, 4096, file);
24}
25
26void death(const char *msg, FILE *fdesc, const char *fname)
27{
28 printf(msg);
29 fclose(fdesc);
30 unlink(fname);
31 exit(1);
32}
33
34int main(int argc, char **argv)
35{
36 char inbuf[4096];
37 FILE *ramDisk = NULL;
38 FILE *inputVmlinux = NULL;
39 FILE *outputVmlinux = NULL;
40 unsigned i = 0;
41 u_int32_t ramFileLen = 0;
42 u_int32_t ramLen = 0;
43 u_int32_t roundR = 0;
44 u_int32_t kernelLen = 0;
45 u_int32_t actualKernelLen = 0;
46 u_int32_t round = 0;
47 u_int32_t roundedKernelLen = 0;
48 u_int32_t ramStartOffs = 0;
49 u_int32_t ramPages = 0;
50 u_int32_t roundedKernelPages = 0;
51 u_int32_t hvReleaseData = 0;
52 u_int32_t eyeCatcher = 0xc8a5d9c4;
53 u_int32_t naca = 0;
54 u_int32_t xRamDisk = 0;
55 u_int32_t xRamDiskSize = 0;
56 if ( argc < 2 ) {
57 printf("Name of RAM disk file missing.\n");
58 exit(1);
59 }
60
61 if ( argc < 3 ) {
62 printf("Name of vmlinux file missing.\n");
63 exit(1);
64 }
65
66 if ( argc < 4 ) {
67 printf("Name of vmlinux output file missing.\n");
68 exit(1);
69 }
70
71 ramDisk = fopen(argv[1], "r");
72 if ( ! ramDisk ) {
73 printf("RAM disk file \"%s\" failed to open.\n", argv[1]);
74 exit(1);
75 }
76 inputVmlinux = fopen(argv[2], "r");
77 if ( ! inputVmlinux ) {
78 printf("vmlinux file \"%s\" failed to open.\n", argv[2]);
79 exit(1);
80 }
81 outputVmlinux = fopen(argv[3], "w+");
82 if ( ! outputVmlinux ) {
83 printf("output vmlinux file \"%s\" failed to open.\n", argv[3]);
84 exit(1);
85 }
86 fseek(ramDisk, 0, SEEK_END);
87 ramFileLen = ftell(ramDisk);
88 fseek(ramDisk, 0, SEEK_SET);
89 printf("%s file size = %d\n", argv[1], ramFileLen);
90
91 ramLen = ramFileLen;
92
93 roundR = 4096 - (ramLen % 4096);
94 if ( roundR ) {
95 printf("Rounding RAM disk file up to a multiple of 4096, adding %d\n", roundR);
96 ramLen += roundR;
97 }
98
99 printf("Rounded RAM disk size is %d\n", ramLen);
100 fseek(inputVmlinux, 0, SEEK_END);
101 kernelLen = ftell(inputVmlinux);
102 fseek(inputVmlinux, 0, SEEK_SET);
103 printf("kernel file size = %d\n", kernelLen);
104 if ( kernelLen == 0 ) {
105 printf("You must have a linux kernel specified as argv[2]\n");
106 exit(1);
107 }
108
109 actualKernelLen = kernelLen - ElfHeaderSize;
110
111 printf("actual kernel length (minus ELF header) = %d\n", actualKernelLen);
112
113 round = actualKernelLen % 4096;
114 roundedKernelLen = actualKernelLen;
115 if ( round )
116 roundedKernelLen += (4096 - round);
117
118 printf("actual kernel length rounded up to a 4k multiple = %d\n", roundedKernelLen);
119
120 ramStartOffs = roundedKernelLen;
121 ramPages = ramLen / 4096;
122
123 printf("RAM disk pages to copy = %d\n", ramPages);
124
125 // Copy 64K ELF header
126 for (i=0; i<(ElfPages); ++i) {
127 get4k( inputVmlinux, inbuf );
128 put4k( outputVmlinux, inbuf );
129 }
130
131 roundedKernelPages = roundedKernelLen / 4096;
132
133 fseek(inputVmlinux, ElfHeaderSize, SEEK_SET);
134
135 for ( i=0; i<roundedKernelPages; ++i ) {
136 get4k( inputVmlinux, inbuf );
137 put4k( outputVmlinux, inbuf );
138 }
139
140 for ( i=0; i<ramPages; ++i ) {
141 get4k( ramDisk, inbuf );
142 put4k( outputVmlinux, inbuf );
143 }
144
145 /* Close the input files */
146 fclose(ramDisk);
147 fclose(inputVmlinux);
148 /* And flush the written output file */
149 fflush(outputVmlinux);
150
151 /* fseek to the hvReleaseData pointer */
152 fseek(outputVmlinux, ElfHeaderSize + 0x24, SEEK_SET);
153 if (fread(&hvReleaseData, 4, 1, outputVmlinux) != 1) {
154 death("Could not read hvReleaseData pointer\n", outputVmlinux, argv[3]);
155 }
156 hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */
157 printf("hvReleaseData is at %08x\n", hvReleaseData);
158
159 /* fseek to the hvReleaseData */
160 fseek(outputVmlinux, ElfHeaderSize + hvReleaseData, SEEK_SET);
161 if (fread(inbuf, 0x40, 1, outputVmlinux) != 1) {
162 death("Could not read hvReleaseData\n", outputVmlinux, argv[3]);
163 }
164 /* Check hvReleaseData sanity */
165 if (memcmp(inbuf, &eyeCatcher, 4) != 0) {
166 death("hvReleaseData is invalid\n", outputVmlinux, argv[3]);
167 }
168 /* Get the naca pointer */
169 naca = ntohl(*((u_int32_t *) &inbuf[0x0c])) - KERNELBASE;
170 printf("naca is at %08x\n", naca);
171
172 /* fseek to the naca */
173 fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
174 if (fread(inbuf, 0x18, 1, outputVmlinux) != 1) {
175 death("Could not read naca\n", outputVmlinux, argv[3]);
176 }
177 xRamDisk = ntohl(*((u_int32_t *) &inbuf[0x0c]));
178 xRamDiskSize = ntohl(*((u_int32_t *) &inbuf[0x14]));
179 /* Make sure a RAM disk isn't already present */
180 if ((xRamDisk != 0) || (xRamDiskSize != 0)) {
181 death("RAM disk is already attached to this kernel\n", outputVmlinux, argv[3]);
182 }
183 /* Fill in the values */
184 *((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs);
185 *((u_int32_t *) &inbuf[0x14]) = htonl(ramPages);
186
187 /* Write out the new naca */
188 fflush(outputVmlinux);
189 fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
190 if (fwrite(inbuf, 0x18, 1, outputVmlinux) != 1) {
191 death("Could not write naca\n", outputVmlinux, argv[3]);
192 }
193 printf("RAM Disk of 0x%x pages size is attached to the kernel at offset 0x%08x\n",
194 ramPages, ramStartOffs);
195
196 /* Done */
197 fclose(outputVmlinux);
198 /* Set permission to executable */
199 chmod(argv[3], S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
200
201 return 0;
202}
203
diff --git a/arch/ppc/boot/utils/addSystemMap.c b/arch/ppc/boot/utils/addSystemMap.c
new file mode 100644
index 000000000000..4654f891b274
--- /dev/null
+++ b/arch/ppc/boot/utils/addSystemMap.c
@@ -0,0 +1,186 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <byteswap.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6
7void xlate( char * inb, char * trb, unsigned len )
8{
9 unsigned i;
10 for ( i=0; i<len; ++i ) {
11 char c = *inb++;
12 char c1 = c >> 4;
13 char c2 = c & 0xf;
14 if ( c1 > 9 )
15 c1 = c1 + 'A' - 10;
16 else
17 c1 = c1 + '0';
18 if ( c2 > 9 )
19 c2 = c2 + 'A' - 10;
20 else
21 c2 = c2 + '0';
22 *trb++ = c1;
23 *trb++ = c2;
24 }
25 *trb = 0;
26}
27
28#define ElfHeaderSize (64 * 1024)
29#define ElfPages (ElfHeaderSize / 4096)
30#define KERNELBASE (0xc0000000)
31
32void get4k( /*istream *inf*/FILE *file, char *buf )
33{
34 unsigned j;
35 unsigned num = fread(buf, 1, 4096, file);
36 for ( j=num; j<4096; ++j )
37 buf[j] = 0;
38}
39
40void put4k( /*ostream *outf*/FILE *file, char *buf )
41{
42 fwrite(buf, 1, 4096, file);
43}
44
45int main(int argc, char **argv)
46{
47 char inbuf[4096];
48 FILE *ramDisk = NULL;
49 FILE *inputVmlinux = NULL;
50 FILE *outputVmlinux = NULL;
51 unsigned i = 0;
52 unsigned long ramFileLen = 0;
53 unsigned long ramLen = 0;
54 unsigned long roundR = 0;
55 unsigned long kernelLen = 0;
56 unsigned long actualKernelLen = 0;
57 unsigned long round = 0;
58 unsigned long roundedKernelLen = 0;
59 unsigned long ramStartOffs = 0;
60 unsigned long ramPages = 0;
61 unsigned long roundedKernelPages = 0;
62 if ( argc < 2 ) {
63 printf("Name of System Map file missing.\n");
64 exit(1);
65 }
66
67 if ( argc < 3 ) {
68 printf("Name of vmlinux file missing.\n");
69 exit(1);
70 }
71
72 if ( argc < 4 ) {
73 printf("Name of vmlinux output file missing.\n");
74 exit(1);
75 }
76
77 ramDisk = fopen(argv[1], "r");
78 if ( ! ramDisk ) {
79 printf("System Map file \"%s\" failed to open.\n", argv[1]);
80 exit(1);
81 }
82 inputVmlinux = fopen(argv[2], "r");
83 if ( ! inputVmlinux ) {
84 printf("vmlinux file \"%s\" failed to open.\n", argv[2]);
85 exit(1);
86 }
87 outputVmlinux = fopen(argv[3], "w");
88 if ( ! outputVmlinux ) {
89 printf("output vmlinux file \"%s\" failed to open.\n", argv[3]);
90 exit(1);
91 }
92 fseek(ramDisk, 0, SEEK_END);
93 ramFileLen = ftell(ramDisk);
94 fseek(ramDisk, 0, SEEK_SET);
95 printf("%s file size = %ld\n", argv[1], ramFileLen);
96
97 ramLen = ramFileLen;
98
99 roundR = 4096 - (ramLen % 4096);
100 if ( roundR ) {
101 printf("Rounding System Map file up to a multiple of 4096, adding %ld\n", roundR);
102 ramLen += roundR;
103 }
104
105 printf("Rounded System Map size is %ld\n", ramLen);
106 fseek(inputVmlinux, 0, SEEK_END);
107 kernelLen = ftell(inputVmlinux);
108 fseek(inputVmlinux, 0, SEEK_SET);
109 printf("kernel file size = %ld\n", kernelLen);
110 if ( kernelLen == 0 ) {
111 printf("You must have a linux kernel specified as argv[2]\n");
112 exit(1);
113 }
114
115 actualKernelLen = kernelLen - ElfHeaderSize;
116
117 printf("actual kernel length (minus ELF header) = %ld\n", actualKernelLen);
118
119 round = actualKernelLen % 4096;
120 roundedKernelLen = actualKernelLen;
121 if ( round )
122 roundedKernelLen += (4096 - round);
123
124 printf("actual kernel length rounded up to a 4k multiple = %ld\n", roundedKernelLen);
125
126 ramStartOffs = roundedKernelLen;
127 ramPages = ramLen / 4096;
128
129 printf("System map pages to copy = %ld\n", ramPages);
130
131 // Copy 64K ELF header
132 for (i=0; i<(ElfPages); ++i) {
133 get4k( inputVmlinux, inbuf );
134 put4k( outputVmlinux, inbuf );
135 }
136
137
138
139 roundedKernelPages = roundedKernelLen / 4096;
140
141 fseek(inputVmlinux, ElfHeaderSize, SEEK_SET);
142
143 {
144 for ( i=0; i<roundedKernelPages; ++i ) {
145 get4k( inputVmlinux, inbuf );
146 if ( i == 0 ) {
147 unsigned long * p;
148 printf("Storing embedded_sysmap_start at 0x3c\n");
149 p = (unsigned long *)(inbuf + 0x3c);
150
151#if (BYTE_ORDER == __BIG_ENDIAN)
152 *p = ramStartOffs;
153#else
154 *p = bswap_32(ramStartOffs);
155#endif
156
157 printf("Storing embedded_sysmap_end at 0x44\n");
158 p = (unsigned long *)(inbuf + 0x44);
159#if (BYTE_ORDER == __BIG_ENDIAN)
160 *p = ramStartOffs + ramFileLen;
161#else
162 *p = bswap_32(ramStartOffs + ramFileLen);
163#endif
164 }
165 put4k( outputVmlinux, inbuf );
166 }
167 }
168
169 {
170 for ( i=0; i<ramPages; ++i ) {
171 get4k( ramDisk, inbuf );
172 put4k( outputVmlinux, inbuf );
173 }
174 }
175
176
177 fclose(ramDisk);
178 fclose(inputVmlinux);
179 fclose(outputVmlinux);
180 /* Set permission to executable */
181 chmod(argv[3], S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
182
183 return 0;
184
185}
186
diff --git a/arch/ppc/boot/utils/addnote.c b/arch/ppc/boot/utils/addnote.c
new file mode 100644
index 000000000000..6c52b18f2d04
--- /dev/null
+++ b/arch/ppc/boot/utils/addnote.c
@@ -0,0 +1,175 @@
1/*
2 * Program to hack in a PT_NOTE program header entry in an ELF file.
3 * This is needed for OF on RS/6000s to load an image correctly.
4 * Note that OF needs a program header entry for the note, not an
5 * ELF section.
6 *
7 * Copyright 2000 Paul Mackerras.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 *
14 * Usage: addnote zImage
15 */
16#include <stdio.h>
17#include <stdlib.h>
18#include <fcntl.h>
19#include <unistd.h>
20#include <string.h>
21
22char arch[] = "PowerPC";
23
24#define N_DESCR 6
25unsigned int descr[N_DESCR] = {
26#if 1
27 /* values for IBM RS/6000 machines */
28 0xffffffff, /* real-mode = true */
29 0x00c00000, /* real-base, i.e. where we expect OF to be */
30 0xffffffff, /* real-size */
31 0xffffffff, /* virt-base */
32 0xffffffff, /* virt-size */
33 0x4000, /* load-base */
34#else
35 /* values for longtrail CHRP */
36 0, /* real-mode = false */
37 0xffffffff, /* real-base */
38 0xffffffff, /* real-size */
39 0xffffffff, /* virt-base */
40 0xffffffff, /* virt-size */
41 0x00600000, /* load-base */
42#endif
43};
44
45unsigned char buf[512];
46
47#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1]))
48#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2))
49
50#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \
51 buf[(off) + 1] = (v) & 0xff)
52#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \
53 PUT_16BE((off) + 2, (v)))
54
55/* Structure of an ELF file */
56#define E_IDENT 0 /* ELF header */
57#define E_PHOFF 28
58#define E_PHENTSIZE 42
59#define E_PHNUM 44
60#define E_HSIZE 52 /* size of ELF header */
61
62#define EI_MAGIC 0 /* offsets in E_IDENT area */
63#define EI_CLASS 4
64#define EI_DATA 5
65
66#define PH_TYPE 0 /* ELF program header */
67#define PH_OFFSET 4
68#define PH_FILESZ 16
69#define PH_HSIZE 32 /* size of program header */
70
71#define PT_NOTE 4 /* Program header type = note */
72
73#define ELFCLASS32 1
74#define ELFDATA2MSB 2
75
76unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
77
78int main(int ac, char **av)
79{
80 int fd, n, i;
81 int ph, ps, np;
82 int nnote, ns;
83
84 if (ac != 2) {
85 fprintf(stderr, "Usage: %s elf-file\n", av[0]);
86 exit(1);
87 }
88 fd = open(av[1], O_RDWR);
89 if (fd < 0) {
90 perror(av[1]);
91 exit(1);
92 }
93
94 nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4;
95
96 n = read(fd, buf, sizeof(buf));
97 if (n < 0) {
98 perror("read");
99 exit(1);
100 }
101
102 if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0)
103 goto notelf;
104
105 if (buf[E_IDENT+EI_CLASS] != ELFCLASS32
106 || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) {
107 fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n",
108 av[1]);
109 exit(1);
110 }
111
112 ph = GET_32BE(E_PHOFF);
113 ps = GET_16BE(E_PHENTSIZE);
114 np = GET_16BE(E_PHNUM);
115 if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
116 goto notelf;
117 if (ph + (np + 1) * ps + nnote > n)
118 goto nospace;
119
120 for (i = 0; i < np; ++i) {
121 if (GET_32BE(ph + PH_TYPE) == PT_NOTE) {
122 fprintf(stderr, "%s already has a note entry\n",
123 av[1]);
124 exit(0);
125 }
126 ph += ps;
127 }
128
129 /* XXX check that the area we want to use is all zeroes */
130 for (i = 0; i < ps + nnote; ++i)
131 if (buf[ph + i] != 0)
132 goto nospace;
133
134 /* fill in the program header entry */
135 ns = ph + ps;
136 PUT_32BE(ph + PH_TYPE, PT_NOTE);
137 PUT_32BE(ph + PH_OFFSET, ns);
138 PUT_32BE(ph + PH_FILESZ, nnote);
139
140 /* fill in the note area we point to */
141 /* XXX we should probably make this a proper section */
142 PUT_32BE(ns, strlen(arch) + 1);
143 PUT_32BE(ns + 4, N_DESCR * 4);
144 PUT_32BE(ns + 8, 0x1275);
145 strcpy(&buf[ns + 12], arch);
146 ns += 12 + strlen(arch) + 1;
147 for (i = 0; i < N_DESCR; ++i)
148 PUT_32BE(ns + i * 4, descr[i]);
149
150 /* Update the number of program headers */
151 PUT_16BE(E_PHNUM, np + 1);
152
153 /* write back */
154 lseek(fd, (long) 0, SEEK_SET);
155 i = write(fd, buf, n);
156 if (i < 0) {
157 perror("write");
158 exit(1);
159 }
160 if (i < n) {
161 fprintf(stderr, "%s: write truncated\n", av[1]);
162 exit(1);
163 }
164
165 exit(0);
166
167 notelf:
168 fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]);
169 exit(1);
170
171 nospace:
172 fprintf(stderr, "sorry, I can't find space in %s to put the note\n",
173 av[0]);
174 exit(1);
175}
diff --git a/arch/ppc/boot/utils/elf.pl b/arch/ppc/boot/utils/elf.pl
new file mode 100644
index 000000000000..d3e9d9d5b84e
--- /dev/null
+++ b/arch/ppc/boot/utils/elf.pl
@@ -0,0 +1,33 @@
1#
2# ELF header field numbers
3#
4
5$e_ident = 0; # Identification bytes / magic number
6$e_type = 1; # ELF file type
7$e_machine = 2; # Target machine type
8$e_version = 3; # File version
9$e_entry = 4; # Start address
10$e_phoff = 5; # Program header file offset
11$e_shoff = 6; # Section header file offset
12$e_flags = 7; # File flags
13$e_ehsize = 8; # Size of ELF header
14$e_phentsize = 9; # Size of program header
15$e_phnum = 10; # Number of program header entries
16$e_shentsize = 11; # Size of section header
17$e_shnum = 12; # Number of section header entries
18$e_shstrndx = 13; # Section header table string index
19
20#
21# Section header field numbers
22#
23
24$sh_name = 0; # Section name
25$sh_type = 1; # Section header type
26$sh_flags = 2; # Section header flags
27$sh_addr = 3; # Virtual address
28$sh_offset = 4; # File offset
29$sh_size = 5; # Section size
30$sh_link = 6; # Miscellaneous info
31$sh_info = 7; # More miscellaneous info
32$sh_addralign = 8; # Memory alignment
33$sh_entsize = 9; # Entry size if this is a table
diff --git a/arch/ppc/boot/utils/hack-coff.c b/arch/ppc/boot/utils/hack-coff.c
new file mode 100644
index 000000000000..5e5a6573a1ef
--- /dev/null
+++ b/arch/ppc/boot/utils/hack-coff.c
@@ -0,0 +1,84 @@
1/*
2 * hack-coff.c - hack the header of an xcoff file to fill in
3 * a few fields needed by the Open Firmware xcoff loader on
4 * Power Macs but not initialized by objcopy.
5 *
6 * Copyright (C) Paul Mackerras 1997.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <fcntl.h>
17#include <string.h>
18#include "rs6000.h"
19
20#define AOUT_MAGIC 0x010b
21
22#define get_16be(x) ((((unsigned char *)(x))[0] << 8) \
23 + ((unsigned char *)(x))[1])
24#define put_16be(x, v) (((unsigned char *)(x))[0] = (v) >> 8, \
25 ((unsigned char *)(x))[1] = (v) & 0xff)
26#define get_32be(x) ((((unsigned char *)(x))[0] << 24) \
27 + (((unsigned char *)(x))[1] << 16) \
28 + (((unsigned char *)(x))[2] << 8) \
29 + ((unsigned char *)(x))[3])
30
31int
32main(int ac, char **av)
33{
34 int fd;
35 int i, nsect;
36 int aoutsz;
37 struct external_filehdr fhdr;
38 AOUTHDR aout;
39 struct external_scnhdr shdr;
40
41 if (ac != 2) {
42 fprintf(stderr, "Usage: hack-coff coff-file\n");
43 exit(1);
44 }
45 if ((fd = open(av[1], 2)) == -1) {
46 perror(av[2]);
47 exit(1);
48 }
49 if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr))
50 goto readerr;
51 i = get_16be(fhdr.f_magic);
52 if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) {
53 fprintf(stderr, "%s: not an xcoff file\n", av[1]);
54 exit(1);
55 }
56 aoutsz = get_16be(fhdr.f_opthdr);
57 if (read(fd, &aout, aoutsz) != aoutsz)
58 goto readerr;
59 nsect = get_16be(fhdr.f_nscns);
60 for (i = 0; i < nsect; ++i) {
61 if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
62 goto readerr;
63 if (strcmp(shdr.s_name, ".text") == 0) {
64 put_16be(aout.o_snentry, i+1);
65 put_16be(aout.o_sntext, i+1);
66 } else if (strcmp(shdr.s_name, ".data") == 0) {
67 put_16be(aout.o_sndata, i+1);
68 } else if (strcmp(shdr.s_name, ".bss") == 0) {
69 put_16be(aout.o_snbss, i+1);
70 }
71 }
72 put_16be(aout.magic, AOUT_MAGIC);
73 if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1
74 || write(fd, &aout, aoutsz) != aoutsz) {
75 fprintf(stderr, "%s: write error\n", av[1]);
76 exit(1);
77 }
78 close(fd);
79 exit(0);
80
81readerr:
82 fprintf(stderr, "%s: read error or file too short\n", av[1]);
83 exit(1);
84}
diff --git a/arch/ppc/boot/utils/mkbugboot.c b/arch/ppc/boot/utils/mkbugboot.c
new file mode 100644
index 000000000000..886122283f39
--- /dev/null
+++ b/arch/ppc/boot/utils/mkbugboot.c
@@ -0,0 +1,187 @@
1/*
2 * arch/ppc/boot/utils/mkbugboot.c
3 *
4 * Makes a Motorola PPCBUG ROM bootable image which can be flashed
5 * into one of the FLASH banks on a Motorola PowerPlus board.
6 *
7 * Author: Matt Porter <mporter@mvista.com>
8 *
9 * 2001 (c) MontaVista, Software, Inc. This file is licensed under
10 * the terms of the GNU General Public License version 2. This program
11 * is licensed "as is" without any warranty of any kind, whether express
12 * or implied.
13 */
14
15#define ELF_HEADER_SIZE 65536
16
17#include <unistd.h>
18#include <sys/stat.h>
19#include <string.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <errno.h>
23#include <fcntl.h>
24#ifdef __sun__
25#include <inttypes.h>
26#else
27#include <stdint.h>
28#endif
29
30#ifdef __i386__
31#define cpu_to_be32(x) le32_to_cpu(x)
32#define cpu_to_be16(x) le16_to_cpu(x)
33#else
34#define cpu_to_be32(x) (x)
35#define cpu_to_be16(x) (x)
36#endif
37
38#define cpu_to_le32(x) le32_to_cpu((x))
39unsigned long le32_to_cpu(unsigned long x)
40{
41 return (((x & 0x000000ffU) << 24) |
42 ((x & 0x0000ff00U) << 8) |
43 ((x & 0x00ff0000U) >> 8) |
44 ((x & 0xff000000U) >> 24));
45}
46
47#define cpu_to_le16(x) le16_to_cpu((x))
48unsigned short le16_to_cpu(unsigned short x)
49{
50 return (((x & 0x00ff) << 8) |
51 ((x & 0xff00) >> 8));
52}
53
54/* size of read buffer */
55#define SIZE 0x1000
56
57/* PPCBUG ROM boot header */
58typedef struct bug_boot_header {
59 uint8_t magic_word[4]; /* "BOOT" */
60 uint32_t entry_offset; /* Offset from top of header to code */
61 uint32_t routine_length; /* Length of code */
62 uint8_t routine_name[8]; /* Name of the boot code */
63} bug_boot_header_t;
64
65#define HEADER_SIZE sizeof(bug_boot_header_t)
66
67uint32_t copy_image(int32_t in_fd, int32_t out_fd)
68{
69 uint8_t buf[SIZE];
70 int n;
71 uint32_t image_size = 0;
72 uint8_t zero = 0;
73
74 lseek(in_fd, ELF_HEADER_SIZE, SEEK_SET);
75
76 /* Copy an image while recording its size */
77 while ( (n = read(in_fd, buf, SIZE)) > 0 )
78 {
79 image_size = image_size + n;
80 write(out_fd, buf, n);
81 }
82
83 /* BUG romboot requires that our size is divisible by 2 */
84 /* align image to 2 byte boundary */
85 if (image_size % 2)
86 {
87 image_size++;
88 write(out_fd, &zero, 1);
89 }
90
91 return image_size;
92}
93
94void write_bugboot_header(int32_t out_fd, uint32_t boot_size)
95{
96 uint8_t header_block[HEADER_SIZE];
97 bug_boot_header_t *bbh = (bug_boot_header_t *)&header_block[0];
98
99 memset(header_block, 0, HEADER_SIZE);
100
101 /* Fill in the PPCBUG ROM boot header */
102 strncpy(bbh->magic_word, "BOOT", 4); /* PPCBUG magic word */
103 bbh->entry_offset = cpu_to_be32(HEADER_SIZE); /* Entry address */
104 bbh->routine_length= cpu_to_be32(HEADER_SIZE+boot_size+2); /* Routine length */
105 strncpy(bbh->routine_name, "LINUXROM", 8); /* Routine name */
106
107 /* Output the header and bootloader to the file */
108 write(out_fd, header_block, HEADER_SIZE);
109}
110
111uint16_t calc_checksum(int32_t bug_fd)
112{
113 uint32_t checksum_var = 0;
114 uint8_t buf[2];
115 int n;
116
117 /* Checksum loop */
118 while ( (n = read(bug_fd, buf, 2) ) )
119 {
120 checksum_var = checksum_var + *(uint16_t *)buf;
121
122 /* If we carry out, mask it and add one to the checksum */
123 if (checksum_var >> 16)
124 checksum_var = (checksum_var & 0x0000ffff) + 1;
125 }
126
127 return checksum_var;
128}
129
130int main(int argc, char *argv[])
131{
132 int32_t image_fd, bugboot_fd;
133 int argptr = 1;
134 uint32_t kernel_size = 0;
135 uint16_t checksum = 0;
136 uint8_t bugbootname[256];
137
138 if ( (argc != 3) )
139 {
140 fprintf(stderr, "usage: %s <kernel_image> <bugboot>\n",argv[0]);
141 exit(-1);
142 }
143
144 /* Get file args */
145
146 /* kernel image file */
147 if ((image_fd = open( argv[argptr] , 0)) < 0)
148 exit(-1);
149 argptr++;
150
151 /* bugboot file */
152 if ( !strcmp( argv[argptr], "-" ) )
153 bugboot_fd = 1; /* stdout */
154 else
155 if ((bugboot_fd = creat( argv[argptr] , 0755)) < 0)
156 exit(-1);
157 else
158 strcpy(bugbootname, argv[argptr]);
159 argptr++;
160
161 /* Set file position after ROM header block where zImage will be written */
162 lseek(bugboot_fd, HEADER_SIZE, SEEK_SET);
163
164 /* Copy kernel image into bugboot image */
165 kernel_size = copy_image(image_fd, bugboot_fd);
166 close(image_fd);
167
168 /* Set file position to beginning where header/romboot will be written */
169 lseek(bugboot_fd, 0, SEEK_SET);
170
171 /* Write out BUG header/romboot */
172 write_bugboot_header(bugboot_fd, kernel_size);
173
174 /* Close bugboot file */
175 close(bugboot_fd);
176
177 /* Reopen it as read/write */
178 bugboot_fd = open(bugbootname, O_RDWR);
179
180 /* Calculate checksum */
181 checksum = calc_checksum(bugboot_fd);
182
183 /* Write out the calculated checksum */
184 write(bugboot_fd, &checksum, 2);
185
186 return 0;
187}
diff --git a/arch/ppc/boot/utils/mknote.c b/arch/ppc/boot/utils/mknote.c
new file mode 100644
index 000000000000..b9fbb2cbfc8f
--- /dev/null
+++ b/arch/ppc/boot/utils/mknote.c
@@ -0,0 +1,44 @@
1/*
2 * Copyright (C) Cort Dougan 1999.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Generate a note section as per the CHRP specification.
10 *
11 */
12
13#include <stdio.h>
14#include <string.h>
15
16#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff );
17
18int main(void)
19{
20/* header */
21 /* namesz */
22 PL(strlen("PowerPC")+1);
23 /* descrsz */
24 PL(6*4);
25 /* type */
26 PL(0x1275);
27 /* name */
28 printf("PowerPC"); printf("%c", 0);
29
30/* descriptor */
31 /* real-mode */
32 PL(0xffffffff);
33 /* real-base */
34 PL(0x00c00000);
35 /* real-size */
36 PL(0xffffffff);
37 /* virt-base */
38 PL(0xffffffff);
39 /* virt-size */
40 PL(0xffffffff);
41 /* load-base */
42 PL(0x4000);
43 return 0;
44}
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))
27unsigned 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))
37unsigned 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
52typedef unsigned long dword_t;
53typedef unsigned short word_t;
54typedef unsigned char byte_t;
55typedef byte_t block_t[512];
56typedef byte_t page_t[4096];
57
58
59/*
60 * Partition table entry
61 * - from the PReP spec
62 */
63typedef 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
81void copy_image(int , int);
82void write_prep_partition(int , int );
83void write_asm_data( int in, int out );
84
85unsigned int elfhdr_size = 65536;
86
87int 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
149void 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
233void
234copy_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
244void
245write_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}
diff --git a/arch/ppc/boot/utils/mktree.c b/arch/ppc/boot/utils/mktree.c
new file mode 100644
index 000000000000..2be22e28f2b3
--- /dev/null
+++ b/arch/ppc/boot/utils/mktree.c
@@ -0,0 +1,152 @@
1/*
2 * Makes a tree bootable image for IBM Evaluation boards.
3 * Basically, just take a zImage, skip the ELF header, and stuff
4 * a 32 byte header on the front.
5 *
6 * We use htonl, which is a network macro, to make sure we're doing
7 * The Right Thing on an LE machine. It's non-obvious, but it should
8 * work on anything BSD'ish.
9 */
10
11#include <fcntl.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/stat.h>
16#include <unistd.h>
17#include <netinet/in.h>
18#ifdef __sun__
19#include <inttypes.h>
20#else
21#include <stdint.h>
22#endif
23
24/* This gets tacked on the front of the image. There are also a few
25 * bytes allocated after the _start label used by the boot rom (see
26 * head.S for details).
27 */
28typedef struct boot_block {
29 uint32_t bb_magic; /* 0x0052504F */
30 uint32_t bb_dest; /* Target address of the image */
31 uint32_t bb_num_512blocks; /* Size, rounded-up, in 512 byte blks */
32 uint32_t bb_debug_flag; /* Run debugger or image after load */
33 uint32_t bb_entry_point; /* The image address to start */
34 uint32_t bb_checksum; /* 32 bit checksum including header */
35 uint32_t reserved[2];
36} boot_block_t;
37
38#define IMGBLK 512
39char tmpbuf[IMGBLK];
40
41int main(int argc, char *argv[])
42{
43 int in_fd, out_fd;
44 int nblks, i;
45 uint cksum, *cp;
46 struct stat st;
47 boot_block_t bt;
48
49 if (argc < 3) {
50 fprintf(stderr, "usage: %s <zImage-file> <boot-image> [entry-point]\n",argv[0]);
51 exit(1);
52 }
53
54 if (stat(argv[1], &st) < 0) {
55 perror("stat");
56 exit(2);
57 }
58
59 nblks = (st.st_size + IMGBLK) / IMGBLK;
60
61 bt.bb_magic = htonl(0x0052504F);
62
63 /* If we have the optional entry point parameter, use it */
64 if (argc == 4)
65 bt.bb_dest = bt.bb_entry_point = htonl(strtoul(argv[3], NULL, 0));
66 else
67 bt.bb_dest = bt.bb_entry_point = htonl(0x500000);
68
69 /* We know these from the linker command.
70 * ...and then move it up into memory a little more so the
71 * relocation can happen.
72 */
73 bt.bb_num_512blocks = htonl(nblks);
74 bt.bb_debug_flag = 0;
75
76 bt.bb_checksum = 0;
77
78 /* To be neat and tidy :-).
79 */
80 bt.reserved[0] = 0;
81 bt.reserved[1] = 0;
82
83 if ((in_fd = open(argv[1], O_RDONLY)) < 0) {
84 perror("zImage open");
85 exit(3);
86 }
87
88 if ((out_fd = open(argv[2], (O_RDWR | O_CREAT | O_TRUNC), 0666)) < 0) {
89 perror("bootfile open");
90 exit(3);
91 }
92
93 cksum = 0;
94 cp = (void *)&bt;
95 for (i=0; i<sizeof(bt)/sizeof(uint); i++)
96 cksum += *cp++;
97
98 /* Assume zImage is an ELF file, and skip the 64K header.
99 */
100 if (read(in_fd, tmpbuf, IMGBLK) != IMGBLK) {
101 fprintf(stderr, "%s is too small to be an ELF image\n",
102 argv[1]);
103 exit(4);
104 }
105
106 if ((*(uint *)tmpbuf) != htonl(0x7f454c46)) {
107 fprintf(stderr, "%s is not an ELF image\n", argv[1]);
108 exit(4);
109 }
110
111 if (lseek(in_fd, (64 * 1024), SEEK_SET) < 0) {
112 fprintf(stderr, "%s failed to seek in ELF image\n", argv[1]);
113 exit(4);
114 }
115
116 nblks -= (64 * 1024) / IMGBLK;
117
118 /* And away we go......
119 */
120 if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) {
121 perror("boot-image write");
122 exit(5);
123 }
124
125 while (nblks-- > 0) {
126 if (read(in_fd, tmpbuf, IMGBLK) < 0) {
127 perror("zImage read");
128 exit(5);
129 }
130 cp = (uint *)tmpbuf;
131 for (i=0; i<sizeof(tmpbuf)/sizeof(uint); i++)
132 cksum += *cp++;
133 if (write(out_fd, tmpbuf, sizeof(tmpbuf)) != sizeof(tmpbuf)) {
134 perror("boot-image write");
135 exit(5);
136 }
137 }
138
139 /* rewrite the header with the computed checksum.
140 */
141 bt.bb_checksum = htonl(cksum);
142 if (lseek(out_fd, 0, SEEK_SET) < 0) {
143 perror("rewrite seek");
144 exit(1);
145 }
146 if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) {
147 perror("boot-image rewrite");
148 exit(1);
149 }
150
151 exit(0);
152}