4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
32 #include <sys/types.h>
33 #include <sys/inttypes.h>
35 #include <sys/elf_notes.h>
38 #include <sys/sysmacros.h>
39 #include "sys/multiboot.h"
40 #include "sys/multiboot2.h"
44 static char *image
; /* pointer to the ELF file in memory */
46 #define ELFSEEK(offset) ((void *)(image + offset))
49 * Find MB2 header tags for entry and patch it.
50 * The first tag is right after header.
53 patch64_mb2(multiboot2_header_t
*mbh2
, int file_offset
,
54 Elf64_Addr ptload_start
, Elf32_Off ptload_offset
)
56 multiboot_header_tag_t
*tagp
= mbh2
->mb2_tags
;
57 multiboot_header_tag_address_t
*mbaddr
= NULL
;
58 multiboot_header_tag_entry_address_t
*mbentry
= NULL
;
61 * Loop until we get end TAG or we have both tags.
63 while (tagp
->mbh_type
!= MULTIBOOT_HEADER_TAG_END
&&
64 (mbaddr
== NULL
|| mbentry
== NULL
)) {
65 switch (tagp
->mbh_type
) {
66 case MULTIBOOT_HEADER_TAG_ADDRESS
:
67 mbaddr
= (multiboot_header_tag_address_t
*)tagp
;
69 case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS
:
70 mbentry
= (multiboot_header_tag_entry_address_t
*)tagp
;
73 tagp
= (multiboot_header_tag_t
*)
75 P2ROUNDUP(tagp
->mbh_size
, MULTIBOOT_TAG_ALIGN
));
78 if (mbaddr
== NULL
|| mbentry
== NULL
) {
79 (void) fprintf(stderr
, "Missing multiboot2 %s tag\n",
80 (mbaddr
== NULL
)? "address" : "entry");
85 mbaddr
->mbh_load_addr
= ptload_start
- ptload_offset
;
86 mbaddr
->mbh_header_addr
= mbaddr
->mbh_load_addr
+ file_offset
;
87 mbentry
->mbh_entry_addr
= ptload_start
;
90 (void) printf(" ELF64 MB2 header patched\n");
91 (void) printf("\tload_addr now: 0x%x\n", mbaddr
->mbh_load_addr
);
92 (void) printf("\theader_addr now: 0x%x\n", mbaddr
->mbh_header_addr
);
93 (void) printf("\tentry_addr now: 0x%x\n", mbentry
->mbh_entry_addr
);
99 * Patch the load address / entry address for MB1 and MB2 if present.
100 * Find the physical load address of the 1st PT_LOAD segment.
101 * Find the amount that e_entry exceeds that amount.
102 * Now go back and subtract the excess from the p_paddr of the LOAD segment.
105 patch64(Elf64_Ehdr
*eh
)
108 caddr_t phdrs
= NULL
;
110 multiboot_header_t
*mbh
;
111 multiboot2_header_t
*mbh2
;
114 * Verify some ELF basics - this must be an executable with program
117 if (eh
->e_type
!= ET_EXEC
) {
118 (void) fprintf(stderr
, "%s: %s: not ET_EXEC, e_type = 0x%x\n",
119 pname
, fname
, eh
->e_type
);
122 if ((eh
->e_phnum
== 0) || (eh
->e_phoff
== 0)) {
123 (void) fprintf(stderr
, "%s: %s: no program headers\n", pname
,
129 * Get the program headers.
131 if ((phdrs
= ELFSEEK(eh
->e_phoff
)) == NULL
) {
132 (void) fprintf(stderr
, "%s: %s: failed to get %d program "
133 "hdrs\n", pname
, fname
, eh
->e_phnum
);
138 * Look for multiboot1 header. It must be 32-bit aligned and
139 * completely contained in the 1st 8K of the file.
141 for (mem
= 0; mem
< 8192 - sizeof (multiboot_header_t
); mem
+= 4) {
143 if (mbh
->magic
== MB_HEADER_MAGIC
)
147 if (mem
>= 8192 - sizeof (multiboot_header_t
)) {
148 (void) fprintf(stderr
, "%s: %s: Didn't find multiboot header\n",
154 * Look for multiboot2 header. It must be 64-bit aligned and
155 * completely contained in the 1st 32K of the file.
156 * We do not require it to be present.
160 mem2
<= MULTIBOOT_SEARCH
- sizeof (multiboot2_header_t
);
161 mem2
+= MULTIBOOT_HEADER_ALIGN
) {
162 mbh2
= ELFSEEK(mem2
);
163 ndx
= mbh2
->mb2_header_length
;
164 if (mbh2
->mb2_magic
== MULTIBOOT2_HEADER_MAGIC
)
169 if (ndx
== 0 || mem2
+ ndx
> MULTIBOOT_SEARCH
) {
171 (void) fprintf(stderr
, "%s: %s: Didn't find multiboot2 "
172 "header\n", pname
, fname
);
178 * Find the 1:1 mapped PT_LOAD section
180 for (ndx
= 0; ndx
< eh
->e_phnum
; ndx
++) {
181 /*LINTED [ELF program header alignment]*/
182 phdr
= (Elf64_Phdr
*)(phdrs
+ eh
->e_phentsize
* ndx
);
185 * Find the low memory 1:1 PT_LOAD section!
187 if (phdr
->p_type
!= PT_LOAD
)
190 if (phdr
->p_memsz
== 0)
193 if (phdr
->p_paddr
!= phdr
->p_vaddr
)
197 * Make sure the multiboot header is part of the first PT_LOAD
198 * segment, and that the executables entry point starts at the
201 if ((mem
< phdr
->p_offset
) ||
202 (mem
>= (phdr
->p_offset
+ phdr
->p_filesz
))) {
203 (void) fprintf(stderr
, "%s: %s: identity mapped "
204 "PT_LOAD wasn't 1st PT_LOAD\n", pname
, fname
);
207 if (eh
->e_entry
!= phdr
->p_paddr
) {
208 (void) fprintf(stderr
, "%s: %s: entry != paddr\n",
213 if (mbh2
!= NULL
&& ((mem2
< phdr
->p_offset
) ||
214 (mem2
>= (phdr
->p_offset
+ phdr
->p_filesz
)))) {
216 (void) fprintf(stderr
, "%s: %s: multiboot2 header not"
217 " in 1st PT_LOAD\n", pname
, fname
);
224 * Patch the multiboot header fields to get entire file loaded.
225 * Grub uses the MB header for 64 bit loading.
227 mbh
->load_addr
= phdr
->p_paddr
- phdr
->p_offset
;
228 mbh
->entry_addr
= phdr
->p_paddr
;
229 mbh
->header_addr
= mbh
->load_addr
+ mem
;
231 (void) printf(" %s: ELF64 MB header patched\n", fname
);
232 (void) printf("\tload_addr now: 0x%x\n", mbh
->load_addr
);
233 (void) printf("\tentry_addr now: 0x%x\n", mbh
->entry_addr
);
234 (void) printf("\theader_addr now: 0x%x\n", mbh
->header_addr
);
237 return (patch64_mb2(mbh2
, mem2
, phdr
->p_paddr
,
242 (void) fprintf(stderr
, "%s: %s: Didn't find 1:1 mapped PT_LOAD "
243 "section\n", pname
, fname
);
248 main(int argc
, char **argv
)
256 * We expect one argument -- the elf file.
259 (void) fprintf(stderr
, "usage: %s <unix-elf-file>\n", argv
[0]);
263 pname
= strrchr(argv
[0], '/');
270 if ((fd
= open(fname
, O_RDWR
)) < 0) {
271 (void) fprintf(stderr
, "%s: open(%s, O_RDWR) failed: %s\n",
272 pname
, fname
, strerror(errno
));
276 if (fstat(fd
, &sb
) != 0) {
277 (void) fprintf(stderr
, "%s: fstat failed: %s\n",
278 pname
, strerror(errno
));
282 /* Make sure we have at least MULTIBOOT_SEARCH bytes. */
283 if (sb
.st_size
< MULTIBOOT_SEARCH
) {
284 (void) fprintf(stderr
, "%s: %s is too small for a kernel\n",
290 * mmap the 1st 32K -- MB1 header is within first 8k and MB2 header
293 image
= mmap(NULL
, MULTIBOOT_SEARCH
, PROT_READ
| PROT_WRITE
,
295 if (image
== MAP_FAILED
) {
296 (void) fprintf(stderr
, "%s: mmap() of %s failed: %s\n",
297 pname
, fname
, strerror(errno
));
302 if (ident
[EI_MAG0
] != ELFMAG0
|| ident
[EI_MAG1
] != ELFMAG1
||
303 ident
[EI_MAG2
] != ELFMAG2
|| ident
[EI_MAG3
] != ELFMAG3
) {
304 (void) fprintf(stderr
, "%s: %s: not an ELF file!\n", pname
,
309 if (ident
[EI_CLASS
] == ELFCLASS64
) {
311 return (patch64(hdr
));
313 if (ident
[EI_CLASS
] != ELFCLASS32
) {
314 (void) fprintf(stderr
, "%s: Unknown ELF class 0x%x\n", pname
,