/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/sysmacros.h>
#include <sys/elf_notes.h>
#include <sys/bootconf.h>
#include <sys/platnames.h>
#include "util.h"
#ifdef BOOTAMD64
#include <amd64/amd64_page.h>
#endif /* BOOTAMD64 */
union {
struct exec X;
} ex;
#define x ex.X
typedef int (*func_t)();
#define ALIGN(x, a) \
int use_align = 0;
int npagesize = 0;
/*
* This file gets compiled in LP64 (for sun4u) and ILP32 models.
* For LP64 compilation, the "client" file we load and run may be LP64 or ILP32,
* and during bringup, the LP64 clients may have ELF32 headers.
*/
#ifdef _ELF64_SUPPORT
#ifndef BOOTAMD64
/*
* Bootstrap vector for ELF32 LP64 client - neither supported nor needed for
* AMD64
*/
#endif /* !BOOTAMD64 */
#endif /* _ELF64_SUPPORT */
/*
* Also, the sun4u booter must create this for ILP32 clients.
*/
/*
* Read in a Unix executable file and return its entry point.
* Handle the various a.out formats correctly.
* "fd" is the standalone file descriptor to read from.
* Print informative little messages if "print" is on.
* Returns -1 for errors.
*/
#ifdef DEBUG
#else /* DEBUG */
static int debug = 0;
#endif /* DEBUG */
#ifdef _ELF64_SUPPORT
typedef struct {
#ifdef BOOTAMD64
#endif /* BOOTAMD64 */
union {
#ifndef BOOTAMD64
#endif /* !BOOTAMD64 */
} a_un;
} auxv64_t;
#if defined(__sparcv9)
extern int client_isLP64;
#endif /* __sparcv9 */
#endif /* _ELF64_SUPPORT */
#if defined(i386) && !defined(_SYSCALL32)
#endif
static int openpath(char *, char *, int);
static char *getmodpath(char *);
extern void setup_aux(void);
extern void *kmem_alloc(size_t, int);
extern int cons_gets(char *, int);
#ifdef BOOTAMD64
extern const char *amd64_getmmulist(void);
extern int amd64_elf64;
extern int is_amd64;
#endif /* BOOTAMD64 */
#ifdef lint
/*
* This function is currently inlined
*/
/*ARGSUSED*/
void
{}
#else /* lint */
#endif /* lint */
extern int verbosemode;
extern int boothowto;
extern int pagesize;
extern char filename[];
/*
* repeat reads (forever) until size of request is satisfied
* (Thus, you don't want to use this cases where short reads are ok)
*/
{
int errorcount = 0;
ssize_t i;
if (i < 0) {
++errorcount;
if (verbosemode)
continue;
}
bytesread += i;
p += i;
}
return (bytesread);
}
{
#ifdef _ELF64_SUPPORT
#ifdef BOOTAMD64
#else /* !BOOTAMD64 */
#endif /* BOOTAMD64 */
#endif /* _ELF64_SUPPORT */
ssize_t i;
int shared = 0;
if (verbosemode) {
}
shared = 1;
if (i != sizeof (Elf64_Ehdr)) {
printf("Error reading ELF header.\n");
return (FAIL);
}
if (verbosemode) {
dprintf("calling readelf, elfheader is:\n");
dprintf("e_ident\t0x%x, 0x%x, 0x%x, 0x%x\n",
}
#ifdef _ELF64_SUPPORT
dprintf("ELF file CLASS 0x%x 32 is %x 64 is %x\n",
#ifdef BOOTAMD64
printf("FATAL: 64-bit ELF executable "
"not for AMD64\n (e_machine "
return (FAIL);
}
/*
* OK, we know the executable is for an AMD64
* CPU. Make sure we ARE an AMD64 CPU before
* proceeding.
*/
if (is_amd64 == 0) {
printf("FATAL: AMD64 executables not "
" supported on this CPU.\n");
return (FAIL);
}
#endif /* BOOTAMD64 */
(Elf64_Ehdr *)&elfhdr);
#ifdef BOOTAMD64
if (elf64_go2 != FAIL_READELF64)
"mmu64", 0);
OK);
#else /* !BOOTAMD64 */
#endif /* BOOTAMD64 */
} else
#endif /* _ELF64_SUPPORT */
} else {
printf("File not executable.\n");
return (FAIL);
}
}
return (FAIL);
}
/*
* and the aux vector. Use the type-cast to convert integers
* to pointers first to suppress the gcc warning.
*/
static func_t
{
int i;
int bss_seen = 0;
/* Initialize pointers so we won't free bogus ones on elferror */
#ifdef _ELF64_SUPPORT
if (verbosemode)
printf("Elf32 client\n");
#endif /* _ELF64_SUPPORT */
goto elferror;
/* use uintptr_t to suppress the gcc warning */
if (verbosemode)
/*
* Allocate and read in all the program headers.
*/
goto elferror;
if (verbosemode)
goto elferror;
goto elferror;
/*
* First look for PT_NOTE headers that tell us what pagesize to
* use in allocating program memory.
*/
npagesize = 0;
for (i = 0; i < nphdrs; i++) {
void *note_buf;
continue;
if (verbosemode) {
dprintf("allocating 0x%x bytes for note hdr\n",
}
goto elferror;
if (verbosemode)
goto elferror;
if (verbosemode) {
dprintf("reading 0x%x bytes into %p\n",
}
goto elferror;
if (verbosemode) {
dprintf("p_note namesz %x descsz %x type %x\n",
}
/*
* Iterate through all ELF PT_NOTE elements looking for
* ELF_NOTE_SOLARIS which, if present, will specify the
* executable's preferred pagesize.
*/
do {
if (verbosemode)
}
}
/*
* Next look for PT_LOAD headers to read in.
*/
if (print)
printf("Size: ");
for (i = 0; i < nphdrs; i++) {
if (verbosemode) {
dprintf("Doing header 0x%x\n", i);
dprintf("phdr\n");
dprintf("\tp_offset = %x, p_vaddr = %x\n",
dprintf("\tp_memsz = %x, p_filesz = %x\n",
}
if (verbosemode)
goto elferror;
/*
* It's a PT_LOAD segment that is RW but
* not executable and has a vaddr
* of zero. This is relocation info that
* doesn't need to stick around after
* krtld is done with it. We allocate boot
* memory for this segment, since we don't want
* it mapped in permanently as part of
* the kernel image.
*/
goto elferror;
/*
* Save this to pass on
* to the interpreter.
*/
} else {
if (print)
/*
* If we found a new pagesize above, use it
* to adjust the memory allocation.
*/
} else {
npagesize = 0;
}
/*
* Check if it's text or data.
*/
else
/*
* If memory size is zero just ignore this
* header.
*/
if (size == 0)
continue;
if (verbosemode)
dprintf("allocating memory: %x %lx "
/*
* We're all set up to read.
* Now let's allocate some memory.
*/
#ifdef i386
/*
* If vaddr == paddr and npagesize is 0, that
* means the executable needs to be identity
* mapped in memory (va == pa, mapped 1:1)
*
* Otherwise load as usual.
*/
(npagesize == 0)) {
size_t, int);
uint_t n;
if (n) {
base -= n;
size += n;
}
goto elferror;
} else
#endif /* i386 */
/* use uintptr_t to suppress the gcc warning */
goto elferror;
}
if (verbosemode) {
dprintf("reading 0x%x bytes into 0x%x\n",
}
/* use uintptr_t to suppress the gcc warning */
goto elferror;
/* zero out BSS */
if (verbosemode) {
dprintf("bss from 0x%x size 0x%x\n",
}
/* use uintptr_t to suppress the gcc warning */
bss_seen++;
if (print)
printf("0x%x Bytes\n",
}
/* force instructions to be visible to icache */
}
/*
* Dynamically-linked executable.
*/
interp = 1;
goto elferror;
}
/*
* Get the name of the interpreter.
*/
goto elferror;
}
}
printf("0 Bytes\n");
/*
* Load the interpreter
* if there is one.
*/
if (interp) {
/*
* Load it.
*/
goto elferror;
/*
* Build bootstrap and aux vectors.
*/
setup_aux();
if (use_align)
/*
* Realloc vectors and copy them.
*/
goto elferror;
printf("readelf: overrun of available aux vectors\n");
goto elferror;
}
/* use uintptr_t to suppress the gcc warning */
goto elferror;
}
/* use uintptr_t to suppress the gcc warning */
#if defined(_ELF64_SUPPORT) && !defined(BOOTAMD64)
/*
* Make an LP64 copy of the vector for use by 64-bit standalones
* even if they have ELF32.
*/
== NULL)
goto elferror;
/* use uintptr_t to suppress the gcc warning */
goto elferror;
} else {
a64++;
}
}
#endif /* _ELF64_SUPPORT && !BOOTAMD64 */
} else {
}
return (entrypt);
printf("Elf32 read error.\n");
return (FAIL);
}
#ifdef _ELF64_SUPPORT
/*
* and the aux vector.
*/
static uint64_t
{
int i;
int bss_seen = 0;
/* Initialize pointers so we won't free bogus ones on elf64error */
#if defined(__sparcv9)
client_isLP64 = 1;
#endif /* __sparcv9 */
if (verbosemode)
printf("Elf64 client\n");
goto elf64error;
if (verbosemode)
/*
* Allocate and read in all the program headers.
*/
goto elf64error;
if (verbosemode)
goto elf64error;
goto elf64error;
/*
* First look for PT_NOTE headers that tell us what pagesize to
* use in allocating program memory.
*/
npagesize = 0;
for (i = 0; i < nphdrs; i++) {
void *note_buf;
continue;
if (verbosemode) {
dprintf("allocating 0x%llx bytes for note hdr\n",
}
goto elf64error;
if (verbosemode)
dprintf("seeking to 0x%llx\n",
goto elf64error;
if (verbosemode) {
dprintf("reading 0x%llx bytes into 0x%p\n",
}
goto elf64error;
if (verbosemode) {
dprintf("p_note namesz %x descsz %x type %x\n",
}
/*
* Iterate through all ELF PT_NOTE elements looking for
* ELF_NOTE_SOLARIS which, if present, will specify the
* executable's preferred pagesize.
*/
do {
if (verbosemode)
}
}
/*
* Next look for PT_LOAD headers to read in.
*/
if (print)
printf("Size: ");
for (i = 0; i < nphdrs; i++) {
if (verbosemode) {
dprintf("Doing header 0x%x\n", i);
dprintf("phdr\n");
dprintf("\tp_offset = %llx, p_vaddr = %llx\n",
dprintf("\tp_memsz = %llx, p_filesz = %llx\n",
dprintf("\tp_type = %x, p_flags = %x\n",
}
if (verbosemode)
dprintf("seeking to 0x%llx\n",
goto elf64error;
/*
* It's a PT_LOAD segment that is RW but
* not executable and has a vaddr
* of zero. This is relocation info that
* doesn't need to stick around after
* krtld is done with it. We allocate boot
* memory for this segment, since we don't want
* it mapped in permanently as part of
* the kernel image.
*/
#ifdef BOOTAMD64
if ((loadaddr = (Elf64_Addr)
== NULL)
#else /* !BOOTAMD64 */
#endif /* BOOTAMD64 */
goto elf64error;
/*
* Save this to pass on
* to the interpreter.
*/
} else {
if (print)
printf("0x%llx+",
/*
* If we found a new pagesize above, use it
* to adjust the memory allocation.
*/
} else {
npagesize = 0;
}
/*
* Check if it's text or data.
*/
else
if (verbosemode)
"allocating memory: %llx %lx %x\n",
/*
* If memory size is zero just ignore this
* header.
*/
if (size == 0)
continue;
/*
* We're all set up to read.
* Now let's allocate some memory.
*/
goto elf64error;
}
if (verbosemode) {
dprintf("reading 0x%llx bytes into 0x%llx\n",
}
goto elf64error;
/* zero out BSS */
if (verbosemode) {
dprintf("bss from 0x%llx size 0x%llx\n",
}
bss_seen++;
if (print)
printf("0x%llx Bytes\n",
}
/* force instructions to be visible to icache */
/*
* Dynamically-linked executable.
*/
interp = 1;
goto elf64error;
}
/*
* Get the name of the interpreter.
*/
goto elf64error;
}
}
printf("0 Bytes\n");
/*
* Load the interpreter
* if there is one.
*/
if (interp) {
/*
* Load it.
*/
goto elf64error;
/*
* Build bootstrap and aux vectors.
*/
setup_aux();
if (npagesize)
#ifdef BOOTAMD64
goto elf64error;
#endif /* BOOTAMD64 */
/*
* Realloc vectors and copy them.
*/
if ((elfbootvecELF64 =
goto elf64error;
printf("readelf: overrun of available aux vectors\n");
goto elf64error;
}
#ifdef BOOTAMD64
goto elf64error;
}
#else /* !BOOTAMD64 */
goto elf64error;
}
size);
#endif /* BOOTAMD64 */
} else {
}
printf("Elf64 read error.\n");
return (FAIL_READELF64);
}
#endif /* _ELF64_SUPPORT */
/*
* Load the interpreter. It expects a
* relocatable .o capable of bootstrapping
* itself.
*/
static func_t
{
uint_t i;
int fd;
int size;
/* use uintptr_t to suppress the gcc warning */
/*
* Get the module path.
*/
goto errorx;
}
/*
* Allocate and read the ELF header.
*/
goto error;
}
goto error;
}
goto error;
}
/*
* Read the section headers.
*/
printf("boot: error reading section headers\n");
goto error;
}
/*
* Load sections into the appropriate dynamic segment.
*/
/*
* If it's not allocated and not required
* to do relocation, skip it.
*/
#ifdef i386
#else
#endif
continue;
/*
* If the section is read-only,
* it goes in as text.
*/
/*
* Make some room for it.
*/
printf("boot: allocating memory for sections failed\n");
goto error;
}
/*
* Compute the entry point of the linker.
*/
if (dl_entry == 0 &&
}
/*
* If it's bss, just zero it out.
*/
} else {
/*
* Read the section contents.
*/
printf("boot: error reading sections\n");
goto error;
}
}
/*
* Assign the section's virtual addr. Use uintptr_t to
* suppress the gcc warning.
*/
/*
* Force instructions to be visible to icache. Use
* uintptr_t to suppress the gcc warning as well.
*/
}
/*
* Update sizes of segments.
*/
/* load and relocate symbol tables in SAS */
if (ehdr)
if (shdrs)
return (FAIL);
}
#ifdef _ELF64_SUPPORT
/*
* Load the interpreter. It expects a
* relocatable .o capable of bootstrapping
* itself.
*/
static Elf64_Addr
{
uint_t i;
int fd;
int size;
/*
* Get the module path.
*/
goto errorx;
}
/*
* Allocate and read the ELF header.
*/
#ifdef BOOTAMD64
0)) == NULL) {
#else /* !BOOTAMD64 */
#endif /* BOOTAMD64 */
goto error;
}
goto error;
}
goto error;
}
/*
* Read the section headers.
*/
printf("boot: error reading section headers\n");
goto error;
}
#ifdef BOOTAMD64
#else /* !BOOTAMD64 */
#endif /* BOOTAMD64 */
/*
* Load sections into the appropriate dynamic segment.
*/
/*
* If it's not allocated and not required
* to do relocation, skip it.
*/
continue;
/*
* If the section is read-only,
* it goes in as text.
*/
/*
* Make some room for it.
*/
#ifdef BOOTAMD64
#else /* !BOOTAMD64 */
sp->sh_addralign);
#endif /* BOOTAMD64 */
printf("boot: allocating memory for section %d "
"failed\n", i);
goto error;
}
/*
* Compute the entry point of the linker.
*/
if (dl_entry == 0 &&
if (verbosemode)
dprintf("boot: loading linker @ 0x%llx\n",
}
/*
* If it's bss, just zero it out.
*/
} else {
/*
* Read the section contents.
*/
printf("boot: error reading section %d\n", i);
goto error;
}
}
/*
* Assign the section's virtual addr.
*/
if (verbosemode)
dprintf("boot: section %d, type %d, loaded @ 0x%llx, "
/* force instructions to be visible to icache */
}
/*
* Update sizes of segments.
*/
/* load and relocate symbol tables in SAS */
return (dl_entry);
if (ehdr)
if (shdrs)
return (FAIL_ILOAD64);
}
#endif /* _ELF64_SUPPORT */
/*
* Extend the segment's "break" value by bytes.
*/
static caddr_t
{
unsigned int alloc_align = 0;
if (npagesize) {
}
/*
* Need more pages?
*/
printf("boot: segbrk allocation failed, "
return (NULL);
}
}
return (va);
}
/*
* Open the file using a search path and
* return the file descriptor (or -1 on failure).
*/
static int
char *path;
char *fname;
int flags;
{
register char *p, *q;
int fd;
/*
* If the file name is absolute,
* don't use the module search path.
*/
if (fname[0] == '/')
q = NULL;
for (p = path; /* forever */; p = q) {
while (*p == ' ' || *p == '\t' || *p == ':')
p++;
if (*p == '\0')
break;
q = p;
while (*q && *q != ' ' && *q != '\t' && *q != ':')
q++;
if (q[-1] != '/') {
buf[q - p] = '/';
} else {
/*
* This checks for paths that end in '/'
*/
}
return (fd);
}
return (-1);
}
/*
* Get the module search path.
*/
static char *
char *fname;
{
extern char *impl_arch_name;
#ifdef __sparcv9
#endif /* __sparcv9 */
#ifdef BOOTAMD64
#endif /* BOOTAMD64 */
#endif /* __sparcv9 || BOOTAMD64 */
if (p == NULL) {
/* strchr could not find a "/" */
return (NULL);
}
p--; /* remove trailing "/"s */
if (p == fname)
p++; /* "/" is the modpath in this case */
#if defined(__sparcv9)
if ((client_isLP64 == 0) && verbosemode)
client_isLP64 = 1;
#endif /* __sparcv9 */
}
#endif /* __sparcv9 || BOOTAMD64 */
if (boothowto & RB_ASKNAME) {
if (buf[0] != '\0')
}
if (verbosemode)
return (mod_path);
}