New boot program.

Load and execute NetBSD/x68k kernel from Human68k.
This commit is contained in:
itohy 1998-09-01 19:55:32 +00:00
parent 8f7b16dd71
commit ecc30b1784
5 changed files with 865 additions and 0 deletions

View File

@ -0,0 +1,36 @@
# $NetBSD: Makefile,v 1.1 1998/09/01 19:55:32 itohy Exp $
BASE= loadbsd
PROG= ${BASE}.x # Human68k ".x" executable
STRIPFLAG= # not an a.out
BINMODE=444 # not to be run on NetBSD
SRCS= start.S loadbsd.c xprintf.c trampoline.S
MAN= ${BASE}.8
BINDIR= /usr/mdec
MANSUBDIR= /${MACHINE}
.PATH: ${.CURDIR}/../common
AOUT2HUX!=cd ${.CURDIR}/../aout2hux; echo `${MAKE} print-objdir`/aout2hux
LIBDOS!=cd ${.CURDIR}/../libdos; ${MAKE} print-objdir
LIBIOCS!=cd ${.CURDIR}/../libiocs; ${MAKE} print-objdir
CPPFLAGS= -W -Wall -O -fomit-frame-pointer
CPPFLAGS+= -m68000 -Wa,-mc68000
CPPFLAGS+= -I${.CURDIR}/../libdos -I${.CURDIR}/../libiocs
LDFLAGS= -nostdlib -static -N
LDLIBS= -L${LIBDOS} -ldos -L${LIBIOCS} -liocs -lc
DPADD+= ${AOUT2HUX}
CLEANFILES+= ${BASE}1 ${BASE}2
${PROG}: ${BASE}1 ${BASE}2
${AOUT2HUX} -o ${.TARGET} ${BASE}1 11000 ${BASE}2 22000
.include <bsd.prog.mk>
.for i in 1 2
${BASE}${i}: ${OBJS} ${LIBDOS}/libdos.a ${LIBIOCS}/libiocs.a
${CC} -o ${.TARGET} ${LDFLAGS} -Wl,-T${i}${i}000 ${OBJS} ${LDLIBS}
.endfor

View File

@ -0,0 +1,135 @@
.\" $NetBSD: loadbsd.8,v 1.1 1998/09/01 19:55:33 itohy Exp $
.Dd Aug 13, 1998
.Dt LOADBSD 8 x68k
.Os NetBSD
.Sh NAME
.Nm loadbsd
.Nd load and boot NetBSD/x68k kernel from Human68k
.Sh SYNOPSIS
.Nm loadbsd.x
.Op Fl hvV
.Op Fl abDs
.Op Fl r Ar root_device
.Ar kernel_file
.Sh DESCRIPTION
.Nm
is a program runs on Human68k.
It loads and executes the specified
.Nx Ns Tn /x68k
kernel.
.Pp
The options (for
.Nm
itself) are as follows:
.Bl -tag -width flag
.It Fl h
Show help and exit.
.It Fl v
Enable verbose mode.
.It Fl V
Print version of
.Nm
and exit.
.El
.Pp
The options for
.Nx
kernel are as follows:
.Bl -tag -width flag
.It Fl a
Auto (multi-user) boot.
This disables
.Fl s
flag.
.It Fl b
Ask boot device during boot.
Pass
.Dv RB_ASKNAME
boot flag to the kernel.
.It Fl d
Use compiled-in rootdev.
Pass
.Dv RB_DFLTROOT
boot flag to the kernel.
.It Fl D
Enter kernel debugger.
Pass
.Dv RB_KDB
boot flag to the kernel.
.It Fl r Ar root_device
Specify boot device, which shall be mounted as root device.
The default device is
.Sq Li sd@0,0:a .
Note that the boot device name is
.Em not
the same as that of
.Nx .
See
.Sx BOOT DEVICE NAMES
below.
.It Fl s
Single user boot.
Pass
.Dv RB_SINGLE
boot flag to the kernel.
This disables
.Fl a
flag.
This flag is set by default.
.El
.Pp
Although listed separately, the options may be in any order.
.Sh BOOT DEVICE NAMES
The format of boot device names is:
.Pp
.Dl "[/interface/]dev@unit[,lun][:partition]"
.Pp
.Bl -tag -width Fl
.It interface
SCSI interface type.
One of:
.Sq Li spc@0 ,
.Sq Li spc@1 ,
.Sq Li mha@0 .
If the dev is a SCSI device, and interface is omitted,
the current boot interface is used.
.It dev
Device type.
One of:
.Sq Li fd
(floppy disk drive),
.Sq Li sd
(SCSI disk),
.Sq Li cd
(SCSI CD-ROM),
.Sq Li md
(Memory disk).
.It unit
Device unit #.
You must specify the target SCSI ID if dev is a SCSI device.
.It lun
SCSI LUN #.
0 is assumed if omitted.
.It partition
Partition letter of device.
Partition
.Sq Li a
is used if omitted.
.El
.Sh FILES
.Bl -tag -width /usr/mdec/loadbsd.xxxx -compact
.It Pa /usr/mdec/loadbsd.x
You will find this program here.
.El
.Sh SEE ALSO
.Xr reboot 2 ,
.Xr boot 8
.Sh BUGS
.Nm
reads the entire kernel image at once,
and requires enough free area on the main memory.
.Sh HISTORY
The
.Nm
utility first appeared in
.Nx 1.4 .

