xref: /onnv-gate/usr/src/uts/i86pc/dboot/dboot_elfload.c (revision 7656:2621e50fdf4a)
13446Smrj /*
23446Smrj  * CDDL HEADER START
33446Smrj  *
43446Smrj  * The contents of this file are subject to the terms of the
53446Smrj  * Common Development and Distribution License (the "License").
63446Smrj  * You may not use this file except in compliance with the License.
73446Smrj  *
83446Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93446Smrj  * or http://www.opensolaris.org/os/licensing.
103446Smrj  * See the License for the specific language governing permissions
113446Smrj  * and limitations under the License.
123446Smrj  *
133446Smrj  * When distributing Covered Code, include this CDDL HEADER in each
143446Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153446Smrj  * If applicable, add the following below this CDDL HEADER, with the
163446Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
173446Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
183446Smrj  *
193446Smrj  * CDDL HEADER END
203446Smrj  */
213446Smrj 
223446Smrj /*
23*7656SSherry.Moore@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
243446Smrj  * Use is subject to license terms.
253446Smrj  */
263446Smrj 
273446Smrj 
283446Smrj #include <sys/types.h>
293446Smrj #include <sys/inttypes.h>
303446Smrj #include <sys/systm.h>
313446Smrj #include <sys/elf.h>
323446Smrj #include <sys/elf_notes.h>
333446Smrj 
343446Smrj #include <util/memcpy.h>
353446Smrj 
363446Smrj #include "dboot_xboot.h"
373446Smrj #include "dboot_elfload.h"
383446Smrj #include "dboot_printf.h"
393446Smrj 
403446Smrj static caddr_t elf_file = 0;
413446Smrj 
423446Smrj #define	PGETBYTES(offset)	((void *)(elf_file + (offset)))
433446Smrj 
443446Smrj static void *
getehdr(void)453446Smrj getehdr(void)
463446Smrj {
473446Smrj 	uchar_t *ident;
483446Smrj 	void *hdr = NULL;
493446Smrj 
503446Smrj 	ident = PGETBYTES(0);
513446Smrj 	if (ident == NULL)
525084Sjohnlev 		dboot_panic("Cannot read kernel ELF header");
533446Smrj 
543446Smrj 	if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 ||
553446Smrj 	    ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3)
565084Sjohnlev 		dboot_panic("not an ELF file!");
573446Smrj 
583446Smrj 	if (ident[EI_CLASS] == ELFCLASS32)
593446Smrj 		hdr = PGETBYTES(0);
603446Smrj 	else if (ident[EI_CLASS] == ELFCLASS64)
613446Smrj 		hdr = PGETBYTES(0);
623446Smrj 	else
635084Sjohnlev 		dboot_panic("Unknown ELF class");
643446Smrj 
653446Smrj 	return (hdr);
663446Smrj }
673446Smrj 
683446Smrj 
693446Smrj /*
703446Smrj  * parse the elf file for program information
713446Smrj  */
723446Smrj int
dboot_elfload64(uintptr_t file_image)733446Smrj dboot_elfload64(uintptr_t file_image)
743446Smrj {
753446Smrj 	Elf64_Ehdr *eh;
763446Smrj 	Elf64_Phdr *phdr;
77*7656SSherry.Moore@Sun.COM 	Elf64_Shdr *shdr;
78*7656SSherry.Moore@Sun.COM 	caddr_t allphdrs, sechdrs;
793446Smrj 	int i;
803446Smrj 	paddr_t src;
813446Smrj 	paddr_t dst;
82*7656SSherry.Moore@Sun.COM 	paddr_t next_addr;
833446Smrj 
843446Smrj 	elf_file = (caddr_t)file_image;
853446Smrj 
863446Smrj 	allphdrs = NULL;
873446Smrj 
883446Smrj 	eh = getehdr();
893446Smrj 	if (eh == NULL)
905084Sjohnlev 		dboot_panic("getehdr() failed");
913446Smrj 
923446Smrj 	if (eh->e_type != ET_EXEC)
935084Sjohnlev 		dboot_panic("not ET_EXEC, e_type = 0x%x", eh->e_type);
943446Smrj 
953446Smrj 	if (eh->e_phnum == 0 || eh->e_phoff == 0)
965084Sjohnlev 		dboot_panic("no program headers");
973446Smrj 
983446Smrj 	/*
993446Smrj 	 * Get the program headers.
1003446Smrj 	 */
1013446Smrj 	allphdrs = PGETBYTES(eh->e_phoff);
1023446Smrj 	if (allphdrs == NULL)
1035084Sjohnlev 		dboot_panic("Failed to get program headers e_phnum = %d",
1043446Smrj 		    eh->e_phnum);
1053446Smrj 
1063446Smrj 	/*
107*7656SSherry.Moore@Sun.COM 	 * Get the section headers.
108*7656SSherry.Moore@Sun.COM 	 */
109*7656SSherry.Moore@Sun.COM 	sechdrs = PGETBYTES(eh->e_shoff);
110*7656SSherry.Moore@Sun.COM 	if (sechdrs == NULL)
111*7656SSherry.Moore@Sun.COM 		dboot_panic("Failed to get section headers e_shnum = %d",
112*7656SSherry.Moore@Sun.COM 		    eh->e_shnum);
113*7656SSherry.Moore@Sun.COM 
114*7656SSherry.Moore@Sun.COM 	/*
1153446Smrj 	 * Next look for interesting program headers.
1163446Smrj 	 */
1173446Smrj 	for (i = 0; i < eh->e_phnum; i++) {
1183446Smrj 		/*LINTED [ELF program header alignment]*/
1193446Smrj 		phdr = (Elf64_Phdr *)(allphdrs + eh->e_phentsize * i);
1203446Smrj 
1213446Smrj 		/*
1223446Smrj 		 * Dynamically-linked executable.
1233446Smrj 		 * Complain.
1243446Smrj 		 */
1253446Smrj 		if (phdr->p_type == PT_INTERP) {
1263446Smrj 			dboot_printf("warning: PT_INTERP section\n");
1273446Smrj 			continue;
1283446Smrj 		}
1293446Smrj 
1303446Smrj 		/*
1313446Smrj 		 * at this point we only care about PT_LOAD segments
1323446Smrj 		 */
1333446Smrj 		if (phdr->p_type != PT_LOAD)
1343446Smrj 			continue;
1353446Smrj 
1363446Smrj 		if (phdr->p_flags == (PF_R | PF_W) && phdr->p_vaddr == 0) {
1373446Smrj 			dboot_printf("warning: krtld reloc info?\n");
1383446Smrj 			continue;
1393446Smrj 		}
1403446Smrj 
1413446Smrj 		/*
1423446Smrj 		 * If memory size is zero just ignore this header.
1433446Smrj 		 */
1443446Smrj 		if (phdr->p_memsz == 0)
1453446Smrj 			continue;
1463446Smrj 
1473446Smrj 		/*
1483446Smrj 		 * If load address 1:1 then ignore this header.
1493446Smrj 		 */
1503446Smrj 		if (phdr->p_paddr == phdr->p_vaddr) {
1513446Smrj 			if (prom_debug)
1523446Smrj 				dboot_printf("Skipping PT_LOAD segment for "
1533446Smrj 				    "paddr = 0x%lx\n", (ulong_t)phdr->p_paddr);
1543446Smrj 			continue;
1553446Smrj 		}
1563446Smrj 
1573446Smrj 		/*
1583446Smrj 		 * copy the data to kernel area
1593446Smrj 		 */
1603446Smrj 		if (phdr->p_paddr != FOUR_MEG && phdr->p_paddr != 2 * FOUR_MEG)
1615084Sjohnlev 			dboot_panic("Bad paddr for kernel nucleus segment");
1623446Smrj 		src = (uintptr_t)PGETBYTES(phdr->p_offset);
1633446Smrj 		dst = ktext_phys + phdr->p_paddr - FOUR_MEG;
1643446Smrj 		if (prom_debug)
1654088Srscott 			dboot_printf("copying %ld bytes from ELF offset 0x%lx "
1663446Smrj 			    "to physaddr 0x%lx (va=0x%lx)\n",
1673446Smrj 			    (ulong_t)phdr->p_filesz, (ulong_t)phdr->p_offset,
1683446Smrj 			    (ulong_t)dst, (ulong_t)phdr->p_vaddr);
1693446Smrj 		(void) memcpy((void *)(uintptr_t)dst,
1703446Smrj 		    (void *)(uintptr_t)src, (size_t)phdr->p_filesz);
171*7656SSherry.Moore@Sun.COM 
172*7656SSherry.Moore@Sun.COM 		next_addr = dst + phdr->p_filesz;
173*7656SSherry.Moore@Sun.COM 	}
174*7656SSherry.Moore@Sun.COM 
175*7656SSherry.Moore@Sun.COM 
176*7656SSherry.Moore@Sun.COM 	/*
177*7656SSherry.Moore@Sun.COM 	 * Next look for bss
178*7656SSherry.Moore@Sun.COM 	 */
179*7656SSherry.Moore@Sun.COM 	for (i = 0; i < eh->e_shnum; i++) {
180*7656SSherry.Moore@Sun.COM 		shdr = (Elf64_Shdr *)(sechdrs + eh->e_shentsize * i);
181*7656SSherry.Moore@Sun.COM 
182*7656SSherry.Moore@Sun.COM 		/* zero out bss */
183*7656SSherry.Moore@Sun.COM 		if (shdr->sh_type == SHT_NOBITS) {
184*7656SSherry.Moore@Sun.COM 			(void) memset((void *)(uintptr_t)next_addr, 0,
185*7656SSherry.Moore@Sun.COM 			    shdr->sh_size);
186*7656SSherry.Moore@Sun.COM 			break;
187*7656SSherry.Moore@Sun.COM 		}
1883446Smrj 	}
1893446Smrj 
1903446Smrj 	/*
1913446Smrj 	 * Ignore the intepreter (or should we die if there is one??)
1923446Smrj 	 */
1933446Smrj 	return (0);
1943446Smrj }
195