NetBSD/hp700 FFS/LFS Primary Bootstrap

This commit is contained in:
itohy 2004-06-15 03:10:30 +00:00
parent 3b60dfd3bd
commit b119940e75
10 changed files with 2392 additions and 0 deletions

View 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 $@

View 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)

View 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;
}

View 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;
}

View 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

View 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

View 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

View 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;
}

View 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;
}

View 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