View File

@ -0,0 +1,592 @@
/*
* Load and boot NetBSD kernel on Human68k
*
* written by Yasha (ITOH Yasufumi)
* public domain
*
* loadbsd [-hvV] [-abDs] [-r root_device] netbsd
*
* loadbsd options:
* -h help
* -v verbose
* -V print version and exit
*
* kernel options:
* -a auto boot, opposite of -s
* -s single user boot (default)
* -D enter kernel debugger
* -b ask root device
* -d use compiled-in rootdev
* -r specify root device
*
* $NetBSD: loadbsd.c,v 1.1 1998/09/01 19:55:33 itohy Exp $
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: loadbsd.c,v 1.1 1998/09/01 19:55:33 itohy Exp $");
#define VERSION "$Revision: 1.1 $ $Date: 1998/09/01 19:55:33 $"
#include <sys/types.h> /* ntohl */
#include <sys/reboot.h>
#include <sys/param.h> /* ALIGN, ALIGNBYTES */
#include <a.out.h>
#include <string.h>
#include <machine/bootinfo.h>
#include <dos.h>
#include <iocs.h>
#include "../common/xprintf.h"
#include "trampoline.h"
#define DEFAULT_ROOTDEVNAME "sd@0,0:a"
#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
#define GETDECIMAL(var, str) \
do { var *= 10; var += *str++ - '0'; } while (ISDIGIT(*str))
static const char *lookupif __P((const char *name,
unsigned *pif, unsigned *punit));
static void get_current_scsi_interface __P((unsigned *pif, unsigned *punit));
static int bootdev __P((const char *devstr));
static struct tramparg *read_kernel __P((const char *fn));
static int chkmpu __P((void));
static __dead void usage __P((int status, const char *msg))
__attribute__((noreturn));
int main __P((int argc, char *argv[]));
int opt_v;
int opt_N;
const struct hatbl {
char name[4];
unsigned short id;
} hatable[] = {
X68K_BOOT_SCSIIF_LIST
};
/*
* parse interface name
* returns the next position
*/
static const char *
lookupif(name, pif, punit)
const char *name;
unsigned *pif, *punit;
{
unsigned u, unit;
const char *p;
for (u = 0; u < sizeof hatable / sizeof hatable[0]; u++) {
const char *n;
for (n = hatable[u].name, p = name; *n && *n == *p; n++, p++)
;
if (!*n)
goto found;
}
/* not found */
return (char *) 0;
found:
if (*p == '@')
p++;
/* get unit # */
if (!ISDIGIT(*p))
return (char *) 0;
unit = 0;
GETDECIMAL(unit, p);
*pif = hatable[u].id;
*punit = unit;
return p;
}
/*
* if the SCSI interface is not specified, use the current one
*/
static void
get_current_scsi_interface(pif, punit)
unsigned *pif, *punit;
{
unsigned binf;
char *bootrom;
int bus_err_buf;
binf = (unsigned) IOCS_BOOTINF();
if (binf < 0x00fc0000)
return; /* not booted from SCSI */
bootrom = (char *) (binf & 0x00ffffe0);
if (IOCS_B_LPEEK(bootrom + 0x24) == 0x53435349 && /* 'SCSI' */
IOCS_B_WPEEK(bootrom + 0x28) == 0x494E) { /* 'IN' */
/* spc0 */
*pif = X68K_BOOT_SCSIIF_SPC;
*punit = 0;
} else if (DOS_BUS_ERR(&bus_err_buf, (void *)EXSPC_BDID, 1)) {
/* mha0 */
*pif = X68K_BOOT_SCSIIF_MHA;
*punit = 0;
} else {
/* spc1 */
*pif = X68K_BOOT_SCSIIF_SPC;
*punit = 1;
}
}
/*
* parse device name
*
* [/<controller>@<unit>/]<device>@<unit>[,<lun>][:<partition>]
*
* <unit> must be target SCSI ID if <device> is a SCSI device
*
* full form:
* /spc@0/sd@1,2:e
*
* partial form:
* /mha@0/sd@1 = /mha@0/sd@1,0,:a
* sd@1:e = /current_device/sd@1,0e
* sd@1,2:e = /current_device/sd@1,2:e
*/
const struct devtbl {
char name[3];
u_char major;
} devtable[] = {
X68K_BOOT_DEV_LIST
};
static int
bootdev(devstr)
const char *devstr;
{
unsigned u;
unsigned major, unit, lun, partition;
int dev;
const char *s = devstr;
unsigned interface = 0, unit_if = 0;
if (*s == '/') {
/*
* /<interface>/<device>"
* "/spc@1/sd@2,3:e"
*/
while (*++s == '/') /* skip slashes */
;
if (!strchr(s, '/'))
xerrx(1, "%s: bad format", devstr);
if (!(s = lookupif(s, &interface, &unit_if)))
xerrx(1, "%s: unknown interface", devstr);
while (*s == '/') /* skip slashes */
s++;
} else {
/* make lint happy */
interface = 0;
unit_if = 0;
}
/* allow r at the top */
if (*s == 'r')
s++;
for (u = 0; u < sizeof devtable / sizeof devtable[0]; u++)
if (s[0] == devtable[u].name[0] && s[1] == devtable[u].name[1])
goto found;
/* not found */
xerrx(1, "%s: unknown device", devstr);
found: major = devtable[u].major;
/*
* <type>@unit[,lun][:part]
* "sd@1,3:a"
*/
/* get device unit # */
s += 2;
if (*s == '@')
s++;
if (!*s)
xerrx(1, "%s: missing unit number", devstr);
if (!ISDIGIT(*s))
xerrx(1, "%s: wrong device", devstr);
unit = 0;
GETDECIMAL(unit, s);
lun = 0;
if (*s == ',') {
s++;
if (!ISDIGIT(*s))
xerrx(1, "%s: wrong device", devstr);
GETDECIMAL(lun, s);
}
/* get device partition */
if (*s == ':')
s++;
if (!*s)
partition = 0; /* no partition letter -- assuming 'a' */
else if (!s[1])
partition = *s - 'a';
else
xerrx(1, "%s: wrong partition letter", devstr);
/*
* sanity check
*/
if (unit_if >= 16)
xerrx(1, "%s: interface unit # too large", devstr);
if (unit >= 16)
xerrx(1, "%s: device unit # too large", devstr);
if (lun >= 8)
xerrx(1, "%s: SCSI LUN >= 8 is not supported yet", devstr);
if (partition >= 16)
xerrx(1, "%s: unsupported partition", devstr);
/*
* encode device to be passed to kernel
*/
if (X68K_BOOT_DEV_IS_SCSI(major)) {
/*
* encode SCSI device
*/
if (interface == 0)
get_current_scsi_interface(&interface, &unit_if);
dev = X68K_MAKESCSIBOOTDEV(major, interface, unit_if,
unit, lun, partition);
} else {
/* encode non-SCSI device */
dev = X68K_MAKEBOOTDEV(major, unit, partition);
}
if (opt_v)
xwarnx("%s: major %u, if %u, un_if %u, unit %u, lun %u, partition %u; bootdev 0x%x",
devstr, major, interface, unit_if, unit, lun, partition, dev);
return dev;
}
/*
* read kernel and create trampoline
*
* |----------------------| <- allocated buf addr
* | kernel image |
* ~ (header is excluded) ~
* | |
* |----------------------| <- return value (entry addr of trampoline)
* | struct tramparg |
* | (trampoline args) |
* |----------------------|
* | trampoline code |
* | (in assembly) |
* |----------------------|
*/
static struct tramparg *
read_kernel(fn)
const char *fn;
{
int fd;
union dos_fcb *fcb;
size_t filesize, nread;
void *buf;
struct exec hdr;
int i;
struct tramparg *arg;
size_t size_tramp = end_trampoline - trampoline;
if ((fd = DOS_OPEN(fn, 0x20)) < 0) /* RO, share READ */
xerr(1, "%s: open", fn);
if ((int)(fcb = DOS_GET_FCB_ADR(fd)) < 0)
xerr(1, "%s: get_fcb_adr", fn);
/*
* XXX FCB is in supervisor area
*/
/*if (fcb->blk.mode != 0)*/
if (IOCS_B_BPEEK((char *)fcb + 1) & 0x80)
xerrx(1, "%s: Not a regular file", fn);
/*filesize = fcb->blk.size;*/
filesize = IOCS_B_LPEEK(&fcb->blk.size);
/*
* read a.out header
*/
if ((nread = DOS_READ(fd, (void *) &hdr, sizeof hdr)) != sizeof hdr) {
if ((int)nread < 0)
xerr(1, "%s: read header", fn);
else
xerrx(1, "%s: Not an a.out", fn);
}
/*
* check header
*/
if (N_GETMAGIC(hdr) != NMAGIC)
xerrx(1, "%s: Bad magic number", fn);
if ((i = N_GETMID(hdr)) != MID_M68K)
xerrx(1, "%s: Wrong architecture (mid %d)", fn, i);
if (opt_v)
xwarnx("%s: %u bytes; text %u, data %u, bss %u, sym %u",
fn, filesize, hdr.a_text, hdr.a_data,
hdr.a_bss, hdr.a_syms);
/*
* then, read entire body
*/
if ((int)(buf = DOS_MALLOC(filesize + ALIGNBYTES - sizeof hdr
+ sizeof(struct tramparg)
+ size_tramp + SIZE_TMPSTACK)) < 0)
xerr(1, "read_kernel");
if ((nread = DOS_READ(fd, buf, filesize - sizeof hdr))
!= filesize - sizeof hdr) {
if ((int)nread < 0)
xerr(1, "%s: read", fn);
else
xerrx(1, "%s: short read", fn);
}
if (DOS_CLOSE(fd) < 0)
xerr(1, "%s: close", fn);
/*
* create argument for trampoline code
*/
arg = (struct tramparg *) ALIGN(buf + nread);
if (opt_v)
xwarnx("trampoline arg at %p", arg);
arg->bsr_inst = TRAMP_BSR + sizeof(struct tramparg) - 4;
arg->tmp_stack = (char *) arg + sizeof(struct tramparg)
+ size_tramp + SIZE_TMPSTACK;
arg->mpu_type = IOCS_MPU_STAT() & 0xff;
arg->xk.image_top = buf;
arg->xk.load_addr = 0x00000000; /* XXX should not be a fixed addr */
arg->xk.text_size = hdr.a_text;
arg->xk.data_size = hdr.a_data;
arg->xk.bss_size = hdr.a_bss;
arg->xk.symbol_size = hdr.a_syms;
arg->xk.d5 = IOCS_BOOTINF(); /* unused for now */
#if 0
/* filled afterwards */
arg->xk.rootdev =
arg->xk.boothowto =
#endif
arg->xk.entry_addr = hdr.a_entry;
if (opt_v)
xwarnx("args: mpu %d, image %p, load 0x%x, entry 0x%x",
arg->mpu_type, arg->xk.image_top, arg->xk.load_addr,
arg->xk.entry_addr);
/*
* copy trampoline code
*/
if (opt_v)
xwarnx("trampoline code at %p (%u bytes)",
(char *) arg + sizeof(struct tramparg), size_tramp);
memcpy((char *) arg + sizeof(struct tramparg), trampoline, size_tramp);
return arg;
}
/*
* MC68000/010 -> return zero
* MC68020 and later -> return nonzero
*/
static int
chkmpu()
{
register int ret asm("d0");
asm("| %0 <- this must be d0\n\
moveq #1,d0\n\
.long 0x103B02FF | foo: moveb pc@((foo+1)-foo-2:B,d0:W:2),d0\n\
| ^ ^\n\
| d0.b = 0x02 (68000/010)\n\
| = 0xff (68020 and later)\n\
bmis 1f\n\
moveq #0,d0 | 68000/010\n\
1:" : "=d" (ret));
return ret;
}
static __dead void
usage(status, msg)
int status;
const char *msg;
{
extern const char *const __progname;
if (msg)
xwarnx("%s", msg);
xerrprintf("\
%s [-hvV] [-abDs] [-r root_device] netbsd\n\
\n\
loadbsd options:\n\
\t-h help\n\
\t-v verbose\n\
\t-V print version and exit\n\
\n\
kernel options:\n\
\t-a auto boot, opposite of -s\n\
\t-s single user boot (default)\n\
\t-D enter kernel debugger\n\
\t-b ask root device\n\
\t-d use compiled-in rootdev\n\
\t-r specify root device (default %s)\n\
\t format: [/interface/]device@unit[,lun][:partition]\n\
\t interface: one of spc@0, spc@1, mha@0\n\
\t (current boot interface if omitted)\n\
\t device: one of fd, sd, cd, md\n\
\t unit: device unit number (SCSI ID for SCSI device)\n\
\t lun: SCSI LUN # (0 if omitted)\n\
\t partition: partition letter ('a' if omitted)\n\
", __progname, DEFAULT_ROOTDEVNAME);
DOS_EXIT2(status);
}
int
main(argc, argv)
int argc;
char *argv[];
{
char *rootdevname = 0;
int rootdev;
u_long boothowto = RB_SINGLE;
const char *kernel;
char *p, **flg, **arg;
struct tramparg *tramp;
struct dos_dregs regs; /* unused... */
int i;
/* parse options */
for (arg = flg = argv + 1; (p = *flg) && *p == '-'; ) {
int c;
while ((c = *++p))
switch (c) {
case 'h':
usage(0, (char *) 0);
/* NOTREACHED */
break;
case 'N': /* don't actually execute kernel */
opt_N = 1;
break;
case 'v':
opt_v = 1;
break;
case 'V':
xprintf("loadbsd %s\n", VERSION);
return 0;
/*
* kernel boot flags
*/
case 'r':
if (rootdevname)
usage(1, "multiple -r flags");
else if (!*++arg)
usage(1, "-r requires device name");
else
rootdevname = *arg;
break;
case 'd':
boothowto |= RB_DFLTROOT;
break;
case 'b':
boothowto |= RB_ASKNAME;
break;
case 'a':
boothowto &= ~RB_SINGLE;
break;
case 's':
boothowto |= RB_SINGLE;
break;
case 'D':
boothowto |= RB_KDB;
break;
default:
usage(1, (char *) 0);
/* NOTREACHED */
break;
}
flg = ++arg;
}
/* check MPU */
if (chkmpu() == 0)
xerrx(1, "Can't boot NetBSD on 68000/010");
argc -= arg - argv;
argv = arg;
if (argc != 1)
usage(1, (char *) 0);
kernel = *argv;
rootdev = bootdev(rootdevname ? rootdevname : DEFAULT_ROOTDEVNAME);
if (opt_v)
xwarnx("boothowto 0x%x", boothowto);
tramp = read_kernel(kernel);
tramp->xk.rootdev = rootdev;
tramp->xk.boothowto = boothowto;
/*
* we never returns, and make sure the disk cache
* be flushed (if write-back cache is enabled)
*/
if (opt_v)
xwarnx("flush disk cache...");
i = DOS_FFLUSH_SET(1); /* enable fflush */
DOS_FFLUSH(); /* then, issue fflush */
(void) DOS_FFLUSH_SET(i); /* restore old mode just in case */
/*
* the program assumes the MPU caches off
*/
if (opt_v)
xwarnx("flush and disable MPU caches...");
IOCS_CACHE_MD(-1); /* flush */
if (!opt_N)
IOCS_CACHE_MD(0); /* disable both caches */
if (opt_v)
xwarnx("Jumping to the kernel. Good Luck!");
if (opt_N)
xerrx(0, "But don't actually do it.");
DOS_SUPER_JSR((void (*) __P((void))) tramp, &regs, &regs);
/* NOTREACHED */
xwarnx("??? return from kernel");
return 1;
}

