use the -newos toolchain even if -elf is present.
[newos.git] / tools / bootmaker.c
blobc28bd38027ed898e1388f32e5f899965f9058e11
1 /*
2 ** Portions Copyright 2001-2004, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
4 */
5 /*
6 ** Copyright 1998 Brian J. Swetland
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 ** 1. Redistributions of source code must retain the above copyright
13 ** notice, this list of conditions, and the following disclaimer.
14 ** 2. Redistributions in binary form must reproduce the above copyright
15 ** notice, this list of conditions, and the following disclaimer in the
16 ** documentation and/or other materials provided with the distribution.
17 ** 3. The name of the author may not be used to endorse or promote products
18 ** derived from this software without specific prior written permission.
20 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "../include/boot/bootdir.h"
33 #include "sparcbootblock.h"
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <fcntl.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <string.h>
43 #ifdef sparc
44 #define xBIG_ENDIAN 1
45 #endif
46 #ifdef i386
47 #define xLITTLE_ENDIAN 1
48 #endif
49 #ifdef __x86_64
50 #define xLITTLE_ENDIAN 1
51 #endif
52 #ifdef __ppc__
53 #define xBIG_ENDIAN 1
54 #endif
55 #ifdef __powerpc__
56 #define xBIG_ENDIAN 1
57 #endif
59 #define SWAP32(x) \
60 ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24))
61 #define SWAP64(x) \
62 SWAP32((x) << 32) | SWAP32((x) >> 32)
64 #if xBIG_ENDIAN
65 #define HOST_TO_BENDIAN32(x) (x)
66 #define BENDIAN_TO_HOST32(x) (x)
67 #define HOST_TO_LENDIAN32(x) SWAP32(x)
68 #define LENDIAN_TO_HOST32(x) SWAP32(x)
69 #endif
70 #if xLITTLE_ENDIAN
71 #define HOST_TO_BENDIAN32(x) SWAP32(x)
72 #define BENDIAN_TO_HOST32(x) SWAP32(x)
73 #define HOST_TO_LENDIAN32(x) (x)
74 #define LENDIAN_TO_HOST32(x) (x)
75 #endif
77 #if !xBIG_ENDIAN && !xLITTLE_ENDIAN
78 #error not sure which endian the host processor is, please edit bootmaker.c
79 #endif
81 // ELF stuff
82 #define ELF_MAGIC "\x7f""ELF"
83 #define EI_MAG0 0
84 #define EI_MAG1 1
85 #define EI_MAG2 2
86 #define EI_MAG3 3
87 #define EI_CLASS 4
88 #define EI_DATA 5
89 #define EI_VERSION 6
90 #define EI_PAD 7
91 #define EI_NIDENT 16
93 #define ELFCLASS32 1
94 #define ELFCLASS64 2
95 #define ELFDATA2LSB 1
96 #define ELFDATA2MSB 2
98 // XXX not safe across all build architectures
99 typedef unsigned int Elf32_Addr;
100 typedef unsigned short Elf32_Half;
101 typedef unsigned int Elf32_Off;
102 typedef int Elf32_Sword;
103 typedef unsigned int Elf32_Word;
105 struct Elf32_Ehdr {
106 unsigned char e_ident[EI_NIDENT];
107 Elf32_Half e_type;
108 Elf32_Half e_machine;
109 Elf32_Word e_version;
110 Elf32_Addr e_entry;
111 Elf32_Off e_phoff;
112 Elf32_Off e_shoff;
113 Elf32_Word e_flags;
114 Elf32_Half e_ehsize;
115 Elf32_Half e_phentsize;
116 Elf32_Half e_phnum;
117 Elf32_Half e_shentsize;
118 Elf32_Half e_shnum;
119 Elf32_Half e_shstrndx;
122 struct Elf32_Phdr {
123 Elf32_Word p_type;
124 Elf32_Off p_offset;
125 Elf32_Addr p_vaddr;
126 Elf32_Addr p_paddr;
127 Elf32_Word p_filesz;
128 Elf32_Word p_memsz;
129 Elf32_Word p_flags;
130 Elf32_Word p_align;
133 // ELF64 stuff
134 typedef unsigned long long Elf64_Addr;
135 typedef unsigned short Elf64_Quarter;
136 typedef unsigned int Elf64_Half;
137 typedef unsigned long long Elf64_Off;
138 typedef unsigned long long Elf64_Size;
139 typedef long long Elf64_Sword;
140 typedef unsigned long long Elf64_Word;
142 struct Elf64_Ehdr {
143 unsigned char e_ident[EI_NIDENT];
144 Elf64_Quarter e_type;
145 Elf64_Quarter e_machine;
146 Elf64_Half e_version;
147 Elf64_Addr e_entry;
148 Elf64_Off e_phoff;
149 Elf64_Off e_shoff;
150 Elf64_Half e_flags;
151 Elf64_Quarter e_ehsize;
152 Elf64_Quarter e_phentsize;
153 Elf64_Quarter e_phnum;
154 Elf64_Quarter e_shentsize;
155 Elf64_Quarter e_shnum;
156 Elf64_Quarter e_shstrndx;
159 struct Elf64_Phdr {
160 Elf64_Half p_type;
161 Elf64_Half p_flags;
162 Elf64_Off p_offset;
163 Elf64_Addr p_vaddr;
164 Elf64_Addr p_paddr;
165 Elf64_Size p_filesz;
166 Elf64_Size p_memsz;
167 Elf64_Size p_align;
170 #ifndef O_BINARY
171 #define O_BINARY 0
172 #endif
174 #define LE 0
175 #define BE 1
177 static int target_endian = LE;
179 #define fix(x) ((target_endian == BE) ? HOST_TO_BENDIAN32(x) : HOST_TO_LENDIAN32(x))
181 static int make_sparcboot = 0;
182 static int strip_debug = 0;
183 static char *strip_binary = "strip";
185 void die(char *s, char *a)
187 fprintf(stderr,"error: ");
188 fprintf(stderr,s,a);
189 fprintf(stderr,"\n");
190 exit(1);
193 void *loadtextfile(char *file, int *size)
195 int fd;
196 char *data;
197 char c;
198 struct stat info;
199 int ret;
200 int i;
202 *size = 0;
204 if((fd = open(file,O_BINARY|O_RDONLY)) != -1){
205 if(fstat(fd,&info)){
206 close(fd);
207 return NULL;
210 data = (char *) malloc(info.st_size);
212 i = 0;
213 while((ret = read(fd, &c, 1)) > 0) {
214 if(c != '\r') {
215 data[i++] = c;
216 (*size)++;
220 close(fd);
221 return data;
223 return NULL;
226 void *loadfile(char *file, int *size)
228 int fd;
229 char *data;
230 struct stat info;
232 if((fd = open(file,O_BINARY|O_RDONLY)) != -1){
233 if(fstat(fd,&info)){
234 close(fd);
235 *size = 0;
236 return NULL;
238 data = (char *) malloc(info.st_size);
239 if(read(fd, data, info.st_size) != info.st_size) {
240 close(fd);
241 *size = 0;
242 return NULL;
244 close(fd);
245 *size = info.st_size;
246 return data;
248 *size = 0;
249 return NULL;
252 void *loadstripfile(char *file, int *size)
254 char temp[L_tmpnam];
255 char cmd[4096];
256 void *retval;
259 if(strip_debug) {
260 /* This is broken for cygwin
261 strcpy(temp, "/tmp/mkboot.XXXXXXXX");
262 mkstemp(temp); */
263 tmpnam(temp);
265 sprintf(cmd, "cp %s %s; %s %s", file, temp, strip_binary, temp);
266 system(cmd);
268 retval = loadfile(temp, size);
270 unlink(temp);
271 } else {
272 retval = loadfile(file, size);
275 return retval;
278 // write a boot block to the head of the dir.
279 // note: the first 0x20 bytes are removed by the sparc prom
280 // which makes the whole file off by 0x20 bytes
281 int writesparcbootblock(int fd, unsigned int blocks)
283 unsigned char bb[0x200+0x20];
285 memset(bb, 0, sizeof(bb));
286 memcpy(bb, sparcbootblock, sizeof(sparcbootblock));
288 return write(fd, bb, sizeof(bb));
291 typedef struct _nvpair
293 struct _nvpair *next;
294 char *name;
295 char *value;
296 } nvpair;
299 typedef struct _section
301 struct _section *next;
302 char *name;
303 struct _nvpair *firstnv;
304 } section;
306 void print_sections(section *first)
308 nvpair *p;
310 while(first){
311 printf("\n[%s]\n",first->name);
312 for(p = first->firstnv; p; p = p->next){
313 printf("%s=%s\n",p->name,p->value);
315 first = first->next;
319 #define stNEWLINE 0
320 #define stSKIPLINE 1
321 #define stHEADER 2
322 #define stLHS 3
323 #define stRHS 4
325 section *first = NULL;
326 section *last = NULL;
328 section *load_ini(char *file)
330 char *data,*end;
331 int size;
332 int state = stNEWLINE;
333 section *cur;
335 char *lhs,*rhs;
337 if(!(data = loadfile(file,&size))){
338 return NULL;
340 end = data+size;
342 while(data < end){
343 switch(state){
344 case stSKIPLINE:
345 if(*data == '\n' || *data == '\r'){
346 state = stNEWLINE;
348 data++;
349 break;
351 case stNEWLINE:
352 if(*data == '\n' || *data == '\r'){
353 data++;
354 break;
356 if(*data == '['){
357 lhs = data+1;
358 state = stHEADER;
359 data++;
360 break;
362 if(*data == '#' || *data <= ' '){
363 state = stSKIPLINE;
364 data++;
365 break;
367 lhs = data;
368 data++;
369 state = stLHS;
370 break;
371 case stHEADER:
372 if(*data == ']'){
373 cur = (section *) malloc(sizeof(section));
374 cur->name = lhs;
375 cur->firstnv = NULL;
376 cur->next = NULL;
377 if(last){
378 last->next = cur;
379 last = cur;
380 } else {
381 last = first = cur;
383 *data = 0;
384 state = stSKIPLINE;
386 data++;
387 break;
388 case stLHS:
389 if(*data == '\n' || *data == '\r'){
390 state = stNEWLINE;
392 if(*data == '='){
393 *data = 0;
394 rhs = data+1;
395 state = stRHS;
397 data++;
398 continue;
399 case stRHS:
400 if(*data == '\n' || *data == '\r'){
401 nvpair *p = (nvpair *) malloc(sizeof(nvpair));
402 p->name = lhs;
403 p->value = rhs;
404 *data = 0;
405 p->next = cur->firstnv;
406 cur->firstnv = p;
407 state = stNEWLINE;
409 data++;
410 break;
413 return first;
418 char *getval(section *s, char *name)
420 nvpair *p;
421 for(p = s->firstnv; p; p = p->next){
422 if(!strcmp(p->name,name)) return p->value;
424 return NULL;
427 char *getvaldef(section *s, char *name, char *def)
429 nvpair *p;
430 for(p = s->firstnv; p; p = p->next){
431 if(!strcmp(p->name,name)) return p->value;
433 return def;
436 Elf32_Off elf32_find_entry(void *buf, int size)
438 struct Elf32_Ehdr *header;
439 char *cbuf = buf;
440 int byte_swap;
441 int index;
443 #define SWAPIT(x) ((byte_swap) ? SWAP32(x) : (x))
445 if(memcmp(cbuf, ELF_MAGIC, sizeof(ELF_MAGIC)-1) != 0) {
446 fprintf(stderr, "file does not have proper magic value\n");
447 return 0;
450 if(cbuf[EI_CLASS] != ELFCLASS32) {
451 fprintf(stderr, "wrong elf class (%d)\n", cbuf[EI_CLASS]);
452 return 0;
455 if(cbuf[EI_VERSION] != 1) {
456 fprintf(stderr, "elf file has unsupported version (%d)\n", cbuf[EI_VERSION]);
457 return 0;
460 byte_swap = 0;
461 #if xBIG_ENDIAN
462 if(cbuf[EI_DATA] == ELFDATA2LSB) {
463 byte_swap = 1;
465 #else
466 if(cbuf[EI_DATA] == ELFDATA2MSB) {
467 byte_swap = 1;
469 #endif
471 header = (struct Elf32_Ehdr *)buf;
472 return SWAPIT(header->e_entry);
473 #undef SWAPIT
476 Elf64_Off elf64_find_entry(void *buf, int size)
478 struct Elf64_Ehdr *header;
479 char *cbuf = buf;
480 int byte_swap;
481 int index;
483 #define SWAPIT(x) ((byte_swap) ? SWAP64(x) : (x))
485 if(memcmp(cbuf, ELF_MAGIC, sizeof(ELF_MAGIC)-1) != 0) {
486 fprintf(stderr, "file does not have proper magic value\n");
487 return 0;
490 if(cbuf[EI_CLASS] != ELFCLASS64) {
491 fprintf(stderr, "wrong elf class (%d)\n", cbuf[EI_CLASS]);
492 return 0;
495 if(cbuf[EI_VERSION] != 1) {
496 fprintf(stderr, "elf file has unsupported version (%d)\n", cbuf[EI_VERSION]);
497 return 0;
500 byte_swap = 0;
501 #if xBIG_ENDIAN
502 if(cbuf[EI_DATA] == ELFDATA2LSB) {
503 byte_swap = 1;
505 #else
506 if(cbuf[EI_DATA] == ELFDATA2MSB) {
507 byte_swap = 1;
509 #endif
511 // XXX 64bit entrypoint doesn't fit here
512 header = (struct Elf64_Ehdr *)buf;
513 return SWAPIT(header->e_entry);
514 #undef SWAPIT
517 #define centry bdir.bd_entry[c]
518 void makeboot(section *s, char *outfile)
520 int fd;
521 void *rawdata[BOOTDIR_MAX_ENTRIES];
522 int rawsize[BOOTDIR_MAX_ENTRIES];
523 char fill[4096];
524 boot_dir bdir;
525 int i,c;
526 int nextpage = 0; /* page rel offset of next loaded object */
527 long outlen = 0;
529 memset(fill,0,4096);
531 memset(&bdir, 0, sizeof(bdir));
532 for(i=0;i<BOOTDIR_MAX_ENTRIES;i++){
533 rawdata[i] = NULL;
534 rawsize[i] = 0;
537 c = 1;
539 bdir.bd_entry[0].be_type = fix(BE_TYPE_DIRECTORY);
540 bdir.bd_entry[0].be_size = fix(sizeof(bdir)/4096);
541 bdir.bd_entry[0].be_vsize = fix(sizeof(bdir));
542 rawdata[0] = (void *) &bdir;
543 rawsize[0] = sizeof(bdir);
544 nextpage += sizeof(bdir)/4096;
546 strcpy(bdir.bd_entry[0].be_name,"SBBB/Directory");
547 printf("directory size %d\n", rawsize[0]);
549 while(s){
550 char *type = getvaldef(s,"type","NONE");
551 char *file = getval(s,"file");
553 if(!type) die("section %s has no type",s->name);
555 strncpy(centry.be_name,s->name,BOOTDIR_NAMELEN);
556 centry.be_name[BOOTDIR_NAMELEN-1] = 0;
558 if(!file) die("section %s has no file",s->name);
560 if(!strcmp(type, "elf32") || !strcmp(type, "elf64"))
561 rawdata[c] = loadstripfile(file,&rawsize[c]);
562 else if(!strcmp(type, "text"))
563 rawdata[c] = loadtextfile(file,&rawsize[c]);
564 else
565 rawdata[c] = loadfile(file,&rawsize[c]);
567 if(!rawdata[c])
568 die("cannot load \"%s\"",file);
570 centry.be_size = rawsize[c] / 4096 + (rawsize[c] % 4096 ? 1 : 0);
571 centry.be_vsize = rawsize[c];
573 centry.be_offset = nextpage;
574 nextpage += centry.be_size;
576 centry.be_size = fix(centry.be_size);
577 centry.be_vsize = fix(centry.be_vsize);
578 centry.be_offset = fix(centry.be_offset);
580 if(!strcmp(type,"boot")){
581 centry.be_type = fix(BE_TYPE_BOOTSTRAP);
582 centry.be_code_vaddr = fix(atoi(getvaldef(s,"vaddr","0")));
583 centry.be_code_ventr = fix(atoi(getvaldef(s,"ventry","0")));
585 if(!strcmp(type,"code")){
586 centry.be_type = fix(BE_TYPE_CODE);
587 centry.be_code_vaddr = fix(atoi(getvaldef(s,"vaddr","0")));
588 centry.be_code_ventr = fix(atoi(getvaldef(s,"ventry","0")));
590 if(!strcmp(type,"data") || !strcmp(type,"text")){
591 centry.be_type = fix(BE_TYPE_DATA);
593 if(!strcmp(type,"elf32")){
594 centry.be_type = fix(BE_TYPE_ELF32);
595 centry.be_code_vaddr = 0;
596 centry.be_code_ventr = fix(elf32_find_entry(rawdata[c], rawsize[c]));
598 if(!strcmp(type,"elf64")){
599 centry.be_type = fix(BE_TYPE_ELF64);
600 centry.be_code_vaddr = 0;
601 centry.be_code_ventr = fix(elf64_find_entry(rawdata[c], rawsize[c]));
604 if(centry.be_type == BE_TYPE_NONE){
605 die("unrecognized section type \"%s\"",type);
608 printf(" %8s %8d %s\n", type, fix(centry.be_vsize), centry.be_name);
610 c++;
611 s = s->next;
613 if(c==BOOTDIR_MAX_ENTRIES) die("too many sections (>128)",NULL);
616 if((fd = open(outfile, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
617 die("cannot write to \"%s\"",outfile);
620 if(make_sparcboot) {
621 writesparcbootblock(fd, nextpage+1);
624 for(i=0;i<c;i++){
625 write(fd, rawdata[i], rawsize[i]);
626 outlen += rawsize[i];
627 if(rawsize[i]%4096) {
628 write(fd, fill, 4096 - (rawsize[i]%4096));
629 outlen += 4096 - (rawsize[i]%4096);
632 close(fd);
633 printf("wrote %ld bytes to output file %s\n", outlen, outfile);
636 int main(int argc, char **argv)
638 char *file = NULL;
639 section *s;
641 if(argc < 2){
642 usage:
643 fprintf(stderr,"usage: %s [--littleendian (default)] [--bigendian ] [ --strip-binary <binary ] [ --strip-debug] [ --sparc | -s ] [ <inifile> ... ] -o <bootfile>\n",argv[0]);
644 return 1;
647 argc--;
648 argv++;
650 while(argc){
651 if(!strcmp(*argv,"--sparc")) {
652 make_sparcboot = 1;
653 } else if(!strcmp(*argv, "--bigendian")) {
654 target_endian = BE;
655 } else if(!strcmp(*argv,"-o")) {
656 argc--;
657 argv++;
658 if(argc) {
659 file = *argv;
660 } else {
661 goto usage;
663 } else if(!strcmp(*argv, "--strip-binary")) {
664 argc--;
665 argv++;
666 if(argc) {
667 strip_binary = *argv;
668 } else {
669 goto usage;
671 } else if(!strcmp(*argv, "--strip-debug")) {
672 strip_debug = 1;
673 } else {
674 if(load_ini(*argv) == NULL) {
675 fprintf(stderr,"warning: cannot load '%s'\n",*argv);
678 argc--;
679 argv++;
683 if((argc > 3) && !strcmp(argv[3],"-sparc")){
684 make_sparcboot = 1;
687 if(!file){
688 fprintf(stderr,"error: no output specified\n");
689 goto usage;
692 if(!first){
693 fprintf(stderr,"error: no data to write?!\n");
694 goto usage;
697 makeboot(first,file);
699 return 0;