/* $NetBSD: bootxx.c,v 1.5.70.1 2020/06/20 13:49:32 martin Exp $ */
/*-
* Copyright (c) 2004, 2005 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* 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.
*/
#ifdef _STANDALONE
#include <lib/libsa/stand.h>
#include <lib/libkern/libkern.h>
#endif
#include <sys/types.h>
#include <sys/param.h>
#include "bootxx.h"
#include <sys/exec_ecoff.h>
#include <sys/exec_elf.h>
#include <machine/sector.h>
#include <machine/sbd.h>
#include "common.h"
#define IS_TEXT(p) (p.p_flags & PF_X)
#define IS_DATA(p) ((p.p_flags & PF_X) == 0)
#define IS_BSS(p) (p.p_filesz < p.p_memsz)
#define FILHSZ (sizeof(struct ecoff_filehdr))
#define SCNHSZ (sizeof(struct ecoff_scnhdr))
#define N_TXTOFF(f, a) \
((a)->vstamp < 23 ? \
((FILHSZ +(f)->f_opthdr +(f)->f_nscns * SCNHSZ + 7) & ~7) : \
((FILHSZ +(f)->f_opthdr +(f)->f_nscns * SCNHSZ + 15) & ~15))
int main(void);
int loader(const char *, uint32_t *);
int load_elf(uint8_t *, uint32_t *);
int load_coff(uint8_t *, uint32_t *);
int dk_read(int, int, void *);
const char *errmsg[] = {
[BERR_PDINFO] = "No PDINFO",
[BERR_RDVTOC] = "VTOC read error",
[BERR_VTOC] = "VTOC bad magic",
[BERR_NOBFS] = "No BFS partition",
[BERR_RDINODE] = "I-node read error",
[BERR_NOROOT] = "No root",
[BERR_RDDIRENT] = "Dirent read error",
[BERR_NOFILE] = "No such a file",
[BERR_RDFILE] = "File read error",
[BERR_FILEMAGIC] = "Bad file magic",
[BERR_AOUTHDR] = "Not a OMAGIC",
[BERR_ELFHDR] = "Not a ELF",
[BERR_TARHDR] = "Read tar file",
[BERR_TARMAGIC] = "Bad tar magic",
};
const char *boottab[] = {
"boot", /* NetBSD (bfs,ustarfs) */
"iopboot", /* EWS-UX (bfs) */
0 /* terminate */
};
int __dk_unit, __dk_type, __spb;
bool (*fd_position)(uint32_t, uint32_t *, int *);
int
main(void)
{
char msg[] = "[+++] NetBSD/ews4800mips >> ";
const char *p;
const char **boot;
uint32_t entry;
int err;
#ifdef _STANDALONE
int i, fd_format;
boot_device(&__dk_type, &__dk_unit, &fd_format);
msg[1] = __dk_type + '0';
msg[2] = __dk_unit + '0';
msg[3] = FS_SIGNATURE;
for (i = 0; msg[i] != 0; i++)
ROM_PUTC(32 + i * 12, 536, msg[i]);
if (__dk_type == NVSRAM_BOOTDEV_FLOPPYDISK) {
fd_position = blk_to_2d_position;
if (fd_format == FD_FORMAT_2D) {
fd_position = blk_to_2d_position;
__spb = 2; /* 256bytes/sector */
} else {
fd_position = blk_to_2hd_position;
__dk_unit |= 0x1000000; /* | 2HD flag */
__spb = 1;
}
}
#else
printf("%s\n", msg);
sector_init("/dev/rsd1p", DEV_BSIZE);
sector_read(SDBOOT_PDINFOADDR, PDINFO_SECTOR);
#endif
for (boot = boottab; *boot; boot++) {
if ((err = loader(*boot, &entry)) == 0) {
#ifdef _STANDALONE
ROM_PUTC(0, 0, '\n');
ROM_PUTC(0, 0, '\r');
return entry;
#else
printf("entry=%p\n", (void *)entry);
sector_fini();
return 0;
#endif
}
p = errmsg[err];
#ifdef _STANDALONE
for (i = 0; p[i] != 0; i++)
ROM_PUTC(600 + i * 12, 536, p[i]);
#else
DPRINTF("***ERROR *** %s\n", p);
#endif
}
#ifdef _STANDALONE
while (/*CONSTCOND*/1)
;
/* NOTREACHED */
#else
sector_fini();
#endif
return 0;
}
int
loader(const char *fname, uint32_t *entry)
{
int err;
uint16_t mag;
size_t sz;
#ifdef _STANDALONE
int i;
for (i = 0; fname[i] != 0; i++)
ROM_PUTC(380 + i * 12, 536, fname[i]);
#else
printf("%s\n", fname);
#endif
if ((err = fileread(fname, &sz)) != 0)
return err;
DPRINTF("%s found. %d bytes.\n", fname, sz);
mag = *(uint16_t *)SDBOOT_SCRATCHADDR;
if (mag == 0x7f45)
return load_elf((uint8_t *)SDBOOT_SCRATCHADDR, entry);
else if (mag == ECOFF_MAGIC_MIPSEB)
return load_coff((uint8_t *)SDBOOT_SCRATCHADDR, entry);
return BERR_FILEMAGIC;
}
int
load_elf(uint8_t *buf, uint32_t *entry)
{
Elf32_Ehdr *e = (void *)buf;
Elf32_Phdr *p;
int i;
if (e->e_ident[EI_MAG2] != 'L' || e->e_ident[EI_MAG3] != 'F' ||
e->e_ident[EI_CLASS] != ELFCLASS32 ||
e->e_ident[EI_DATA] != ELFDATA2MSB ||
e->e_type != ET_EXEC ||
e->e_machine != EM_MIPS)
return BERR_ELFHDR;
BASSERT(e->e_phentsize == sizeof(Elf32_Phdr));
p = (void *)(buf + e->e_phoff);
#ifdef _STANDALONE
for (i = 0; i < e->e_phnum; i++) {
if (p[i].p_type != PT_LOAD ||
(p[i].p_flags & (PF_W|PF_R|PF_X)) == 0)
continue;
if (IS_TEXT(p[i]) || IS_DATA(p[i])) {
memcpy((void *)p[i].p_vaddr,
buf + p[i].p_offset, p[i].p_filesz);
}
if (IS_BSS(p[i])) {
memset((void *)(p[i].p_vaddr + p[i].p_filesz), 0,
p[i].p_memsz - p[i].p_filesz);
}
}
#else
DPRINTF("ELF entry point 0x%08x\n", e->e_entry);
for (i = 0; i < e->e_phnum; i++) {
if (p[i].p_type != PT_LOAD ||
(p[i].p_flags & (PF_W|PF_R|PF_X)) == 0)
continue;
if (IS_TEXT(p[i]) || IS_DATA(p[i])) {
DPRINTF("[text/data] 0x%08x 0x%x %dbyte.\n",
p[i].p_vaddr, p[i].p_offset, p[i].p_filesz);
}
if (IS_BSS(p[i])) {
DPRINTF("[bss] 0x%08x %dbyte.\n",
p[i].p_vaddr + p[i].p_filesz,
p[i].p_memsz - p[i].p_filesz);
}
}
#endif
*entry = e->e_entry;
return 0;
}
int
load_coff(uint8_t *p, uint32_t *entry)
{
struct ecoff_exechdr *eh = (void *)p;
struct ecoff_aouthdr *a = &eh->a;
struct ecoff_filehdr *f = &eh->f;
if (a->magic != ECOFF_OMAGIC)
return BERR_AOUTHDR;
p += N_TXTOFF(f, a);
DPRINTF("file offset = 0x%x\n", N_TXTOFF(f, a));
#ifdef _STANDALONE
memcpy((void *)a->text_start, p, a->tsize);
memcpy((void *)a->data_start, p + a->tsize, a->dsize);
#else
DPRINTF("COFF entry point 0x%08lx\n", a->entry);
DPRINTF("[text] 0x%08lx %ld byte.\n", a->text_start, a->tsize);
DPRINTF("[data] 0x%08lx %ld byte.\n", a->data_start, a->dsize);
#endif
*entry = a->entry;
return 0;
}
int
dk_read(int sector, int count, void *buf)
{
#ifdef _STANDALONE
int cnt;
uint32_t pos;
uint8_t *p = buf;
if (__dk_type == NVSRAM_BOOTDEV_HARDDISK) { /* DISK */
if ((ROM_DK_READ(__dk_unit, sector, count, p) & 0x7f) != 0)
return 1;
} else { /* FD */
while (count > 0) {
fd_position(sector, &pos, &cnt);
if (cnt > count)
cnt = count;
if ((ROM_FD_READ(__dk_unit, pos, cnt * __spb, p)
& 0x7f) != 0)
return 1;
count -= cnt;
sector += cnt;
p += 512 * cnt;
}
}
#else
sector_read_n(buf, sector, count);
#endif
return 0;
}