NetBSD/hp700 FFS/LFS Primary Bootstrap
This commit is contained in:
parent
3b60dfd3bd
commit
b119940e75
65
sys/arch/hp700/stand/xxboot/Makefile
Normal file
65
sys/arch/hp700/stand/xxboot/Makefile
Normal file
@ -0,0 +1,65 @@
|
||||
# $NetBSD: Makefile,v 1.1 2004/06/15 03:10:30 itohy Exp $
|
||||
|
||||
PROG= xxboot
|
||||
SRCS= start.s main.c readufs.c readufs_ffs.c readufs_lfs.c milli_tiny.s
|
||||
|
||||
CPPFLAGS+= -mpa-risc-1-0 -I${.CURDIR}/../../../.. -I. -D_STANDALONE
|
||||
# configuration for readufs module
|
||||
CPPFLAGS+= -DUSE_LFS -DUSE_FFS -DUSE_UFS1 -DUSE_UFS2
|
||||
# IODC can handle only 2GB, so this is enough
|
||||
CPPFLAGS+= -D__daddr_t=int32_t
|
||||
# require -O for relocatable code
|
||||
# -funsigned-char may reduce size
|
||||
DBG= -O -funsigned-char -W -Wall
|
||||
# ANSI C feature prevents from being relocatable
|
||||
#CPPFLAGS+= -traditional # would be best
|
||||
CPPFLAGS+= -fwritable-strings -Dconst=
|
||||
|
||||
LINKS= ${BINDIR}/${PROG} ${BINDIR}/sdboot
|
||||
|
||||
BINDIR= /usr/mdec
|
||||
STRIPFLAG=
|
||||
BINMODE= 444
|
||||
MKMAN= no
|
||||
|
||||
# standalone program
|
||||
LIBCRTBEGIN=
|
||||
LIBCRT0=
|
||||
LIBCRTEND=
|
||||
LIBC=
|
||||
|
||||
${PROG}: iplsum
|
||||
${LD} -Ttext 0 -Tdata 0 -e '$$START$$' -N -o $@1 $(OBJS)
|
||||
${LD} -Ttext 0x100 -Tdata 0x23456780 -e '$$START$$' -N -o $@2 $(OBJS)
|
||||
${SIZE} $@1
|
||||
${OBJCOPY} -O binary -j .data $@1 $@1.bin
|
||||
${OBJCOPY} -O binary -j .data $@2 $@2.bin
|
||||
cmp $@1.bin $@2.bin # should be same
|
||||
${OBJCOPY} -O binary -j .text $@1 $@2.bin
|
||||
test ! -s $@2.bin # text section must be empty
|
||||
./iplsum $@1.bin $@
|
||||
|
||||
iplsum: iplsum.c
|
||||
${HOST_CC} -o $@ ${.CURDIR}/iplsum.c
|
||||
|
||||
CLEANFILES+= ${PROG}1 ${PROG}2 ${PROG}1.bin ${PROG}2.bin ${PROG}.bin iplsum
|
||||
CLEANFILES+= ${SRCS:M*.c:S/.c$/.o.s/}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
# override default rules
|
||||
|
||||
# Place code to data section.
|
||||
.s.o:
|
||||
sed -e 's/\.code/.data/' \
|
||||
-e 's/\.bss/.section .bss,"aw",@nobits/' \
|
||||
-e 's/\.allow$$/.level 1.0/' -e 's/\.allow/.level/' \
|
||||
$< | ${AS} -o $@
|
||||
|
||||
# Place code to data section, and make sure all address calculations
|
||||
# are relative to $global$.
|
||||
.c.o:
|
||||
${CC} ${CFLAGS} ${CPPFLAGS} -o $@.s -S $<
|
||||
@grep -i 'ldil' $@.s | egrep -v "ldil L'-?[0-9]*," || exit 0; \
|
||||
echo 'found non-relocatable code' >&2; exit 1
|
||||
sed -e 's/\.text/.data/' $@.s | ${AS} -o $@
|
69
sys/arch/hp700/stand/xxboot/README.ipl
Normal file
69
sys/arch/hp700/stand/xxboot/README.ipl
Normal file
@ -0,0 +1,69 @@
|
||||
# $NetBSD: README.ipl,v 1.1 2004/06/15 03:10:30 itohy Exp $
|
||||
|
||||
Coding note:
|
||||
|
||||
In order to make this relocatable, you must follow following
|
||||
restrictions:
|
||||
|
||||
1. Do not place any objects in text segment
|
||||
1.1. For compiler,
|
||||
(1) do not declare or define any objects to be placed in
|
||||
text segment, that is, do not use ``const'' keyword
|
||||
(but declaring a pointer to const is probably OK),
|
||||
|
||||
(2) make sure string literals, if any, are placed in data
|
||||
segment (use traditional compiler),
|
||||
|
||||
(3) avoid initialization of automatic objects (non-static
|
||||
function-local variables) of aggregate types (arrays,
|
||||
structs and unions), which may implicitly emits
|
||||
constant data.
|
||||
|
||||
In summary, do not use ANSI extension. Use traditional C. :-)
|
||||
|
||||
1.2. For linker, do not actually place objects in text segment.
|
||||
|
||||
2. Do not use function pointers.
|
||||
|
||||
|
||||
On-disk layout:
|
||||
|
||||
We have 6.5KB for the primary boot.
|
||||
|
||||
disk address
|
||||
start size
|
||||
000000 0000FC LIF header
|
||||
0000FC 000104 unused
|
||||
000200 000194 disklabel (404 bytes for 16-partition label)
|
||||
000394 00006C unused
|
||||
000400 000400 ipl part 2 (1KB)
|
||||
000800 000100 optional LIF directory
|
||||
000900 000100 unused
|
||||
000A00 000600 ipl part 3 (1.5KB)
|
||||
001000 001000 ipl part 1 (4KB)
|
||||
002000 (file system starts here)
|
||||
|
||||
|
||||
On-memory layout on IPL startup:
|
||||
|
||||
The firmware loads ipl part 1 on the memory, and executes it.
|
||||
|
||||
address offset
|
||||
start size
|
||||
000000 001000 ipl part 1
|
||||
001000 000A00 (not loaded yet)
|
||||
(bss section etc)
|
||||
x 001000 temporary disk buffer
|
||||
x+1000 stack
|
||||
|
||||
|
||||
Then the IPL will load the rest of itself:
|
||||
|
||||
ipl part 1 loads parts 2 and 3, then continues execution.
|
||||
|
||||
address offset
|
||||
start size
|
||||
000000 001000 ipl part 1
|
||||
001000 000400 ipl part 2
|
||||
001400 000600 ipl part 3
|
||||
001A00 xxxxxx (bss section etc)
|
120
sys/arch/hp700/stand/xxboot/iplsum.c
Normal file
120
sys/arch/hp700/stand/xxboot/iplsum.c
Normal file
@ -0,0 +1,120 @@
|
||||
/* $NetBSD: iplsum.c,v 1.1 2004/06/15 03:10:30 itohy Exp $ */
|
||||
|
||||
/*
|
||||
* Calculate 32bit checksum of IPL and store in a certain location
|
||||
*
|
||||
* Written in 2003 by ITOH Yasufumi (itohy@NetBSD.org).
|
||||
* Public domain
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifndef __BIT_TYPES_DEFINED__
|
||||
typedef unsigned int u_int32_t;
|
||||
#endif
|
||||
|
||||
/* see README.ipl */
|
||||
#define IPLOFF (4*1024) /* 4KB */
|
||||
#define IPL1SIZE (4*1024) /* 4KB */
|
||||
#define IPL2SIZE (1*1024) /* 1KB */
|
||||
#define IPL2ONDISK 0x0400
|
||||
#define IPL3SIZE (3*512) /* 1.5KB */
|
||||
#define IPL3ONDISK 0x0A00
|
||||
#define IPLSIZE (IPL1SIZE + IPL2SIZE + IPL3SIZE)
|
||||
#define BOOTSIZE (IPLOFF + IPLSIZE)
|
||||
#define BOOTBLOCKSIZE 8192
|
||||
|
||||
u_int32_t bootblk[BOOTSIZE / sizeof(u_int32_t) + 1];
|
||||
|
||||
#define SUMOFF ((IPLOFF + 4) / sizeof(u_int32_t))
|
||||
|
||||
#ifdef __STDC__
|
||||
int main(int, char *[]);
|
||||
#endif
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
FILE *fp;
|
||||
int len;
|
||||
u_int32_t sum, *p;
|
||||
int iploff, iplsumsize;
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: %s <input> <output>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* read file */
|
||||
if ((fp = fopen(argv[1], "rb")) == NULL) {
|
||||
perror(argv[1]);
|
||||
return 1;
|
||||
}
|
||||
if ((len = fread(bootblk, 1, sizeof bootblk, fp)) <= IPLOFF) {
|
||||
fprintf(stderr, "%s: too short\n", argv[1]);
|
||||
return 1;
|
||||
} else if (len > BOOTSIZE) {
|
||||
fprintf(stderr, "%s: too long\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
(void) fclose(fp);
|
||||
|
||||
/* sanity check */
|
||||
if ((ntohl(bootblk[0]) & 0xffff0000) != 0x80000000) {
|
||||
fprintf(stderr, "%s: bad LIF magic\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
iploff = ntohl(bootblk[0xf0 / sizeof(u_int32_t)]);
|
||||
iplsumsize = ntohl(bootblk[0xf4 / sizeof(u_int32_t)]);
|
||||
printf("%d bytes free, ipl offset = %d, ipl sum size = %d\n",
|
||||
BOOTSIZE - len, iploff, iplsumsize);
|
||||
if (iploff != IPLOFF || iplsumsize <= 0 || iplsumsize % 2048 ||
|
||||
iploff + iplsumsize > BOOTBLOCKSIZE) {
|
||||
fprintf(stderr, "%s: bad ipl offset / size\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* checksum */
|
||||
sum = 0;
|
||||
for (p = bootblk + IPLOFF / sizeof(u_int32_t);
|
||||
p < bootblk + (IPLOFF + IPL1SIZE) / sizeof(u_int32_t); p++)
|
||||
sum += ntohl(*p);
|
||||
|
||||
bootblk[SUMOFF] = htonl(ntohl(bootblk[SUMOFF]) - sum);
|
||||
|
||||
/* transfer ipl part 2 */
|
||||
memcpy(bootblk + IPL2ONDISK / sizeof(u_int32_t),
|
||||
bootblk + (IPLOFF + IPL1SIZE) / sizeof(u_int32_t),
|
||||
IPL2SIZE);
|
||||
|
||||
/* transfer ipl part 3 */
|
||||
memcpy(bootblk + IPL3ONDISK / sizeof(u_int32_t),
|
||||
bootblk + (IPLOFF + IPL1SIZE + IPL2SIZE) / sizeof(u_int32_t),
|
||||
IPL3SIZE);
|
||||
|
||||
/* write file */
|
||||
if ((fp = fopen(argv[2], "wb")) == NULL) {
|
||||
perror(argv[2]);
|
||||
return 1;
|
||||
}
|
||||
if ((len = fwrite(bootblk, 1, BOOTBLOCKSIZE, fp)) != BOOTBLOCKSIZE) {
|
||||
if (len < 0)
|
||||
perror(argv[2]);
|
||||
else
|
||||
fprintf(stderr, "%s: short write\n", argv[2]);
|
||||
fclose(fp);
|
||||
(void) remove(argv[2]);
|
||||
return 1;
|
||||
}
|
||||
if (fclose(fp)) {
|
||||
perror(argv[2]);
|
||||
(void) remove(argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
453
sys/arch/hp700/stand/xxboot/main.c
Normal file
453
sys/arch/hp700/stand/xxboot/main.c
Normal file
@ -0,0 +1,453 @@
|
||||
/* $NetBSD: main.c,v 1.1 2004/06/15 03:10:30 itohy Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003 ITOH Yasufumi.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 forms are unlimited.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
|
||||
*/
|
||||
|
||||
#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 /* sequential record access media */
|
||||
|
||||
static char *hexstr __P((char *, unsigned));
|
||||
void ipl_main __P((unsigned /*interactive*/,
|
||||
unsigned /*sptop*/, unsigned /*psw*/));
|
||||
void load_file __P((const char *, unsigned /*loadadr*/,
|
||||
unsigned /*interactive*/, int /*part*/));
|
||||
void load_file_ino __P((ino_t, const char *, unsigned /*loadadr*/,
|
||||
unsigned /*interactive*/, int /*part*/));
|
||||
|
||||
struct loadinfo {
|
||||
void *sec_image;
|
||||
unsigned sec_size;
|
||||
#if 0
|
||||
unsigned sec_pad;
|
||||
#endif
|
||||
unsigned entry_offset;
|
||||
};
|
||||
static __inline void xi_elf32 __P((struct loadinfo *, Elf32_Ehdr *));
|
||||
static __inline void xi_elf64 __P((struct loadinfo *, Elf64_Ehdr *));
|
||||
int xi_load __P((struct loadinfo *, void *));
|
||||
|
||||
void reboot __P((void)), halt __P((void));
|
||||
void dispatch __P((unsigned /*interactive*/, unsigned /*top*/,
|
||||
unsigned /*end*/, int /*part*/, unsigned /*entry*/));
|
||||
void print __P((const char *));
|
||||
void putch __P((int));
|
||||
int getch __P((void));
|
||||
int boot_input __P((void *, int /*len*/, int /*pos*/));
|
||||
|
||||
/* to make generated code relocatable, do NOT mark them as const */
|
||||
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 __P((void *, const void *, size_t));
|
||||
#endif
|
||||
void *memmove __P((void *, const void *, size_t));
|
||||
|
||||
/* disklabel */
|
||||
union {
|
||||
char dklsec[512];
|
||||
struct disklabel dkl; /* to ensure alignment */
|
||||
} 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(buf, blkpos, bytelen)
|
||||
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) {
|
||||
/*
|
||||
* read 2KB, avoiding unneeded read
|
||||
*/
|
||||
devoff = dbtob(blkpos & ~MASK_BLK_PER_READ) + offset_raw_read;
|
||||
if (prvdevoff != devoff) {
|
||||
#if 1 /* supports sequential media */
|
||||
if ((*(unsigned *)(PZ_MEM_BOOT+DEV_CLASS) & DEV_CL_MASK)
|
||||
== DEV_CL_SEQU) {
|
||||
/*
|
||||
* sequential media
|
||||
* -- read sequentially or rewind
|
||||
*/
|
||||
pos = prvdevoff + dbtob(BLK_PER_READ);
|
||||
if (devoff < pos)
|
||||
pos = 0; /* rewind */
|
||||
|
||||
/* "repositioning media...\r\n" */
|
||||
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);
|
||||
}
|
||||
/*
|
||||
* copy specified size to the destination
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* convert number to hex string
|
||||
* buf must have enough space
|
||||
*/
|
||||
static char *
|
||||
hexstr(buf, val)
|
||||
char *buf;
|
||||
unsigned val;
|
||||
{
|
||||
unsigned v;
|
||||
char rev[16];
|
||||
char *r = rev, *b = buf;
|
||||
|
||||
/* inverse order */
|
||||
do {
|
||||
v = val & 0xf;
|
||||
*r++ = (v <= 9) ? '0' + v : 'a' - 10 + v;
|
||||
val >>= 4;
|
||||
} while (val);
|
||||
|
||||
/* reverse string */
|
||||
while (r > rev)
|
||||
*b++ = *--r;
|
||||
|
||||
*b = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
ipl_main(interactive, sptop, psw)
|
||||
unsigned interactive; /* parameters from PDC */
|
||||
unsigned sptop; /* value of sp on function entry */
|
||||
unsigned psw; /* PSW on startup */
|
||||
{
|
||||
char buf[32];
|
||||
int part = 0; /* default partition "a" */
|
||||
unsigned secsz, partoff, partsz;
|
||||
int c, c1;
|
||||
unsigned 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); /* "bit firmware\r\n" */
|
||||
|
||||
/*
|
||||
* check disklabel
|
||||
* (dklabel has disklabel on startup)
|
||||
*/
|
||||
if (dklabel.d_magic == DISKMAGIC && (secsz = dklabel.d_secsize) != 0) {
|
||||
/*
|
||||
* select boot partition
|
||||
*/
|
||||
if (interactive) {
|
||||
select_partition:
|
||||
/* "boot partition (a-p, ! to reboot) [a]:" */
|
||||
print(str_bootpart);
|
||||
part = 0; /* default partition "a" */
|
||||
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 '!': /* reset */
|
||||
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; /* reset */
|
||||
}
|
||||
|
||||
/*
|
||||
* "\r\nbooting from partition _\r\n"
|
||||
*/
|
||||
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); /* "unused partition\r\n" */
|
||||
goto select_partition;
|
||||
}
|
||||
|
||||
/* boot partition must be below 2GB */
|
||||
if (partoff + partsz >=
|
||||
(unsigned)((unsigned)2*1024*1024*1024 -1 + secsz) / secsz) {
|
||||
/* "boot partition exceeds 2GB boundary\r\n" */
|
||||
print(str_warn_2GB);
|
||||
goto select_partition;
|
||||
}
|
||||
|
||||
/*
|
||||
* following device accesses are only in the partition
|
||||
*/
|
||||
offset_raw_read = partoff * secsz;
|
||||
} else {
|
||||
/*
|
||||
* no disklabel --- assume the whole of the device
|
||||
* is a filesystem
|
||||
*/
|
||||
print(str_nolabel); /* "no disklabel\r\n" */
|
||||
}
|
||||
|
||||
if (ufs_init()) {
|
||||
print(str_nofs); /* "no filesystem found\r\n" */
|
||||
return;
|
||||
}
|
||||
str_filesystem[12] = (ufs_info.fstype == UFSTYPE_FFS) ? 'F' : 'L';
|
||||
print(str_filesystem); /* "filesystem: _FS\r\n" */
|
||||
|
||||
loadadr = (sptop + STACK_SIZE + LOAD_ALIGN - 1) & (-LOAD_ALIGN);
|
||||
load_file(str_boot1, loadadr, interactive, part); /* "boot.hp700" */
|
||||
load_file(str_boot2, loadadr, interactive, part); /* "boot" */
|
||||
load_file(str_boot3, loadadr, interactive, part); /* "usr/mdec/boot" */
|
||||
|
||||
print(str_noboot); /* "no secondary boot found\r\n" */
|
||||
}
|
||||
|
||||
void
|
||||
load_file(path, loadadr, interactive, part)
|
||||
const char *path;
|
||||
unsigned loadadr, interactive;
|
||||
int part;
|
||||
{
|
||||
|
||||
/* look-up the file */
|
||||
print(str_lookup); /* "looking up " */
|
||||
print(path);
|
||||
print(str_crlf);
|
||||
load_file_ino(ufs_lookup_path(path), path, loadadr, interactive, part);
|
||||
}
|
||||
|
||||
void
|
||||
load_file_ino(ino, fn, loadadr, interactive, part)
|
||||
ino_t ino;
|
||||
const char *fn; /* for message only */
|
||||
unsigned loadadr, 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; /* not found */
|
||||
|
||||
print(str_loading); /* "loading " */
|
||||
print(fn);
|
||||
print(str_at); /* " at 0x" */
|
||||
print(hexstr(buf, loadadr));
|
||||
print(str_dddot); /* "..." */
|
||||
|
||||
sz = DI_SIZE(&dinode);
|
||||
ufs_read(&dinode, (void *) loadadr, 0, sz);
|
||||
|
||||
print(str_done); /* "done\r\n" */
|
||||
|
||||
/* digest executable format */
|
||||
inf.sec_size = sz;
|
||||
inf.entry_offset = 0;
|
||||
if (xi_load(&inf, (void *) loadadr)) {
|
||||
print(fn);
|
||||
print(str_ukfmt); /* ": unknown format -- exec from top\r\n" */
|
||||
}
|
||||
|
||||
/* pass control to the secondary boot */
|
||||
dispatch(interactive, loadadr, loadadr + inf.sec_size, part,
|
||||
loadadr + inf.entry_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* fill in loading information from an ELF executable
|
||||
*/
|
||||
static __inline void
|
||||
xi_elf32(inf, hdr)
|
||||
struct loadinfo *inf;
|
||||
Elf32_Ehdr *hdr;
|
||||
{
|
||||
char *top = (void *) hdr;
|
||||
Elf32_Phdr *ph;
|
||||
|
||||
/* text + data, bss */
|
||||
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
|
||||
/* entry */
|
||||
inf->entry_offset = hdr->e_entry - ph->p_vaddr;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
xi_elf64(inf, hdr)
|
||||
struct loadinfo *inf;
|
||||
Elf64_Ehdr *hdr;
|
||||
{
|
||||
char *top = (void *) hdr;
|
||||
Elf64_Phdr *ph;
|
||||
|
||||
/*
|
||||
* secondary boot is not so large, so 32bit (unsigned) arithmetic
|
||||
* is enough
|
||||
*/
|
||||
/* text + data, bss */
|
||||
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
|
||||
/* entry */
|
||||
inf->entry_offset = (unsigned) hdr->e_entry - (unsigned) ph->p_vaddr;
|
||||
}
|
||||
|
||||
int
|
||||
xi_load(inf, buf)
|
||||
struct loadinfo *inf;
|
||||
void *buf;
|
||||
{
|
||||
Elf32_Ehdr *e32hdr = buf;
|
||||
Elf64_Ehdr *e64hdr = buf;
|
||||
u_int16_t class_data;
|
||||
|
||||
/*
|
||||
* check ELF header
|
||||
* (optimized assuming big endian byte order)
|
||||
*/
|
||||
/* ELF magic */
|
||||
if (*(u_int32_t *)&e32hdr->e_ident[EI_MAG0] !=
|
||||
(ELFMAG0 << 24 | ELFMAG1 << 16 | ELFMAG2 << 8 | ELFMAG3) ||
|
||||
e32hdr->e_ident[EI_VERSION] != EV_CURRENT)
|
||||
return 1; /* Not an ELF */
|
||||
|
||||
/* file and machine type */
|
||||
if (*(u_int32_t *)&e32hdr->e_type != (ET_EXEC << 16 | EM_PARISC))
|
||||
return 1; /* Not an executable / Wrong architecture */
|
||||
|
||||
if ((class_data = *(u_int16_t *)&e32hdr->e_ident[EI_CLASS]) ==
|
||||
(ELFCLASS32 << 8 | ELFDATA2MSB)) {
|
||||
|
||||
/* support one section executable (ld -N) only */
|
||||
if (e32hdr->e_phnum != 1)
|
||||
return 1; /* Wrong number of loading sections */
|
||||
|
||||
/* fill in loading information */
|
||||
xi_elf32(inf, e32hdr);
|
||||
|
||||
} else if (class_data == (ELFCLASS64 << 8 | ELFDATA2MSB)) {
|
||||
|
||||
/* support one section executable (ld -N) only */
|
||||
if (e64hdr->e_phnum != 1)
|
||||
return 1; /* Wrong number of loading sections */
|
||||
|
||||
/* fill in loading information */
|
||||
xi_elf64(inf, e64hdr);
|
||||
|
||||
} else
|
||||
return 1; /* Not a 32bit or 64bit ELF */
|
||||
|
||||
/* move text + data to the top address */
|
||||
memmove(buf, inf->sec_image, inf->sec_size);
|
||||
|
||||
#if 0 /* XXX bss clear is done by the secondary boot itself */
|
||||
bzero((char *) buf + inf->sec_size, inf->sec_pad);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
131
sys/arch/hp700/stand/xxboot/milli_tiny.s
Normal file
131
sys/arch/hp700/stand/xxboot/milli_tiny.s
Normal file
@ -0,0 +1,131 @@
|
||||
; $NetBSD: milli_tiny.s,v 1.1 2004/06/15 03:10:30 itohy Exp $
|
||||
|
||||
; Copyright (c) 2003 ITOH Yasufumi.
|
||||
; All rights reserved.
|
||||
;
|
||||
; 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 forms are unlimited.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
|
||||
|
||||
; millicode library, optimized for size
|
||||
|
||||
.level 1.0
|
||||
.code
|
||||
.align 4
|
||||
|
||||
; $$divU unsigned division, return quotient
|
||||
;
|
||||
; inputs:
|
||||
; %r26 dividend
|
||||
; %r25 divisor
|
||||
; %r31 return address
|
||||
; outputs:
|
||||
; %r29 quotient
|
||||
; %r1, %r25, %r26 undefined
|
||||
.export $$divU,millicode
|
||||
$$divU:
|
||||
.proc
|
||||
.callinfo millicode,no_unwind
|
||||
.entry
|
||||
comb,<,n %r25,0,bigdivisor_divU ; special case (>=0x80000000)
|
||||
bl sub_divU,%r29
|
||||
subt,= %r0,%r25,%r1 ; trap divide by 0, negate
|
||||
|
||||
bv %r0(%r31) ; return millicode
|
||||
.exit
|
||||
addc %r26,%r26,%r29 ; fix quotient
|
||||
bigdivisor_divU:
|
||||
comclr,<< %r26,%r25,%r29 ; if dividend >= divisor
|
||||
ldi 1,%r29 ; quotient is 1
|
||||
bv,n %r0(%r31) ; return millicode
|
||||
.procend
|
||||
|
||||
; Note this is not a normal subroutine
|
||||
; r29: return address
|
||||
sub_divU:
|
||||
stwm %r19,64(%sp)
|
||||
ldi 31,%r19
|
||||
|
||||
ds %r0,%r1,%r0
|
||||
addc %r26,%r26,%r26
|
||||
ds %r0,%r25,%r1
|
||||
loop_sub_divU: ; addc/ds 31 times
|
||||
addc %r26,%r26,%r26
|
||||
addib,<> -1,%r19,loop_sub_divU
|
||||
ds %r1,%r25,%r1
|
||||
|
||||
bv %r0(%r29)
|
||||
ldwm -64(%sp),%r19
|
||||
|
||||
; $$remU unsigned division, return remainder
|
||||
;
|
||||
; inputs:
|
||||
; %r26 dividend
|
||||
; %r25 divisor
|
||||
; %r31 return address
|
||||
; outputs:
|
||||
; %r29 remainder
|
||||
; %r1, %r25, %r26 undefined
|
||||
.export $$remU,millicode
|
||||
$$remU:
|
||||
.proc
|
||||
.callinfo millicode,no_unwind
|
||||
.entry
|
||||
comb,<,n %r25,0,bigdivisor_remU ; special case (>=0x80000000)
|
||||
bl sub_divU,%r29
|
||||
subt,= %r0,%r25,%r1 ; trap divide by 0, negate
|
||||
|
||||
comclr,>= %r1,%r0,%r0
|
||||
addl %r1,%r25,%r1 ; fix remainder
|
||||
bv %r0(%r31) ; return millicode
|
||||
.exit
|
||||
copy %r1,%r29 ; the return value is remainder
|
||||
bigdivisor_remU:
|
||||
sub,>>= %r26,%r25,%r29 ; if dividend < divisor
|
||||
copy %r26,%r29 ; the remainder is dividend
|
||||
bv,n %r0(%r31) ; return millicode
|
||||
.procend
|
||||
|
||||
; $$mulU unsigned multiplication
|
||||
;
|
||||
; inputs:
|
||||
; %r26 multiplicand
|
||||
; %r25 multiplier
|
||||
; %r31 return address
|
||||
; outputs:
|
||||
; %r29 product
|
||||
; %r1, %r25, %r26 undefined
|
||||
.export $$mulU,millicode
|
||||
.export $$mulI,millicode
|
||||
$$mulU:
|
||||
$$mulI: ; XXX actually wrong (not signed) but works for small positive numbers
|
||||
.proc
|
||||
.callinfo frame=0,no_calls,millicode
|
||||
.entry
|
||||
copy %r0,%r29
|
||||
ldi 32,%r1 ; loop counter
|
||||
|
||||
add,nuv %r25,%r25,%r25 ; shift left, skip next if not C
|
||||
loop_mul:
|
||||
sh1add,tr %r29,%r26,%r29 ; shift left and add, skip next
|
||||
sh1add %r29,%r0,%r29 ; shift left only
|
||||
addib,<>,n -1,%r1,loop_mul ; check loop condition
|
||||
add,nuv %r25,%r25,%r25 ; shift left, skip next if not C
|
||||
.exit
|
||||
bv,n %r0(%r31) ; return millicode
|
||||
.procend
|
377
sys/arch/hp700/stand/xxboot/readufs.c
Normal file
377
sys/arch/hp700/stand/xxboot/readufs.c
Normal file
@ -0,0 +1,377 @@
|
||||
/* $NetBSD: readufs.c,v 1.1 2004/06/15 03:10:30 itohy Exp $ */
|
||||
/* from Id: readufs.c,v 1.9 2003/12/16 13:54:11 itohy Exp */
|
||||
|
||||
/*
|
||||
* Read UFS (FFS / LFS)
|
||||
*
|
||||
* Written in 1999, 2002, 2003 by ITOH Yasufumi (itohy@NetBSD.org).
|
||||
* Public domain.
|
||||
*
|
||||
* Intended to be used for boot programs (first stage).
|
||||
* DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT.
|
||||
*/
|
||||
|
||||
#include "readufs.h"
|
||||
|
||||
#define fs ufs_info
|
||||
|
||||
static void raw_read_queue __P((void *buf, daddr_t blkpos, size_t bytelen));
|
||||
static int ufs_read_indirect __P((daddr_t blk, int level, caddr_t *buf,
|
||||
unsigned *poff, size_t count));
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
void ufs_list_dir __P((ino_t dirino));
|
||||
int main __P((int argc, char *argv[]));
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
int fd;
|
||||
|
||||
void
|
||||
RAW_READ(buf, blkpos, bytelen)
|
||||
void *buf;
|
||||
daddr_t blkpos;
|
||||
size_t bytelen;
|
||||
{
|
||||
|
||||
if (pread(fd, buf, bytelen, (off_t)dbtob(blkpos)) != (ssize_t) bytelen)
|
||||
err(1, "pread: buf %p, blk %d, len %u",
|
||||
buf, (int) blkpos, bytelen);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ufs_info fs;
|
||||
|
||||
/*
|
||||
* Read contiguous sectors at once for speedup.
|
||||
*/
|
||||
static size_t rq_len;
|
||||
|
||||
static void
|
||||
raw_read_queue(buf, blkpos, bytelen)
|
||||
void *buf;
|
||||
daddr_t blkpos;
|
||||
size_t bytelen; /* must be DEV_BSIZE aligned */
|
||||
{
|
||||
static daddr_t rq_start;
|
||||
static char *rq_buf;
|
||||
|
||||
if (rq_len) {
|
||||
if (bytelen && blkpos == rq_start + (ssize_t) btodb(rq_len)
|
||||
&& buf == rq_buf + rq_len) {
|
||||
rq_len += bytelen;
|
||||
return;
|
||||
} else {
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("raw_read_queue: read: buf %p, blk %d, len %d\n",
|
||||
rq_buf, (int) rq_start, rq_len);
|
||||
#endif
|
||||
RAW_READ(rq_buf, rq_start, rq_len);
|
||||
}
|
||||
}
|
||||
rq_buf = buf;
|
||||
rq_start = blkpos;
|
||||
rq_len = bytelen;
|
||||
}
|
||||
|
||||
#define RAW_READ_QUEUE_INIT() (rq_len = 0)
|
||||
#define RAW_READ_QUEUE_FLUSH() \
|
||||
raw_read_queue((void *) 0, (daddr_t) 0, (size_t) 0)
|
||||
|
||||
|
||||
/*
|
||||
* Read a file, specified by dinode.
|
||||
* No support for holes or (short) symbolic links.
|
||||
*/
|
||||
size_t
|
||||
ufs_read(di, buf, off, count)
|
||||
union ufs_dinode *di;
|
||||
void *buf;
|
||||
unsigned off; /* position in block */
|
||||
size_t count;
|
||||
{
|
||||
struct ufs_info *ufsinfo = &fs;
|
||||
size_t bsize = ufsinfo->bsize;
|
||||
caddr_t b = buf;
|
||||
int i;
|
||||
size_t disize, nread;
|
||||
daddr_t pos;
|
||||
#if defined(USE_UFS1) && defined(USE_UFS2)
|
||||
enum ufs_ufstype uver = ufsinfo->ufstype;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("ufs_read: off: %d, count %u\n", off, count);
|
||||
#endif
|
||||
|
||||
disize = DI_SIZE(di);
|
||||
|
||||
if (disize < count + off * bsize)
|
||||
count = disize - off * bsize;
|
||||
|
||||
/* FS block size alignment. */
|
||||
nread = count;
|
||||
count = (count + bsize - 1) & ~(bsize - 1);
|
||||
|
||||
RAW_READ_QUEUE_INIT();
|
||||
|
||||
/* Read direct blocks. */
|
||||
for ( ; off < NDADDR && count > 0; off++) {
|
||||
#if defined(USE_UFS1) && defined(USE_UFS2)
|
||||
if (uver == UFSTYPE_UFS1)
|
||||
pos = di->di1.di_db[off];
|
||||
else
|
||||
pos = di->di2.di_db[off];
|
||||
#else
|
||||
pos = di->di_thisver.di_db[off];
|
||||
#endif
|
||||
#if 0
|
||||
printf("ufs_read: read: blk: %d\n",
|
||||
(int) pos << ufsinfo->fsbtodb);
|
||||
#endif
|
||||
raw_read_queue(b, pos << ufsinfo->fsbtodb, bsize);
|
||||
b += bsize;
|
||||
count -= bsize;
|
||||
}
|
||||
off -= NDADDR;
|
||||
|
||||
/* Read indirect blocks. */
|
||||
for (i = 0; i < NIADDR && count > 0; i++) {
|
||||
#if defined(USE_UFS1) && defined(USE_UFS2)
|
||||
if (uver == UFSTYPE_UFS1)
|
||||
pos = di->di1.di_ib[i];
|
||||
else
|
||||
pos = di->di2.di_ib[i];
|
||||
#else
|
||||
pos = di->di_thisver.di_ib[i];
|
||||
#endif
|
||||
count = ufs_read_indirect(pos, i, &b, &off, count);
|
||||
}
|
||||
|
||||
RAW_READ_QUEUE_FLUSH();
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
static int
|
||||
ufs_read_indirect(blk, level, buf, poff, count)
|
||||
daddr_t blk;
|
||||
int level;
|
||||
caddr_t *buf;
|
||||
unsigned *poff; /* position in block */
|
||||
size_t count;
|
||||
{
|
||||
struct ufs_info *ufsinfo = &fs;
|
||||
size_t bsize = ufsinfo->bsize;
|
||||
void *idbuf = alloca(bsize);
|
||||
#ifdef USE_UFS1
|
||||
int32_t *idbuf1 = idbuf;
|
||||
#endif
|
||||
#ifdef USE_UFS2
|
||||
int64_t *idbuf2 = idbuf;
|
||||
#endif
|
||||
daddr_t pos;
|
||||
unsigned off = *poff;
|
||||
unsigned b;
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("ufs_read_indirect: off: %d, count %u\n", off, count);
|
||||
#endif
|
||||
if (off) {
|
||||
unsigned subindirsize = 1, indirsize;
|
||||
int i;
|
||||
|
||||
for (i = level; i > 0; i--)
|
||||
subindirsize *= ufsinfo->nindir;
|
||||
indirsize = subindirsize * ufsinfo->nindir;
|
||||
if (off >= indirsize) {
|
||||
/* no need to read any data */
|
||||
*poff = off - indirsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
b = off / subindirsize;
|
||||
off -= b * subindirsize;
|
||||
*poff = 0;
|
||||
} else
|
||||
b = 0;
|
||||
|
||||
/* read the indirect block */
|
||||
RAW_READ(idbuf, blk << ufsinfo->fsbtodb, bsize);
|
||||
|
||||
for ( ; b < ufsinfo->nindir && count > 0; b++) {
|
||||
#if defined(USE_UFS1) && defined(USE_UFS2)
|
||||
if (ufsinfo->ufstype == UFSTYPE_UFS1)
|
||||
#endif
|
||||
#ifdef USE_UFS1
|
||||
pos = idbuf1[b];
|
||||
#endif
|
||||
#if defined(USE_UFS1) && defined(USE_UFS2)
|
||||
else
|
||||
#endif
|
||||
#ifdef USE_UFS2
|
||||
pos = idbuf2[b];
|
||||
#endif
|
||||
|
||||
if (level)
|
||||
count = ufs_read_indirect(pos, level - 1, buf, &off, count);
|
||||
else {
|
||||
#if 0
|
||||
printf("ufs_read: read: blk: %d\n",
|
||||
(int) pos << ufsinfo->fsbtodb);
|
||||
#endif
|
||||
raw_read_queue(*buf, pos << ufsinfo->fsbtodb, bsize);
|
||||
*buf += bsize;
|
||||
count -= bsize;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* look-up fn in directory dirino
|
||||
*/
|
||||
ino_t
|
||||
ufs_lookup(dirino, fn)
|
||||
ino_t dirino;
|
||||
const char *fn;
|
||||
{
|
||||
union ufs_dinode dirdi;
|
||||
struct direct *pdir;
|
||||
char *p, *endp;
|
||||
size_t disize;
|
||||
|
||||
if (ufs_get_inode(dirino, &dirdi))
|
||||
return 0;
|
||||
|
||||
if ((dirdi.di_common.di_mode & IFMT) != IFDIR)
|
||||
return 0; /* Not a directory */
|
||||
|
||||
disize = DI_SIZE(&dirdi);
|
||||
|
||||
p = alloca((disize + fs.bsize - 1) & ~(fs.bsize - 1));
|
||||
ufs_read(&dirdi, p, 0, disize);
|
||||
endp = p + disize;
|
||||
for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) {
|
||||
if (pdir->d_ino && !strcmp(fn, pdir->d_name))
|
||||
return pdir->d_ino;
|
||||
}
|
||||
return 0; /* No such file or directory */
|
||||
}
|
||||
|
||||
/*
|
||||
* look-up a file in absolute pathname from the root directory
|
||||
*/
|
||||
ino_t
|
||||
ufs_lookup_path(path)
|
||||
const char *path;
|
||||
{
|
||||
char fn[MAXNAMLEN + 1];
|
||||
char *p;
|
||||
ino_t ino = ROOTINO;
|
||||
|
||||
do {
|
||||
while (*path == '/')
|
||||
path++;
|
||||
for (p = fn; *path && *path != '/'; )
|
||||
*p++ = *path++;
|
||||
*p++ = '\0';
|
||||
ino = ufs_lookup(ino, fn);
|
||||
} while (ino && *path);
|
||||
|
||||
return ino;
|
||||
}
|
||||
|
||||
#if 0
|
||||
size_t
|
||||
ufs_load_file(buf, dirino, fn)
|
||||
void *buf;
|
||||
ino_t dirino;
|
||||
const char *fn;
|
||||
{
|
||||
size_t cnt, disize;
|
||||
union ufs_dinode dinode;
|
||||
|
||||
if (ufs_fn_inode(dirino, fn, &dinode))
|
||||
return (unsigned) 0;
|
||||
disize = DI_SIZE(&dinode);
|
||||
cnt = ufs_read(&dinode, buf, 0, disize);
|
||||
|
||||
return cnt;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
ufs_init()
|
||||
{
|
||||
return 1
|
||||
#ifdef USE_FFS
|
||||
&& try_ffs()
|
||||
#endif
|
||||
#ifdef USE_LFS
|
||||
&& try_lfs()
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
void
|
||||
ufs_list_dir(dirino)
|
||||
ino_t dirino;
|
||||
{
|
||||
union ufs_dinode dirdi;
|
||||
struct direct *pdir;
|
||||
char *p, *endp;
|
||||
size_t disize;
|
||||
|
||||
if (ufs_get_inode(dirino, &dirdi))
|
||||
errx(1, "ino = %d: not found", dirino);
|
||||
|
||||
disize = DI_SIZE(&dirdi);
|
||||
p = alloca((disize + fs.bsize - 1) & ~(fs.bsize - 1));
|
||||
ufs_read(&dirdi, p, 0, disize);
|
||||
endp = p + disize;
|
||||
for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) {
|
||||
if (pdir->d_ino)
|
||||
printf("%6d %s\n", pdir->d_ino, pdir->d_name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc __attribute__((unused));
|
||||
char *argv[];
|
||||
{
|
||||
union ufs_dinode dinode;
|
||||
|
||||
if ((fd = open(argv[1], O_RDONLY)) < 0)
|
||||
err(1, "open: %s", argv[1]);
|
||||
|
||||
if (ufs_init())
|
||||
errx(1, "%s: unknown fs", argv[1]);
|
||||
|
||||
#if 1
|
||||
ufs_list_dir(ROOTINO);
|
||||
{
|
||||
void *p;
|
||||
size_t cnt;
|
||||
ino_t ino;
|
||||
size_t disize;
|
||||
|
||||
if ((ino = ufs_lookup_path(argv[2])) == 0)
|
||||
errx(1, "%s: not found", argv[2]);
|
||||
ufs_get_inode(ino, &dinode);
|
||||
disize = DI_SIZE(&dinode);
|
||||
p = malloc((disize + fs.bsize - 1) & ~(fs.bsize - 1));
|
||||
cnt = ufs_read(&dinode, p, 0, disize);
|
||||
write(3, p, cnt);
|
||||
free(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
155
sys/arch/hp700/stand/xxboot/readufs.h
Normal file
155
sys/arch/hp700/stand/xxboot/readufs.h
Normal file
@ -0,0 +1,155 @@
|
||||
/* $NetBSD: readufs.h,v 1.1 2004/06/15 03:10:30 itohy Exp $ */
|
||||
/* from Id: readufs.h,v 1.10 2003/12/16 13:54:11 itohy Exp */
|
||||
|
||||
/*
|
||||
* Written in 1999, 2002, 2003 by ITOH Yasufumi (itohy@NetBSD.org).
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
|
||||
/*
|
||||
* UFS1 / UFS2
|
||||
*/
|
||||
union ufs_dinode {
|
||||
#ifdef USE_UFS1
|
||||
struct ufs1_dinode di1;
|
||||
#endif
|
||||
#ifdef USE_UFS2
|
||||
struct ufs2_dinode di2;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* short-cut for common fields (di_mode, di_nlink) */
|
||||
#ifdef USE_UFS1
|
||||
# define di_common di1
|
||||
#elif defined USE_UFS2
|
||||
# define di_common di2
|
||||
#endif
|
||||
|
||||
/* for fields of same names and different locations */
|
||||
#if !(defined(USE_UFS1) && defined(USE_UFS2))
|
||||
# ifdef USE_UFS1
|
||||
# define di_thisver di1
|
||||
# endif
|
||||
# ifdef USE_UFS2
|
||||
# define di_thisver di2
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* this is a size hack */
|
||||
#if defined(USE_UFS1) && defined(USE_UFS2)
|
||||
# define DI_SIZE(di) ((di)->di1.di_size)
|
||||
#else
|
||||
# define DI_SIZE(di) ((di)->di_thisver.di_size)
|
||||
#endif
|
||||
/* and may break following fields on UFS2 */
|
||||
#define di_gid di_gid__is_not_available
|
||||
#define di_blksize di_blksize__is_not_available
|
||||
|
||||
/*
|
||||
* filesystem information
|
||||
*/
|
||||
struct ufs_info {
|
||||
enum ufs_fstype {
|
||||
UFSTYPE_UNKNOWN
|
||||
#ifdef USE_FFS
|
||||
, UFSTYPE_FFS
|
||||
#endif
|
||||
#ifdef USE_LFS
|
||||
, UFSTYPE_LFS
|
||||
#endif
|
||||
} fstype;
|
||||
#if defined(USE_UFS1) && defined(USE_UFS2)
|
||||
enum ufs_ufstype {
|
||||
UFSTYPE_UFS1, UFSTYPE_UFS2
|
||||
} ufstype;
|
||||
#endif
|
||||
#if 0
|
||||
int (*get_inode) __P((ino_t ino, union ufs_dinode *dibuf));
|
||||
#endif
|
||||
|
||||
/* superblock information */
|
||||
u_int32_t bsize; /* fs block size */
|
||||
u_int32_t nindir; /* # indirect per block */
|
||||
u_int32_t fsbtodb; /* block -> sector shift count */
|
||||
union {
|
||||
#ifdef USE_FFS
|
||||
struct {
|
||||
daddr_t iblkno; /* inode-block offset */
|
||||
int32_t old_cgoffset; /* cylinder group offset */
|
||||
int32_t old_cgmask; /* cylinder group mask */
|
||||
int32_t fragshift; /* block to fragmentation */
|
||||
int32_t inopb; /* # inodes per block */
|
||||
int32_t ipg; /* # inodes per group */
|
||||
int32_t fpg; /* # inodes per group * frag */
|
||||
int32_t magic; /* FS_UFSx_MAGIC */
|
||||
} u_ffs;
|
||||
#endif
|
||||
#ifdef USE_LFS
|
||||
struct {
|
||||
u_int32_t version; /* LFS version # */
|
||||
daddr_t idaddr; /* ifile inode disk address */
|
||||
u_int32_t inopb; /* inodes per block (v1) */
|
||||
/* inodes per frag (v2) */
|
||||
u_int32_t ifpb; /* inode addrs / ifile block */
|
||||
u_int32_t ioffset; /* start of inode in ifile */
|
||||
/* (in sector) */
|
||||
u_int32_t ibsize; /* size of inode block */
|
||||
} u_lfs;
|
||||
#endif
|
||||
} fs_u;
|
||||
};
|
||||
|
||||
extern struct ufs_info ufs_info;
|
||||
|
||||
int get_ffs_inode __P((ino_t ino, union ufs_dinode *dibuf));
|
||||
int get_lfs_inode __P((ino_t ino, union ufs_dinode *dibuf));
|
||||
#if defined(USE_FFS) && defined(USE_LFS)
|
||||
#define ufs_get_inode(ino, di) ((ufs_info.fstype == UFSTYPE_FFS) ? \
|
||||
get_ffs_inode((ino), (di)) : get_lfs_inode((ino), (di)))
|
||||
#else
|
||||
# ifdef USE_FFS
|
||||
# define ufs_get_inode(ino, di) (get_ffs_inode((ino), (di)))
|
||||
# endif
|
||||
# ifdef USE_LFS
|
||||
# define ufs_get_inode(ino, di) (get_lfs_inode((ino), (di)))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
void RAW_READ __P((void *buf, daddr_t blkpos, size_t bytelen));
|
||||
|
||||
size_t ufs_read __P((union ufs_dinode *di, void *buf, unsigned off,
|
||||
size_t count));
|
||||
ino_t ufs_lookup __P((ino_t dirino, const char *fn));
|
||||
ino_t ufs_lookup_path __P((const char *path));
|
||||
size_t ufs_load_file __P((void *buf, ino_t dirino, const char *fn));
|
||||
int ufs_init __P((void));
|
||||
|
||||
#ifdef USE_FFS
|
||||
int try_ffs __P((void));
|
||||
#endif
|
||||
|
||||
#ifdef USE_LFS
|
||||
int try_lfs __P((void));
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifndef alloca
|
||||
# define alloca(n) __builtin_alloca(n)
|
||||
# endif
|
||||
# ifndef strcmp
|
||||
# define strcmp(p, q) __builtin_strcmp(p, q)
|
||||
# endif
|
||||
#endif
|
163
sys/arch/hp700/stand/xxboot/readufs_ffs.c
Normal file
163
sys/arch/hp700/stand/xxboot/readufs_ffs.c
Normal file
@ -0,0 +1,163 @@
|
||||
/* $NetBSD: readufs_ffs.c,v 1.1 2004/06/15 03:10:30 itohy Exp $ */
|
||||
/* from Id: readufs_ffs.c,v 1.8 2004/06/12 04:26:39 itohy Exp */
|
||||
|
||||
/*
|
||||
* FS specific support for 4.2BSD Fast Filesystem
|
||||
*
|
||||
* Written in 1999, 2002, 2003 by ITOH Yasufumi (itohy@NetBSD.org).
|
||||
* Public domain.
|
||||
*
|
||||
* Intended to be used for boot programs (first stage).
|
||||
* DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT.
|
||||
*/
|
||||
|
||||
#include "readufs.h"
|
||||
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#define fsi (*ufsinfo)
|
||||
#define fsi_ffs fsi.fs_u.u_ffs
|
||||
|
||||
/*
|
||||
* Read and check superblock.
|
||||
* If it is an FFS, save information from the superblock.
|
||||
*/
|
||||
int
|
||||
try_ffs()
|
||||
{
|
||||
union {
|
||||
struct fs sblk;
|
||||
unsigned char pad[SBLOCKSIZE];
|
||||
} buf;
|
||||
struct ufs_info *ufsinfo = &ufs_info;
|
||||
static int sblocs[] = SBLOCKSEARCH;
|
||||
int *sbl;
|
||||
int magic;
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("trying FFS\n");
|
||||
#endif
|
||||
/* read FFS superblock */
|
||||
for (sbl = sblocs; ; sbl++) {
|
||||
if (*sbl == -1)
|
||||
return 1;
|
||||
|
||||
RAW_READ(&buf, (daddr_t) btodb(*sbl), SBLOCKSIZE);
|
||||
|
||||
magic = buf.sblk.fs_magic;
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("FFS: sblk: pos %d magic 0x%x\n", btodb(*sbl), magic);
|
||||
#endif
|
||||
#ifdef USE_UFS1
|
||||
if (magic == FS_UFS1_MAGIC
|
||||
&& !(buf.sblk.fs_old_flags & FS_FLAGS_UPDATED)) {
|
||||
if (*sbl == SBLOCK_UFS2)
|
||||
/* might be an alternate suberblock */
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (*sbl != buf.sblk.fs_sblockloc)
|
||||
/* must be an alternate suberblock */
|
||||
continue;
|
||||
|
||||
#ifdef USE_UFS1
|
||||
if (magic == FS_UFS1_MAGIC)
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_UFS2
|
||||
if (magic == FS_UFS2_MAGIC) {
|
||||
#ifdef USE_UFS1
|
||||
fsi.ufstype = UFSTYPE_UFS2;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX <ufs/ffs/fs.h> always uses fs_magic
|
||||
* (UFS1 only or UFS2 only is impossible)
|
||||
*/
|
||||
fsi_ffs.magic = magic;
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("FFS: detected UFS%d format\n", (magic == FS_UFS2_MAGIC) + 1);
|
||||
#endif
|
||||
|
||||
/* This partition looks like an FFS. */
|
||||
fsi.fstype = UFSTYPE_FFS;
|
||||
#if 0
|
||||
fsi.get_inode = get_ffs_inode;
|
||||
#endif
|
||||
|
||||
/* Get information from the superblock. */
|
||||
fsi.bsize = buf.sblk.fs_bsize;
|
||||
fsi.fsbtodb = buf.sblk.fs_fsbtodb;
|
||||
fsi.nindir = buf.sblk.fs_nindir;
|
||||
|
||||
fsi_ffs.iblkno = buf.sblk.fs_iblkno;
|
||||
fsi_ffs.old_cgoffset = buf.sblk.fs_old_cgoffset;
|
||||
fsi_ffs.old_cgmask = buf.sblk.fs_old_cgmask;
|
||||
fsi_ffs.fragshift = buf.sblk.fs_fragshift;
|
||||
fsi_ffs.inopb = buf.sblk.fs_inopb;
|
||||
fsi_ffs.ipg = buf.sblk.fs_ipg;
|
||||
fsi_ffs.fpg = buf.sblk.fs_fpg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* for inode macros */
|
||||
#define fs_ipg fs_u.u_ffs.ipg
|
||||
#define fs_iblkno fs_u.u_ffs.iblkno
|
||||
#define fs_old_cgoffset fs_u.u_ffs.old_cgoffset
|
||||
#define fs_old_cgmask fs_u.u_ffs.old_cgmask
|
||||
#define fs_fpg fs_u.u_ffs.fpg
|
||||
#define fs_magic fs_u.u_ffs.magic
|
||||
#define fs_inopb fs_u.u_ffs.inopb
|
||||
#define fs_fragshift fs_u.u_ffs.fragshift
|
||||
#define fs_fsbtodb fsbtodb
|
||||
|
||||
/*
|
||||
* Get inode from disk.
|
||||
*/
|
||||
int
|
||||
get_ffs_inode(ino, dibuf)
|
||||
ino_t ino;
|
||||
union ufs_dinode *dibuf;
|
||||
{
|
||||
struct ufs_info *ufsinfo = &ufs_info;
|
||||
union ufs_dinode *buf = alloca((size_t) fsi.bsize);
|
||||
union ufs_dinode *di;
|
||||
unsigned ioff;
|
||||
|
||||
RAW_READ(buf, fsbtodb(&fsi, ino_to_fsba(&fsi, ino)),
|
||||
(size_t) fsi.bsize);
|
||||
|
||||
ioff = ino_to_fsbo(&fsi, ino);
|
||||
|
||||
#if defined(USE_UFS1) && defined(USE_UFS2)
|
||||
if (ufsinfo->ufstype == UFSTYPE_UFS1)
|
||||
di = (void *) &(&buf->di1)[ioff];
|
||||
else {
|
||||
di = (void *) &(&buf->di2)[ioff];
|
||||
|
||||
/* XXX for DI_SIZE() macro */
|
||||
di->di1.di_size = di->di2.di_size;
|
||||
}
|
||||
#else
|
||||
di = &buf[ioff];
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("FFS: dinode(%d): mode 0%o, nlink %d, size %u\n",
|
||||
ino, di->di_common.di_mode, di->di_common.di_nlink,
|
||||
(unsigned) DI_SIZE(di));
|
||||
#endif
|
||||
|
||||
if (di->di_common.di_mode == 0)
|
||||
return 1; /* unused inode (file is not found) */
|
||||
|
||||
*dibuf = *di;
|
||||
|
||||
return 0;
|
||||
}
|
218
sys/arch/hp700/stand/xxboot/readufs_lfs.c
Normal file
218
sys/arch/hp700/stand/xxboot/readufs_lfs.c
Normal file
@ -0,0 +1,218 @@
|
||||
/* $NetBSD: readufs_lfs.c,v 1.1 2004/06/15 03:10:30 itohy Exp $ */
|
||||
/* from Id: readufs_lfs.c,v 1.8 2003/12/16 13:54:11 itohy Exp */
|
||||
|
||||
/*
|
||||
* FS specific support for 4.4BSD Log-structured Filesystem
|
||||
*
|
||||
* Written in 1999, 2002, 2003 by ITOH Yasufumi (itohy@NetBSD.org).
|
||||
* Public domain.
|
||||
*
|
||||
* Intended to be used for boot programs (first stage).
|
||||
* DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT.
|
||||
*/
|
||||
|
||||
#include "readufs.h"
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <ufs/lfs/lfs.h>
|
||||
|
||||
#ifndef USE_UFS1
|
||||
#error LFS currently requires USE_UFS1
|
||||
#endif
|
||||
|
||||
static struct ufs1_dinode ifile_dinode;
|
||||
|
||||
#define fsi (*ufsinfo)
|
||||
#define fsi_lfs fsi.fs_u.u_lfs
|
||||
|
||||
/*
|
||||
* Read and check superblock.
|
||||
* If it is an LFS, save information from the superblock.
|
||||
*/
|
||||
int
|
||||
try_lfs()
|
||||
{
|
||||
struct ufs_info *ufsinfo = &ufs_info;
|
||||
struct dlfs sblk, sblk2;
|
||||
struct dlfs *s = &sblk;
|
||||
daddr_t sbpos;
|
||||
int fsbshift;
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("trying LFS\n");
|
||||
#endif
|
||||
sbpos = btodb(LFS_LABELPAD);
|
||||
|
||||
/* read primary superblock */
|
||||
for (;;) {
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("LFS: reading primary sblk at: 0x%x\n", (unsigned)sbpos);
|
||||
#endif
|
||||
RAW_READ(&sblk, sbpos, sizeof sblk);
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("LFS: sblk: magic: 0x%x, version: %d\n",
|
||||
sblk.dlfs_magic, sblk.dlfs_version);
|
||||
#endif
|
||||
|
||||
if (sblk.dlfs_magic != LFS_MAGIC)
|
||||
return 1;
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("LFS: bsize %d, fsize %d, bshift %d, blktodb %d, fsbtodb %d, inopf %d, inopb %d\n",
|
||||
sblk.dlfs_bsize, sblk.dlfs_fsize,
|
||||
sblk.dlfs_bshift, sblk.dlfs_blktodb, sblk.dlfs_fsbtodb,
|
||||
sblk.dlfs_inopf, sblk.dlfs_inopb);
|
||||
#endif
|
||||
if ((fsi_lfs.version = sblk.dlfs_version) == 1) {
|
||||
fsbshift = 0;
|
||||
break;
|
||||
} else {
|
||||
daddr_t sbpos1;
|
||||
#if 0
|
||||
fsbshift = sblk.dlfs_bshift - sblk.dlfs_blktodb + sblk.dlfs_fsbtodb - DEV_BSHIFT;
|
||||
#endif
|
||||
fsbshift = sblk.dlfs_fsbtodb;
|
||||
sbpos1 = sblk.dlfs_sboffs[0] << fsbshift;
|
||||
if (sbpos == sbpos1)
|
||||
break;
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("LFS: correcting primary sblk location\n");
|
||||
#endif
|
||||
sbpos = sbpos1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("fsbshift: %d\n", fsbshift);
|
||||
printf("sboff[1]: %d\n", sblk.dlfs_sboffs[1]);
|
||||
#endif
|
||||
|
||||
if (sblk.dlfs_sboffs[1] > 0) {
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("LFS: reading secondary sblk at: 0x%x\n",
|
||||
sblk.dlfs_sboffs[1] << fsbshift);
|
||||
#endif
|
||||
/* read secondary superblock */
|
||||
RAW_READ(&sblk2, (daddr_t) sblk.dlfs_sboffs[1] << fsbshift,
|
||||
sizeof sblk2);
|
||||
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("LFS: sblk2: magic: 0x%x, version: %d\n",
|
||||
sblk2.dlfs_magic, sblk2.dlfs_version);
|
||||
#endif
|
||||
|
||||
if (sblk2.dlfs_magic == LFS_MAGIC) {
|
||||
if (fsi_lfs.version == 1) {
|
||||
if (sblk.dlfs_otstamp > sblk2.dlfs_otstamp)
|
||||
s = &sblk2;
|
||||
} else {
|
||||
if (sblk.dlfs_serial > sblk2.dlfs_serial)
|
||||
s = &sblk2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This partition looks like an LFS. */
|
||||
#if 0
|
||||
fsi.get_inode = get_lfs_inode;
|
||||
#endif
|
||||
/*
|
||||
* version 1: disk addr is in disk sector --- no shifting
|
||||
* version 2: disk addr is in fragment
|
||||
*/
|
||||
fsi.fsbtodb = fsbshift;
|
||||
|
||||
/* Get information from the superblock. */
|
||||
fsi.bsize = s->dlfs_bsize;
|
||||
fsi.nindir = s->dlfs_nindir;
|
||||
fsi_lfs.idaddr = s->dlfs_idaddr;
|
||||
fsi_lfs.ibsize = (fsi_lfs.version == 1) ? s->dlfs_bsize : s->dlfs_fsize;
|
||||
|
||||
/*
|
||||
* version 1: number of inode per block
|
||||
* version 2: number of inode per fragment (but in dlfs_inopb)
|
||||
*/
|
||||
fsi_lfs.inopb = s->dlfs_inopb;
|
||||
|
||||
fsi_lfs.ifpb = s->dlfs_ifpb;
|
||||
fsi_lfs.ioffset = s->dlfs_cleansz + s->dlfs_segtabsz;
|
||||
|
||||
/* ifile is always used to look-up other inodes, so keep its inode. */
|
||||
if (get_lfs_inode(LFS_IFILE_INUM, (union ufs_dinode *)&ifile_dinode))
|
||||
return 1; /* OOPS, failed to find inode of ifile! */
|
||||
|
||||
fsi.fstype = UFSTYPE_LFS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get inode from disk.
|
||||
*/
|
||||
int
|
||||
get_lfs_inode(ino, dibuf)
|
||||
ino_t ino;
|
||||
union ufs_dinode *dibuf;
|
||||
{
|
||||
struct ufs_info *ufsinfo = &ufs_info;
|
||||
daddr_t daddr;
|
||||
char *buf = alloca(fsi.bsize);
|
||||
struct ufs1_dinode *di, *diend;
|
||||
int i;
|
||||
|
||||
/* Get fs block which contains the specified inode. */
|
||||
if (ino == LFS_IFILE_INUM)
|
||||
daddr = fsi_lfs.idaddr;
|
||||
else {
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("LFS: ino: %d\nifpb: %d, bsize: %d\n",
|
||||
ino, fsi_lfs.ifpb, fsi.bsize);
|
||||
#endif
|
||||
ufs_read((union ufs_dinode *) &ifile_dinode, buf,
|
||||
ino / fsi_lfs.ifpb + fsi_lfs.ioffset,
|
||||
fsi.bsize);
|
||||
i = ino % fsi_lfs.ifpb;
|
||||
daddr = (fsi_lfs.version == 1) ?
|
||||
((IFILE_V1 *) buf + i)->if_daddr
|
||||
: ((IFILE *) buf + i)->if_daddr;
|
||||
}
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("LFS(%d): daddr: %d\n", ino, (int) daddr);
|
||||
#endif
|
||||
|
||||
if (daddr == LFS_UNUSED_DADDR)
|
||||
return 1;
|
||||
|
||||
/* Read the inode block. */
|
||||
RAW_READ(buf, daddr << fsi.fsbtodb, fsi_lfs.ibsize);
|
||||
|
||||
/* Search for the inode. */
|
||||
di = (struct ufs1_dinode *) buf;
|
||||
diend = di + fsi_lfs.inopb;
|
||||
|
||||
for ( ; di < diend; di++)
|
||||
if (di->di_inumber == ino)
|
||||
goto found;
|
||||
/* not found */
|
||||
return 1;
|
||||
|
||||
found:
|
||||
#ifdef DEBUG_WITH_STDIO
|
||||
printf("LFS: dinode(%d): mode 0%o, nlink %d, inumber %d, size %d, uid %d, db[0] %d\n",
|
||||
ino, di->di_mode, di->di_nlink, di->di_inumber,
|
||||
(int) di->di_size, di->di_uid, di->di_db[0]);
|
||||
#endif
|
||||
|
||||
#if 0 /* currently UFS1 only */
|
||||
#if defined(USE_UFS1) && defined(USE_UFS2)
|
||||
/* XXX for DI_SIZE() macro */
|
||||
if (ufsinfo->ufstype != UFSTYPE_UFS1)
|
||||
di->di1.di_size = di->si2.di_size;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
dibuf->di1 = *di;
|
||||
|
||||
return 0;
|
||||
}
|
641
sys/arch/hp700/stand/xxboot/start.s
Normal file
641
sys/arch/hp700/stand/xxboot/start.s
Normal file
@ -0,0 +1,641 @@
|
||||
; $NetBSD: start.s,v 1.1 2004/06/15 03:10:30 itohy Exp $
|
||||
|
||||
; Copyright (c) 2003 ITOH Yasufumi.
|
||||
; All rights reserved.
|
||||
;
|
||||
; 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 forms are unlimited.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
|
||||
|
||||
.level 1.0
|
||||
|
||||
.code
|
||||
.origin 0
|
||||
;
|
||||
; LIF (Logical Interchange Format) header
|
||||
;
|
||||
lifhdr: .byte 0x80,0x00 ; LIF magic
|
||||
.string "NetBSD" ; volume label (6 chars, fill with space)
|
||||
.origin 0xf0
|
||||
; 0xf0
|
||||
lif_ipl_addr:
|
||||
.word top-lifhdr ; start at 4KB (must be 2KB aligned)
|
||||
lif_ipl_size:
|
||||
.word 0x00001000 ; size 4KB (must be 2KB aligned)
|
||||
lif_ipl_entry:
|
||||
.word $START$-top ; entry offset
|
||||
|
||||
; ipl part 1 starts here
|
||||
.origin 4096
|
||||
top:
|
||||
;
|
||||
; IPL startup
|
||||
;
|
||||
; arg0 = interact flag (1: interactive, 0: otherwise)
|
||||
; arg1 = address of first doubleword past the end of ipl part 1
|
||||
;
|
||||
.export $START$,entry
|
||||
$START$:
|
||||
b,n start ; 0: entry address
|
||||
|
||||
; version of interface of primary to secondary boot
|
||||
BOOT_IF_VERSION: .equ 0
|
||||
; version 0: arg0 = interact flag, arg1 = version (0),
|
||||
; arg2 = end addr, arg3 = selected boot partition
|
||||
; r1, r3 - r22, r28, r29, r31 = cleared to zeros
|
||||
|
||||
cksum: .word 0 ; 4: checksum will be stored here
|
||||
version: .word BOOT_IF_VERSION ; 8: version of interface
|
||||
rsvd1: .word 0 ; 12: future use
|
||||
rsvd2: .word 0 ; 16: future use
|
||||
rsvd3: .word 0 ; 20: future use
|
||||
|
||||
start:
|
||||
; set data pointer for relocatable data access
|
||||
blr %r0,%r27
|
||||
; get PSW at entry
|
||||
ssm 0,%r4
|
||||
.export $global$,data
|
||||
$global$:
|
||||
|
||||
; save parameters for main
|
||||
copy %arg0,%r3
|
||||
|
||||
tmpdiskbufsz: .equ 0x1000 ; 4KB
|
||||
tmpdiskbuf_labelsec: .equ 0x0200 ; dbtob(LABELSECTOR)
|
||||
tmpdiskbuf_labelsecsz: .equ 512
|
||||
tmpdiskbuf_part2: .equ 0x0400
|
||||
tmpdiskbuf_part2sz: .equ 0x0400
|
||||
tmpdiskbuf_part3: .equ 0x0A00
|
||||
tmpdiskbuf_part3sz: .equ 0x0600
|
||||
|
||||
part1sz: .equ 0x1000
|
||||
|
||||
; get next free address
|
||||
.import _end,data
|
||||
addil L%_end-$global$,%r27;%r1
|
||||
ldo R%_end-$global$(%r1),%r1
|
||||
|
||||
; 32bit environment (and this code) requires stack is 64byte aligned.
|
||||
ldi 64-1,%r2
|
||||
add %r1,%r2,%r1
|
||||
andcm %r1,%r2,%r6 ; r6 = tmp disk buffer
|
||||
ldo tmpdiskbufsz+64(%r6),%sp ; tmp stack
|
||||
|
||||
bl print,%rp
|
||||
ldo str_startup-$global$(%r27),%arg0
|
||||
|
||||
;
|
||||
; read part 2 and 3 of ipl (see README.ipl)
|
||||
;
|
||||
|
||||
; read disk blocks which contains ipl part 2 and part 3
|
||||
copy %r6,%arg0
|
||||
ldi 0,%arg2 ; offset = 0
|
||||
bl boot_input,%rp
|
||||
ldi tmpdiskbufsz,%arg1 ; read size
|
||||
|
||||
; part 2 address
|
||||
ldo top-$global$+part1sz(%r27),%r19
|
||||
|
||||
; copy part 2
|
||||
ldo tmpdiskbuf_part2(%r6),%r20
|
||||
addi,tr tmpdiskbuf_part2sz/4,%r0,%r2 ; loop count, skip next
|
||||
cpipl2: stws,ma %r1,4(0,%r19) ; write to dst
|
||||
addib,uv,n -1,%r2,cpipl2 ; check loop condition
|
||||
ldws,ma 4(0,%r20),%r1 ; read from src
|
||||
|
||||
; copy part 3
|
||||
; (r19 already has destination address of part 3)
|
||||
ldo tmpdiskbuf_part3(%r6),%r20
|
||||
addi,tr tmpdiskbuf_part3sz/4,%r0,%r2 ; loop count, skip next
|
||||
cpipl3: stws,ma %r1,4(0,%r19) ; write to dst
|
||||
addib,uv,n -1,%r2,cpipl3 ; check loop condition
|
||||
ldws,ma 4(0,%r20),%r1 ; read from src
|
||||
|
||||
; flush data cache / invalidate instruction cache
|
||||
ldo top-$global$+part1sz(%r27),%r1 ; part 2 address
|
||||
ldi 16,%r20 ; 16: cache line size
|
||||
flipl: fdc 0(0,%r1) ; flush data cache line at r1
|
||||
comb,< %r1,%r19,flipl
|
||||
fic,m %r20(0,%r1) ; flush instruction cache line at r1, r1 += 16
|
||||
sync ; I/O operation is guaranteed to finish
|
||||
; in eight instructions after sync
|
||||
;
|
||||
; Now, whole the IPL is loaded
|
||||
;
|
||||
|
||||
; clear BSS
|
||||
.import _edata,data
|
||||
addil L%_edata-$global$,%r27;%r1
|
||||
ldo R%_edata-$global$(%r1),%r1
|
||||
clrbss: comb,< %r1,%r6,clrbss
|
||||
stws,ma %r0,4(0,%r1)
|
||||
|
||||
; we have read disklabel -- save it for later use
|
||||
.import labelsector,data
|
||||
addil L%labelsector-$global$,%r27;%r1
|
||||
ldo R%labelsector-$global$(%r1),%r20
|
||||
ldo tmpdiskbuf_labelsec(%r6),%r21
|
||||
addi,tr tmpdiskbuf_labelsecsz/4,%r0,%r2 ; loop count, skip next
|
||||
cplbl: stws,ma %r1,4(0,%r20) ; write to dst
|
||||
addib,uv,n -1,%r2,cplbl ; check loop condition
|
||||
ldws,ma 4(0,%r21),%r1 ; read from src
|
||||
|
||||
; set stack
|
||||
; (r6 points at free space, 64byte aligned)
|
||||
; 32bit environment (and this code) requires stack is 64byte aligned.
|
||||
ldo 64(%r6),%sp ; 64 > 48: frame marker (32) + args(up to 4)
|
||||
|
||||
; stack usage
|
||||
; 12bytes arguments
|
||||
; 32 frame marker
|
||||
|
||||
; parameters for main
|
||||
copy %r3,%arg0
|
||||
copy %r4,%arg2
|
||||
|
||||
.import ipl_main,entry
|
||||
bl ipl_main,%rp
|
||||
copy %sp,%arg1
|
||||
|
||||
; main returned --- perform reset
|
||||
bl print,%rp
|
||||
ldo str_reset-$global$(%r27),%arg0
|
||||
; FALLTHROUGH
|
||||
|
||||
IOMOD_CMD: .equ 0xFFFC0000 + (4*12)
|
||||
IOMOD_CMD_STOP: .equ 0
|
||||
IOMOD_CMD_RESET: .equ 5
|
||||
|
||||
; void reboot(void)
|
||||
; void halt(void)
|
||||
.export reboot,entry
|
||||
.export halt,entry
|
||||
reboot:
|
||||
addi,tr IOMOD_CMD_RESET,%r0,%r1 ; %r1 = IOMOD_CMD_RESET, skip next
|
||||
halt: ldi IOMOD_CMD_STOP,%r1
|
||||
iomcmd: ldil L%IOMOD_CMD,%r2
|
||||
ldo R%IOMOD_CMD(%r2),%r2
|
||||
stwas %r1,0(%r2)
|
||||
b,n .
|
||||
|
||||
str_startup:
|
||||
.string "\r\n\n"
|
||||
.stringz "NetBSD/hp700 FFS/LFS Primary Bootstrap\r\n\n"
|
||||
str_reset:
|
||||
.stringz "\r\nresetting..."
|
||||
.align 4
|
||||
|
||||
; void dispatch(unsigned interactive, unsigned top, unsigned end, int part,
|
||||
; unsigned entry)
|
||||
.export dispatch,entry
|
||||
dispatch:
|
||||
; flush data cache / invalidate instruction cache
|
||||
ldi 16,%r20 ; 16: cache line size
|
||||
flush: fdc 0(0,%arg1) ; flush data cache line at arg1
|
||||
comb,< %arg1,%arg2,flush
|
||||
fic,m %r20(0,%arg1) ; flush instruction cache line at arg1, arg1+=16
|
||||
sync
|
||||
copy %r0,%r1 ; I/O operation is guaranteed to finish
|
||||
copy %r0,%r3 ; in eight instructions after sync
|
||||
copy %r0,%r4
|
||||
copy %r0,%r5 ; while waiting, clear unused registers
|
||||
copy %r0,%r6 ; for future compatibility
|
||||
copy %r0,%r7
|
||||
copy %r0,%r8
|
||||
copy %r0,%r9
|
||||
copy %r0,%r10
|
||||
copy %r0,%r11
|
||||
copy %r0,%r12
|
||||
copy %r0,%r13
|
||||
copy %r0,%r14
|
||||
copy %r0,%r15
|
||||
copy %r0,%r16
|
||||
copy %r0,%r17
|
||||
copy %r0,%r18
|
||||
copy %r0,%r19
|
||||
copy %r0,%r20
|
||||
copy %r0,%r21
|
||||
copy %r0,%r22
|
||||
copy %r0,%r28 ; r23-r26: arg3-arg0, r27: dp
|
||||
copy %r0,%r29 ; r30: sp
|
||||
copy %r0,%r31
|
||||
ldw -52(%sp),%arg1 ; arg4: exec address
|
||||
ldo reboot-$global$(%r27),%rp ; reboot if returns
|
||||
bv %r0(%arg1) ; execute
|
||||
ldi BOOT_IF_VERSION,%arg1
|
||||
|
||||
;
|
||||
; IODC subroutines
|
||||
;
|
||||
PZ_MEM_CONSOLE: .equ 0x3a0
|
||||
PZ_MEM_BOOT: .equ 0x3d0
|
||||
PZ_MEM_KEYBOARD: .equ 0x400
|
||||
|
||||
DEV_PATH: .equ 0x00
|
||||
DEV_LAYERS: .equ 0x08
|
||||
DEV_HPA: .equ 0x20 ; hard physical adderss space
|
||||
DEV_SPA: .equ 0x24 ; soft physical address space
|
||||
DEV_IODC_ENTRY: .equ 0x28
|
||||
DEV_CLASS: .equ 0x2c
|
||||
DEV_CL_DUPLEX: .equ 0x7 ; full-duplex console class
|
||||
|
||||
IODC_ENTRY_IO_BOOTIN: .equ 0
|
||||
IODC_ENTRY_IO_CONSOLEIN: .equ 2
|
||||
IODC_ENTRY_IO_CONSOLEOUT: .equ 3
|
||||
|
||||
; call_iodc
|
||||
; inputs:
|
||||
; %ret0 IODC base in page zero
|
||||
; %rp return address
|
||||
; %r29 arg 8
|
||||
; %r19 arg 7
|
||||
; %r20 arg 6
|
||||
; %r21 arg 5
|
||||
; %r25 arg 1
|
||||
; outputs
|
||||
; all scratch regs undefined, unless defined by the IODC call
|
||||
call_iodc:
|
||||
; set common arguments in registers
|
||||
addil L%retbuf-$global$,%r27;%r1
|
||||
ldo R%retbuf-$global$(%r1),%r22 ; arg4: return buffer
|
||||
ldo DEV_LAYERS(%ret0),%arg3 ; arg3: layer
|
||||
ldw DEV_SPA(%ret0),%arg2 ; arg2: spa
|
||||
ldw DEV_HPA(%ret0),%arg0 ; arg0: hpa
|
||||
; check if narrow or wide mode
|
||||
ssm 0,%r1 ; get PSW
|
||||
bb,< %r1,4,call_iodc_64 ; if W, call in 64bit mode
|
||||
ldw DEV_IODC_ENTRY(%ret0),%r1 ; ENTRY_IO address
|
||||
|
||||
; narrow mode
|
||||
stw %r29,-68(%sp) ; arg8: maxsize / lang
|
||||
stw %r19,-64(%sp) ; arg7: size
|
||||
stw %r20,-60(%sp) ; arg6: buf
|
||||
stw %r21,-56(%sp) ; arg5: devaddr / unused
|
||||
bv %r0(%r1) ; call ENTRY_IO
|
||||
stw %r22,-52(%sp) ; arg4: return buffer
|
||||
|
||||
call_iodc_64:
|
||||
.allow 2.0
|
||||
; On PA64 convention, arg0 - arg7 are passed in registers.
|
||||
; Parameters are placed in INCREASING order.
|
||||
; The argument pointer points at the first stack parameter.
|
||||
; stack usage:
|
||||
; 64bytes allocated for register arguments arg0-arg7
|
||||
; 8 arg8 (argument pointer points here)
|
||||
; 16 frame marker
|
||||
std %r29,-16-8(%sp) ; arg8: maxsize / lang
|
||||
; std %sp,-8(%sp) ; psp in frame marker
|
||||
bv %r0(%r1) ; call ENTRY_IO
|
||||
ldo -16-8(%sp),%r29 ; argument pointer
|
||||
.allow
|
||||
|
||||
;
|
||||
; console output
|
||||
;
|
||||
; void putch(int)
|
||||
; void print(const char *string)
|
||||
.align 4
|
||||
.export putch,entry
|
||||
.export print,entry
|
||||
putch:
|
||||
stwm %arg0,128(%sp) ; fake up a string on the stack
|
||||
stb %r0,-124(%sp) ; (see stack usage below)
|
||||
addi,tr -125,%sp,%arg0 ; string address, skip next
|
||||
print:
|
||||
.proc
|
||||
.callinfo frame=128,save_rp,no_unwind
|
||||
.entry
|
||||
ldo 128(%sp),%sp
|
||||
stw %rp,-128-20(%sp)
|
||||
|
||||
; stack usage:
|
||||
; 36byte IODC buffer (assume %sp was 64byte aligned)
|
||||
; 4 saved reg
|
||||
; 88 arguments, frame marker
|
||||
; 32bit: 36 (arguments) + 32 (frame marker)
|
||||
; 64bit: 72 (arguments) + 16 (frame marker)
|
||||
prbufsiz: .equ 36
|
||||
|
||||
; save callee-saves
|
||||
stw %r3,-92(%sp)
|
||||
|
||||
copy %arg0,%r3
|
||||
|
||||
prloop:
|
||||
copy %r0,%r19
|
||||
ldi prbufsiz,%r20
|
||||
ldo -128(%sp),%r1
|
||||
|
||||
strloop:
|
||||
ldb 0(%r3),%r2
|
||||
comb,= %r2,%r0,endstr
|
||||
stbs,ma %r2,1(0,%r1)
|
||||
ldo 1(%r19),%r19
|
||||
comb,<> %r19,%r20,strloop
|
||||
ldo 1(%r3),%r3
|
||||
|
||||
endstr:
|
||||
comb,=,n %r19,%r0,endpr
|
||||
|
||||
; see IODC 3-51
|
||||
; arg0 hpa
|
||||
; arg1 option (ENTRY_IO_CONSOLEOUT (3))
|
||||
; arg2 spa
|
||||
; arg3 ID_addr (pointer to LAYER)
|
||||
; arg4 R_addr (pointer to return buffer (64word?))
|
||||
; arg5 unused (0)
|
||||
; arg6 memaddr (64byte-aligned) string buffer
|
||||
; arg7 reqsize
|
||||
; arg8 lang (0)
|
||||
ldi PZ_MEM_CONSOLE,%ret0 ; IODC base in page zero
|
||||
copy %r0,%r29 ; arg8: lang
|
||||
; copy %r19,%r19 ; arg7: size
|
||||
ldo -128(%sp),%r20 ; arg6: buf
|
||||
; copy %r0,%r21 ; arg5: unused
|
||||
bl call_iodc,%rp
|
||||
ldi IODC_ENTRY_IO_CONSOLEOUT,%arg1 ; arg1: option
|
||||
b,n prloop
|
||||
|
||||
endpr:
|
||||
; restore callee-saves
|
||||
ldw -92(%sp),%r3
|
||||
|
||||
; return subroutine
|
||||
ldw -128-20(%sp),%rp
|
||||
bv %r0(%rp)
|
||||
.exit
|
||||
ldo -128(%sp),%sp
|
||||
.procend
|
||||
|
||||
;
|
||||
; console input
|
||||
;
|
||||
; int getch(void)
|
||||
.align 4
|
||||
.export getch,entry
|
||||
getch:
|
||||
.proc
|
||||
.callinfo frame=192,save_rp,no_unwind
|
||||
.entry
|
||||
stw %rp,-20(%sp)
|
||||
ldo 192(%sp),%sp
|
||||
|
||||
; stack usage:
|
||||
; 64byte IODC buffer (assume %sp was 64byte aligned)
|
||||
; 40 unused
|
||||
; 88 arguments, frame marker
|
||||
; 32bit: 36 (arguments) + 32 (frame marker)
|
||||
; 64bit: 72 (arguments) + 16 (frame marker)
|
||||
|
||||
; check if console is full or half duplex
|
||||
ldw PZ_MEM_CONSOLE+DEV_CLASS(%r0),%r1 ; device class
|
||||
extru %r1,31,4,%r1 ; right 4bits are valid
|
||||
ldi PZ_MEM_CONSOLE,%ret0
|
||||
comib,=,n DEV_CL_DUPLEX,%r1,getch_console ; use CONSOLE if full
|
||||
ldi PZ_MEM_KEYBOARD,%ret0 ; otherwise KEYBOARD
|
||||
getch_console:
|
||||
|
||||
; see IODC 3-50
|
||||
; arg0 hpa
|
||||
; arg1 option (ENTRY_IO_CONSOLEIN (2))
|
||||
; arg2 spa
|
||||
; arg3 ID_addr (pointer to LAYER)
|
||||
; arg4 R_addr (pointer to return buffer (64word?))
|
||||
; arg5 unused (0)
|
||||
; arg6 memaddr (64byte-aligned, must have 64byte) data buffer
|
||||
; arg7 reqsize
|
||||
; arg8 lang (0)
|
||||
; copy %rp,%rp ; IODC base in page zero
|
||||
copy %r0,%r29 ; arg8: lang
|
||||
ldi 1,%r19 ; arg7: size (1)
|
||||
ldo -192(%sp),%r20 ; arg6: buf
|
||||
; copy %r0,%r21 ; arg5: unused
|
||||
bl call_iodc,%rp
|
||||
ldi IODC_ENTRY_IO_CONSOLEIN,%arg1 ; arg1: option
|
||||
|
||||
; make return value
|
||||
comb,<> %ret0,%r0,getch_ret ; return -1 on error
|
||||
ldi -1,%ret0
|
||||
ldi 1,%r19
|
||||
|
||||
; check if narrow or wide mode
|
||||
ssm 0,%r1 ; get PSW
|
||||
bb,< %r1,4,getch_64
|
||||
addil L%retbuf-$global$,%r27;%r1
|
||||
ldw R%retbuf-$global$(%r1),%r2 ; ret[0]
|
||||
comclr,<> %r19,%r2,%ret0 ; return 0 if no char available
|
||||
getch_retc:
|
||||
ldb -192(%sp),%ret0 ; otherwise return the char
|
||||
|
||||
getch_ret:
|
||||
; return subroutine
|
||||
ldw -192-20(%sp),%rp
|
||||
bv %r0(%rp)
|
||||
.exit
|
||||
ldo -192(%sp),%sp
|
||||
|
||||
getch_64:
|
||||
.allow 2.0
|
||||
ldd R%retbuf-$global$(%r1),%r2 ; ret[0] (64bit)
|
||||
b getch_retc
|
||||
cmpclr,*<> %r19,%r2,%ret0 ; return 0 if no char available
|
||||
.allow
|
||||
.procend
|
||||
|
||||
;
|
||||
; read boot device
|
||||
;
|
||||
; void boot_input(void *buf, unsigned len, unsigned pos)
|
||||
.align 4
|
||||
.export boot_input,entry
|
||||
boot_input:
|
||||
.proc
|
||||
.callinfo frame=128,save_rp,no_unwind
|
||||
.entry
|
||||
stw %rp,-20(%sp)
|
||||
ldo 128(%sp),%sp
|
||||
|
||||
; stack usage:
|
||||
; 40byte unused (alignment)
|
||||
; 88 arguments, frame marker
|
||||
; 32bit: 36 (arguments) + 32 (frame marker)
|
||||
; 64bit: 72 (arguments) + 16 (frame marker)
|
||||
|
||||
; see IODC 3-46
|
||||
; arg0 hpa
|
||||
; arg1 option (ENTRY_IO_BOOTIN (0))
|
||||
; arg2 spa
|
||||
; arg3 ID_addr (pointer to LAYER)
|
||||
; arg4 R_addr (pointer to return buffer (64word?))
|
||||
; arg5 devaddr
|
||||
; arg6 memaddr (64byte-aligned) string buffer
|
||||
; arg7 reqsize
|
||||
; arg8 maxsize
|
||||
ldi PZ_MEM_BOOT,%ret0 ; IODC base in page zero
|
||||
copy %arg1,%r29 ; arg8: maxsize
|
||||
copy %arg1,%r19 ; arg7: size
|
||||
copy %arg0,%r20 ; arg6: buf
|
||||
copy %arg2,%r21 ; arg5: devaddr
|
||||
bl call_iodc,%rp
|
||||
ldi IODC_ENTRY_IO_BOOTIN,%arg1 ; arg1: option
|
||||
|
||||
; return subroutine
|
||||
ldw -128-20(%sp),%rp
|
||||
bv %r0(%rp)
|
||||
.exit
|
||||
ldo -128(%sp),%sp
|
||||
.procend
|
||||
|
||||
;
|
||||
; utilities
|
||||
; optimized for size
|
||||
;
|
||||
|
||||
; int strcmp(const char *str1, const char *str2)
|
||||
.align 4
|
||||
.export strcmp,entry
|
||||
strcmp:
|
||||
.proc
|
||||
.callinfo frame=0,no_calls
|
||||
.entry
|
||||
ldbs,ma 1(0,%arg0),%r1
|
||||
strcmp_loop:
|
||||
comb,= %r1,%r0,strcmp_eos
|
||||
ldbs,ma 1(0,%arg1),%r19
|
||||
comb,=,n %r1,%r19,strcmp_loop
|
||||
ldbs,ma 1(0,%arg0),%r1
|
||||
strcmp_eos:
|
||||
bv %r0(%rp)
|
||||
.exit
|
||||
sub %r1,%r19,%ret0
|
||||
.procend
|
||||
|
||||
; void memcpy(void *dst, const void *src, unsigned len)
|
||||
.align 4
|
||||
.export memcpy,entry
|
||||
.export memmove,entry
|
||||
memcpy:
|
||||
memmove:
|
||||
.proc
|
||||
.callinfo no_unwind ; multiple exit points
|
||||
.entry
|
||||
; copy %arg0,%ret0 ; uncomment this to conform ANSI
|
||||
comb,<<,n %arg0,%arg1,memcpy0 ; copy forward or backward?
|
||||
add %arg0,%arg2,%arg0 ; dst end address
|
||||
add,tr %arg1,%arg2,%arg1 ; src end address, skip next
|
||||
memcpy_bwd:
|
||||
stbs,mb %r1,-1(0,%arg0) ; write to dst
|
||||
addib,uv,n -1,%arg2,memcpy_bwd ; check loop condition
|
||||
ldbs,mb -1(0,%arg1),%r1 ; read from src
|
||||
bv,n %r0(%rp) ; return subroutine
|
||||
memcpy_fwd:
|
||||
stbs,ma %r1,1(0,%arg0) ; write to dst
|
||||
memcpy0:
|
||||
addib,uv,n -1,%arg2,memcpy_fwd ; check loop condition
|
||||
ldbs,ma 1(0,%arg1),%r1 ; read from src
|
||||
.exit
|
||||
bv,n %r0(%rp) ; return subroutine
|
||||
.procend
|
||||
|
||||
;
|
||||
; string table
|
||||
; placed here to save space
|
||||
;
|
||||
.export str_seekseq, data
|
||||
.export str_startup, data
|
||||
.export str_bit_firmware, data
|
||||
.export str_crlf, data
|
||||
.export str_space, data
|
||||
.export str_rubout, data
|
||||
str_seekseq:
|
||||
.stringz "repositioning media...\r\n"
|
||||
str_bit_firmware:
|
||||
.stringz "bit firmware\r\n"
|
||||
str_rubout:
|
||||
.byte 0x08, 0x20, 0x08, 0x00 ; "\b \b"
|
||||
|
||||
.export str_bootpart, data
|
||||
str_bootpart:
|
||||
.string "boot partition (a-p, ! to reboot) [a]:"
|
||||
str_space:
|
||||
.stringz " "
|
||||
.export str_booting_part, data
|
||||
str_booting_part:
|
||||
.string "\r\nbooting from partition _"
|
||||
str_crlf:
|
||||
.stringz "\r\n"
|
||||
.export str_warn_2GB, data
|
||||
str_warn_2GB:
|
||||
.stringz "boot partition exceeds 2GB boundary\r\n"
|
||||
.export str_warn_unused, data
|
||||
str_warn_unused:
|
||||
.stringz "unused partition\r\n"
|
||||
.export str_nolabel, data
|
||||
str_nolabel:
|
||||
.stringz "no disklabel\r\n"
|
||||
|
||||
.export str_filesystem, data
|
||||
str_filesystem:
|
||||
.stringz "filesystem: _FS\r\n"
|
||||
.export str_nofs, data
|
||||
str_nofs:
|
||||
.stringz "no filesystem found\r\n"
|
||||
.export str_lookup, data
|
||||
.export str_loading, data
|
||||
.export str_at, data
|
||||
.export str_dddot, data
|
||||
.export str_done, data
|
||||
str_lookup:
|
||||
.stringz "looking up "
|
||||
str_loading:
|
||||
.stringz "loading "
|
||||
str_at:
|
||||
.stringz " at 0x"
|
||||
str_dddot:
|
||||
.stringz "..."
|
||||
str_done:
|
||||
.stringz "done\r\n"
|
||||
|
||||
.export str_boot1, data
|
||||
.export str_boot2, data
|
||||
.export str_boot3, data
|
||||
str_boot1:
|
||||
.stringz "boot.hp700"
|
||||
str_boot2:
|
||||
.stringz "boot"
|
||||
str_boot3:
|
||||
.stringz "usr/mdec/boot"
|
||||
|
||||
.export str_noboot, data
|
||||
str_noboot:
|
||||
.stringz "no secondary boot found\r\n"
|
||||
|
||||
.export str_ukfmt, data
|
||||
str_ukfmt:
|
||||
.stringz ": unknown format -- exec from top\r\n"
|
||||
|
||||
.bss
|
||||
.align 64
|
||||
retbuf: .block 32*8 ; *4 for narrow mode / *8 for wide mode
|
||||
|
||||
.export diskbuf,data
|
||||
.align 64
|
||||
diskbuf:
|
||||
.block 2048
|
Loading…
Reference in New Issue
Block a user