dboot_elfload.c revision 7656:2621e50fdf4a
1/*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28#include <sys/types.h>
29#include <sys/inttypes.h>
30#include <sys/systm.h>
31#include <sys/elf.h>
32#include <sys/elf_notes.h>
33
34#include <util/memcpy.h>
35
36#include "dboot_xboot.h"
37#include "dboot_elfload.h"
38#include "dboot_printf.h"
39
40static caddr_t elf_file = 0;
41
42#define	PGETBYTES(offset)	((void *)(elf_file + (offset)))
43
44static void *
45getehdr(void)
46{
47	uchar_t *ident;
48	void *hdr = NULL;
49
50	ident = PGETBYTES(0);
51	if (ident == NULL)
52		dboot_panic("Cannot read kernel ELF header");
53
54	if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 ||
55	    ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3)
56		dboot_panic("not an ELF file!");
57
58	if (ident[EI_CLASS] == ELFCLASS32)
59		hdr = PGETBYTES(0);
60	else if (ident[EI_CLASS] == ELFCLASS64)
61		hdr = PGETBYTES(0);
62	else
63		dboot_panic("Unknown ELF class");
64
65	return (hdr);
66}
67
68
69/*
70 * parse the elf file for program information
71 */
72int
73dboot_elfload64(uintptr_t file_image)
74{
75	Elf64_Ehdr *eh;
76	Elf64_Phdr *phdr;
77	Elf64_Shdr *shdr;
78	caddr_t allphdrs, sechdrs;
79	int i;
80	paddr_t src;
81	paddr_t dst;
82	paddr_t next_addr;
83
84	elf_file = (caddr_t)file_image;
85
86	allphdrs = NULL;
87
88	eh = getehdr();
89	if (eh == NULL)
90		dboot_panic("getehdr() failed");
91
92	if (eh->e_type != ET_EXEC)
93		dboot_panic("not ET_EXEC, e_type = 0x%x", eh->e_type);
94
95	if (eh->e_phnum == 0 || eh->e_phoff == 0)
96		dboot_panic("no program headers");
97
98	/*
99	 * Get the program headers.
100	 */
101	allphdrs = PGETBYTES(eh->e_phoff);
102	if (allphdrs == NULL)
103		dboot_panic("Failed to get program headers e_phnum = %d",
104		    eh->e_phnum);
105
106	/*
107	 * Get the section headers.
108	 */
109	sechdrs = PGETBYTES(eh->e_shoff);
110	if (sechdrs == NULL)
111		dboot_panic("Failed to get section headers e_shnum = %d",
112		    eh->e_shnum);
113
114	/*
115	 * Next look for interesting program headers.
116	 */
117	for (i = 0; i < eh->e_phnum; i++) {
118		/*LINTED [ELF program header alignment]*/
119		phdr = (Elf64_Phdr *)(allphdrs + eh->e_phentsize * i);
120
121		/*
122		 * Dynamically-linked executable.
123		 * Complain.
124		 */
125		if (phdr->p_type == PT_INTERP) {
126			dboot_printf("warning: PT_INTERP section\n");
127			continue;
128		}
129
130		/*
131		 * at this point we only care about PT_LOAD segments
132		 */
133		if (phdr->p_type != PT_LOAD)
134			continue;
135
136		if (phdr->p_flags == (PF_R | PF_W) && phdr->p_vaddr == 0) {
137			dboot_printf("warning: krtld reloc info?\n");
138			continue;
139		}
140
141		/*
142		 * If memory size is zero just ignore this header.
143		 */
144		if (phdr->p_memsz == 0)
145			continue;
146
147		/*
148		 * If load address 1:1 then ignore this header.
149		 */
150		if (phdr->p_paddr == phdr->p_vaddr) {
151			if (prom_debug)
152				dboot_printf("Skipping PT_LOAD segment for "
153				    "paddr = 0x%lx\n", (ulong_t)phdr->p_paddr);
154			continue;
155		}
156
157		/*
158		 * copy the data to kernel area
159		 */
160		if (phdr->p_paddr != FOUR_MEG && phdr->p_paddr != 2 * FOUR_MEG)
161			dboot_panic("Bad paddr for kernel nucleus segment");
162		src = (uintptr_t)PGETBYTES(phdr->p_offset);
163		dst = ktext_phys + phdr->p_paddr - FOUR_MEG;
164		if (prom_debug)
165			dboot_printf("copying %ld bytes from ELF offset 0x%lx "
166			    "to physaddr 0x%lx (va=0x%lx)\n",
167			    (ulong_t)phdr->p_filesz, (ulong_t)phdr->p_offset,
168			    (ulong_t)dst, (ulong_t)phdr->p_vaddr);
169		(void) memcpy((void *)(uintptr_t)dst,
170		    (void *)(uintptr_t)src, (size_t)phdr->p_filesz);
171
172		next_addr = dst + phdr->p_filesz;
173	}
174
175
176	/*
177	 * Next look for bss
178	 */
179	for (i = 0; i < eh->e_shnum; i++) {
180		shdr = (Elf64_Shdr *)(sechdrs + eh->e_shentsize * i);
181
182		/* zero out bss */
183		if (shdr->sh_type == SHT_NOBITS) {
184			(void) memset((void *)(uintptr_t)next_addr, 0,
185			    shdr->sh_size);
186			break;
187		}
188	}
189
190	/*
191	 * Ignore the intepreter (or should we die if there is one??)
192	 */
193	return (0);
194}
195