View File

@ -0,0 +1,69 @@
|
| copy binary image and execute
|
| written by Yasha (ITOH Yasufumi)
| public domain
|
| $NetBSD: trampoline.S,v 1.1 1998/09/01 19:55:33 itohy Exp $
#include <machine/asm.h>
#include "trampoline.h"
| arg+0 bsr trampoline
| +4 a3+0 temporary stack address
| +8 a3+4 processor type
| +12 a3+8 struct execkern_arg
| +52 trampoline
ENTRY_NOPROFILE(trampoline)
oriw #0x0700,sr | keep out interrupts
moveal sp@+,a3
moveal a3@+,sp | set temporary stack
movel a3@+,d2 | MPU type
|
| turn off MMU
|
moveq #MPU_68030,d0
cmpl d2,d0
bccs Lmmu030
| 040/060
moveq #0,d0
.long 0x4E7B0003 | movec d0,tc
.long 0x4E7B0004 | movec d0,itt0
.long 0x4E7B0005 | movec d0,itt1
.long 0x4E7B0006 | movec d0,dtt0
.long 0x4E7B0007 | movec d0,dtt1
.long 0x4E7B0806 | movec d0,urp
.long 0x4E7B0807 | movec d0,srp
bras Lmmudone
Lmmu030:
| 020/030
clrl sp@-
.long 0xF0174000 | pmove sp@,tc
cmpl d0,d2
bnes Lmmu020 | 68851 has no tt regs
.long 0xF0170800 | pmove sp@,tt0
.long 0xF0170C00 | pmove sp@,tt1
Lmmu020:
movel #0x7fff0001,sp@- | null root pointer
.long 0xF0174C00 | pmove sp@,crp
.long 0xF0174800 | pmove sp@,srp
addql #8,sp
Lmmudone:
| minimize supervisor protection
clrb AREA_SET_REG
| reset VBR (for compatibility)
subal a1,a1
.long 0x4E7B9801 | movec a1,vbr
| then transfer and exec kernel
#define XK_NO_C_INTERFACE /* pass arg with a3 */
#include "../common/execkern.S"
GLOBAL(end_trampoline)

View File

@ -0,0 +1,33 @@
/*
* definitions for trampoline code
*
* written by Yasha (ITOH Yasufumi)
* public domain
*
* $NetBSD: trampoline.h,v 1.1 1998/09/01 19:55:33 itohy Exp $
*/
#define MPU_68030 3
#define MPU_68040 4
#define MPU_68060 6
#define AREA_SET_REG 0x00E86001 /* (B) supervisor protection reg */
#define EXSPC 0x00EA0000 /* external SCSI board */
#define EXSPC_BDID (EXSPC + 1) /* (B) SCSI board bdid reg */
#define SIZE_TMPSTACK 8192
#ifndef __ASSEMBLER__
#include "../common/execkern.h"
struct tramparg {
unsigned bsr_inst;
#define TRAMP_BSR 0x61000000 /* bsr xxx */
void *tmp_stack;
int mpu_type;
struct execkern_arg xk;
};
extern char trampoline[], end_trampoline[];
#endif