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