2 ** Portions Copyright 2001-2004, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
6 ** Copyright 1998 Brian J. Swetland
7 ** All rights reserved.
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
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"
36 #include <sys/types.h>
47 #define xLITTLE_ENDIAN 1
50 #define xLITTLE_ENDIAN 1
60 ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24))
62 SWAP32((x) << 32) | SWAP32((x) >> 32)
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)
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)
77 #if !xBIG_ENDIAN && !xLITTLE_ENDIAN
78 #error not sure which endian the host processor is, please edit bootmaker.c
82 #define ELF_MAGIC "\x7f""ELF"
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
;
106 unsigned char e_ident
[EI_NIDENT
];
108 Elf32_Half e_machine
;
109 Elf32_Word e_version
;
115 Elf32_Half e_phentsize
;
117 Elf32_Half e_shentsize
;
119 Elf32_Half e_shstrndx
;
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
;
143 unsigned char e_ident
[EI_NIDENT
];
144 Elf64_Quarter e_type
;
145 Elf64_Quarter e_machine
;
146 Elf64_Half e_version
;
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
;
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: ");
189 fprintf(stderr
,"\n");
193 void *loadtextfile(char *file
, int *size
)
204 if((fd
= open(file
,O_BINARY
|O_RDONLY
)) != -1){
210 data
= (char *) malloc(info
.st_size
);
213 while((ret
= read(fd
, &c
, 1)) > 0) {
226 void *loadfile(char *file
, int *size
)
232 if((fd
= open(file
,O_BINARY
|O_RDONLY
)) != -1){
238 data
= (char *) malloc(info
.st_size
);
239 if(read(fd
, data
, info
.st_size
) != info
.st_size
) {
245 *size
= info
.st_size
;
252 void *loadstripfile(char *file
, int *size
)
260 /* This is broken for cygwin
261 strcpy(temp, "/tmp/mkboot.XXXXXXXX");
265 sprintf(cmd
, "cp %s %s; %s %s", file
, temp
, strip_binary
, temp
);
268 retval
= loadfile(temp
, size
);
272 retval
= loadfile(file
, size
);
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
;
299 typedef struct _section
301 struct _section
*next
;
303 struct _nvpair
*firstnv
;
306 void print_sections(section
*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
);
325 section
*first
= NULL
;
326 section
*last
= NULL
;
328 section
*load_ini(char *file
)
332 int state
= stNEWLINE
;
337 if(!(data
= loadfile(file
,&size
))){
345 if(*data
== '\n' || *data
== '\r'){
352 if(*data
== '\n' || *data
== '\r'){
362 if(*data
== '#' || *data
<= ' '){
373 cur
= (section
*) malloc(sizeof(section
));
389 if(*data
== '\n' || *data
== '\r'){
400 if(*data
== '\n' || *data
== '\r'){
401 nvpair
*p
= (nvpair
*) malloc(sizeof(nvpair
));
405 p
->next
= cur
->firstnv
;
418 char *getval(section
*s
, char *name
)
421 for(p
= s
->firstnv
; p
; p
= p
->next
){
422 if(!strcmp(p
->name
,name
)) return p
->value
;
427 char *getvaldef(section
*s
, char *name
, char *def
)
430 for(p
= s
->firstnv
; p
; p
= p
->next
){
431 if(!strcmp(p
->name
,name
)) return p
->value
;
436 Elf32_Off
elf32_find_entry(void *buf
, int size
)
438 struct Elf32_Ehdr
*header
;
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");
450 if(cbuf
[EI_CLASS
] != ELFCLASS32
) {
451 fprintf(stderr
, "wrong elf class (%d)\n", cbuf
[EI_CLASS
]);
455 if(cbuf
[EI_VERSION
] != 1) {
456 fprintf(stderr
, "elf file has unsupported version (%d)\n", cbuf
[EI_VERSION
]);
462 if(cbuf
[EI_DATA
] == ELFDATA2LSB
) {
466 if(cbuf
[EI_DATA
] == ELFDATA2MSB
) {
471 header
= (struct Elf32_Ehdr
*)buf
;
472 return SWAPIT(header
->e_entry
);
476 Elf64_Off
elf64_find_entry(void *buf
, int size
)
478 struct Elf64_Ehdr
*header
;
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");
490 if(cbuf
[EI_CLASS
] != ELFCLASS64
) {
491 fprintf(stderr
, "wrong elf class (%d)\n", cbuf
[EI_CLASS
]);
495 if(cbuf
[EI_VERSION
] != 1) {
496 fprintf(stderr
, "elf file has unsupported version (%d)\n", cbuf
[EI_VERSION
]);
502 if(cbuf
[EI_DATA
] == ELFDATA2LSB
) {
506 if(cbuf
[EI_DATA
] == ELFDATA2MSB
) {
511 // XXX 64bit entrypoint doesn't fit here
512 header
= (struct Elf64_Ehdr
*)buf
;
513 return SWAPIT(header
->e_entry
);
517 #define centry bdir.bd_entry[c]
518 void makeboot(section
*s
, char *outfile
)
521 void *rawdata
[BOOTDIR_MAX_ENTRIES
];
522 int rawsize
[BOOTDIR_MAX_ENTRIES
];
526 int nextpage
= 0; /* page rel offset of next loaded object */
531 memset(&bdir
, 0, sizeof(bdir
));
532 for(i
=0;i
<BOOTDIR_MAX_ENTRIES
;i
++){
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]);
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
]);
565 rawdata
[c
] = loadfile(file
,&rawsize
[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
);
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
);
621 writesparcbootblock(fd
, nextpage
+1);
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);
633 printf("wrote %ld bytes to output file %s\n", outlen
, outfile
);
636 int main(int argc
, char **argv
)
643 fprintf(stderr
,"usage: %s [--littleendian (default)] [--bigendian ] [ --strip-binary <binary ] [ --strip-debug] [ --sparc | -s ] [ <inifile> ... ] -o <bootfile>\n",argv
[0]);
651 if(!strcmp(*argv
,"--sparc")) {
653 } else if(!strcmp(*argv
, "--bigendian")) {
655 } else if(!strcmp(*argv
,"-o")) {
663 } else if(!strcmp(*argv
, "--strip-binary")) {
667 strip_binary
= *argv
;
671 } else if(!strcmp(*argv
, "--strip-debug")) {
674 if(load_ini(*argv
) == NULL
) {
675 fprintf(stderr
,"warning: cannot load '%s'\n",*argv
);
683 if((argc
> 3) && !strcmp(argv
[3],"-sparc")){
688 fprintf(stderr
,"error: no output specified\n");
693 fprintf(stderr
,"error: no data to write?!\n");
697 makeboot(first
,file
);