#include <sys/types.h>
#include <sys/param.h>
#include <ufs/ufs/dinode.h>
#include <sys/disklabel.h>
#include <sys/exec_elf.h>
#include "readufs.h"
#define STACK_SIZE ((unsigned) (64*1024))
#define LOAD_ALIGN ((unsigned) 2048)
#define PZ_MEM_BOOT 0x3d0
#define DEV_CLASS 0x2c
#define DEV_CL_MASK 0xf
#define DEV_CL_SEQU 0x2
static char *hexstr(char *, unsigned);
void ipl_main(unsigned , unsigned , unsigned );
void load_file(const char *, uintptr_t , unsigned ,
int );
void load_file_ino(ino32_t, const char *, uintptr_t ,
unsigned , int );
struct loadinfo {
void *sec_image;
unsigned sec_size;
#if 0
unsigned sec_pad;
#endif
unsigned entry_offset;
};
static inline void xi_elf32(struct loadinfo *, Elf32_Ehdr *);
static inline void xi_elf64(struct loadinfo *, Elf64_Ehdr *);
int xi_load(struct loadinfo *, void *);
void reboot(void);
void halt(void);
void dispatch(unsigned , unsigned ,
unsigned , int , unsigned );
void print(const char *);
void putch(int);
int getch(void);
int boot_input(void *, int , int );
extern char str_seekseq[], str_bit_firmware[];
extern char str_crlf[], str_space[], str_rubout[];
extern char str_bootpart[], str_booting_part[];
extern char str_warn_2GB[], str_warn_unused[], str_nolabel[];
extern char str_filesystem[], str_nofs[];
extern char str_lookup[], str_loading[], str_at[], str_dddot[], str_done[];
extern char str_boot1[], str_boot2[], str_boot3[];
extern char str_noboot[];
extern char str_ukfmt[];
#ifdef __GNUC__
#define memcpy(d, s, n) __builtin_memcpy(d, s, n)
#else
void *memcpy(void *, const void *, size_t);
#endif
void *memmove(void *, const void *, size_t);
union {
char dklsec[512];
struct disklabel dkl;
} labelsector;
#define dklabel (*(struct disklabel *)(labelsector.dklsec + LABELOFFSET))
unsigned offset_raw_read;
extern char diskbuf[2048];
#define BLK_PER_READ 4
#define MASK_BLK_PER_READ (BLK_PER_READ - 1)
void
RAW_READ(void *buf, daddr_t blkpos, size_t bytelen)
{
char *b = buf;
size_t off, readlen;
int devoff;
static int prvdevoff = -dbtob(BLK_PER_READ);
int pos;
for ( ; bytelen > 0; b += readlen, bytelen -= readlen) {
devoff = dbtob(blkpos & ~MASK_BLK_PER_READ) + offset_raw_read;
if (prvdevoff != devoff) {
#if 1
if ((*(unsigned *)(PZ_MEM_BOOT+DEV_CLASS) & DEV_CL_MASK)
== DEV_CL_SEQU) {
pos = prvdevoff + dbtob(BLK_PER_READ);
if (devoff < pos)
pos = 0;
if (devoff - pos > 512 * 1024)
print(str_seekseq);
for (; pos < devoff; pos += dbtob(BLK_PER_READ))
boot_input(diskbuf,
dbtob(BLK_PER_READ), pos);
}
#endif
prvdevoff = devoff;
boot_input(diskbuf, dbtob(BLK_PER_READ), devoff);
}
off = dbtob(blkpos & MASK_BLK_PER_READ),
readlen = dbtob(BLK_PER_READ) - off;
if (readlen > bytelen)
readlen = bytelen;
memcpy(b, diskbuf + off, readlen);
blkpos = (blkpos & ~MASK_BLK_PER_READ) + BLK_PER_READ;
}
}
static char *
hexstr(char *buf, unsigned val)
{
unsigned v;
char rev[16];
char *r = rev, *b = buf;
do {
v = val & 0xf;
*r++ = (v <= 9) ? '0' + v : 'a' - 10 + v;
val >>= 4;
} while (val);
while (r > rev)
*b++ = *--r;
*b = '\0';
return buf;
}
void
ipl_main(unsigned interactive, unsigned sptop, unsigned psw)
{
char buf[32];
int part = 0;
unsigned secsz, partoff, partsz;
int c, c1;
uintptr_t loadadr;
#if 0
print(hexstr(buf, interactive));
print(str_crlf);
print(hexstr(buf, sptop));
print(str_crlf);
print(hexstr(buf, psw));
print(str_crlf);
#endif
print(hexstr(buf, (psw & 0x08000000) ? (unsigned) 0x64 : 0x32));
print(str_bit_firmware);
if (dklabel.d_magic == DISKMAGIC && (secsz = dklabel.d_secsize) != 0) {
if (interactive) {
select_partition:
print(str_bootpart);
part = 0;
c1 = 0;
while ((c = getch()) >= 0) {
switch (c) {
case '\n':
case '\r':
goto break_while;
case '\b':
case '\177':
if (c1) {
print(str_rubout);
part = c1 = 0;
}
break;
case '!':
if (c1 == 0) {
part = -1;
goto echoback;
}
break;
default:
if (c1 == 0 && c >= 'a' && c <= 'p') {
part = c - 'a';
echoback:
putch(c);
c1 = 1;
}
break;
}
}
break_while:
if (part == -1)
return;
}
str_booting_part[25] = 'a' + part;
print(str_booting_part);
partoff = dklabel.d_partitions[part].p_offset;
partsz = dklabel.d_partitions[part].p_size;
if (part >= (int) dklabel.d_npartitions || partsz == 0) {
print(str_warn_unused);
goto select_partition;
}
if (partoff + partsz > ((unsigned)2*1024*1024*1024) / secsz) {
print(str_warn_2GB);
goto select_partition;
}
offset_raw_read = partoff * secsz;
} else {
print(str_nolabel);
}
if (ufs_init()) {
print(str_nofs);
return;
}
str_filesystem[12] = (ufs_info.fstype == UFSTYPE_FFS) ? 'F' : 'L';
print(str_filesystem);
loadadr = (sptop + STACK_SIZE + LOAD_ALIGN - 1) & (-LOAD_ALIGN);
load_file(str_boot1, loadadr, interactive, part);
load_file(str_boot2, loadadr, interactive, part);
load_file(str_boot3, loadadr, interactive, part);
print(str_noboot);
}
void
load_file(const char *path, uintptr_t loadadr, unsigned interactive, int part)
{
print(str_lookup);
print(path);
print(str_crlf);
load_file_ino(ufs_lookup_path(path), path, loadadr, interactive, part);
}
void
load_file_ino(ino32_t ino, const char *fn, uintptr_t loadadr, unsigned interactive, int part)
{
union ufs_dinode dinode;
size_t sz;
struct loadinfo inf;
char buf[32];
if (ino == 0 || ufs_get_inode(ino, &dinode))
return;
print(str_loading);
print(fn);
print(str_at);
print(hexstr(buf, loadadr));
print(str_dddot);
sz = DI_SIZE(&dinode);
ufs_read(&dinode, (void *) loadadr, 0, sz);
print(str_done);
inf.sec_size = sz;
inf.entry_offset = 0;
if (xi_load(&inf, (void *) loadadr)) {
print(fn);
print(str_ukfmt);
}
dispatch(interactive, loadadr, loadadr + inf.sec_size, part,
loadadr + inf.entry_offset);
}
static inline void
xi_elf32(struct loadinfo *inf, Elf32_Ehdr *hdr)
{
char *top = (void *) hdr;
Elf32_Phdr *ph;
ph = (void *) (top + hdr->e_phoff);
inf->sec_image = top + ph->p_offset;
inf->sec_size = ph->p_filesz;
#if 0
inf->sec_pad = ph->p_memsz - ph->p_filesz;
#endif
inf->entry_offset = hdr->e_entry - ph->p_vaddr;
}
static inline void
xi_elf64(struct loadinfo *inf, Elf64_Ehdr *hdr)
{
char *top = (void *) hdr;
Elf64_Phdr *ph;
ph = (void *) (top + (unsigned) hdr->e_phoff);
inf->sec_image = top + (unsigned) ph->p_offset;
inf->sec_size = (unsigned) ph->p_filesz;
#if 0
inf->sec_pad = (unsigned) ph->p_memsz - (unsigned) ph->p_filesz;
#endif
inf->entry_offset = (unsigned) hdr->e_entry - (unsigned) ph->p_vaddr;
}
int
xi_load(struct loadinfo *inf, void *buf)
{
Elf32_Ehdr *e32hdr = buf;
Elf64_Ehdr *e64hdr = buf;
uint16_t class_data;
if (*(uint32_t *)&e32hdr->e_ident[EI_MAG0] !=
(ELFMAG0 << 24 | ELFMAG1 << 16 | ELFMAG2 << 8 | ELFMAG3) ||
e32hdr->e_ident[EI_VERSION] != EV_CURRENT)
return 1;
if (*(uint32_t *)&e32hdr->e_type != (ET_EXEC << 16 | EM_PARISC))
return 1;
if ((class_data = *(uint16_t *)&e32hdr->e_ident[EI_CLASS]) ==
(ELFCLASS32 << 8 | ELFDATA2MSB)) {
if (e32hdr->e_phnum != 1)
return 1;
xi_elf32(inf, e32hdr);
} else if (class_data == (ELFCLASS64 << 8 | ELFDATA2MSB)) {
if (e64hdr->e_phnum != 1)
return 1;
xi_elf64(inf, e64hdr);
} else
return 1;
memmove(buf, inf->sec_image, inf->sec_size);
#if 0
memset((char *) buf + inf->sec_size, 0, inf->sec_pad);
#endif
return 0;
}