/*
* Copyright (c) 1997, 2008, 2017 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center, by Christos Zoulas, and by Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* If not included by exec_elf64.c, ELFSIZE won't be defined. */
#ifndef ELFSIZE
#define ELFSIZE 32
#endif
#ifndef _STANDALONE
/*
* Byte swapping may be necessary in the non-_STANDLONE case because
* we may be built with a host compiler.
*/
#ifndef LIBSA_BIENDIAN_SUPPORT
#define LIBSA_BIENDIAN_SUPPORT
#endif
#endif
#define KERNALIGN_SMALL (1 << 12) /* XXX should depend on marks[] */
#define KERNALIGN_LARGE (1 << 21) /* XXX should depend on marks[] */
/*
* Read some data from a file, and put it in the bootloader memory (local).
*/
static int
ELFNAMEEND(readfile_local)(int fd, Elf_Off elfoff, void *addr, size_t size)
{
ssize_t nr;
/*
* Read some data from a file, and put it in wherever in memory (global).
*/
static int
ELFNAMEEND(readfile_global)(int fd, u_long offset, Elf_Off elfoff,
Elf_Addr addr, size_t size)
{
ssize_t nr;
/* some ports dont use the offset */
(void)&offset;
if (lseek(fd, elfoff, SEEK_SET) == -1) {
WARN(("lseek section"));
return -1;
}
nr = READ(fd, addr, size);
if (nr == -1) {
WARN(("read section"));
return -1;
}
if (nr != (ssize_t)size) {
errno = EIO;
WARN(("read section"));
return -1;
}
return 0;
}
/*
* Load a dynamic ELF binary into memory. Layout of the memory:
* +------------+--------------+------------+------------------------+
* | ELF HEADER | SECT HEADERS | KERN SECTS | REL/RELA/SYM/STR SECTS |
* +------------+--------------+------------+------------------------+
* The ELF HEADER start address is marks[MARK_END]. We then map the rest
* by increasing maxp. An alignment is enforced between the code sections.
*
* The offsets of the KERNEL and SYM+REL sections are relative to the start
* address of the ELF HEADER. We just give the kernel a pointer to the ELF
* HEADER, and we let the kernel find the location and number of symbols by
* itself.
*/
static int
ELFNAMEEND(loadfile_dynamic)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
{
const u_long offset = marks[MARK_START];
Elf_Shdr *shdr;
Elf_Addr shpp, addr;
int i, j, loaded;
size_t size, shdrsz, align;
Elf_Addr maxp, elfp = 0;
int ret;
#ifdef LIBSA_BIENDIAN_SUPPORT
for (i = 0; i < elf->e_shnum; i++)
internalize_shdr(elf->e_ident[EI_DATA], &shp[i]);
#endif
/*
* First load the section names section. Only useful for CTF.
*/
if (boot_load_ctf && (elf->e_shstrndx != SHN_UNDEF)) {
Elf_Off shstroff = shp[elf->e_shstrndx].sh_offset;
shstrsz = shp[elf->e_shstrndx].sh_size;
if (flags & LOAD_SYM) {
ret = ELFNAMEEND(readfile_global)(fd, offset,
shstroff, maxp, shstrsz);
if (ret == -1) {
goto out;
}
}
/* Create a local copy */
shstr = ALLOC(shstrsz);
ret = ELFNAMEEND(readfile_local)(fd, shstroff, shstr, shstrsz);
if (ret == -1) {
goto out;
}
shp[elf->e_shstrndx].sh_offset = maxp - elfp;
maxp += roundup(shstrsz, ELFROUND);
}
/*
* Now load the symbol sections themselves. Make sure the sections are
* ELFROUND-aligned. Update sh_offset to be relative to elfp. Set it to
* zero when we don't want the sections to be taken care of, the kernel
* will properly skip them.
*/
first = 1;
for (i = 1; i < elf->e_shnum; i++) {
if (i == elf->e_shstrndx) {
/* already loaded this section */
continue;
}
switch (shp[i].sh_type) {
case SHT_PROGBITS:
if (boot_load_ctf && shstr) {
/* got a CTF section? */
if (strncmp(&shstr[shp[i].sh_name],
".SUNW_ctf", 10) == 0) {
goto havesym;
}
}
shp[i].sh_offset = 0;
break;
case SHT_STRTAB:
for (j = 1; j < elf->e_shnum; j++)
if (shp[j].sh_type == SHT_SYMTAB &&
shp[j].sh_link == (unsigned int)i)
goto havesym;
/*
* Don't bother with any string table that isn't
* referenced by a symbol table.
*/
shp[i].sh_offset = 0;
break;
havesym:
case SHT_SYMTAB:
if (flags & LOAD_SYM) {
PROGRESS(("%s%ld", first ? " [" : "+",
(u_long)shp[i].sh_size));
ret = ELFNAMEEND(readfile_global)(fd, offset,
shp[i].sh_offset, maxp, shp[i].sh_size);
if (ret == -1) {
goto out;
}
}
shp[i].sh_offset = maxp - elfp;
maxp += roundup(shp[i].sh_size, ELFROUND);
first = 0;
break;
case SHT_NOTE:
if ((flags & LOAD_NOTE) == 0)
break;
if (shp[i].sh_size < sizeof(note)) {
shp[i].sh_offset = 0;
break;
}
ret = ELFNAMEEND(readfile_local)(fd, shp[i].sh_offset,
¬e, sizeof(note));
if (ret == -1) {
goto out;
}
/*
* Load a static ELF binary into memory. Layout of the memory:
* +-----------------+------------+-----------------+-----------------+
* | KERNEL SEGMENTS | ELF HEADER | SECTION HEADERS | SYMBOL SECTIONS |
* +-----------------+------------+-----------------+-----------------+
* The KERNEL SEGMENTS start address is fixed by the segments themselves. We
* then map the rest by increasing maxp.
*
* The offsets of the SYMBOL SECTIONS are relative to the start address of the
* ELF HEADER. The shdr offset of ELF HEADER points to SECTION HEADERS.
*
* We just give the kernel a pointer to the ELF HEADER, which is enough for it
* to find the location and number of symbols by itself later.
*/
static int
ELFNAMEEND(loadfile_static)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
{
const u_long offset = marks[MARK_START];
Elf_Phdr *phdr;
int i, first;
size_t sz;
Elf_Addr minp = ~0, maxp = 0, pos = 0, elfp = 0;
int ret;
/* for ports that define progress to nothing */
(void)&first;
/* have not seen a data segment so far */
marks[MARK_DATA] = 0;