freebsd-dev/sys/boot/alpha/boot1/boot1.c
2002-06-11 06:56:31 +00:00

279 lines
4.5 KiB
C

/*
* $FreeBSD$
* From $NetBSD: bootxx.c,v 1.4 1997/09/06 14:08:29 drochner Exp $
*/
/*
* Copyright (c) 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <string.h>
#include <sys/param.h>
#include <sys/dirent.h>
#include <machine/prom.h>
#include <machine/rpb.h>
#define DEBUGxx
void puts(const char *s);
void puthex(u_long v);
static int dskread(void *, u_int64_t, size_t);
#define printf(...) \
while (0)
#define memcpy(dst, src, len) \
bcopy(src, dst, len)
#include "ufsread.c"
extern end[];
int errno;
char *heap = (char*) end;
void
bcopy(const void *src, void *dst, size_t len)
{
const char *s;
char *d;
for (d = dst, s = src; len; len--)
*d++ = *s++;
}
void
putchar(int c)
{
if (c == '\n')
prom_putchar('\r');
prom_putchar(c);
}
int
getchar()
{
return prom_getchar();
}
int
ischar()
{
return prom_poll();
}
void
puts(const char *s)
{
while (*s)
putchar(*s++);
}
void
panic(const char *message, ...)
{
puts(message);
puts("\r\n");
halt();
}
int prom_fd = 0;
int
devopen()
{
prom_return_t ret;
char devname[64];
if (prom_fd)
return;
ret.bits = prom_getenv(PROM_E_BOOTED_DEV, devname, sizeof devname);
ret.bits = prom_open(devname, ret.u.retval + 1);
if (ret.u.status)
panic("devopen: open failed\n");
prom_fd = ret.u.retval;
/* XXX read disklabel and setup partition offset */
return 0;
}
#ifdef DEBUG
void
puthex(u_long v)
{
int digit;
char hex[] = "0123456789abcdef";
puts("0x");
if (!v) {
puts("0");
return;
}
for (digit = 0; v >= (0x10L << digit); digit += 4)
;
for (; digit >= 0; digit -= 4)
putchar(hex[(v >> digit) & 0xf]);
}
#endif
int
dskread(void *buf, u_int64_t block, size_t size)
{
#ifdef DEBUG
puts("dskread(");
puthex((u_long)buf);
puts(",");
puthex(block);
puts(",");
puthex(size);
puts(")\n");
#endif
prom_read(prom_fd, size * DEV_BSIZE, buf, block);
return (0);
}
static inline void
devclose()
{
if (prom_fd) {
prom_close(prom_fd);
prom_fd = 0;
}
}
static inline void
getfilename(char *filename, const char *defname)
{
int c;
char *p = filename;
puts("Boot: ");
while ((c = getchar()) != '\r') {
if (c == '\b' || c == 0177) {
if (p > filename) {
puts("\b \b");
p--;
}
} else {
putchar(c);
*p++ = c;
}
}
putchar('\n');
*p = '\0';
if (!*filename)
strcpy(filename, defname);
return;
}
static struct dmadat __dmadat;
static inline void
loadfile(char *name, char *addr)
{
int n;
char *p;
ino_t ino;
puts("Loading ");
puts(name);
puts("\n");
dmadat = &__dmadat;
if (devopen() || (ino = lookup(name)) == 0) {
puts("Can't open file ");
puts(name);
puts("\n");
halt();
}
p = addr;
do {
n = fsread(ino, p, VBLKSIZE);
if (n < 0) {
puts("Can't read file ");
puts(name);
puts("\n");
halt();
}
p += n;
twiddle();
} while (n == VBLKSIZE);
devclose();
}
static inline u_long rpcc()
{
u_long v;
__asm__ __volatile__ ("rpcc %0" : "=r"(v));
return v & 0xffffffff;
}
int
main()
{
char *loadaddr = (char*) SECONDARY_LOAD_ADDRESS;
char *name = "/boot/loader";
char *p;
char filename[512];
void (*entry) __P((void));
u_long start, freq;
int i;
init_prom_calls();
start = rpcc();
freq = ((struct rpb *)HWRPB_ADDR)->rpb_cc_freq;
while (((rpcc() - start) & 0xffffffff) < freq) {
twiddle();
if (ischar()) {
getfilename(filename, name);
name = filename;
break;
}
}
loadfile(name, loadaddr);
entry = (void (*)())loadaddr;
(*entry)();
return 0;
}