File: [local] / sys / arch / sgi / stand / boot / boot.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:07:49 2008 UTC (16 years, 4 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: boot.c,v 1.8 2007/05/11 10:28:20 jj Exp $ */
/*
* Copyright (c) 2004 Opsycon AB, www.opsycon.se.
*
* 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 AUTHOR ``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 AUTHOR 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.
*
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/exec.h>
#include <sys/exec_elf.h>
#include <stand.h>
#include <mips64/arcbios.h>
void gets(char *);
ssize_t read(int, void *, size_t);
int close(int);
int main(int, char **);
void dobootopts(int, char **);
Elf32_Addr loadfile(char *);
Elf32_Addr loadfile32(int, Elf32_Ehdr *);
Elf32_Addr loadfile64(int, Elf64_Ehdr *);
int loadsymtab32(int, Elf32_Ehdr *, int);
int loadsymtab64(int, Elf64_Ehdr *, int);
enum {
AUTO_NONE,
AUTO_YES,
AUTO_NO,
AUTO_MINI,
AUTO_DEBUG
} bootauto = AUTO_NONE;
char *OSLoadPartition = NULL;
char *OSLoadFilename = NULL;
unsigned long tablebase;
static void *
readtable(int fd, int offs, void *base, int size, char *name, int flags)
{
if (lseek(fd, offs, SEEK_SET) != offs ||
read(fd, base, size) != size) {
printf("\ncannot read %s table", name);
return 0;
}
return (void *) base;
}
static void *
gettable(int size, char *name, int flags, size_t align)
{
long base;
/* Put table after loaded code to support kernel DDB */
tablebase = roundup(tablebase, align);
base = tablebase;
tablebase += size;
return (void *) base;
}
/*
*/
int
main(int argc, char *argv[])
{
char line[1024];
int i;
Elf32_Addr entry;
dobootopts(argc, argv);
if (OSLoadPartition != NULL) {
strlcpy(line, OSLoadPartition, sizeof(line));
i = strlen(line);
if (OSLoadFilename != NULL)
strlcpy(&line[i], OSLoadFilename, sizeof(line) - i -1);
} else
strlcpy("invalid argument setup", line, sizeof(line));
for (entry = 0; entry < argc; entry++)
printf("arg %d: %s\n", entry, argv[entry]);
printf("\nOpenBSD/sgi Arcbios boot\n");
printf("Boot: %s\n", line);
entry = loadfile(line);
if (entry != NULL)
((void (*)())entry)(argc, argv);
printf("Boot FAILED!\n ");
Bios_Restart();
}
/*
* Decode boot options.
*/
void
dobootopts(int argc, char **argv)
{
char *SystemPartition = NULL;
char *cp;
int i;
for (i = 1; i < argc; i++) {
cp = argv[i];
if (cp == NULL)
continue;
if (strncmp(cp, "OSLoadOptions=", 14) == 0) {
if (strcmp(&cp[14], "auto") == 0)
bootauto = AUTO_YES;
else if (strcmp(&cp[14], "single") == 0)
bootauto = AUTO_NO;
else if (strcmp(&cp[14], "mini") == 0)
bootauto = AUTO_MINI;
else if (strcmp(&cp[14], "debug") == 0)
bootauto = AUTO_DEBUG;
} else if (strncmp(cp, "OSLoadPartition=", 16) == 0)
OSLoadPartition = &cp[16];
else if (strncmp(cp, "OSLoadFilename=", 15) == 0)
OSLoadFilename = &cp[15];
else if (strncmp(cp, "SystemPartition=", 16) == 0)
SystemPartition = &cp[16];
}
/* If "OSLoadOptions=" is missing, see if any arg was given */
if (bootauto == AUTO_NONE && *argv[1] == '/')
OSLoadFilename = argv[1];
if (bootauto == AUTO_MINI) {
static char loadpart[64];
char *p;
strlcpy(loadpart, argv[0], sizeof loadpart);
p = strstr(loadpart, "partition(8)");
if (p) {
p += strlen("partition(");
p[0] = '0'; p[2] = 0;
OSLoadPartition = loadpart;
OSLoadFilename = "/bsd.rd";
}
}
}
/*
* Open 'filename', read in program and return the entry point or -1 if error.
*/
Elf32_Addr
loadfile(fname)
register char *fname;
{
union {
Elf32_Ehdr eh32;
Elf64_Ehdr eh64;
} eh;
int fd;
Elf32_Addr entry;
if ((fd = open(fname, 0)) < 0) {
printf("can't open file %s\n", fname);
return NULL;
}
/* read the ELF header and check that it IS an ELF header */
if (read(fd, (char *)&eh, sizeof(eh)) != sizeof(eh)) {
printf("error: ELF header read error\n");
return NULL;
}
if (!IS_ELF(eh.eh32)) {
printf("not an elf file\n");
return NULL;
}
/* Determine CLASS */
if (eh.eh32.e_ident[EI_CLASS] == ELFCLASS32)
entry = loadfile32(fd, (void *)&eh);
else if (eh.eh32.e_ident[EI_CLASS] == ELFCLASS64)
entry = loadfile64(fd, (void *)&eh);
else {
printf("unknown ELF class\n");
return NULL;
}
return entry;
}
Elf32_Addr
loadfile32(int fd, Elf32_Ehdr *eh)
{
char buf[4096];
Elf32_Phdr *ph;
int i;
ph = (Elf32_Phdr *) buf;
lseek(fd, eh->e_phoff, 0);
if (read(fd, (char *)ph, 4096) != 4096) {
printf("unexpected EOF\n");
return NULL;
}
tablebase = 0;
printf("Loading ELF32 file\n");
for (i = 0; i < eh->e_phnum; i++, ph++) {
if (ph->p_type == PT_LOAD) {
lseek(fd, ph->p_offset, 0);
printf("0x%x:0x%x, ",(long)ph->p_paddr, (long)ph->p_filesz);
if (read(fd, (char *)ph->p_paddr,
ph->p_filesz) != ph->p_filesz) {
printf("unexpected EOF\n");
return NULL;
}
if(ph->p_memsz > ph->p_filesz) {
printf("Zero 0x%x:0x%x, ",
(long)(ph->p_paddr + ph->p_filesz),
(long)(ph->p_memsz - ph->p_filesz));
bzero((void *)(ph->p_paddr + ph->p_filesz),
ph->p_memsz - ph->p_filesz);
}
if((ph->p_paddr + ph->p_memsz) > tablebase)
tablebase = ph->p_paddr + ph->p_memsz;
}
}
memset((void *)tablebase, 0, 4096);
loadsymtab32(fd, eh, 0);
printf("Start at 0x%x\n", eh->e_entry);
return(eh->e_entry);
}
Elf32_Addr
loadfile64(int fd, Elf64_Ehdr *eh)
{
char buf[4096];
Elf64_Phdr *ph;
int i;
ph = (Elf64_Phdr *) buf;
lseek(fd, eh->e_phoff, 0);
if (read(fd, (char *)ph, 4096) != 4096) {
printf("unexpected EOF\n");
return NULL;
}
tablebase = 0;
printf("Loading ELF64 file\n");
for (i = 0; i < eh->e_phnum; i++, ph++) {
if (ph->p_type == PT_LOAD) {
lseek(fd, ph->p_offset, 0);
printf("0x%llx:0x%llx, ",ph->p_paddr, ph->p_filesz);
if (read(fd, (char *)(long)ph->p_paddr,
ph->p_filesz) != ph->p_filesz) {
printf("unexpected EOF\n");
return NULL;
}
if(ph->p_memsz > ph->p_filesz) {
printf("Zero 0x%llx:0x%llx, ",
ph->p_paddr + ph->p_filesz,
ph->p_memsz - ph->p_filesz);
bzero((void *)(long)(ph->p_paddr + ph->p_filesz),
ph->p_memsz - ph->p_filesz);
}
if((ph->p_paddr + ph->p_memsz) > tablebase)
tablebase = ph->p_paddr + ph->p_memsz;
}
}
memset((void *)tablebase, 0, 4096);
loadsymtab64(fd, eh, 0);
printf("Start at 0x%llx\n", eh->e_entry);
return(eh->e_entry);
}
int
loadsymtab32(int fd, Elf32_Ehdr *eh, int flags)
{
Elf32_Ehdr *keh;
Elf32_Shdr *shtab;
Elf32_Shdr *sh, *ksh, *shstrh, *strh;
Elf32_Sym *symtab;
int *symptr;
char *shstrtab, *strtab, *symend;
int i, nsym, offs, size;
printf("Loading symbol table\n");
size = eh->e_shnum * sizeof(Elf32_Shdr);
shtab = (Elf32_Shdr *) alloc(size);
if (lseek (fd, eh->e_shoff, SEEK_SET) != eh->e_shoff ||
read (fd, shtab, size) != size) {
printf("Seek to section headers failed.\n");
return -1;
}
tablebase = roundup(tablebase, sizeof(long));
symptr = (int *)tablebase;
tablebase = roundup(tablebase, 4096);
keh = (Elf32_Ehdr *)tablebase;
tablebase += sizeof(Elf32_Ehdr);
tablebase = roundup(tablebase, sizeof(long));
ksh = (Elf32_Shdr *)tablebase;
tablebase += roundup((sizeof(Elf32_Shdr) * eh->e_shnum), sizeof(long));
memcpy(ksh, shtab, roundup((sizeof(Elf32_Shdr) * eh->e_shnum), sizeof(long)));
sh = ksh;
shstrh = &sh[eh->e_shstrndx];
for (i = 0; i < eh->e_shnum; sh++, i++) {
if (sh->sh_type == SHT_SYMTAB)
break;
}
if (i >= eh->e_shnum) {
printf("No symbol table found!\n");
return -1;
}
strh = &ksh[sh->sh_link];
nsym = sh->sh_size / sh->sh_entsize;
offs = sh->sh_offset;
size = sh->sh_size;
/*
* Allocate tables in correct order so the kernel groks it.
* Then we read them in the order they are in the ELF file.
*/
shstrtab = gettable(shstrh->sh_size, "shstrtab", flags, sizeof(long));
strtab = gettable(strh->sh_size, "strtab", flags, sizeof(long));
symtab = gettable(size, "symtab", flags, sizeof(long));
symend = (char *)symtab + size;
do {
if(shstrh->sh_offset < offs && shstrh->sh_offset < strh->sh_offset) {
#if 0
/*
* We would like to read the shstrtab from the file
* but since this table is located in front of the shtab
* it is already gone. We can't position backwards
* outside the current segment when using tftp.
* Instead we create the names we need in the string
* table because it can be reconstructed from the info
* we now have access to.
*/
if (!readtable (shstrh->sh_offset, (void *)shstrtab,
shstrh->sh_size, "shstring", flags))
return(0);
#else
memset(shstrtab, 0, shstrh->sh_size);
strncpy(shstrtab + shstrh->sh_name, ".shstrtab", 10);
strncpy(shstrtab + strh->sh_name, ".strtab", 10);
strncpy(shstrtab + sh->sh_name, ".symtab", 10);
#endif
shstrh->sh_offset = 0x7fffffff;
}
if (offs < strh->sh_offset && offs < shstrh->sh_offset) {
if (!(readtable(fd, offs, (void *)symtab, size,
"sym", flags)))
return (0);
offs = 0x7fffffff;
}
if (strh->sh_offset < offs && strh->sh_offset < shstrh->sh_offset) {
if (!(readtable (fd, strh->sh_offset, (void *)strtab,
strh->sh_size, "string", flags)))
return (0);
strh->sh_offset = 0x7fffffff;
}
if (offs == 0x7fffffff && strh->sh_offset == 0x7fffffff &&
shstrh->sh_offset == 0x7fffffff)
break;
} while(1);
/*
* Update the kernel headers with the current info.
*/
shstrh->sh_offset = (Elf32_Off)shstrtab - (Elf32_Off)keh;
strh->sh_offset = (Elf32_Off)strtab - (Elf32_Off)keh;
sh->sh_offset = (Elf32_Off)symtab - (Elf32_Off)keh;
memcpy(keh, eh, sizeof(Elf32_Ehdr));
keh->e_phoff = 0;
keh->e_shoff = sizeof(Elf32_Ehdr);
keh->e_phentsize = 0;
keh->e_phnum = 0;
symptr[0] = (int)keh;
symptr[1] = roundup((int)symend, sizeof(int));
return(0);
}
int
loadsymtab64(int fd, Elf64_Ehdr *eh, int flags)
{
Elf64_Ehdr *keh;
Elf64_Shdr *shtab;
Elf64_Shdr *sh, *ksh, *shstrh, *strh;
Elf64_Sym *symtab;
u_int64_t *symptr;
char *shstrtab, *strtab, *symend;
int i, nsym;
Elf64_Xword size;
Elf64_Off offs;
printf("Loading symbol table\n");
size = eh->e_shnum * sizeof(Elf64_Shdr);
shtab = (Elf64_Shdr *) alloc(size);
if (lseek (fd, (int)eh->e_shoff, SEEK_SET) != (int)eh->e_shoff ||
read (fd, shtab, size) != size) {
printf("Seek to section headers failed.\n");
return -1;
}
tablebase = roundup(tablebase, sizeof(u_int64_t));
symptr = (u_int64_t *)tablebase;
tablebase = roundup(tablebase, 4096);
keh = (Elf64_Ehdr *)tablebase;
tablebase += sizeof(Elf64_Ehdr);
tablebase = roundup(tablebase, sizeof(u_int64_t));
ksh = (Elf64_Shdr *)tablebase;
tablebase += roundup((sizeof(Elf64_Shdr) * eh->e_shnum), sizeof(u_int64_t));
memcpy(ksh, shtab, roundup((sizeof(Elf64_Shdr) * eh->e_shnum),
sizeof(u_int64_t)));
sh = ksh;
shstrh = &sh[eh->e_shstrndx];
for (i = 0; i < eh->e_shnum; sh++, i++) {
if (sh->sh_type == SHT_SYMTAB) {
break;
}
}
if (i >= eh->e_shnum) {
printf("No symbol table found!\n");
return -1;
}
strh = &ksh[sh->sh_link];
nsym = sh->sh_size / sh->sh_entsize;
offs = sh->sh_offset;
size = sh->sh_size;
/*
* Allocate tables in correct order so the kernel groks it.
* Then we read them in the order they are in the ELF file.
*/
shstrtab = gettable(shstrh->sh_size, "shstrtab", flags, sizeof(u_int64_t));
strtab = gettable(strh->sh_size, "strtab", flags, sizeof(u_int64_t));
symtab = gettable(size, "symtab", flags, sizeof(u_int64_t));
symend = (char *)symtab + size;
do {
if(shstrh->sh_offset < offs && shstrh->sh_offset < strh->sh_offset) {
#if 0
/*
* We would like to read the shstrtab from the file
* but since this table is located in front of the shtab
* it is already gone. We can't position backwards
* outside the current segment when using tftp.
* Instead we create the names we need in the string
* table because it can be reconstructed from the
* info we now have access to.
*/
if (!readtable (shstrh->sh_offset, (void *)shstrtab,
shstrh->sh_size, "shstring", flags))
return(0);
#else
memset(shstrtab, 0, shstrh->sh_size);
strncpy(shstrtab + shstrh->sh_name, ".shstrtab", 10);
strncpy(shstrtab + strh->sh_name, ".strtab", 10);
strncpy(shstrtab + sh->sh_name, ".symtab", 10);
#endif
shstrh->sh_offset = 0x7fffffff;
}
if (offs < strh->sh_offset && offs < shstrh->sh_offset) {
if (!(readtable(fd, offs, (void *)symtab,
size, "sym", flags)))
return (0);
offs = 0x7fffffff;
}
if (strh->sh_offset < offs && strh->sh_offset < shstrh->sh_offset) {
if (!(readtable (fd, strh->sh_offset, (void *)strtab,
strh->sh_size, "string", flags))) {
return (0);
}
strh->sh_offset = 0x7fffffff;
}
if (offs == 0x7fffffff && strh->sh_offset == 0x7fffffff &&
shstrh->sh_offset == 0x7fffffff)
break;
} while(1);
/*
* Update the kernel headers with the current info.
*/
shstrh->sh_offset = (Elf64_Off)(long)shstrtab - (Elf64_Off)(long)keh;
strh->sh_offset = (Elf64_Off)(long)strtab - (Elf64_Off)(long)keh;
sh->sh_offset = (Elf64_Off)(long)symtab - (Elf64_Off)(long)keh;
memcpy(keh, eh, sizeof(Elf64_Ehdr));
keh->e_phoff = 0;
keh->e_shoff = sizeof(Elf64_Ehdr);
keh->e_phentsize = 0;
keh->e_phnum = 0;
symptr[0] = (Elf64_Off)keh;
symptr[1] = (Elf64_Off)roundup((Elf64_Off)symend, sizeof(u_int64_t));
return(0);
}