summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorkato <kato@FreeBSD.org>1999-02-03 08:39:09 +0000
committerkato <kato@FreeBSD.org>1999-02-03 08:39:09 +0000
commitc40db6cc734847f5d3013132b80d70a078c16615 (patch)
tree8460f4832d3da04f82cedbd05be800e5fd9063e4 /sys
parent850544e5d8903343f0bdde5c29f0147851ea1b4b (diff)
downloadFreeBSD-src-c40db6cc734847f5d3013132b80d70a078c16615.zip
FreeBSD-src-c40db6cc734847f5d3013132b80d70a078c16615.tar.gz
PC98 version of new boot loader. Because boot2 has not yet ported,
files in boot2 directory are copies from legacy biosboot. Submitted by: IMAI Takeshi <take-i@ceres.dti.ne.jp>
Diffstat (limited to 'sys')
-rw-r--r--sys/boot/Makefile2
-rw-r--r--sys/boot/common/isapnp.h6
-rw-r--r--sys/boot/pc98/Makefile5
-rw-r--r--sys/boot/pc98/boot2/Makefile97
-rw-r--r--sys/boot/pc98/boot2/README.serial.9863
-rw-r--r--sys/boot/pc98/boot2/asm.S244
-rw-r--r--sys/boot/pc98/boot2/asm.h144
-rw-r--r--sys/boot/pc98/boot2/bios.S456
-rw-r--r--sys/boot/pc98/boot2/boot.c447
-rw-r--r--sys/boot/pc98/boot2/boot.h109
-rw-r--r--sys/boot/pc98/boot2/boot2.S183
-rw-r--r--sys/boot/pc98/boot2/disk.c330
-rw-r--r--sys/boot/pc98/boot2/io.c429
-rw-r--r--sys/boot/pc98/boot2/probe_keyboard.c39
-rw-r--r--sys/boot/pc98/boot2/serial.S201
-rw-r--r--sys/boot/pc98/boot2/start.S535
-rw-r--r--sys/boot/pc98/boot2/sys.c337
-rw-r--r--sys/boot/pc98/boot2/table.c149
-rw-r--r--sys/boot/pc98/btx/Makefile5
-rw-r--r--sys/boot/pc98/btx/btx/Makefile25
-rw-r--r--sys/boot/pc98/btx/btx/btx.S1071
-rw-r--r--sys/boot/pc98/btx/btx/btx.m459
-rw-r--r--sys/boot/pc98/btx/btx/btx.s1071
-rw-r--r--sys/boot/pc98/btx/btxldr/Makefile26
-rw-r--r--sys/boot/pc98/btx/btxldr/btxldr.S459
-rw-r--r--sys/boot/pc98/btx/btxldr/btxldr.s459
-rw-r--r--sys/boot/pc98/btx/lib/Makefile20
-rw-r--r--sys/boot/pc98/btx/lib/btxcsu.s43
-rw-r--r--sys/boot/pc98/btx/lib/btxsys.s40
-rw-r--r--sys/boot/pc98/btx/lib/btxv86.h63
-rw-r--r--sys/boot/pc98/btx/lib/btxv86.s85
-rw-r--r--sys/boot/pc98/libpc98/Makefile42
-rw-r--r--sys/boot/pc98/libpc98/biosdisk.c1017
-rw-r--r--sys/boot/pc98/libpc98/biosmem.c59
-rw-r--r--sys/boot/pc98/libpc98/bootinfo.c331
-rw-r--r--sys/boot/pc98/libpc98/comconsole.c136
-rw-r--r--sys/boot/pc98/libpc98/gatea20.c57
-rw-r--r--sys/boot/pc98/libpc98/time.c83
-rw-r--r--sys/boot/pc98/libpc98/vidconsole.c800
-rw-r--r--sys/boot/pc98/loader/Makefile117
-rw-r--r--sys/boot/pc98/loader/help.pc9846
-rw-r--r--sys/boot/pc98/loader/main.c244
-rw-r--r--sys/boot/pc98/loader/newvers.sh46
-rw-r--r--sys/boot/pc98/loader/version8
44 files changed, 10185 insertions, 3 deletions
diff --git a/sys/boot/Makefile b/sys/boot/Makefile
index cd27185..c125868 100644
--- a/sys/boot/Makefile
+++ b/sys/boot/Makefile
@@ -2,6 +2,6 @@
SUBDIR+= ficl
# Pick the machine-dependant subdir based on the target architecture.
-SUBDIR+= ${MACHINE_ARCH}
+SUBDIR+= ${MACHINE}
.include <bsd.subdir.mk>
diff --git a/sys/boot/common/isapnp.h b/sys/boot/common/isapnp.h
index 0b3b9ec..d1311b2 100644
--- a/sys/boot/common/isapnp.h
+++ b/sys/boot/common/isapnp.h
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: isapnp.h,v 1.1 1998/09/18 00:24:25 msmith Exp $
+ * $Id: isapnp.h,v 1.2 1998/10/21 20:07:04 msmith Exp $
*/
#ifndef _I386_ISA_PNP_H_
@@ -44,7 +44,8 @@
#define MAX_PNP_LDN 20
/* Static ports to access PnP state machine */
-#if defined(PC98) && defined(KERNEL)
+#ifndef KERNEL
+#ifdef PC98
/* pnp.h is included from pnpinfo.c. */
#define _PNP_ADDRESS 0x259
#define _PNP_WRITE_DATA 0xa59
@@ -52,6 +53,7 @@
#define _PNP_ADDRESS 0x279
#define _PNP_WRITE_DATA 0xa79
#endif
+#endif
/* PnP Registers. Write to ADDRESS and then use WRITE/READ_DATA */
#define SET_RD_DATA 0x00
diff --git a/sys/boot/pc98/Makefile b/sys/boot/pc98/Makefile
new file mode 100644
index 0000000..72ce2ce
--- /dev/null
+++ b/sys/boot/pc98/Makefile
@@ -0,0 +1,5 @@
+# $Id: Makefile,v 1.7 1998/10/14 20:40:56 rnordier Exp $
+
+SUBDIR= btx boot2 libpc98 loader
+
+.include <bsd.subdir.mk>
diff --git a/sys/boot/pc98/boot2/Makefile b/sys/boot/pc98/boot2/Makefile
new file mode 100644
index 0000000..8c9b84e
--- /dev/null
+++ b/sys/boot/pc98/boot2/Makefile
@@ -0,0 +1,97 @@
+# $Id: Makefile,v 1.22 1999/01/04 08:02:13 kato Exp $
+#
+
+PROG= boot
+# Order is very important on the SRCS line for this prog
+SRCS= start.S table.c boot2.S boot.c asm.S bios.S serial.S
+SRCS+= probe_keyboard.c io.c disk.c sys.c
+
+BINDIR= /boot
+BINMODE= 444
+CFLAGS= -O2 -malign-functions=0 -malign-jumps=0 -malign-loops=0 \
+ -mno-486 \
+ -DPC98 -DBOOTWAIT=${BOOTWAIT} -DTIMEOUT=${TIMEOUT}
+CFLAGS+= -DBOOTSEG=${BOOTSEG} -DBOOTSTACK=${BOOTSTACK}
+CFLAGS+= ${CWARNFLAGS}
+CFLAGS+= -I${.CURDIR}/../../.. -aout
+
+
+# By default, if a serial port is going to be used as console, use COM1
+# (aka /dev/ttyd0).
+#BOOT_COMCONSOLE_PORT?=0x30
+BOOT_COMCONSOLE_PORT?=0x238
+BOOT_COMCONSOLE_CLK?=16
+BOOT_COMCONSOLE_MODE=0x0c
+CFLAGS+= -DCOMCONSOLE=${BOOT_COMCONSOLE_PORT} \
+ -DCOMCONSOLE_CLK=${BOOT_COMCONSOLE_CLK} \
+ -DCOMCONSOLE_MODE=${BOOT_COMCONSOLE_MODE}
+
+# feature not implemented
+BOOT_COMCONSOLE_SPEED?=9600
+CFLAGS+= -DCONSPEED=${BOOT_COMCONSOLE_SPEED}
+
+# Enable code to take the default boot string from a fixed location on the
+# disk. See nextboot(8) and README.386BSD for more info.
+#CFLAGS+= -DNAMEBLOCK
+#CFLAGS+= -DNAMEBLOCK_WRITEBACK
+
+# Bias the conversion from the BIOS drive number to the FreeBSD unit number
+# for hard disks. This may be useful for people booting in a mixed IDE/SCSI
+# environment (set BOOT_HD_BIAS to the number of IDE drives).
+#CFLAGS+= -DBOOT_HD_BIAS=1
+#
+# Details: this only applies if BOOT_HD_BIAS > 0. If the BIOS drive number
+# for the boot drive is >= BOOT_HD_BIAS, then the boot drive is assumed to
+# be SCSI and have unit number (BIOS_drive_number - BOOT_HD_BIAS). E.g.,
+# BOOT_HD_BIAS=1 makes BIOS drive 1 correspond to 1:da(0,a) instead of
+# 1:wd(1,a). If `da' is given explicitly, then the drive is assumed to be
+# SCSI and have BIOS drive number (da_unit_number + BOOT_HD_BIAS). E.g.,
+# BOOT_HD_BIAS=1 makes da(0,a) correspond to 1:da(0,a) instead of 0:da(0,a).
+
+CLEANFILES+= boot.nohdr boot.strip boot1 boot2 sizetest
+LDFLAGS+= -N -T 0 -nostdlib
+NOSHARED= YES
+NOMAN=
+STRIP=
+
+# tunable timeout parameter, waiting for keypress, calibrated in ms
+BOOTWAIT?= 5000
+# tunable timeout during string input, calibrated in ms
+#TIMEOUT?= 30000
+
+# Location that boot2 is loaded at
+BOOTSEG= 0x1000
+
+# Offset in BOOTSEG for the top of the stack, keep this 16 byte aligned
+BOOTSTACK= 0xFFF0
+
+boot.strip: boot
+ cp -p boot boot.strip
+ strip -aout boot.strip
+ size -aout boot.strip
+
+boot.nohdr: boot.strip
+ dd if=boot.strip of=boot.nohdr ibs=32 skip=1 obs=1024b
+ ls -l boot.nohdr
+
+boot1: boot.nohdr
+ dd if=boot.nohdr of=boot1 bs=512 count=1
+
+boot2: boot.nohdr
+ dd if=boot.nohdr of=boot2 bs=512 skip=1
+ @dd if=boot2 skip=14 of=sizetest 2> /dev/null
+ @if [ -s sizetest ] ; then \
+ echo "boot2 is too big" >&2 ; \
+ rm boot2 ; \
+ exit 2 ; \
+ fi
+
+all: boot1 boot2
+
+install:
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ boot1 boot2 ${DESTDIR}${BINDIR}
+
+
+.include <bsd.kern.mk>
+.include <bsd.prog.mk>
diff --git a/sys/boot/pc98/boot2/README.serial.98 b/sys/boot/pc98/boot2/README.serial.98
new file mode 100644
index 0000000..de98c82
--- /dev/null
+++ b/sys/boot/pc98/boot2/README.serial.98
@@ -0,0 +1,63 @@
+ README.srieal.98
+ ¥·¥ê¥¢¥ë¥³¥ó¥½¡¼¥ë¤Ë¤Ä¤¤¤Æ
+ ²ÃÆ£¾æŵ (kato@eclogite.eps.nagoya-u.ac.jp)
+ KATO Takenori
+
+FreeBSD(98)¤Î¥³¥ó¥½¡¼¥ë¤È¤·¤Æ¡¢Æâ¢RS-232C¥Ý¡¼¥È¤ËÀܳ¤µ¤ì¤¿¥À¥àüËö¤ò
+»ÈÍѤ¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£¤³¤ì¤Ë¤è¤ê¡¢FreeBSD(98)¤ò¥µ¡¼¥Ð¤È¤·¤Æ»ÈÍѤ¹¤ë
+»þ¤Ë¡¢¥­¡¼¥Ü¡¼¥É¤ä¥â¥Ë¥¿¤òÀܳ¤·¤Ê¤¯¤Æ¤â¤«¤Þ¤ï¤Ê¤¯¤Ê¤ê¤Þ¤¹¡£
+
+¥·¥ê¥¢¥ë¥³¥ó¥½¡¼¥ë¤ò»ÈÍѤ¹¤ëºÝ¤Ï¡¢¤³¤Î¥É¥­¥å¥á¥ó¥È¤ª¤è¤Ó¡¢IBM-PCÍѤΥ«¡¼
+¥Í¥ë¥½¡¼¥¹¤Ë´Þ¤Þ¤ì¤ë¡¢/usr/src/sys/i386/boot/biosboot/READEME.serial¤ò
+Îɤ¯Æɤó¤Ç²¼¤µ¤¤¡£
+
+FreeBSD(98)¤Ç¥·¥ê¥¢¥ë¥³¥ó¥½¡¼¥ë¤ò»ÈÍѤ¹¤ëºÝ¤Ï¡¢°Ê²¼¤Î¼ê½ç¤ò¼Â¹Ô¤·¤Æ²¼
+¤µ¤¤¡£
+
+1: ¥Ö¡¼¥È¥³¡¼¥É¤Î¥³¥ó¥Ñ¥¤¥ë¥ª¥×¥·¥ç¥ó
+ PC-9801¥·¥ê¡¼¥º¤Î¾ì¹ç¡¤¥­¡¼¥Ü¡¼¥É¤¬Àܳ¤µ¤ì¤Æ¤¤¤Ê¤¤¾õÂ֤ȵ췿
+ ¥­¡¼¥Ü¡¼¥É¤¬Àܳ¤µ¤ì¤Æ¤¤¤ë¾õÂ֤Ȥò¶èÊ̤¹¤ëÊýË¡¤¬¤¢¤ê¤Þ¤»¤ó¡¥¤â
+ ¤·¡¤µì·¿¥­¡¼¥Ü¡¼¥É¤ò»ÈÍѤ·¤Æ¤¤¤Æ
+ PROBE_KEYBOARD
+ ¤¬Í­¸ú¤Ë¤Ê¤Ã¤Æ¤¤¤ë¤È¡¤¥­¡¼¥Ü¡¼¥É¤¬Ç§¼±¤µ¤ì¤º¤Ë¥·¥ê¥¢¥ë¥³¥ó¥½¡¼
+ ¥ë¤¬»ÈÍѤµ¤ì¤Þ¤¹¡¥¤Þ¤¿¡¤
+ FORCE_COMCONSOLE
+ ¤¬Í­¸ú¤Ë¤Ê¤Ã¤Æ¤¤¤ë¤È¡¤¥­¡¼¥Ü¡¼¥É¤ÎÀܳ¾õÂ֤˴ؤï¤é¤º¥·¥ê¥¢¥ë¥³
+ ¥ó¥½¡¼¥ë¤ò»ÈÍѤ¹¤ë¤è¤¦¤Ë¤Ê¤ê¤Þ¤¹¡¥
+
+2: ¥­¡¼¥Ü¡¼¥É¤òÀÚ¤êÎ¥¤¹
+ ¥­¡¼¥Ü¡¼¥É¤òÀܳ¤»¤º¤Ë¡¢ËÜÂΤòµ¯Æ°¤µ¤»¤¿¾ì¹ç¡¢¥·¥¹¥Æ¥àÎΰè¤Î¥­¡¼
+ ¥Ü¡¼¥É¥¿¥¤¥×¤¬¡¢µì¼°¥­¡¼¥Ü¡¼¥É(CAPS¤¬µ¡³£¼°¤Î¥­¡¼¥Ü¡¼¥É)¤ÈƱ¤¸
+ ¤Ë¤Ê¤ê¤Þ¤¹¡£FreeBSD(98)¤Î¥Ö¡¼¥È¥³¡¼¥É¤Ï¡¢¤³¤ì¤ò¸¡½Ð¤·¤Æ¼«Æ°Åª
+ ¤Ë¥·¥ê¥¢¥ë¥³¥ó¥½¡¼¥ë¥â¡¼¥É¤Ë°Ü¤ê¤Þ¤¹¡£
+
+3: üËö¤òÀܳ¤¹¤ë
+ Æâ¢RS-232C¥³¥Í¥¯¥¿¤Ë¥À¥àüËö¤òÀܳ¤·¤Æ²¼¤µ¤¤¡£¥À¥àüËö¤¬Ìµ¤¤
+ ¾ì¹ç¤Ï¡¢Å¬Åö¤Ê¥Ñ¥½¥³¥ó¤ÇÄÌ¿®¥½¥Õ¥È¥¦¥§¥¢¤ò¼Â¹Ô¤µ¤»¤¿¤â¤Î¤ä¡¢ÄÌ
+ ¿®µ¡Ç½¤Ä¤­¤Î¥ï¡¼¥×¥í¤Ê¤É¤ò»ÈÍѤ·¤Æ²¼¤µ¤¤¡£
+
+ FreeBSD(98)¤Î¥Ö¡¼¥È¥³¡¼¥É¤Ç¤Ï¡¢RS-232C¥Ý¡¼¥È¤ò9600¥Ü¡¼¡¢8¥Ó¥Ã
+ ¥È¡¢¥Ñ¥ê¥Æ¥£Ìµ¤·¤ËÀßÄꤵ¤ì¤Æ¤¤¤Þ¤¹¡£
+
+4: ËÜÂΤòµ¯Æ°¤¹¤ë
+ ¥Ö¡¼¥È¥Ö¥í¥Ã¥¯¤Ï¡¢µ¯Æ°»þ¤Ë¥­¡¼¥Ü¡¼¥É¤ÎÀܳ¤ò¸¡ºº¤·¤Þ¤¹¡£¤â¤·¡¢
+ ¥­¡¼¥Ü¡¼¥É¤¬Àܳ¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢Ã¼Ëö¤Ë°Ê²¼¤Î¥á¥Ã¥»¡¼¥¸¤¬É½¼¨
+ ¤µ¤ì¤Þ¤¹¡£
+
+ No keyboard found.
+
+ >> FreeBSD BOOT @0x90000 640/25600 k of memory
+ Use hd(1,a)/kernel to boot sd0 when wd0 is also installed.
+ Usage: [[[fd(0,a)]/kernel][-Dabcdhrsv]]
+ Use ? for file list or press Enter for defaults
+
+ Boot:
+
+ ¤³¤ì¤Ï¡¢ÉáÃʸ«¤Æ¤¤¤ë¥á¥Ã¥»¡¼¥¸¤È¤Û¤È¤ó¤ÉÊѤï¤ê¤Þ¤»¤ó¤¬¡¢¤Ï¤¸¤á
+ ¤Ë¡¢`No keyboard found'¤Èɽ¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡£¤³¤³¤Ç¡¢¥À¥àüËö¤«
+ ¤é¡¢¥³¥ó¥½¡¼¥ë¾å¤Çµ¯Æ°¤·¤Æ¤¤¤ë»þ¤ÈƱ¤¸¤è¤¦¤Ë¥«¡¼¥Í¥ë¤òΩ¤Á¾å¤²
+ ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£µ¯Æ°¸å¤Î¥á¥Ã¥»¡¼¥¸¤Ï¥À¥àüËö¤Ëɽ¼¨¤µ¤ì¤Þ¤¹¡£
+
+ ¤â¤·¡¢¥·¥ê¥¢¥ë¥³¥ó¥½¡¼¥ë¤«¤éÄ̾ï¤Î¥³¥ó¥½¡¼¥ë¤ËÀÚÂؤ¨¤ë¤Ë¤Ï¡¢
+ `-h'¥ª¥×¥·¥ç¥ó¤ò¤Ä¤±¤Æµ¯Æ°¤·¤Æ²¼¤µ¤¤¡£
+
diff --git a/sys/boot/pc98/boot2/asm.S b/sys/boot/pc98/boot2/asm.S
new file mode 100644
index 0000000..01d47f2
--- /dev/null
+++ b/sys/boot/pc98/boot2/asm.S
@@ -0,0 +1,244 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:34:13 rpd
+ * $Id: asm.S,v 1.4 1997/09/01 10:38:24 kato Exp $
+ */
+
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+ .file "asm.s"
+
+#include "asm.h"
+
+
+CR0_PE_ON = 0x1
+CR0_PE_OFF = 0xfffffffe
+
+ .text
+
+/*
+ *
+ * real_to_prot()
+ * transfer from real mode to protected mode.
+ */
+
+ENTRY(real_to_prot)
+ /* guarantee that interrupt is disabled when in prot mode */
+ cli
+
+ /* load the gdtr */
+ addr32
+ data32
+ lgdt EXT(Gdtr)
+
+ /* set the PE bit of CR0 */
+ mov %cr0, %eax
+
+ data32
+ or $CR0_PE_ON, %eax
+ mov %eax, %cr0
+
+ /*
+ * make intrasegment jump to flush the processor pipeline and
+ * reload CS register
+ */
+ data32
+ ljmp $0x18, $xprot
+xprot:
+
+ /*
+ * we are in USE32 mode now
+ * set up the protected mode segment registers : DS, SS, ES, FS
+ */
+ movw $0x20, %ax /* data segment */
+ mov %ax, %ds /* gas would waste a prefix byte for movw */
+ mov %ax, %ss
+ mov %ax, %es
+ movw $0x10, %ax /* flat segment */
+ mov %ax, %fs
+
+#ifdef BDE_DEBUGGER
+ /* load idtr so we can debug */
+ lidt EXT(Idtr_prot)
+#endif
+
+ ret
+
+/*
+ *
+ * prot_to_real()
+ * transfer from protected mode to real mode
+ *
+ */
+
+ENTRY(prot_to_real)
+
+ /* Prepare %ax while we're still in a mode that gas understands. */
+ movw $0x30, %ax
+
+ /* Change to use16 mode. */
+ ljmp $0x28, $x16
+x16:
+
+ mov %ax, %ds
+ mov %ax, %ss
+ mov %ax, %es
+ mov %ax, %fs
+
+ /* clear the PE bit of CR0 */
+ mov %cr0, %eax
+ data32
+ and $CR0_PE_OFF, %eax
+ mov %eax, %cr0
+
+ /*
+ * make intersegment jmp to flush the processor pipeline
+ * and reload CS register
+ */
+ data32
+ ljmp $BOOTSEG, $xreal
+xreal:
+
+ /*
+ * we are in real mode now
+ * set up the real mode segment registers : DS, SS, ES, FS
+ */
+ mov %cs, %ax
+ mov %ax, %ds
+ mov %ax, %ss
+ mov %ax, %es
+ mov %ax, %fs
+
+#ifdef BDE_DEBUGGER
+ /* load idtr so we can debug */
+ addr32
+ data32
+ lidt EXT(Idtr_real)
+#endif
+
+ data32
+ ret
+
+/*
+ * startprog(phyaddr)
+ * start the program on protected mode where phyaddr is the entry point
+ *
+ * XXX This whole mess should go away and we should run the boot code in
+ * flat 32 bit mode with it linked -T BOOTSEG. See the netboot code for
+ * how this is done.
+ */
+
+ENTRY(startprog)
+ push %ebp
+ mov %esp, %ebp
+ movl %esp, %eax /* Use eax as the old stack pointer */
+
+ /* convert the current stack to a 32 bit flat model */
+ movw $0x10, %bx
+ mov %bx, %ss
+ addl $(BOOTSEG<<4),%esp
+
+ /* copy the arguments from the old stack to the new stack */
+ pushl 0x14(%eax) /* &bootinfo */
+ pushl $0 /* was &nfsdiskless */
+ pushl $0 /* was esym */
+ pushl $0 /* was cyloffset */
+ pushl 0x10(%eax) /* bootdev */
+ pushl 0x0C(%eax) /* howto */
+ movl $(ourreturn),%ebx
+ addl $(BOOTSEG<<4),%ebx /* Fix it up for flat segments */
+ pushl %ebx /* our return address */
+
+ /* push on our entry address */
+ pushl $0x08 /* segment selector */
+ pushl 0x08(%eax) /* kernel entry address */
+
+ /* convert over the other data segs */
+ movw $0x10, %bx
+ mov %bx, %ds
+ mov %bx, %es
+
+ /* convert the PC (and code seg) */
+ lret
+ourreturn:
+ /* For now there is not much we can do, just lock in a loop */
+ jmp ourreturn
+
+/*
+ * pcpy(src, dst, cnt)
+ * where src is a virtual address and dst is a physical address
+ */
+
+ENTRY(pcpy)
+ push %ebp
+ mov %esp, %ebp
+ push %es
+ push %esi
+ push %edi
+ push %ecx
+
+ cld
+
+ /* set %es to point at the flat segment */
+ movw $0x10, %ax
+ mov %ax, %es
+
+ mov 0x8(%ebp), %esi /* source */
+ mov 0xc(%ebp), %edi /* destination */
+ mov 0x10(%ebp), %ecx /* count */
+
+ rep
+ movsb
+
+ pop %ecx
+ pop %edi
+ pop %esi
+ pop %es
+ pop %ebp
+
+ ret
diff --git a/sys/boot/pc98/boot2/asm.h b/sys/boot/pc98/boot2/asm.h
new file mode 100644
index 0000000..2e0fcac
--- /dev/null
+++ b/sys/boot/pc98/boot2/asm.h
@@ -0,0 +1,144 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.7 92/02/29 15:33:41 rpd
+ * $Id: asm.h,v 1.3 1997/02/22 09:43:04 peter Exp $
+ */
+
+#define S_ARG0 4(%esp)
+#define S_ARG1 8(%esp)
+#define S_ARG2 12(%esp)
+#define S_ARG3 16(%esp)
+
+#define FRAME pushl %ebp; movl %esp, %ebp
+#define EMARF leave
+
+#define B_ARG0 8(%ebp)
+#define B_ARG1 12(%ebp)
+#define B_ARG2 16(%ebp)
+#define B_ARG3 20(%ebp)
+
+#ifdef wheeze
+
+#define ALIGN 4
+#define EXT(x) x
+#define LEXT(x) x:
+#define LCL(x) ./**/x
+
+#define LB(x,n) ./**/x
+#define LBb(x,n) ./**/x
+#define LBf(x,n) ./**/x
+
+#define SVC lcall $7,$0
+
+#define String .string
+#define Value .value
+#define Times(a,b) [a\*b]
+#define Divide(a,b) [a\\b]
+
+#define INB inb (%dx)
+#define OUTB outb (%dx)
+#define INL inl (%dx)
+#define OUTL outl (%dx)
+
+#else wheeze
+#define ALIGN
+#define LCL(x) x
+
+#define LB(x,n) n
+#ifdef __STDC__
+#define EXT(x) _ ## x
+#define LEXT(x) _ ## x ## :
+
+#define LBb(x,n) n ## b
+#define LBf(x,n) n ## f
+#else __STDC__
+#define EXT(x) _/**/x
+#define LEXT(x) _/**/x/**/:
+#define LBb(x,n) n/**/b
+#define LBf(x,n) n/**/f
+#endif __STDC__
+#define SVC .byte 0x9a; .long 0; .word 0x7
+
+#define String .ascii
+#define Value .word
+#define Times(a,b) (a*b)
+#define Divide(a,b) (a/b)
+
+#define INB inb %dx, %al
+#define OUTB outb %al, %dx
+#define INL inl %dx, %eax
+#define OUTL outl %eax, %dx
+
+#endif wheeze
+
+#define addr32 .byte 0x67
+#define data32 .byte 0x66
+
+#ifdef GPROF
+#ifdef __STDC__
+
+#define MCOUNT .data; LB(x, 9); .long 0; .text; lea LBb(x, 9),%edx; call mcount
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ASENTRY(x) .globl x; .align ALIGN; x ## : ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+
+#else __STDC__
+
+#define MCOUNT .data; LB(x, 9): .long 0; .text; lea LBb(x, 9),%edx; call mcount
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x: ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+
+#endif __STDC__
+#else GPROF
+#ifdef __STDC__
+
+#define MCOUNT
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x ## :
+
+#else __STDC__
+
+#define MCOUNT
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x:
+
+#endif __STDC__
+#endif GPROF
+
+#define Entry(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define DATA(x) .globl EXT(x); .align ALIGN; LEXT(x)
diff --git a/sys/boot/pc98/boot2/bios.S b/sys/boot/pc98/boot2/bios.S
new file mode 100644
index 0000000..4c66744
--- /dev/null
+++ b/sys/boot/pc98/boot2/bios.S
@@ -0,0 +1,456 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:34:26 rpd
+ * $Id: bios.S,v 1.9 1998/05/02 02:06:07 kato Exp $
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+/*
+ * Ported to PC-9801 by Yoshio Kimura
+ */
+
+/*
+ * Extensions for El Torito CD-ROM booting:
+ *
+ * Copyright © 1997 Pluto Technologies International, Inc. Boulder CO
+ * Copyright © 1997 interface business GmbH, Dresden.
+ * All rights reserved.
+ *
+ * This code has been written by Jörg Wunsch, Dresden.
+ * Direct comments to <joerg_wunsch@interface-business.de>.
+ *
+ * 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 form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+ *
+ */
+
+ .file "bios.s"
+
+#include "asm.h"
+ .text
+
+#ifndef CDBOOT
+
+/*
+ * biosread(dev, cyl, head, sec, nsec, offset)
+ * Read "nsec" sectors from disk to offset "offset" in boot segment
+ * BIOS call "INT 0x1B Function 0xn6" to read sectors from disk into memory
+ * Call with %ah = 0xd6(for floppy disk) or 0x06(for hard disk)
+ * %al = DA/UA
+ * %bx = data length
+ * %ch = sector size(for floppy) or cylinder(for hard)
+ * %cl = cylinder
+ * %dh = head
+ * %dl = sector
+ * %es:%bp = segment:offset of buffer
+ * Return:
+ * %al = 0x0 on success; err code on failure
+ */
+
+ENTRY(biosread)
+ push %ebp
+ mov %esp, %ebp
+
+ push %ebx
+ push %esi
+ push %edi
+
+ movb 0x14(%ebp), %dl /* sector */
+ movb 0x10(%ebp), %dh /* head */
+ movw 0x0c(%ebp), %cx /* cylinder */
+ movb 0x08(%ebp), %al /* DA/UA */
+ movb $0x06, %ah
+ andb $0xf0, %al
+ cmpb $0x30, %al
+ jz fd
+ cmpb $0x90, %al
+ jnz 1f
+fd:
+ incb %dl
+ movb $0x02, %ch
+ movb $0xd6, %ah
+1:
+ movb 0x08(%ebp), %al
+ movl %eax, %ebx
+
+ /* prot_to_real will set %es to BOOTSEG */
+ call EXT(prot_to_real) /* enter real mode */
+ mov %ebx, %eax
+ xor %ebx, %ebx
+ addr32
+ movb 0x18(%ebp), %bl /* number of sectors */
+ data32
+ shl $9, %ebx
+ data32
+ push %ebx
+ addr32
+ data32
+ mov 0x1c(%ebp), %ebx
+ data32
+ mov %ebx, %ebp
+ data32
+ pop %ebx
+
+ int $0x1b
+ jc 1f
+ xor %eax, %eax
+1:
+ /* save return value (actually movw %ax, %bx) */
+ mov %eax, %ebx
+
+ data32
+ call EXT(real_to_prot) /* back to protected mode */
+
+ xor %eax, %eax
+ movb %bh, %al /* return value in %ax */
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ pop %ebp
+
+ ret
+
+#else /* CDBOOT */
+
+
+/*
+ * int
+ * getbootspec(struct specpacket *offset)
+ *
+ * Read CD-ROM boot specification packet to "offset".
+ */
+ENTRY(getbootspec)
+ push %ebp
+ mov %esp, %ebp
+
+ push %esi
+ push %ebx
+
+ movw 0x8(%ebp), %si
+ mov $0x7f, %edx
+
+ /* prot_to_real will set %es to BOOTSEG */
+ call EXT(prot_to_real) /* enter real mode */
+ movw $0x4b01, %ax /* (do not) terminate disk emulation */
+ movb $0x7f, %dl /* any drive */
+
+ sti
+ int $0x13
+ cli
+
+ /* save return value (actually movw %ax, %bx) */
+ mov %eax, %ebx
+
+ data32
+ call EXT(real_to_prot) /* back to protected mode */
+
+ xor %eax, %eax
+ movb %bh, %al /* return value in %ax */
+
+ pop %ebx
+ pop %esi
+ pop %ebp
+
+ ret
+
+
+/*
+ * int
+ * biosreadlba(struct daddrpacket *daddr)
+ * Read sectors using the BIOS "read extended" function
+ * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
+ * Call with %ah = 0x42
+ * %dl = drive (0x0 for floppy disk, or emulated CD)
+ * %ds:%si = ptr to disk address packet
+ * Return:
+ * %ah = 0x0 on success; err code on failure
+ */
+
+ENTRY(biosreadlba)
+ push %ebp
+ mov %esp, %ebp
+
+ push %ebx
+ push %esi
+
+ movw 8(%ebp), %si
+ movl $0, %edx /* emulated CD is always drive 0 */
+
+ /* prot_to_real will set %es to BOOTSEG */
+ call EXT(prot_to_real) /* enter real mode */
+ movw $0x4200, %ax /* subfunction */
+ movb $0, %dl
+
+ sti
+ int $0x13
+ cli
+
+ /* save return value (actually movw %ax, %bx) */
+ mov %eax, %ebx
+
+ data32
+ call EXT(real_to_prot) /* back to protected mode */
+
+ xor %eax, %eax
+ movb %bh, %al /* return value in %ax */
+
+ pop %esi
+ pop %ebx
+ pop %ebp
+
+ ret
+
+#endif /* !CDBOOT */
+
+/*
+ * getc()
+ * BIOS call "INT 18H Function 00H" to read character from keyboard
+ * Call with %ah = 0x0
+ * Return: %ah = keyboard scan code
+ * %al = ASCII character
+ */
+
+ENTRY(getc)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx /* save %ebx */
+ push %esi
+ push %edi
+
+ call EXT(prot_to_real)
+
+ movb $0x0, %ah
+ int $0x18
+
+ movb %al, %bl /* real_to_prot uses %eax */
+
+ data32
+ call EXT(real_to_prot)
+
+ xor %eax, %eax
+ movb %bl, %al
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ pop %ebp
+ ret
+/*
+ * ischar()
+ * if there is a character pending, return it; otherwise return 0
+ * BIOS call "INT 18H Function 01H" to check whether a character is pending
+ * Call with %ah = 0x1
+ * Return:
+ * If key waiting to be input:
+ * %ah = keyboard scan code
+ * %al = ASCII character
+ * %bh = 1
+ * else
+ * %bh = 0
+ */
+ENTRY(ischar)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ call EXT(prot_to_real) /* enter real mode */
+
+ xor %ebx, %ebx
+ movb $0x1, %ah
+ int $0x18
+ andb %bh, %bh
+ data32
+ jz nochar
+ movb %al, %bl
+
+nochar:
+ data32
+ call EXT(real_to_prot)
+
+ xor %eax, %eax
+ movb %bl, %al
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ pop %ebp
+ ret
+
+/*
+ *
+ * get_diskinfo(): return a word that represents the
+ * max number of sectors and heads and drives for this device
+ *
+ */
+
+ENTRY(get_diskinfo)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ movb 0x8(%ebp), %dl /* diskinfo(drive #) */
+ call EXT(prot_to_real) /* enter real mode */
+
+ movb %dl, %al /* ask for disk info */
+ andb $0xf0, %al
+ cmpb $0x30, %al
+ jz fdd4
+ cmpb $0x90, %al
+ jz fdd
+
+ movb %dl, %al
+ movb $0x84, %ah
+
+ int $0x1b
+
+ jnc ok
+ /*
+ * Urk. Call failed. It is not supported for floppies by old BIOS's.
+ * Guess it's a 15-sector floppy.
+ */
+fdd4:
+ movb $18, %dl
+ jmp 1f
+fdd:
+ movb $15, %dl /* max sector */
+1:
+ subb %ah, %ah /* %ax = 0 */
+ movb %al, %al
+ movb %ah, %bh /* %bh = 0 */
+ movb $2, %bl /* %bl bits 0-3 = drive type,
+ bit 2 = 1.2M */
+ movb $79, %ch /* max track */
+ movb $1, %cl /* # floppy drives installed */
+ movb $2, %dh /* max head */
+ /* es:di = parameter table */
+ /* carry = 0 */
+ok:
+
+ data32
+ call EXT(real_to_prot) /* back to protected mode */
+
+ /*
+ * form a longword representing all this gunk:
+ * 16 bit cylinder
+ * 8 bit head
+ * 8 bit sector
+ */
+ mov %ecx, %eax
+ sall $16,%eax /* << 16 */
+ movb %dh, %ah /* max head */
+ movb %dl, %al /* max sector (and # sectors) */
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ pop %ebp
+ ret
+
+/*
+ *
+ * memsize(i) : return the memory size in KB. i == 0 for conventional memory,
+ * i == 1 for extended memory
+ * Both have the return value in AX.
+ *
+ */
+
+ENTRY(memsize)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+ push %esi
+ push %edi
+
+ mov 8(%ebp), %ebx
+
+ xor %eax, %eax
+ cmpb $0x01, %bl
+ jnz memcnv
+memext:
+ movb 0xA1401 - BOOTSEG * 0x10, %al
+ shll $7, %eax
+ xorl %ebx, %ebx
+ movw 0xA1594 - BOOTSEG * 0x10, %bx
+ shll $10, %ebx
+ addl %ebx, %eax
+ jmp xdone
+
+memcnv:
+ movb 0xA1501 - BOOTSEG * 0x10, %al
+ andb $0x07, %al
+ incl %eax
+ shll $7, %eax
+
+xdone:
+ pop %edi
+ pop %esi
+ pop %ebx
+ pop %ebp
+ ret
diff --git a/sys/boot/pc98/boot2/boot.c b/sys/boot/pc98/boot2/boot.c
new file mode 100644
index 0000000..0b4c3c4
--- /dev/null
+++ b/sys/boot/pc98/boot2/boot.c
@@ -0,0 +1,447 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, [92/04/03 16:51:14 rvb]
+ * $Id: boot.c,v 1.19 1998/10/11 15:09:14 kato Exp $
+ */
+
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <sys/param.h>
+#include "boot.h"
+#include <a.out.h>
+#include <sys/reboot.h>
+#include <machine/bootinfo.h>
+
+#define ouraddr (BOOTSEG << 4) /* XXX */
+
+#define BOOT_CONFIG_SIZE 512
+#define BOOT_HELP_SIZE 2048
+#define KERNEL_CONFIG_SIZE 512
+#define NAMEBUF_LEN 1024 /* oversized to defend against gets() */
+
+static char boot_config[BOOT_CONFIG_SIZE];
+static char boot_help[BOOT_HELP_SIZE];
+char *name;
+static char kernel_config[KERNEL_CONFIG_SIZE];
+static char kernel_config_namebuf[NAMEBUF_LEN + sizeof "config"];
+static char linebuf[NAMEBUF_LEN];
+static char namebuf[NAMEBUF_LEN];
+static struct bootinfo bootinfo;
+int loadflags;
+
+static void getbootdev(char *ptr, int *howto);
+static void loadprog(void);
+static void readfile(char *path, char *buf, size_t nbytes);
+
+/* NORETURN */
+void
+boot(int drive)
+{
+ int ret;
+#ifdef PC98
+ int i;
+ unsigned char disk_equips;
+#endif
+
+ /* Pick up the story from the Bios on geometry of disks */
+
+#ifdef PC98
+ for(ret = 0; ret < 2; ret ++) {
+ if (*(unsigned char*)V(0xA155d) & (1 << ret)) {
+ bootinfo.bi_bios_geom[ret] = get_diskinfo(ret + 0x80);
+ }
+#else /* IBM-PC */
+ for(ret = 0; ret < N_BIOS_GEOM; ret ++)
+ bootinfo.bi_bios_geom[ret] = get_diskinfo(ret + 0x80);
+#endif /* PC98 */
+ }
+
+ bootinfo.bi_basemem = memsize(0);
+ bootinfo.bi_extmem = memsize(1);
+ bootinfo.bi_memsizes_valid = 1;
+
+ gateA20();
+
+#ifdef PC98
+ /* set machine type to PC98_SYSTEM_PARAMETER */
+ machine_check();
+#endif /* PC98 */
+
+ /*
+ * The default boot device is the first partition in the
+ * compatibility slice on the boot drive.
+ */
+ dosdev = drive;
+#ifdef PC98
+ maj = (drive&0x70) >> 3; /* a good first bet */
+ if (maj == 4) { /* sd */
+ disk_equips = *(unsigned char *)V(0xA1482);
+ unit = 0;
+ for (i=0; i<(drive&0x0f); i++) {
+ unit += (disk_equips >> i) & 1;
+ }
+ } else {
+ unit = drive & 0x0f;
+ }
+#else /* IBM-PC */
+ maj = 2;
+ unit = drive & 0x7f;
+#ifdef dontneed
+ slice = 0;
+ part = 0;
+#endif
+ if (drive & 0x80) {
+ /* Hard drive. Adjust. */
+ maj = 0;
+#if BOOT_HD_BIAS > 0
+ if (unit >= BOOT_HD_BIAS) {
+ /*
+ * The drive is probably a SCSI drive with a unit
+ * number BOOT_HD_BIAS less than the BIOS drive
+ * number.
+ */
+ maj = 4;
+ unit -= BOOT_HD_BIAS;
+ }
+#endif
+ }
+#endif /* PC98 */
+ name = "/boot/loader";
+ if (boot_config[0] != '\0') {
+ printf("boot.config: %s", boot_config);
+ getbootdev(boot_config, &loadflags);
+ if (openrd() != 0)
+ name = "kernel";
+ }
+loadstart:
+ /* print this all each time.. (saves space to do so) */
+ /* If we have looped, use the previous entries as defaults */
+ printf("\r \n>> FreeBSD BOOT @ 0x%x: %d/%d k of memory, %s%s console\n"
+ "Boot default: %d:%s(%d,%c)%s\n"
+ "%s\n"
+ "boot: ",
+ ouraddr, bootinfo.bi_basemem, bootinfo.bi_extmem,
+ (loadflags & RB_SERIAL) ? "serial" : "internal",
+ (loadflags & RB_DUAL) ? "/dual" : "",
+#ifdef PC98
+ dosdev & 0x0f, devs[maj], unit, 'a' + part,
+#else
+ dosdev & 0x7f, devs[maj], unit, 'a' + part,
+#endif
+ name ? name : "*specify_a_kernel_name*",
+ boot_help);
+
+ /*
+ * Ignore flags from previous attempted boot, if any.
+ * XXX this is now too strict. Settings given in boot.config should
+ * not be changed.
+ */
+ loadflags &= (RB_DUAL | RB_SERIAL);
+
+ /*
+ * Be paranoid and make doubly sure that the input buffer is empty.
+ */
+ if (loadflags & (RB_DUAL | RB_SERIAL))
+ init_serial();
+
+ if (!gets(linebuf))
+ putchar('\n');
+ else
+ getbootdev(linebuf, &loadflags);
+ if (name == NULL)
+ goto loadstart;
+ ret = openrd();
+ if (ret != 0) {
+ if (ret > 0)
+ printf("Can't find %s\n", name);
+ goto loadstart;
+ }
+/* if (inode.i_mode&IEXEC)
+ loadflags |= RB_KDB;
+*/
+ loadprog();
+ goto loadstart;
+}
+
+static void
+loadprog(void)
+{
+ struct exec head;
+ int startaddr;
+ int addr; /* physical address.. not directly useable */
+ int bootdev;
+ int i;
+ unsigned pad;
+ char *s, *t;
+
+ read((void *)&head, sizeof(head));
+ if ( N_BADMAG(head)) {
+ printf("Invalid format!\n");
+ return;
+ }
+
+ poff = N_TXTOFF(head);
+ /*if(poff==0)
+ poff = 32;*/
+
+ /*
+ * We assume that the entry address is the same as the lowest text
+ * address and that the kernel startup code handles relocation by
+ * this address rounded down to a multiple of 16M.
+ */
+ startaddr = head.a_entry & 0x00FFFFFF;
+ addr = startaddr;
+ printf("Booting %d:%s(%d,%c)%s @ 0x%x\n"
+#ifdef PC98
+ , dosdev & 0x0f
+#else
+ , dosdev & 0x7f
+#endif
+ , devs[maj]
+ , unit
+ , 'a'+part
+ , name
+ , addr);
+ if(addr < 0x00100000)
+ {
+ /*
+ * Bail out, instead of risking to damage the BIOS
+ * variables, the loader, or the adapter memory area.
+ * We don't support loading below 1 MB any more.
+ */
+ printf("Start address too low\n");
+ return;
+ }
+ printf("text=0x%x ", head.a_text);
+ /********************************************************/
+ /* LOAD THE TEXT SEGMENT */
+ /********************************************************/
+ xread((void *)addr, head.a_text);
+ addr += head.a_text;
+
+ /********************************************************/
+ /* Load the Initialised data after the text */
+ /********************************************************/
+ while (addr & PAGE_MASK)
+ *(char *)addr++ = 0;
+
+ printf("data=0x%x ", head.a_data);
+ xread((void *)addr, head.a_data);
+ addr += head.a_data;
+
+ /********************************************************/
+ /* Skip over the uninitialised data */
+ /* (but clear it) */
+ /********************************************************/
+ printf("bss=0x%x ", head.a_bss);
+
+/*
+ * XXX however, we should be checking that we don't load ... into
+ * nonexistent memory. A full symbol table is unlikely to fit on 4MB
+ * machines.
+ */
+ /* kzip & kernel will zero their own bss */
+ addr += head.a_bss;
+
+ /* Pad to a page boundary. */
+ pad = (unsigned)addr & PAGE_MASK;
+ if (pad != 0) {
+ pad = PAGE_SIZE - pad;
+ addr += pad;
+ }
+ bootinfo.bi_symtab = addr;
+
+ /********************************************************/
+ /* Copy the symbol table size */
+ /********************************************************/
+ pcpy(&head.a_syms, (void *)addr, sizeof(head.a_syms));
+ addr += sizeof(head.a_syms);
+
+ /********************************************************/
+ /* Load the symbol table */
+ /********************************************************/
+ printf("symbols=[+0x%x+0x%x+0x%x", pad, sizeof(head.a_syms),
+ head.a_syms);
+ xread((void *)addr, head.a_syms);
+ addr += head.a_syms;
+
+ /********************************************************/
+ /* Load the string table size */
+ /********************************************************/
+ read((void *)&i, sizeof(int));
+ pcpy(&i, (void *)addr, sizeof(int));
+ i -= sizeof(int);
+ addr += sizeof(int);
+
+ /********************************************************/
+ /* Load the string table */
+ /********************************************************/
+ printf("+0x%x+0x%x]\n", sizeof(int), i);
+ xread((void *)addr, i);
+ addr += i;
+
+ bootinfo.bi_esymtab = addr;
+
+ /*
+ * For backwards compatibility, use the previously-unused adaptor
+ * and controller bitfields to hold the slice number.
+ */
+ bootdev = MAKEBOOTDEV(maj, (slice >> 4), slice & 0xf, unit, part);
+
+ bootinfo.bi_version = BOOTINFO_VERSION;
+ bootinfo.bi_kernelname = (u_int32_t)(name + ouraddr);
+ bootinfo.bi_nfs_diskless = 0;
+ bootinfo.bi_size = sizeof(bootinfo);
+ bootinfo.bi_bios_dev = dosdev;
+
+ /*
+ * Load the kernel config file (if any). Its name is given by
+ * appending ".config" to the kernel name. Build the name inline
+ * because no str*() functions are available. The file has to be
+ * copied to &disklabel for userconfig. It can't be loaded there
+ * directly because the label is used late in readfile() in some
+ * unusual cases, e.g., for bad144 handling.
+ */
+ s = name;
+ t = kernel_config_namebuf;
+ do
+ ;
+ while ((*t++ = *s++) != '\0');
+ s = ".config";
+ --t;
+ do
+ ;
+ while ((*t++ = *s++) != '\0');
+ readfile(kernel_config_namebuf, kernel_config, KERNEL_CONFIG_SIZE);
+ pcpy(kernel_config, (char *)&disklabel + ouraddr, KERNEL_CONFIG_SIZE);
+
+ printf("total=0x%x entry point=0x%x\n", addr, startaddr);
+ startprog(startaddr, loadflags | RB_BOOTINFO, bootdev,
+ (unsigned)&bootinfo + ouraddr);
+}
+
+static void
+readfile(char *path, char *buf, size_t nbytes)
+{
+ int openstatus;
+
+ buf[0] = '\0';
+ name = path;
+ openstatus = openrd();
+ if (openstatus != 0) {
+ if (openstatus > 0)
+ printf("Can't find file %s\n", name);
+ } else {
+ /* XXX no way to determine file size. */
+ read(buf, nbytes);
+ }
+ buf[nbytes - 1] = '\0';
+}
+
+static void
+getbootdev(char *ptr, int *howto)
+{
+ char c;
+ int f;
+ char *p;
+
+ /* Copy the flags to save some bytes. */
+ f = *howto;
+
+ c = *ptr;
+ for (;;) {
+nextarg:
+ while (c == ' ' || c == '\n')
+ c = *++ptr;
+ if (c == '-')
+ while ((c = *++ptr) != '\0') {
+ if (c == ' ' || c == '\n')
+ goto nextarg;
+ if (c == 'a')
+ f |= RB_ASKNAME;
+ if (c == 'C')
+ f |= RB_CDROM;
+ if (c == 'c')
+ f |= RB_CONFIG;
+ if (c == 'D')
+ f ^= RB_DUAL;
+ if (c == 'd')
+ f |= RB_KDB;
+ if (c == 'g')
+ f |= RB_GDB;
+ if (c == 'h')
+ f ^= RB_SERIAL;
+ if (c == 'P')
+ f |= RB_PROBEKBD;
+ if (c == 'r')
+ f |= RB_DFLTROOT;
+ if (c == 's')
+ f |= RB_SINGLE;
+ if (c == 'v')
+ f |= RB_VERBOSE;
+ }
+ if (c == '\0')
+ break;
+ p = name = namebuf;
+ while (c != '\0' && c != ' ' && c != '\n') {
+ *p++ = c;
+ c = *++ptr;
+ }
+ *p = '\0';
+ }
+ if (f & RB_PROBEKBD) {
+ if (probe_keyboard()) {
+ f |= RB_DUAL | RB_SERIAL;
+ printf("No keyboard found\n");
+ } else
+ printf("Keyboard found\n");
+ }
+ if (f & (RB_DUAL | RB_SERIAL))
+ init_serial();
+ *howto = f;
+}
diff --git a/sys/boot/pc98/boot2/boot.h b/sys/boot/pc98/boot2/boot.h
new file mode 100644
index 0000000..2104071
--- /dev/null
+++ b/sys/boot/pc98/boot2/boot.h
@@ -0,0 +1,109 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:03 rpd
+ * $Id: boot.h,v 1.14 1998/10/11 15:08:50 kato Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <ufs/ffs/fs.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+
+#define RB_DUAL 0x40000 /* XXX */
+#define RB_PROBEKBD 0x80000 /* XXX */
+
+extern char *devs[];
+extern char *name;
+extern struct fs *fs;
+extern struct inode inode;
+extern int dosdev, unit, slice, part, maj, boff, poff;
+extern unsigned tw_chars;
+extern int loadflags;
+extern struct disklabel disklabel;
+
+/* asm.S */
+#if ASM_ONLY
+void real_to_prot(void);
+void prot_to_real(void);
+#endif
+void startprog(unsigned int physaddr, int howto, int bootdev,
+ /* XXX struct bootinfo * */ unsigned int bootinfo);
+void pcpy(const void *src, void *dst, size_t count);
+
+/* bios.S */
+int biosread(int dev, int cyl, int head, int sec, int nsec, void *offset);
+void putc(int c);
+int getc(void);
+int ischar(void);
+int get_diskinfo(int drive);
+int memsize(int extended);
+
+/* boot.c */
+void boot(int drive);
+
+/* boot2.S */
+void boot2(void);
+
+/* disk.c */
+int devopen(void);
+void devread(char *iodest, int sector, int cnt);
+
+/* io.c */
+void gateA20(void);
+void printf(const char *format, ...);
+void putchar(int c);
+void delay1ms(void);
+int gets(char *buf);
+int strcmp(const char *s1, const char *s2);
+#ifdef CDBOOT
+int strcasecmp(const char *s1, const char *s2);
+#endif /* !CDBOOT */
+void bcopy(const void *from, void *to, size_t len);
+void twiddle(void);
+#ifdef PC98
+void machine_check(void);
+#endif
+
+/* probe_keyboard.c */
+int probe_keyboard(void);
+
+/* serial.S */
+void serial_putc(int ch);
+int serial_getc(void);
+int serial_ischar(void);
+void init_serial(void);
+
+/* sys.c */
+void xread(char *addr, int size);
+void read(char *buffer, int count);
+int openrd(void);
+
+#ifdef PC98
+#define V(ra) (ra - BOOTSEG * 0x10)
+#endif
+
diff --git a/sys/boot/pc98/boot2/boot2.S b/sys/boot/pc98/boot2/boot2.S
new file mode 100644
index 0000000..47b9a06
--- /dev/null
+++ b/sys/boot/pc98/boot2/boot2.S
@@ -0,0 +1,183 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:26 rpd
+ * boot2.S,v 1.6 1995/01/25 21:37:40 bde Exp
+ */
+/*
+ * Ported to PC-9801 by Yoshio Kimura
+ */
+
+#include "asm.h"
+
+/* Conventional GDT indexes. */
+#define BOOT_CS_INDEX 3
+#define BOOT_CS16_INDEX 5
+#define BOOT_DS_INDEX 4
+
+#ifdef BDE_DEBUGGER
+#define DB_CS_INDEX 14
+#define DB_CS16_INDEX 15
+#define DB_DS_INDEX 16
+#define GDT_INDEX 17
+#endif
+
+/* Vector numbers. */
+#define BREAKPOINT_VECTOR 3
+#define DEBUG_VECTOR 1
+
+/*
+ * boot2() -- second stage boot
+ * SP points to default string if found
+ */
+
+ENTRY(boot2)
+ data32
+ subl %eax, %eax
+ mov %cs, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ data32
+ shll $4, %eax
+
+ /* fix up GDT entries for bootstrap */
+#define FIXUP(gdt_index) \
+ addr32; \
+ movl %eax, EXT(Gdt)+(8*gdt_index)+2; /* actually movw %ax */ \
+ addr32; \
+ movb %bl, EXT(Gdt)+(8*gdt_index)+4
+
+ data32
+ shld $16, %eax, %ebx
+ FIXUP(BOOT_CS_INDEX)
+ FIXUP(BOOT_CS16_INDEX)
+ FIXUP(BOOT_DS_INDEX)
+
+ /* fix up GDT pointer */
+ data32
+ movl %eax, %ecx
+ data32
+ addl $ EXT(Gdt), %eax
+ addr32
+ data32
+ movl %eax, EXT(Gdtr)+2
+
+#ifdef BDE_DEBUGGER
+ /* fix up GDT entry for GDT */
+ data32
+ shld $16, %eax, %ebx
+ FIXUP(GDT_INDEX)
+
+ /* fix up IDT pointer */
+ data32
+ addl $ EXT(Idt), %ecx
+ addr32
+ data32
+ movl %ecx, EXT(Idtr_prot)+2
+
+ /* %es = vector table segment for a while */
+ push %es
+ data32
+ subl %eax, %eax
+ mov %ax, %es
+
+ /* fix up GDT entries for bdb */
+ data32
+ movl $4*DEBUG_VECTOR, %esi
+ addr32
+ movl %es: 2(%esi), %eax /* actually movw to %ax */
+ data32
+ shll $4, %eax
+ data32
+ shld $16, %eax, %ebx
+ FIXUP(DB_CS_INDEX)
+ FIXUP(DB_CS16_INDEX)
+ FIXUP(DB_DS_INDEX)
+
+ /* Fetch entry points of bdb's protected mode trap handlers. These
+ * are stored at 2 before the corresponding entry points for real mode.
+ */
+ data32
+ subl %ebx, %ebx
+ addr32
+ movl %es: (%esi), %ebx /* actually movw to %bx */
+ data32
+ subl %ecx, %ecx
+ addr32
+ movl %es: 4*(BREAKPOINT_VECTOR-DEBUG_VECTOR)(%esi), %ecx
+ /* actually movw to %cx */
+
+ /* %es = bdb segment for a while */
+ data32
+ shrl $4, %eax
+ mov %ax, %es
+
+ /* fix up IDT entries for bdb */
+ data32
+ subl $2, %ebx /* calculate EA to check it */
+ jb 1f /* give up if it would trap */
+ addr32
+ movl %es: (%ebx), %eax /* actually movw to %ax */
+ addr32
+ movl %eax, EXT(Idt)+8*DEBUG_VECTOR /* actually movw %ax */
+1:
+ data32
+ subl $2, %ecx
+ jb 1f
+ addr32
+ movl %es: (%ecx), %eax /* actually movw to %ax */
+ addr32
+ movl %eax, EXT(Idt)+8*BREAKPOINT_VECTOR /* actually movw %ax */
+1:
+
+ /* finished with groping in real mode segments */
+ pop %es
+#endif /* BDE_DEBUGGER */
+
+ /* change to protected mode */
+ data32
+ call EXT(real_to_prot)
+
+ /* clear the bss */
+ movl $ EXT(edata), %edi /* no EXT(_edata) - krufty ld */
+ movl $ EXT(end), %ecx /* or EXT(_end) */
+ subl %edi, %ecx
+ subb %al, %al
+ rep
+ stosb
+
+#ifdef NAMEBLOCK
+ movl %esp, EXT(dflt_name)
+#endif
+
+#ifdef PC98
+ movb 0xA1584 - BOOTSEG * 0x10, %dl
+#endif
+ movzbl %dl, %edx /* discard head (%dh) and random high bits */
+ pushl %edx
+ call EXT(boot)
+oops:
+ hlt
+ jmp oops
diff --git a/sys/boot/pc98/boot2/disk.c b/sys/boot/pc98/boot2/disk.c
new file mode 100644
index 0000000..7aa768c
--- /dev/null
+++ b/sys/boot/pc98/boot2/disk.c
@@ -0,0 +1,330 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:49 rpd
+ * $Id: disk.c,v 1.9 1997/05/28 09:22:59 kato Exp $
+ */
+
+/*
+ * Ported to PC-9801 by Yoshio Kimura
+ */
+
+/*
+ * 93/10/08 bde
+ * If there is no 386BSD partition, initialize the label sector with
+ * LABELSECTOR instead of with garbage.
+ *
+ * 93/08/22 bde
+ * Fixed reading of bad sector table. It is at the end of the 'c'
+ * partition, which is not always at the end of the disk.
+ */
+
+#include "boot.h"
+#ifdef DO_BAD144
+#include <sys/dkbad.h>
+#endif DO_BAD144
+#include <sys/disklabel.h>
+#include <sys/diskslice.h>
+
+#define BIOS_DEV_FLOPPY 0x0
+#define BIOS_DEV_WIN 0x80
+
+#define BPS 512
+#define SPT(di) ((di)&0xff)
+#define HEADS(di) (((di)>>8)&0xff)
+
+#ifdef DO_BAD144
+static struct dkbad dkb;
+static int do_bad144;
+#endif DO_BAD144
+static int bsize;
+
+static int spt, spc;
+
+struct fs *fs;
+struct inode inode;
+int dosdev, unit, slice, part, maj, boff;
+
+/*#define EMBEDDED_DISKLABEL 1*/
+
+/* Read ahead buffer large enough for one track on a 1440K floppy. For
+ * reading from floppies, the bootstrap has to be loaded on a 64K boundary
+ * to ensure that this buffer doesn't cross a 64K DMA boundary.
+ */
+#define RA_SECTORS 18
+static char ra_buf[RA_SECTORS * BPS];
+static int ra_dev;
+static int ra_end;
+static int ra_first;
+
+static int badsect(int sector);
+static char *Bread(int dosdev, int sector);
+
+int
+devopen(void)
+{
+ struct dos_partition *dptr;
+ struct disklabel *dl;
+ char *p;
+ int i, sector = 0, di, dosdev_copy;
+
+ dosdev_copy = dosdev;
+ di = get_diskinfo(dosdev_copy);
+ spc = (spt = SPT(di)) * HEADS(di);
+
+#ifndef RAWBOOT
+ if ((dosdev_copy & 0xf0) == 0x90)
+ {
+ boff = 0;
+ part = (spt == 15 ? 0 : 1);
+ }
+ else
+ {
+#ifdef EMBEDDED_DISKLABEL
+ dl = &disklabel;
+#else EMBEDDED_DISKLABEL
+#ifdef PC98
+ p = Bread(dosdev_copy, 1);
+ dptr = (struct dos_partition *)p;
+ slice = WHOLE_DISK_SLICE;
+ for (i = 0; i < NDOSPART; i++, dptr++)
+ if (dptr->dp_mid == DOSPTYP_386BSD) {
+ slice = BASE_SLICE + i;
+ sector = dptr->dp_scyl * spc;
+ break;
+ }
+ p = Bread(dosdev, sector + LABELSECTOR);
+ dl=((struct disklabel *)p);
+ disklabel = *dl; /* structure copy (maybe useful later)*/
+#else
+ p = Bread(dosdev_copy, 0);
+ dptr = (struct dos_partition *)(p+DOSPARTOFF);
+ slice = WHOLE_DISK_SLICE;
+ for (i = 0; i < NDOSPART; i++, dptr++)
+ if (dptr->dp_typ == DOSPTYP_386BSD) {
+ slice = BASE_SLICE + i;
+ sector = dptr->dp_start;
+ break;
+ }
+ p = Bread(dosdev_copy, sector + LABELSECTOR);
+ dl=((struct disklabel *)p);
+ disklabel = *dl; /* structure copy (maybe useful later)*/
+#endif /* PC98 */
+#endif EMBEDDED_DISKLABEL
+ if (dl->d_magic != DISKMAGIC) {
+ printf("bad disklabel\n");
+ return 1;
+ }
+ if( (maj == 4) || (maj == 0) || (maj == 1))
+ {
+ if (dl->d_type == DTYPE_SCSI)
+ {
+ maj = 4; /* use scsi as boot dev */
+ }
+ else
+ {
+ maj = 0; /* must be ESDI/IDE */
+ }
+ }
+ /* This little trick is for OnTrack DiskManager disks */
+ boff = dl->d_partitions[part].p_offset -
+ dl->d_partitions[2].p_offset + sector;
+
+#ifndef PC98
+ bsize = dl->d_partitions[part].p_size;
+ if (bsize == 0) {
+ printf("empty partition\n");
+ return 1;
+ }
+
+#endif
+
+#ifdef DO_BAD144
+ do_bad144 = 0;
+ if (dl->d_flags & D_BADSECT) {
+ /* this disk uses bad144 */
+ int i;
+ int dkbbnum;
+ struct dkbad *dkbptr;
+
+ /* find the first readable bad sector table */
+ /* some of this code is copied from ufs/ufs_disksubr.c */
+ /* including the bugs :-( */
+ /* read a bad sector table */
+
+#define BAD144_PART 2 /* XXX scattered magic numbers */
+#define BSD_PART 0 /* XXX should be 2 but bad144.c uses 0 */
+ if (dl->d_partitions[BSD_PART].p_offset != 0)
+ dkbbnum = dl->d_partitions[BAD144_PART].p_offset
+ + dl->d_partitions[BAD144_PART].p_size;
+ else
+ dkbbnum = dl->d_secperunit;
+ dkbbnum -= dl->d_nsectors;
+
+ if (dl->d_secsize > DEV_BSIZE)
+ dkbbnum *= dl->d_secsize / DEV_BSIZE;
+ else
+ dkbbnum /= DEV_BSIZE / dl->d_secsize;
+ i = 0;
+ do_bad144 = 0;
+ do {
+ /* XXX: what if the "DOS sector" < 512 bytes ??? */
+ p = Bread(dosdev_copy, dkbbnum + i);
+ dkbptr = (struct dkbad *) p;
+/* XXX why is this not in <sys/dkbad.h> ??? */
+#define DKBAD_MAGIC 0x4321
+ if (dkbptr->bt_mbz == 0 &&
+ dkbptr->bt_flag == DKBAD_MAGIC) {
+ dkb = *dkbptr; /* structure copy */
+ do_bad144 = 1;
+ break;
+ }
+ i += 2;
+ } while (i < 10 && (unsigned)i < dl->d_nsectors);
+ if (!do_bad144)
+ printf("Bad bad sector table\n");
+ else
+ printf("Using bad sector table at %d\n", dkbbnum+i);
+ }
+#endif /* DO_BAD144 */
+ }
+#endif /* RAWBOOT */
+ return 0;
+}
+
+
+/*
+ * Be aware that cnt is rounded up to N*BPS
+ */
+void
+devread(char *iodest, int sector, int cnt)
+{
+ int offset;
+ char *p;
+ int dosdev_copy;
+
+ for (offset = 0; offset < cnt; offset += BPS)
+ {
+ dosdev_copy = dosdev;
+ p = Bread(dosdev_copy, badsect(sector++));
+ bcopy(p, iodest+offset, BPS);
+ }
+}
+
+
+static char *
+Bread(int dosdev, int sector)
+{
+ if (dosdev != ra_dev || sector < ra_first || sector >= ra_end)
+ {
+ int cyl, head, sec, nsec;
+
+ cyl = sector/spc;
+#ifndef PC98
+ if (cyl > 1023) {
+ printf("Error: C:%d > 1023 (BIOS limit)\n", cyl);
+ for(;;); /* loop forever */
+ }
+#endif
+ head = (sector % spc) / spt;
+ sec = sector % spt;
+ nsec = spt - sec;
+ if (nsec > RA_SECTORS)
+ nsec = RA_SECTORS;
+ twiddle();
+ if (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0)
+ {
+ nsec = 1;
+ twiddle();
+ while (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0) {
+ printf("Error: D:0x%x C:%d H:%d S:%d\n",
+ dosdev, cyl, head, sec);
+ twiddle();
+ }
+ }
+ ra_dev = dosdev;
+ ra_first = sector;
+ ra_end = sector + nsec;
+ }
+ return (ra_buf + (sector - ra_first) * BPS);
+}
+
+static int
+badsect(int sector)
+{
+#if defined(DO_BAD144) && !defined(RAWBOOT)
+ int i;
+ if (do_bad144) {
+ u_short cyl;
+ u_short head;
+ u_short sec;
+ int newsec;
+ struct disklabel *dl = &disklabel;
+
+ /* XXX */
+ /* from wd.c */
+ /* bt_cyl = cylinder number in sorted order */
+ /* bt_trksec is actually (head << 8) + sec */
+
+ /* only remap sectors in the partition */
+ if (sector < boff || sector >= boff + bsize) {
+ goto no_remap;
+ }
+
+ cyl = (sector-boff) / dl->d_secpercyl;
+ head = ((sector-boff) % dl->d_secpercyl) / dl->d_nsectors;
+ sec = (sector-boff) % dl->d_nsectors;
+ sec = (head<<8) + sec;
+
+ /* now, look in the table for a possible bad sector */
+ for (i=0; i<126; i++) {
+ if (dkb.bt_bad[i].bt_cyl == cyl) {
+ /* found same cylinder */
+ if (dkb.bt_bad[i].bt_trksec == sec) {
+ /* FOUND! */
+ break;
+ }
+ } else if (dkb.bt_bad[i].bt_cyl > cyl) {
+ i = 126;
+ break;
+ }
+ }
+ if (i == 126) {
+ /* didn't find bad sector */
+ goto no_remap;
+ }
+ /* otherwise find replacement sector */
+ if (dl->d_partitions[BSD_PART].p_offset != 0)
+ newsec = dl->d_partitions[BAD144_PART].p_offset
+ + dl->d_partitions[BAD144_PART].p_size;
+ else
+ newsec = dl->d_secperunit;
+ newsec -= dl->d_nsectors + i + 1;
+ return newsec;
+ }
+ no_remap:
+#endif
+ return sector;
+}
diff --git a/sys/boot/pc98/boot2/io.c b/sys/boot/pc98/boot2/io.c
new file mode 100644
index 0000000..6047364
--- /dev/null
+++ b/sys/boot/pc98/boot2/io.c
@@ -0,0 +1,429 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:57 rpd
+ * $Id: io.c,v 1.13 1997/12/05 11:50:42 kato Exp $
+ */
+
+#include "boot.h"
+#include <machine/cpufunc.h>
+#include <sys/reboot.h>
+#ifdef PC98
+#include <pc98/pc98/pc98.h>
+#endif
+
+
+static int getchar(int in_buf);
+
+/*
+ * Gate A20 for high memory
+ */
+void
+gateA20(void)
+{
+ outb(0xf2, 0x00);
+ outb(0xf6, 0x02);
+}
+
+/* printf - only handles %d as decimal, %c as char, %s as string */
+
+void
+printf(const char *format, ...)
+{
+ int *dataptr = (int *)&format;
+ char c;
+
+ dataptr++;
+ while ((c = *format++))
+ if (c != '%')
+ putchar(c);
+ else
+ switch (c = *format++) {
+ case 'd': {
+ int num = *dataptr++;
+ char buf[10], *ptr = buf;
+ if (num<0) {
+ num = -num;
+ putchar('-');
+ }
+ do
+ *ptr++ = '0'+num%10;
+ while (num /= 10);
+ do
+ putchar(*--ptr);
+ while (ptr != buf);
+ break;
+ }
+ case 'x': {
+ unsigned int num = *dataptr++, dig;
+ char buf[8], *ptr = buf;
+ do
+ *ptr++ = (dig=(num&0xf)) > 9?
+ 'a' + dig - 10 :
+ '0' + dig;
+ while (num >>= 4);
+ do
+ putchar(*--ptr);
+ while (ptr != buf);
+ break;
+ }
+ case 'c': putchar((*dataptr++)&0xff); break;
+ case 's': {
+ char *ptr = (char *)*dataptr++;
+ while ((c = *ptr++))
+ putchar(c);
+ break;
+ }
+ }
+}
+
+void
+putchar(int c)
+{
+ if (c == '\n')
+ putchar('\r');
+ if (loadflags & RB_DUAL) {
+ putc(c);
+ serial_putc(c);
+ } else if (loadflags & RB_SERIAL)
+ serial_putc(c);
+ else
+ putc(c);
+}
+
+static int
+getchar(int in_buf)
+{
+ int c;
+
+loop:
+ if (loadflags & RB_DUAL) {
+ if (ischar())
+ c = getc();
+ else if (serial_ischar())
+ c = serial_getc();
+ else
+ goto loop;
+ } else if (loadflags & RB_SERIAL)
+ c = serial_getc();
+ else
+ c = getc();
+ if (c == '\r')
+ c = '\n';
+ if (c == '\b') {
+ if (in_buf != 0) {
+ putchar('\b');
+ putchar(' ');
+ } else {
+ goto loop;
+ }
+ }
+ putchar(c);
+ return(c);
+}
+
+/*
+ * This routine uses an inb to an unused port, the time to execute that
+ * inb is approximately 1.25uS. This value is pretty constant across
+ * all CPU's and all buses, with the exception of some PCI implentations
+ * that do not forward this I/O adress to the ISA bus as they know it
+ * is not a valid ISA bus address, those machines execute this inb in
+ * 60 nS :-(.
+ *
+ * XXX this should be converted to use bios_tick.
+ */
+void
+delay1ms(void)
+{
+#ifdef PC98
+ int i = 800;
+ while (--i >= 0)
+ (void)outb(0x5f,0); /* about 600ns */
+#else
+ int i = 800;
+ while (--i >= 0)
+ (void)inb(0x84);
+#endif
+}
+
+static __inline int
+isch(void)
+{
+ int isc;
+
+ /*
+ * Checking the keyboard has the side effect of enabling clock
+ * interrupts so that bios_tick works. Check the keyboard to
+ * get this side effect even if we only want the serial status.
+ */
+ isc = ischar();
+
+ if (loadflags & RB_DUAL) {
+ if (isc != 0)
+ return (isc);
+ } else if (!(loadflags & RB_SERIAL))
+ return (isc);
+ return (serial_ischar());
+}
+
+static __inline unsigned
+pword(unsigned physaddr)
+{
+#ifdef PC98
+ static int counter = 0;
+ int i;
+
+ for (i = 0; i < 512; i++)
+ (void)outb(0x5f, 0);
+
+ return (counter++);
+#else
+ unsigned result;
+
+ /*
+ * Give the fs prefix separately because gas omits it for
+ * "movl %fs:0x46c, %eax".
+ */
+ __asm __volatile("fs; movl %1, %0" : "=r" (result)
+ : "m" (*(unsigned *)physaddr));
+ return (result);
+#endif
+}
+
+int
+gets(char *buf)
+{
+#define bios_tick pword(0x46c)
+#ifdef PC98
+#define BIOS_TICK_MS 1
+#else
+#define BIOS_TICK_MS 55
+#endif
+ unsigned initial_bios_tick;
+ char *ptr=buf;
+
+#if BOOTWAIT
+ for (initial_bios_tick = bios_tick;
+ bios_tick - initial_bios_tick < BOOTWAIT / BIOS_TICK_MS;)
+#endif
+ if (isch())
+ for (;;) {
+ switch(*ptr = getchar(ptr - buf) & 0xff) {
+ case '\n':
+ case '\r':
+ *ptr = '\0';
+ return 1;
+ case '\b':
+ if (ptr > buf) ptr--;
+ continue;
+ default:
+ ptr++;
+ }
+#if TIMEOUT + 0
+#if !BOOTWAIT
+#error "TIMEOUT without BOOTWAIT"
+#endif
+ for (initial_bios_tick = bios_tick;;) {
+ if (isch())
+ break;
+ if (bios_tick - initial_bios_tick >=
+ TIMEOUT / BIOS_TICK_MS)
+ return 0;
+ }
+#endif
+ }
+ return 0;
+}
+
+int
+strcmp(const char *s1, const char *s2)
+{
+ while (*s1 == *s2) {
+ if (!*s1++)
+ return 0;
+ s2++;
+ }
+ return 1;
+}
+
+#ifdef CDBOOT
+int
+strcasecmp(const char *s1, const char *s2)
+{
+ /*
+ * We only consider ASCII chars and don't anticipate
+ * control characters (they are invalid in filenames
+ * anyway).
+ */
+ while ((*s1 & 0x5f) == (*s2 & 0x5f)) {
+ if (!*s1++)
+ return 0;
+ s2++;
+ }
+ return 1;
+}
+#endif /* !CDBOOT */
+
+void
+bcopy(const void *from, void *to, size_t len)
+{
+ char *fp = (char *)from;
+ char *tp = (char *)to;
+
+ while (len-- > 0)
+ *tp++ = *fp++;
+}
+
+/* To quote Ken: "You are not expected to understand this." :) */
+
+void
+twiddle(void)
+{
+ putchar((char)tw_chars);
+ tw_chars = (tw_chars >> 8) | ((tw_chars & (unsigned long)0xFF) << 24);
+ putchar('\b');
+}
+
+static unsigned short *Crtat = (unsigned short *)0;
+static int row;
+static int col;
+
+void putc(int c)
+{
+ static unsigned short *crtat;
+ unsigned char sys_type;
+ unsigned short *cp;
+ int i, pos;
+
+ if (Crtat == 0) {
+ sys_type = *(unsigned char *)V(0xA1501);
+ if (sys_type & 0x08) {
+ Crtat = (unsigned short *)V(0xE0000);
+ crtat = Crtat;
+ row = 31;
+ col = 80;
+ } else {
+ Crtat = (unsigned short *)V(0xA0000);
+ crtat = Crtat;
+ row = 25;
+ col = 80;
+ }
+ }
+
+ switch(c) {
+ case '\t':
+ do {
+ putc(' ');
+ } while ((int)crtat % 16);
+ break;
+ case '\b':
+ crtat--;
+ break;
+ case '\r':
+ crtat -= (crtat - Crtat) % col;
+ break;
+ case '\n':
+ crtat += col;
+ break;
+ default:
+ *crtat = (c == 0x5c ? 0xfc : c);
+ *(crtat++ + 0x1000) = 0xe1;
+ break;
+ }
+
+ if (crtat >= Crtat + col * row) {
+ cp = Crtat;
+ for (i = 1; i < row; i++) {
+ bcopy((void *)(cp+col), (void *)cp, col*2);
+ cp += col;
+ }
+ for (i = 0; i < col; i++) {
+ *cp++ = ' ';
+ }
+ crtat -= col;
+ }
+ pos = crtat - Crtat;
+ while((inb(0x60) & 0x04) == 0) {}
+ outb(0x62, 0x49);
+ outb(0x60, pos & 0xff);
+ outb(0x60, pos >> 8);
+}
+
+void machine_check(void)
+{
+ int ret;
+ int i;
+ int data = 0;
+ u_char epson_machine_id = *(unsigned char *)V(0xA1624);
+
+ /* PC98_SYSTEM_PARAMETER(0x501) */
+ ret = ((*(unsigned char*)V(0xA1501)) & 0x08) >> 3;
+
+ /* Wait V-SYNC */
+ while (inb(0x60) & 0x20) {}
+ while (!(inb(0x60) & 0x20)) {}
+
+ /* ANK 'A' font */
+ outb(0xa1, 0x00);
+ outb(0xa3, 0x41);
+
+ /* M_NORMAL, use CG window (all NEC OK) */
+ /* sum */
+ for (i = 0; i < 4; i++) {
+ data += *((unsigned long*)V(0xA4000) + i);/* 0xa4000 */
+ }
+ if (data == 0x6efc58fc) { /* DA data */
+ ret |= M_NEC_PC98;
+ } else {
+ ret |= M_EPSON_PC98;
+ }
+ ret |= (inb(0x42) & 0x20) ? M_8M : 0;
+
+ /* PC98_SYSTEM_PARAMETER(0x400) */
+ if ((*(unsigned char*)V(0xA1400)) & 0x80) {
+ ret |= M_NOTE;
+ }
+ if (ret & M_NEC_PC98) {
+ /* PC98_SYSTEM_PARAMETER(0x458) */
+ if ((*(unsigned char*)V(0xA1458)) & 0x80) {
+ ret |= M_H98;
+ } else {
+ ret |= M_NOT_H98;
+ }
+ } else {
+ ret |= M_NOT_H98;
+ switch (epson_machine_id) {
+ case 0x20: /* note A */
+ case 0x22: /* note W */
+ case 0x27: /* note AE */
+ case 0x2a: /* note WR */
+ ret |= M_NOTE;
+ break;
+ default:
+ break;
+ }
+ }
+ (*(unsigned long *)V(0xA1620)) = ret;
+}
diff --git a/sys/boot/pc98/boot2/probe_keyboard.c b/sys/boot/pc98/boot2/probe_keyboard.c
new file mode 100644
index 0000000..2450430
--- /dev/null
+++ b/sys/boot/pc98/boot2/probe_keyboard.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) KATO Takenori, 1994-1995. 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 as
+ * the first lines of this file unmodified.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "boot.h"
+
+int probe_keyboard(void)
+{
+ /*
+ * New type (RA and later) keyboard only!
+ */
+ if (*(unsigned char*)V(0xA1481) & 0x48)
+ return 0;
+ return 1; /* keyboard not found */
+}
+
diff --git a/sys/boot/pc98/boot2/serial.S b/sys/boot/pc98/boot2/serial.S
new file mode 100644
index 0000000..5123f0c
--- /dev/null
+++ b/sys/boot/pc98/boot2/serial.S
@@ -0,0 +1,201 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:34:26 rpd
+ * $Id: serial.S,v 1.8 1999/01/03 05:03:46 kato Exp $
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * Serial bootblock interface routines
+ * Copyright (c) 1994, J"org Wunsch
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ */
+
+#if COMCONSOLE == 0x238
+#include "../../../i386/boot/biosboot/serial.S"
+#else
+/*
+ * modified for PC-98 by KATO T. of Nagoya University
+ */
+
+ .file "serial.S"
+
+#include <i386/isa/sioreg.h>
+#include "asm.h"
+
+ .text
+
+/*
+ * The serial port interface routines implement a simple polled i/o
+ * interface to a standard serial port. Due to the space restrictions
+ * for the boot blocks, no BIOS support is used (since BIOS requires
+ * expensive real/protected mode switches), instead the rudimentary
+ * BIOS support is duplicated here.
+ *
+ * The base address for the i/o port is passed from the Makefile in
+ * the COMCONSOLE preprocessor macro. Console parameters are currently
+ * hard-coded to 9600 Bd, 8 bit. This can be changed in the
+ * init_serial() function.
+ */
+
+/*
+ * void serial_putc(char ch)
+ * send ch to serial port
+ *
+ */
+
+ENTRY(serial_putc)
+ mov $COMCONSOLE + 2, %edx # line status reg
+1: inb %dx, %al
+ testb $0x01, %al
+ jz 1b # TX buffer not empty
+
+ movb 0x4(%esp), %al
+
+ sub $2, %edx # TX output reg
+ outb %al, %dx # send this one
+
+ ret
+
+/*
+ * int serial_getc(void)
+ * read a character from serial port
+ */
+
+ENTRY(serial_getc)
+ mov $COMCONSOLE + 2, %edx # line status reg
+1:
+ inb %dx, %al
+ testb $0x02, %al
+ jz 1b # no RX char available
+
+ xorb %eax, %eax
+ subb $2, %edx # RX buffer reg
+ inb %dx, %al # fetch (first) character
+
+ cmp $0x7F, %eax # make DEL...
+ jne 2f
+ movb $0x08, %eax # look like BS
+2:
+ ret
+
+/*
+ * int serial_ischar(void)
+ * if there is a character pending, return true; otherwise return 0
+ */
+ENTRY(serial_ischar)
+ xorl %eax, %eax
+ movl $COMCONSOLE + 2, %edx # line status reg
+ inb %dx, %al
+ andb $0x02, %al # RX char available?
+
+ ret
+
+/*
+ * void init_serial(void)
+ * initialize the serial console port to 9600 Bd, 8 bpc
+ */
+ENTRY(init_serial)
+ /* set 8253 */
+ movb 0xb6, %al
+ outb %al, $0x77
+ movl $COMCONSOLE_CLK, %eax
+ outb %al, $0x75
+ inb $0x5f, %al
+ movb %ah, %al
+ outb %al, $0x75
+
+ /* inhibit com int */
+ inb $0x35, %al
+ andb $0xf8, %al
+ movb %al, %ah
+ inb $0x5f, %al
+ movb %ah, %al
+ outb %al, $0x35
+
+ inb $0x02, %al
+ orb $0x10, %al
+ outb %al, $0x02
+
+ /* dummy command */
+ xorb %al,%al
+ movl $COMCONSOLE + 2, %edx
+ outb %al, %dx
+ inb $0x5f, %al
+ xorb %al,%al
+ outb %al, %dx
+ inb $0x5f, %al
+ xorb %al,%al
+ outb %al, %dx
+ inb $0x5f, %al
+
+ /* RESET 8251 */
+ movb $0x40, %al
+ outb %al, %dx
+
+ movb $COMCONSOLE_MODE , %al
+ andb $0xfc, %al
+ orb $0x02, %al /* factor = 1/16 */
+ outb %al, %dx
+ inb $0x5f, %al
+
+ /* start RS-232C */
+ movb $0x37, %al
+ outb %al, %dx
+
+ ret
+#endif
diff --git a/sys/boot/pc98/boot2/start.S b/sys/boot/pc98/boot2/start.S
new file mode 100644
index 0000000..24459cd
--- /dev/null
+++ b/sys/boot/pc98/boot2/start.S
@@ -0,0 +1,535 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:36:29 rpd
+ * $Id: start.S,v 1.6 1998/07/30 02:27:41 alex Exp $
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+/*
+ * Ported to PC-9801 by Yoshio Kimura
+ */
+
+#include "asm.h"
+
+ .file "start.S"
+
+SIGNATURE= 0xaa55
+LOADSZ= 8192 /* size of unix boot */
+
+NAMEBLOCKMAGIC= 0xfadefeed /* value of magicnumebr for block2 */
+
+/*
+ * This DEBUGMSG(msg) macro may be useful for debugging. Its use is
+ * restricted to this file since it only works in real mode.
+ */
+#define DEBUGMSG(msg) \
+ data32 ; \
+ mov $msg, %esi ; \
+ data32 ; \
+ call message
+
+ .text
+ .globl start
+
+ENTRY(boot1)
+ jmp start
+
+boot_cyl:
+ .word 0
+ String "IPL1 "
+
+start:
+ /* set up %ds */
+ xor %ax, %ax
+ mov %ax, %ds
+
+ /* set up %ss and %esp */
+ data32
+ mov $BOOTSEG, %eax
+ mov %ax, %ss
+ /*
+ * make a little room on the stack for
+ * us to save the default bootstring we might find..
+ * effectively, we push the bootstring.
+ */
+ data32
+ mov $BOOTSTACK-64, %esp
+
+ /* set up %es, (where we will load boot2 to) */
+ mov %ax, %es
+
+ push %es
+ push %cx
+ push %dx
+
+ data32
+ mov $0xa000, %eax
+ mov %ax, %es
+
+ addr32
+ movb 0x501, %al
+ testb $0x08, %al
+ jnz hireso
+normal:
+ /* set up graphic screen */
+ movb $0x42, %ah
+ movb $0xc0, %ch
+ int $0x18
+ movb $0x40, %ah
+ int $0x18
+
+ data32
+ mov $0x0a00, %eax /* 80 x 25 mode */
+ jmp 1f
+hireso:
+ movb $0x08, %al /* set up RAM window */
+ outb %al, $0x91
+ movb $0x0a, %al
+ outb %al, $0x93
+ data32
+ mov $0x0a10, %ax /* 80 x 31 mode */
+1:
+ int $0x18
+ movb $0x0c, %ah /* text on */
+ int $0x18
+
+ /* cursor home and on */
+ xor %edx, %edx
+ movb $0x13, %ah
+ int $0x18
+ movb $0x11, %ah
+ int $0x18
+
+ /* highreso no supported */
+ addr32
+ movb 0x501, %al
+ testb $0x08, %al
+ jz nothireso
+
+ data32
+ mov $ehireso, %esi
+ data32
+ call message
+ hlt
+
+nothireso:
+ /* keyboad reset */
+ movb $0x03, %ah
+ int $0x18
+
+ /* transfer PC-9801 system common area to 0xa1000 */
+ data32
+ mov $0x0000, %esi
+ data32
+ mov $0x1000, %edi
+ data32
+ mov $0x0630, %ecx
+ cld
+ rep
+ movsb
+
+ /* transfer EPSON machine type to 0xa1200 */
+ push %ds
+ data32
+ mov $0xfd00, %eax
+ mov %ax, %ds
+ addr32
+ data32
+ mov 0x804, %eax
+ data32
+ and $0x00ffffff, %eax
+ addr32
+ data32
+ .byte 0x26
+ mov %eax, %es: (0x1624)
+
+ pop %ds
+ pop %dx
+ pop %cx
+ pop %es
+
+ /* bootstrap passes */
+ mov %cs, %bx
+ data32
+ cmp $0x1fe0, %ebx
+ jz fd
+ data32
+ cmp $0x1fc0, %ebx
+ jnz hd
+ data32
+ mov %ebp, %ecx
+ data32
+ mov %ebp, %edx
+ addr32
+ movb 0x584, %al
+ andb $0xf0, %al
+ cmpb $0x30, %al
+ jz fd
+ cmpb $0x90, %al
+ jnz hd
+fd:
+ data32
+ mov $0x0200, %ecx
+ data32
+ mov $0x0001, %edx
+ movb $0xd6, %ah
+ jmp load
+hd:
+ data32
+ and %ecx, %ecx
+ jnz 1f
+ addr32
+ data32
+ mov %cs: (boot_cyl), %ecx
+1:
+ movb $0x06, %ah
+
+/*
+ * BIOS call "INT 0x1B Function 0xn6" to read sectors from disk into memory
+ * Call with %ah = 0xd6(for floppy disk) or 0x06(for hard disk)
+ * %al = DA/UA
+ * %bx = data length
+ * %ch = sector size(for floppy) or cylinder(for hard)
+ * %cl = cylinder
+ * %dh = head
+ * %dl = sector
+ * %es:%bp = segment:offset of buffer
+ * Return:
+ * %ah = 0x0 on success; err code on failure
+ */
+
+load:
+#ifdef NAMEBLOCK
+/*
+ * Load the second sector and see if it is a boot instruction block.
+ * If it is then scan the contents for the first valid string and copy it to
+ * the location of the default boot string.. then zero it out.
+ * Finally write the block back to disk with the zero'd out entry..
+ * I hate writing at this stage but we need this to be persistant.
+ * If the boot fails, then the next boot will get the next string.
+ * /etc/rc will regenerate a complete block2 iff the boot succeeds.
+ *
+ * Format of block 2 is:
+ * [NAMEBLOCKMAGIC] <--0xdeafc0de
+ * [nulls]
+ * [bootstring]NULL <---e.g. 0:wd(0,a)/kernel.experimental
+ * [bootstring]NULL <---e.g. 0:wd(0,a)/kernel.old
+ * ....
+ * [bootstring]NULL <---e.g. 0:wd(0,f)/kernel
+ * FF FF FF
+ */
+where:
+ /*
+ * save things we might smash
+ * (that are not smashed immedatly after us anyway.)
+ */
+ data32
+ push %ecx /* preserve 'cyl,sector ' */
+ data32
+ push %edx
+/*
+ * Load the second sector
+ * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
+ * Call with %ah = 0x2
+ * %al = number of sectors
+ * %ch = cylinder
+ * %cl = sector
+ * %dh = head
+ * %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
+ * %es:%bx = segment:offset of buffer
+ * Return:
+ * %al = 0x0 on success; err code on failure
+ */
+ data32
+ movl $0x0201, %eax /function 2 (read) 1 sector */
+ xor %ebx, %ebx /* %bx = 0 */ /* buffer address (ES:0) */
+ data32
+ movl $0x0002, %ecx /* sector 2, cylinder 0 */
+ data32
+ andl $0x00ff, %edx /* head 0, drive N */
+ int $0x13
+ data32
+ jb read_error
+ /*
+ * confirm that it is one for us
+ */
+ data32
+ xorl %ebx, %ebx /* magic number at start of buffer */
+ data32
+ addr32
+ movl %es:(%ebx), %eax
+ data32
+ cmpl $NAMEBLOCKMAGIC, %eax
+ data32
+ jne notours /* not ours so return to caller */
+ /*
+ * scan for a bootstring
+ * Skip the magic number, and scan till we find a non-null,
+ * or a -1
+ */
+ incl %ebx /* quicker and smaller */
+ incl %ebx
+ incl %ebx
+scan:
+ incl %ebx
+ addr32
+ movb %es:(%ebx), %al /* load the next byte */
+ testb %al, %al /* and if it is null */
+ data32 /* keep scanning (past deleted entries) */
+ jz scan
+ incb %al /* now look for -1 */
+ data32
+ jz notours /* if we reach the 0xFF then we have finished */
+
+ /*
+ * save our settings.. we need them twice..
+ */
+ data32
+ push %ebx
+ /*
+ * copy it to the default string location
+ * which is just above the stack for 64 bytes.
+ */
+ data32
+ movl $BOOTSTACK-64, %ecx /* 64 bytes at the top of the stack */
+nxtbyte:
+ addr32
+ movb %es:(%ebx), %al /* get the next byte in */
+ addr32
+ movb %al, %es:(%ecx) /* and transfer it to the name buffer */
+ incl %ebx /* get on with the next byte */
+ incl %ecx /* get on with the next byte */
+ testb %al, %al /* if it was 0 then quit this */
+ data32
+ jnz nxtbyte /* and looop if more to do */
+
+ /*
+ * restore the saved settings and
+ * zero it out so next time we don't try it again
+ */
+ data32
+ pop %ebx /* get back our starting location */
+#ifdef NAMEBLOCK_WRITEBACK
+nxtbyte2:
+ addr32
+ movb %es:(%ebx), %al /* get the byte */
+ addr32
+ movb $0, %es:(%ebx) /* zero it out */
+ data32
+ incl %ebx /* point to the next byte */
+ testb %al, %al /* check if we have finished.. */
+ data32
+ jne nxtbyte2
+/*
+ * Write the second sector back
+ * Load the second sector
+ * BIOS call "INT 0x13 Function 0x3" to write sectors from memory to disk
+ * Call with %ah = 0x3
+ * %al = number of sectors
+ * %ch = cylinder
+ * %cl = sector
+ * %dh = head
+ * %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
+ * %es:%bx = segment:offset of buffer
+ * Return:
+ * %al = 0x0 on success; err code on failure
+ */
+ data32
+ movl $0x0301, %eax /* write 1 sector */
+ xor %ebx, %ebx /* buffer is at offset 0 */
+ data32
+ movl $0x0002, %ecx /* block 2 */
+ data32
+ andl $0xff, %edx /* head 0 */
+ int $0x13
+ data32
+ jnb notours
+ data32
+ mov $eread, %esi
+ jmp err_stop
+#endif /* NAMEBLOCK_WRITEBACK */
+ /*
+ * return to the main-line
+ */
+notours:
+ data32
+ pop %edx
+ data32
+ pop %ecx
+#endif
+ data32
+ mov $LOADSZ, %ebx
+ addr32
+ movb 0x584, %al
+ xor %ebp, %ebp /* %bp = 0, put it at 0 in the BOOTSEG */
+ int $0x1b
+ jc read_error
+
+ /*
+ * ljmp to the second stage boot loader (boot2).
+ * After ljmp, %cs is BOOTSEG and boot1 (512 bytes) will be used
+ * as an internal buffer "intbuf".
+ */
+
+ data32
+ ljmp $BOOTSEG, $ EXT(boot2)
+
+/*
+ * read_error
+ */
+read_error:
+ data32
+ mov $eread, %esi
+err_stop:
+ data32
+ call message
+ data32
+ jmp stop
+
+/*
+ * message: write the error message in %ds:%esi to console
+ */
+message:
+
+ data32
+ push %eax
+ data32
+ push %ebx
+ push %ds
+ push %es
+ data32
+ mov $0xe000, %eax
+ mov %ax, %es
+ addr32
+ mov 0x501, %al
+ testb $0x08, %al
+ jnz 1f
+ data32
+ mov $0xa000, %eax
+ mov %ax, %es
+1:
+ mov %cs, %ax
+ mov %ax, %ds
+ addr32
+ data32
+ mov vram, %edi
+ data32
+ mov $0x00e1, %ebx
+ cld
+
+nextb:
+ lodsb /* load a byte into %al */
+ cmpb $0x0, %al
+ je done
+ cmpb $0x0d, %al
+ je cr_code
+ cmpb $0x0a, %al
+ je lf_code
+ addr32
+ movb %al, (%edi)
+ addr32
+ movb %bl, 0x2000(%edi)
+ data32
+ inc %edi
+ data32
+ inc %edi
+ jmp nextb
+cr_code:
+ data32
+ add $80, %edi
+ jmp nextb
+lf_code:
+ data32
+ mov %edi, %eax
+ data32
+ mov $80, %edx
+ data32
+ div %ebx
+ data32
+ sub %ebx, %edi
+ jmp nextb
+done:
+ addr32
+ data32
+ mov %edi, vram
+ pop %es
+ pop %ds
+ data32
+ pop %ebx
+ data32
+ pop %eax
+ data32
+ ret
+
+stop: hlt
+ data32
+ jmp stop /* halt doesnt actually halt forever */
+
+vram:
+ .long 0
+
+/* error messages */
+
+
+#ifdef DEBUG
+one: String "1-\0"
+two: String "2-\0"
+three: String "3-\0"
+four: String "4-\0"
+#endif DEBUG
+#ifdef NAMEBLOCK_WRITEBACK
+ewrite: String "Write error\r\n\0"
+#endif /* NAMEBLOCK_WRITEBACK */
+eread: String "Read error\r\n\0"
+enoboot: String "No bootable partition\r\n\0"
+endofcode:
+ehireso: String "Highreso not supported\r\n\0"
+/* the last 2 bytes in the sector 0 contain the signature */
+ . = EXT(boot1) + 0x1fe
+ .value SIGNATURE
+ENTRY(disklabel)
+ . = EXT(boot1) + 0x400
diff --git a/sys/boot/pc98/boot2/sys.c b/sys/boot/pc98/boot2/sys.c
new file mode 100644
index 0000000..591d432
--- /dev/null
+++ b/sys/boot/pc98/boot2/sys.c
@@ -0,0 +1,337 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:36:34 rpd
+ * $Id: sys.c,v 1.15 1998/05/02 02:06:08 kato Exp $
+ */
+
+/*
+ * Ported to PC-9801 by Yoshio Kimura
+ */
+
+#include "boot.h"
+#include <sys/dirent.h>
+#include <sys/reboot.h>
+
+#if 0
+/* #define BUFSIZE 4096 */
+#define BUFSIZE MAXBSIZE
+static char buf[BUFSIZE], fsbuf[SBSIZE], iobuf[MAXBSIZE];
+#endif
+
+static char biosdrivedigit;
+
+#define BUFSIZE 8192
+#define MAPBUFSIZE BUFSIZE
+static char buf[BUFSIZE], fsbuf[BUFSIZE], iobuf[BUFSIZE];
+
+static char mapbuf[MAPBUFSIZE];
+static int mapblock;
+
+int poff;
+
+#ifdef RAWBOOT
+#define STARTBYTE 8192 /* Where on the media the kernel starts */
+#endif
+
+static int block_map(int file_block);
+static int find(char *path);
+
+void
+xread(char *addr, int size)
+{
+ int count = BUFSIZE;
+ while (size > 0) {
+ if (BUFSIZE > size)
+ count = size;
+ read(buf, count);
+ pcpy(buf, addr, count);
+ size -= count;
+ addr += count;
+ }
+}
+
+#ifndef RAWBOOT
+void
+read(char *buffer, int count)
+{
+ int logno, off, size;
+ int cnt2, bnum2;
+ struct fs *fs_copy;
+
+ while (count > 0 && poff < inode.i_size) {
+ fs_copy = fs;
+ off = blkoff(fs_copy, poff);
+ logno = lblkno(fs_copy, poff);
+ cnt2 = size = blksize(fs_copy, &inode, logno);
+ bnum2 = fsbtodb(fs_copy, block_map(logno)) + boff;
+ if ( (!off) && (size <= count)) {
+ devread(buffer, bnum2, cnt2);
+ } else {
+ size -= off;
+ if (size > count)
+ size = count;
+ devread(iobuf, bnum2, cnt2);
+ bcopy(iobuf+off, buffer, size);
+ }
+ buffer += size;
+ count -= size;
+ poff += size;
+ }
+}
+#else
+void
+read(char *buffer, int count)
+{
+ int cnt, bnum, off, size;
+
+ off = STARTBYTE + poff;
+ poff += count;
+
+ /* Read any unaligned bit at the front */
+ cnt = off & 511;
+ if (cnt) {
+ size = 512-cnt;
+ if (count < size)
+ size = count;
+ devread(iobuf, off >> 9, 512);
+ bcopy(iobuf+cnt, buffer, size);
+ count -= size;
+ off += size;
+ buffer += size;
+ }
+ size = count & (~511);
+ if (size && (off & (~511))) {
+ devread(buffer, off >> 9, size);
+ off += size;
+ count -= size;
+ buffer += size;
+ }
+ if (count) {
+ devread(iobuf, off >> 9, 512);
+ bcopy(iobuf, buffer, count);
+ }
+}
+#endif
+
+static int
+find(char *path)
+{
+ char *rest, ch;
+ int block, off, loc, ino = ROOTINO;
+ struct dirent *dp;
+ char list_only;
+
+ list_only = (path[0] == '?' && path[1] == '\0');
+loop:
+ devread(iobuf, fsbtodb(fs, ino_to_fsba(fs, ino)) + boff, fs->fs_bsize);
+ bcopy((void *)&((struct dinode *)iobuf)[ino % fs->fs_inopb],
+ (void *)&inode.i_din,
+ sizeof (struct dinode));
+ if (!*path)
+ return 1;
+ while (*path == '/')
+ path++;
+ if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR))
+ return 0;
+ for (rest = path; (ch = *rest) && ch != '/'; rest++) ;
+ *rest = 0;
+ loc = 0;
+ do {
+ if (loc >= inode.i_size) {
+ if (list_only) {
+ putchar('\n');
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ if (!(off = blkoff(fs, loc))) {
+ block = lblkno(fs, loc);
+ devread(iobuf, fsbtodb(fs, block_map(block)) + boff,
+ blksize(fs, &inode, block));
+ }
+ dp = (struct dirent *)(iobuf + off);
+ loc += dp->d_reclen;
+ if (dp->d_fileno && list_only)
+ printf("%s ", dp->d_name);
+ } while (!dp->d_fileno || strcmp(path, dp->d_name));
+ ino = dp->d_fileno;
+ *(path = rest) = ch;
+ goto loop;
+}
+
+
+static int
+block_map(int file_block)
+{
+ int bnum;
+ if (file_block < NDADDR)
+ return(inode.i_db[file_block]);
+ if ((bnum=fsbtodb(fs, inode.i_ib[0])+boff) != mapblock) {
+ devread(mapbuf, bnum, fs->fs_bsize);
+ mapblock = bnum;
+ }
+ return (((int *)mapbuf)[(file_block - NDADDR) % NINDIR(fs)]);
+}
+
+
+int
+openrd(void)
+{
+ char **devp, *name0 = name, *cp = name0;
+ int biosdrive, dosdev_copy, ret;
+
+ /*******************************************************\
+ * If bracket given look for preceding device name *
+ \*******************************************************/
+ while (*cp && *cp!='(')
+ cp++;
+ if (!*cp)
+ {
+ cp = name0;
+ }
+ else
+ {
+ /*
+ * Look for a BIOS drive number (a leading digit followed
+ * by a colon).
+ */
+ biosdrivedigit = '\0';
+ if (*(name0 + 1) == ':' && *name0 >= '0' && *name0 <= '9') {
+ biosdrivedigit = *name0;
+ name0 += 2;
+ }
+
+ if (cp++ != name0)
+ {
+ for (devp = devs; *devp; devp++)
+ if (name0[0] == (*devp)[0] &&
+ name0[1] == (*devp)[1])
+ break;
+ if (!*devp)
+ {
+ printf("Unknown device\n");
+ return 1;
+ }
+ maj = devp-devs;
+ }
+ /*******************************************************\
+ * Look inside brackets for unit number, and partition *
+ \*******************************************************/
+ /*
+ * Allow any valid digit as the unit number, as the BIOS
+ * will complain if the unit number is out of range.
+ * Restricting the range here prevents the possibilty of using
+ * BIOSes that support more than 2 units.
+ * XXX Bad values may cause strange errors, need to check if
+ * what happens when a value out of range is supplied.
+ */
+ if (*cp >= '0' && *cp <= '9')
+ unit = *cp++ - '0';
+ if (!*cp || (*cp == ',' && !*++cp))
+ return 1;
+ if (*cp >= 'a' && *cp <= 'p')
+ part = *cp++ - 'a';
+ while (*cp && *cp++!=')') ;
+ if (!*cp)
+ return 1;
+ }
+ biosdrive = biosdrivedigit - '0';
+ if (biosdrivedigit == '\0') {
+#ifdef PC98
+ biosdrive = dosdev & 0x0f;
+#else
+ biosdrive = unit;
+#endif
+#if BOOT_HD_BIAS > 0
+ /* XXX */
+ if (maj == 4)
+ biosdrive += BOOT_HD_BIAS;
+#endif
+ }
+ switch(maj)
+ {
+#ifdef PC98
+ case 4: /* sd */
+ dosdev_copy = biosdrive | 0xa0;
+#else /* IBM-PC */
+ case 0:
+ case 4:
+ dosdev_copy = biosdrive | 0x80;
+#endif
+ break;
+#ifdef PC98
+ case 0:
+ case 2:
+ dosdev_copy = (maj << 3) | unit | 0x80;
+#else
+ case 2:
+ dosdev_copy = biosdrive;
+#endif
+ break;
+#ifdef PC98
+ case 6:/* 1.44MB FD */
+ dosdev_copy = (maj << 3) | unit;
+ break;
+#endif
+ default:
+ printf("Unknown device\n");
+ return 1;
+ }
+ dosdev = dosdev_copy;
+#if 0
+ /* XXX this is useful, but misplaced. */
+ printf("dosdev= %x, biosdrive = %d, unit = %d, maj = %d\n",
+ dosdev_copy, biosdrive, unit, maj);
+#endif
+
+ /***********************************************\
+ * Now we know the disk unit and part, *
+ * Load disk info, (open the device) *
+ \***********************************************/
+ if (devopen())
+ return 1;
+
+#ifndef RAWBOOT
+ /***********************************************\
+ * Load Filesystem info (mount the device) *
+ \***********************************************/
+ devread((char *)(fs = (struct fs *)fsbuf), SBLOCK + boff, SBSIZE);
+ /***********************************************\
+ * Find the actual FILE on the mounted device *
+ \***********************************************/
+ ret = find(cp);
+ name = cp;
+ if (ret == 0)
+ return 1;
+ if (ret < 0) {
+ name = NULL;
+ return -1;
+ }
+ poff = 0;
+#endif /* RAWBOOT */
+ return 0;
+}
diff --git a/sys/boot/pc98/boot2/table.c b/sys/boot/pc98/boot2/table.c
new file mode 100644
index 0000000..ed5a028
--- /dev/null
+++ b/sys/boot/pc98/boot2/table.c
@@ -0,0 +1,149 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:36:43 rpd
+ * $Id: table.c,v 1.8 1998/10/11 15:09:36 kato Exp $
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "boot.h"
+
+/* Segment Descriptor
+ *
+ * 31 24 19 16 7 0
+ * ------------------------------------------------------------
+ * | | |B| |A| | | |1|0|E|W|A| |
+ * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 |
+ * | | |D| |L| 19..16| | |1|1|C|R|A| |
+ * ------------------------------------------------------------
+ * | | |
+ * | BASE 15..0 | LIMIT 15..0 |
+ * | | |
+ * ------------------------------------------------------------
+ */
+
+struct seg_desc {
+ unsigned short limit_15_0;
+ unsigned short base_15_0;
+ unsigned char base_23_16;
+ unsigned char p_dpl_type;
+ unsigned char g_b_a_limit;
+ unsigned char base_31_24;
+ };
+
+#define RUN 0 /* not really 0, but filled in at boot time */
+
+struct seg_desc Gdt[] = {
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 0x0 : null */
+ {0xFFFF, 0x0, 0x0, 0x9F, 0xCF, 0x0}, /* 0x08 : kernel code */
+ /* 0x9E? */
+ {0xFFFF, 0x0, 0x0, 0x93, 0xCF, 0x0}, /* 0x10 : kernel data */
+ /* 0x92? */
+ {0xFFFF, RUN, RUN, 0x9E, 0x40, 0x0}, /* 0x18 : boot code */
+#ifdef PC98
+ /*
+ * The limit of boot data should be more than or equal to 0x9FFFF
+ * for saving BIOS parameter and EPSON machine ID into 2'nd T-VRAM,
+ * because base address is normally 0x10000.
+ */
+ {0xFFFF, RUN, RUN, 0x92, 0x4F, 0x0}, /* 0x20 : boot data */
+#else
+ {0xFFFF, RUN, RUN, 0x92, 0x40, 0x0}, /* 0x20 : boot data */
+#endif
+ {0xFFFF, RUN, RUN, 0x9E, 0x0, 0x0}, /* 0x28 : boot code, 16 bits */
+ {0xFFFF, 0x0, 0x0, 0x92, 0x0, 0x0}, /* 0x30 : boot data, 16 bits */
+#ifdef BDE_DEBUGGER
+ /* More for bdb. */
+ {}, /* BIOS_TMP_INDEX = 7 : null */
+ {}, /* TSS_INDEX = 8 : null */
+ {0xFFFF, 0x0, 0x0, 0xB2, 0x40, 0x0}, /* DS_286_INDEX = 9 */
+ {0xFFFF, 0x0, 0x0, 0xB2, 0x40, 0x0}, /* ES_286_INDEX = 10 */
+ {}, /* Unused = 11 : null */
+ {0x7FFF, 0x8000, 0xB, 0xB2, 0x40, 0x0}, /* COLOR_INDEX = 12 */
+ {0x7FFF, 0x0, 0xB, 0xB2, 0x40, 0x0}, /* MONO_INDEX = 13 */
+ {0xFFFF, RUN, RUN, 0x9A, 0x40, 0x0}, /* DB_CS_INDEX = 14 */
+ {0xFFFF, RUN, RUN, 0x9A, 0x0, 0x0}, /* DB_CS16_INDEX = 15 */
+ {0xFFFF, RUN, RUN, 0x92, 0x40, 0x0}, /* DB_DS_INDEX = 16 */
+ {8*18-1, RUN, RUN, 0x92, 0x40, 0x0}, /* GDT_INDEX = 17 */
+#endif /* BDE_DEBUGGER */
+};
+
+#ifdef BDE_DEBUGGER
+struct idt_desc {
+ unsigned short entry_15_0;
+ unsigned short selector;
+ unsigned char padding;
+ unsigned char p_dpl_type;
+ unsigned short entry_31_16;
+};
+
+struct idt_desc Idt[] = {
+ {}, /* Null (int 0) */
+ {RUN, 0x70, 0, 0x8E, 0}, /* DEBUG_VECTOR = 1 */
+ {}, /* Null (int 2) */
+ {RUN, 0x70, 0, 0xEE, 0}, /* BREAKPOINT_VECTOR = 3 */
+};
+#endif /* BDE_DEBUGGER */
+
+struct pseudo_desc {
+ unsigned short limit;
+ unsigned short base_low;
+ unsigned short base_high;
+ };
+
+struct pseudo_desc Gdtr = { sizeof Gdt - 1, RUN, RUN };
+#ifdef BDE_DEBUGGER
+struct pseudo_desc Idtr_prot = { sizeof Idt - 1, RUN, RUN };
+struct pseudo_desc Idtr_real = { 0x400 - 1, 0x0, 0x0 };
+#endif
+
+/*
+ * All initialized data is defined in one file to reduce space wastage from
+ * fragmentation.
+ */
+char *devs[] = { "wd", "dk", "fd", "wt", "da", 0 };
+unsigned tw_chars = 0x5C2D2F7C; /* "\-/|" */
diff --git a/sys/boot/pc98/btx/Makefile b/sys/boot/pc98/btx/Makefile
new file mode 100644
index 0000000..49d05f0
--- /dev/null
+++ b/sys/boot/pc98/btx/Makefile
@@ -0,0 +1,5 @@
+# $Id: Makefile,v 1.4 1998/09/17 23:52:03 msmith Exp $
+
+SUBDIR= btx btxldr lib # client ldrtst
+
+.include <bsd.subdir.mk>
diff --git a/sys/boot/pc98/btx/btx/Makefile b/sys/boot/pc98/btx/btx/Makefile
new file mode 100644
index 0000000..b74deea
--- /dev/null
+++ b/sys/boot/pc98/btx/btx/Makefile
@@ -0,0 +1,25 @@
+# $Id: Makefile,v 1.5 1998/10/13 18:29:18 rnordier Exp $
+
+M4?= m4
+
+ORG= 0x9000
+
+AFLAGS+= --defsym PC98=1
+
+all: btx
+
+btx: btx.o
+.if ${OBJFORMAT} == aout
+ ${LD} -nostdlib -N -s -T ${ORG} -o btx.out btx.o
+ dd if=btx.out of=${.TARGET} ibs=32 skip=1
+.else
+ ${LD} -N -e start -Ttext ${ORG} -o btx.out btx.o
+ objcopy -S -O binary btx.out ${.TARGET}
+.endif
+
+btx.o: btx.m4 btx.s
+ (cd ${.CURDIR}; ${M4} btx.m4 btx.s) | ${AS} ${AFLAGS} -o ${.TARGET}
+
+CLEANFILES+= btx btx.out btx.o
+
+.include <bsd.prog.mk>
diff --git a/sys/boot/pc98/btx/btx/btx.S b/sys/boot/pc98/btx/btx/btx.S
new file mode 100644
index 0000000..b0bd4f2
--- /dev/null
+++ b/sys/boot/pc98/btx/btx/btx.S
@@ -0,0 +1,1071 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btx.s,v 1.9 1999/01/22 13:07:17 rnordier Exp $
+
+#
+# Memory layout.
+#
+ .set MEM_BTX,0x1000 # Start of BTX memory
+ .set MEM_ESP0,0x1800 # Supervisor stack
+ .set MEM_BUF,0x1800 # Scratch buffer
+ .set MEM_ESP1,0x1e00 # Link stack
+ .set MEM_IDT,0x1e00 # IDT
+ .set MEM_TSS,0x1f98 # TSS
+ .set MEM_MAP,0x2000 # I/O bit map
+ .set MEM_DIR,0x4000 # Page directory
+ .set MEM_TBL,0x5000 # Page tables
+ .set MEM_ORG,0x9000 # BTX code
+ .set MEM_USR,0xa000 # Start of user memory
+#
+# Paging control.
+#
+ .set PAG_SIZ,0x1000 # Page size
+ .set PAG_CNT,0x1000 # Pages to map
+#
+# Segment selectors.
+#
+ .set SEL_SCODE,0x8 # Supervisor code
+ .set SEL_SDATA,0x10 # Supervisor data
+ .set SEL_RCODE,0x18 # Real mode code
+ .set SEL_RDATA,0x20 # Real mode data
+ .set SEL_UCODE,0x28|3 # User code
+ .set SEL_UDATA,0x30|3 # User data
+ .set SEL_TSS,0x38 # TSS
+#
+# Task state segment fields.
+#
+ .set TSS_ESP0,0x4 # PL 0 ESP
+ .set TSS_SS0,0x8 # PL 0 SS
+ .set TSS_ESP1,0xc # PL 1 ESP
+ .set TSS_MAP,0x66 # I/O bit map base
+#
+# System calls.
+#
+ .set SYS_EXIT,0x0 # Exit
+ .set SYS_EXEC,0x1 # Exec
+#
+# V86 constants.
+#
+ .set V86_FLG,0x208eff # V86 flag mask
+ .set V86_STK,0x400 # V86 stack allowance
+#
+# Dump format control bytes.
+#
+ .set DMP_X16,0x1 # Word
+ .set DMP_X32,0x2 # Long
+ .set DMP_MEM,0x4 # Memory
+ .set DMP_EOL,0x8 # End of line
+#
+# Screen defaults and assumptions.
+#
+.`ifdef' PC98
+ .set SCR_MAT,0xe1 # Mode/attribute
+.else
+ .set SCR_MAT,0x7 # Mode/attribute
+.endif
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+#
+# BIOS Data Area locations.
+#
+.`ifdef' PC98
+ .set BDA_MEM,0xa1501 # Free memory
+ .set BDA_POS,0xa153e # Cursor position
+.else
+ .set BDA_MEM,0x413 # Free memory
+ .set BDA_SCR,0x449 # Video mode
+ .set BDA_POS,0x450 # Cursor position
+.endif
+#
+# Derivations, for brevity.
+#
+ .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0
+ .set _ESP1H,MEM_ESP1>>0x8 # Byte 1 of ESP1
+ .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base
+ .set _TSSLM,MEM_DIR-MEM_TSS-1 # TSS limit
+ .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit
+#
+# Code segment.
+#
+ .globl start
+start: # Start of code
+#
+# BTX header.
+#
+btx_hdr: .byte 0xeb # Machine ID
+ .byte 0xe # Header size
+ .ascii "BTX" # Magic
+ .byte 0x1 # Major version
+ .byte 0x0 # Minor version
+ .byte 0x0 # Flags
+ .word PAG_CNT-MEM_ORG>>0xc # Paging control
+ .word break-start # Text size
+ .long 0x0 # Entry address
+#
+# Initialization routine.
+#
+init: cli # Disable interrupts
+ xorl %eax,%eax # Zero/segment
+ movl %ax,%ss # Set up
+ movwir(MEM_ESP0,_sp) # stack
+ movl %ax,%es # Address
+ movl %ax,%ds # data
+ pushw $0x2 # Clear
+ popfw # flags
+#
+# Initialize memory.
+#
+ movwir(MEM_IDT,_di) # Memory to initialize
+ movwir((MEM_ORG-MEM_IDT)/2,_cx) # Words to zero
+ pushl %edi # Save
+ rep # Zero-fill
+ stosl # memory
+ popl %edi # Restore
+#
+# Create IDT.
+#
+ movwir(idtctl,_si) # Control string
+init.1: lodsb # Get entry
+ cwde # count
+ xchgl %eax,%ecx # as word
+ jecxz init.4 # If done
+ lodsb # Get segment
+ xchgl %eax,%edx # P:DPL:type
+ lodsl # Get control
+ xchgl %eax,%ebx # set
+ lodsl # Get handler offset
+ movb $SEL_SCODE,%dh # Segment selector
+init.2: shrl %ebx # Handle this int?
+ jnc init.3 # No
+ movwr0(_ax,_di_) # Set handler offset
+ movbr1(_dh,0x2,_di_) # and selector
+ movbr1(_dl,0x5,_di_) # Set P:DPL:type
+ addwia(0x4) # Next handler
+init.3: leaw1r(0x8,_di_,_di) # Next entry
+ loop init.2 # Till set done
+ jmp init.1 # Continue
+#
+# Initialize TSS.
+#
+init.4: movbi1(_ESP0H,TSS_ESP0+1,_di_) # Set ESP0
+ movbi1(SEL_SDATA,TSS_SS0,_di_) # Set SS0
+ movbi1(_ESP1H,TSS_ESP1+1,_di_) # Set ESP1
+ movbi1(_TSSIO,TSS_MAP,_di_) # Set I/O bit map base
+#
+# Create page directory.
+#
+ xorw %dx,%dx # Page
+ movb $PAG_SIZ>>0x8,%dh # size
+ xorw %ax,%ax # Zero
+ movwir(MEM_DIR,_di) # Page directory
+ movb $PAG_CNT>>0xa,%cl # Entries
+ movwir(MEM_TBL|0x7,_ax) # First entry
+init.5: stosw # Write entry
+ addl %edx,%eax # To next
+ loop init.5 # Till done
+#
+# Create page tables.
+#
+ movwir(MEM_TBL,_di) # Page table
+ movb $PAG_CNT>>0x8,%ch # Entries
+ xorl %eax,%eax # Start address
+init.6: movb $0x7,%al # Set U:W:P flags
+ cmpwmr(btx_hdr+0x8,_cx) # Standard user page?
+ jb init.7 # Yes
+ cmpwir(PAG_CNT-MEM_BTX>>0xc,_cx)# BTX memory?
+ jae init.7 # No or first page
+ andb $~0x2,%al # Clear W flag
+ cmpwir(PAG_CNT-MEM_USR>>0xc,_cx)# User page zero?
+ jne init.7 # No
+ tstbim(0x80,btx_hdr+0x7) # Unmap it?
+ jz init.7 # No
+ andb $~0x1,%al # Clear P flag
+init.7: stosw # Set entry
+ addw %dx,%ax # Next address
+ loop init.6 # Till done
+#
+# Bring up the system.
+#
+ movwir(0x2820,_bx) # Set protected mode
+ callwi(setpic) # IRQ offsets
+ lidtwm(idtdesc) # Set IDT
+ xorw %ax,%ax # Set base
+ movb $MEM_DIR>>0x8,%ah # of page
+ movl %eax,%cr3 # directory
+ lgdtwm(gdtdesc) # Set GDT
+ movl %cr0,%eax # Switch to
+ o16 # protected mode
+ orl $0x80000001,%eax # and enable
+ movl %eax,%cr0 # paging
+ jmpfwi(SEL_SCODE,init.8) # To 32-bit code
+init.8: xorl %ecx,%ecx # Zero
+ movb $SEL_SDATA,%cl # To 32-bit
+ movl %cx,%ss # stack
+#
+# Launch user task.
+#
+ movb $SEL_TSS,%cl # Set task
+ ltrl %ecx # register
+ movl $MEM_USR,%edx # User base address
+ movzwl %ss:BDA_MEM,%eax # Get free memory
+.`ifdef' PC98
+ andl $0x7,%eax
+ incl %eax
+ shll $0x11,%eax # To bytes
+.else
+ shll $0xa,%eax # To bytes
+.endif
+ subl $0x1000,%eax # Less arg space
+ subl %edx,%eax # Less base
+ movb $SEL_UDATA,%cl # User data selector
+ pushl %ecx # Set SS
+ pushl %eax # Set ESP
+ pushl $0x202 # Set flags (IF set)
+ pushl $SEL_UCODE # Set CS
+ pushl btx_hdr+0xc # Set EIP
+ pushl %ecx # Set GS
+ pushl %ecx # Set FS
+ pushl %ecx # Set DS
+ pushl %ecx # Set ES
+ pushl %edx # Set EAX
+ movb $0x7,%cl # Set remaining
+init.9: pushb $0x0 # general
+ loop init.9 # registers
+ popa # and initialize
+ popl %es # Initialize
+ popl %ds # user
+ popl %fs # segment
+ popl %gs # registers
+ iret # To user mode
+#
+# Exit routine.
+#
+exit: cli # Disable interrupts
+ movl $MEM_ESP0,%esp # Clear stack
+#
+# Turn off paging.
+#
+ movl %cr0,%eax # Get CR0
+ andl $~0x80000000,%eax # Disable
+ movl %eax,%cr0 # paging
+ xorl %ecx,%ecx # Zero
+ movl %ecx,%cr3 # Flush TLB
+#
+# To 16 bits.
+#
+ o16 # Reload
+ jmpfwi(SEL_RCODE,exit.1) # CS
+exit.1: movb $SEL_RDATA,%cl # 16-bit selector
+ movl %cx,%ss # Reload SS
+ movl %cx,%ds # Load
+ movl %cx,%es # remaining
+ movl %cx,%fs # segment
+ movl %cx,%gs # registers
+#
+# To real-address mode.
+#
+ decl %eax # Switch to
+ movl %eax,%cr0 # real mode
+ jmpfwi(0x0,exit.2) # Reload CS
+exit.2: xorl %eax,%eax # Real mode segment
+ movl %ax,%ss # Reload SS
+ movl %ax,%ds # Address data
+.`ifdef' PC98
+ movwir(0x1008,_bx) # Set real mode
+.else
+ movwir(0x7008,_bx) # Set real mode
+.endif
+ callwi(setpic) # IRQ offsets
+ lidtwm(ivtdesc) # Set IVT
+#
+# Reboot or await reset.
+#
+ sti # Enable interrupts
+ tstbim(0x1,btx_hdr+0x7) # Reboot?
+exit.3: jz exit.3 # No
+.`ifdef' PC98
+ movb $0xa0,%al
+ outb %al,$0x35
+ movb 0,%al
+ outb %al,$0xf0
+exit.4: jmp exit.4
+.else
+ int $0x19 # BIOS: Reboot
+.endif
+#
+# Set IRQ offsets by reprogramming 8259A PICs.
+#
+.`ifdef' PC98
+setpic: inb $0x02,%al # Save master
+ pushl %eax # IMR
+ inb $0x0a,%al # Save slave
+ pushl %eax # IMR
+ movb $0x11,%al # ICW1 to
+ outb %al,$0x00 # master,
+ outb %al,$0x08 # slave
+ movb %bl,%al # ICW2 to
+ outb %al,$0x02 # master
+ movb %bh,%al # ICW2 to
+ outb %al,$0x0a # slave
+ movb $0x80,%al # ICW3 to
+ outb %al,$0x02 # master
+ movb $0x7,%al # ICW3 to
+ outb %al,$0x0a # slave
+ movb $0x1d,%al # ICW4 to
+ outb %al,$0x02 # master,
+ movb $0x9,%al # ICW4 to
+ outb %al,$0x0a # slave
+ popl %eax # Restore slave
+ outb %al,$0x0a # IMR
+ popl %eax # Restore master
+ outb %al,$0x02 # IMR
+.else
+setpic: inb $0x21,%al # Save master
+ pushl %eax # IMR
+ inb $0xa1,%al # Save slave
+ pushl %eax # IMR
+ movb $0x11,%al # ICW1 to
+ outb %al,$0x20 # master,
+ outb %al,$0xa0 # slave
+ movb %bl,%al # ICW2 to
+ outb %al,$0x21 # master
+ movb %bh,%al # ICW2 to
+ outb %al,$0xa1 # slave
+ movb $0x4,%al # ICW3 to
+ outb %al,$0x21 # master
+ movb $0x2,%al # ICW3 to
+ outb %al,$0xa1 # slave
+ movb $0x1,%al # ICW4 to
+ outb %al,$0x21 # master,
+ outb %al,$0xa1 # slave
+ popl %eax # Restore slave
+ outb %al,$0xa1 # IMR
+ popl %eax # Restore master
+ outb %al,$0x21 # IMR
+.endif
+ ret # To caller
+#
+# Initiate return from V86 mode to user mode.
+#
+inthlt: hlt # To supervisor mode
+#
+# Exception jump table.
+#
+intx00: pushb $0x0 # Int 0x0: #DE
+ jmp ex_noc # Divide error
+ pushb $0x1 # Int 0x1: #DB
+ jmp ex_noc # Debug
+ pushb $0x3 # Int 0x3: #BP
+ jmp ex_noc # Breakpoint
+ pushb $0x4 # Int 0x4: #OF
+ jmp ex_noc # Overflow
+ pushb $0x5 # Int 0x5: #BR
+ jmp ex_noc # BOUND range exceeded
+ pushb $0x6 # Int 0x6: #UD
+ jmp ex_noc # Invalid opcode
+ pushb $0x7 # Int 0x7: #NM
+ jmp ex_noc # Device not available
+ pushb $0x8 # Int 0x8: #DF
+ jmp except # Double fault
+ pushb $0xa # Int 0xa: #TS
+ jmp except # Invalid TSS
+ pushb $0xb # Int 0xb: #NP
+ jmp except # Segment not present
+ pushb $0xc # Int 0xc: #SS
+ jmp except # Stack segment fault
+ pushb $0xd # Int 0xd: #GP
+ jmp ex_v86 # General protection
+ pushb $0xe # Int 0xe: #PF
+ jmp except # Page fault
+intx10: pushb $0x10 # Int 0x10: #MF
+ jmp ex_noc # Floating-point error
+#
+# Handle #GP exception.
+#
+ex_v86: testb $0x2,0x12(%esp,1) # V86 mode?
+ jz except # No
+ jmp v86mon # To monitor
+#
+# Save a zero error code.
+#
+ex_noc: pushl (%esp,1) # Duplicate int no
+ movb $0x0,0x4(%esp,1) # Fake error code
+#
+# Handle exception.
+#
+except: cld # String ops inc
+ pushl %ds # Save
+ pushl %es # most
+ pusha # registers
+ movb $0x6,%al # Push loop count
+ testb $0x2,0x3a(%esp,1) # V86 mode?
+ jnz except.1 # Yes
+ pushl %gs # Set GS
+ pushl %fs # Set FS
+ pushl %ds # Set DS
+ pushl %es # Set ES
+ movb $0x2,%al # Push loop count
+ cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode?
+ jne except.1 # No
+ pushl %ss # Set SS
+ leal 0x50(%esp,1),%eax # Set
+ pushl %eax # ESP
+ jmp except.2 # Join common code
+except.1: pushl 0x50(%esp,1) # Set GS, FS, DS, ES
+ decb %al # (if V86 mode), and
+ jne except.1 # SS, ESP
+except.2: pushl $SEL_SDATA # Set up
+ popl %ds # to
+ pushl %ds # address
+ popl %es # data
+ movl %esp,%ebx # Stack frame
+ movl $dmpfmt,%esi # Dump format string
+ movl $MEM_BUF,%edi # Buffer
+.`ifdef' PC98
+ pushl %eax
+ pushl %edx
+wait.1:
+ inb $0x60,%al
+ testb $0x04,%al
+ jz wait.1
+ movb $0xe0,%al
+ outb %al,$0x62
+wait.2:
+ inb $0x60,%al
+ testb $0x01,%al
+ jz wait.2
+ xorl %edx,%edx
+ inb $0x62,%al
+ movb %al,%dl
+ inb $0x62,%al
+ movb %al,%dh
+ inb $0x62,%al
+ inb $0x62,%al
+ inb $0x62,%al
+ movl %edx,%eax
+ shlw $1,%ax
+ movl $BDA_POS,%edx
+ movw %ax,(%edx)
+ popl %edx
+ popl %eax
+.endif
+ pushl %edi # Dump to
+ call dump # buffer
+ popl %esi # and
+ call putstr # display
+ leal 0x18(%esp,1),%esp # Discard frame
+ popa # Restore
+ popl %es # registers
+ popl %ds # saved
+ cmpb $0x3,(%esp,1) # Breakpoint?
+ je except.3 # Yes
+ jmp exit # Exit
+except.3: leal 0x8(%esp,1),%esp # Discard err, int no
+ iret # From interrupt
+#
+# Return to user mode from V86 mode.
+#
+intrtn: cld # String ops inc
+ pushl %ds # Address
+ popl %es # data
+ leal 0x3c(%ebp),%edx # V86 Segment registers
+ movl MEM_TSS+TSS_ESP1,%esi # Link stack pointer
+ lodsl # INT_V86 args pointer
+ movl %esi,%ebx # Saved exception frame
+ testl %eax,%eax # INT_V86 args?
+ jz intrtn.2 # No
+ movl $MEM_USR,%edi # User base
+ movl 0x1c(%esi),%ebx # User ESP
+ movl %eax,(%edi,%ebx,1) # Restore to user stack
+ leal 0x8(%edi,%eax,1),%edi # Arg segment registers
+ testb $0x4,-0x6(%edi) # Return flags?
+ jz intrtn.1 # No
+ movl 0x30(%ebp),%eax # Get V86 flags
+ movw %ax,0x18(%esi) # Set user flags
+intrtn.1: leal 0x10(%esi),%ebx # Saved exception frame
+ xchgl %edx,%esi # Segment registers
+ movb $0x4,%cl # Update seg regs
+ rep # in INT_V86
+ movsl # args
+intrtn.2: movl %edx,%esi # Segment registers
+ leal 0x28(%ebp),%edi # Set up seg
+ movb $0x4,%cl # regs for
+ rep # later
+ movsl # pop
+ movl %ebx,%esi # Restore exception
+ movb $0x5,%cl # frame to
+ rep # supervisor
+ movsl # stack
+ movl %esi,MEM_TSS+TSS_ESP1 # Link stack pointer
+ popa # Restore
+ leal 0x8(%esp,1),%esp # Discard err, int no
+ popl %es # Restore
+ popl %ds # user
+ popl %fs # segment
+ popl %gs # registers
+ iret # To user mode
+#
+# V86 monitor.
+#
+v86mon: cld # String ops inc
+ pushl $SEL_SDATA # Set up for
+ popl %ds # flat addressing
+ pusha # Save registers
+ movl %esp,%ebp # Address stack frame
+ movzwl 0x2c(%ebp),%edi # Load V86 CS
+ shll $0x4,%edi # To linear
+ movl 0x28(%ebp),%esi # Load V86 IP
+ addl %edi,%esi # Code pointer
+ xorl %ecx,%ecx # Zero
+ movb $0x2,%cl # 16-bit operands
+ xorl %eax,%eax # Zero
+v86mon.1: lodsb # Get opcode
+ cmpb $0x66,%al # Operand size prefix?
+ jne v86mon.2 # No
+ movb $0x4,%cl # 32-bit operands
+ jmp v86mon.1 # Continue
+v86mon.2: cmpb $0xf4,%al # HLT?
+ jne v86mon.3 # No
+ cmpl $inthlt+0x1,%esi # Is inthlt?
+ jne v86mon.6 # No (ignore)
+ jmp intrtn # Return to user mode
+v86mon.3: cmpb $0xfa,%al # CLI?
+ je v86cli # Yes
+ cmpb $0xfb,%al # STI?
+ je v86sti # Yes
+ movzwl 0x38(%ebp),%ebx # Load V86 SS
+ shll $0x4,%ebx # To offset
+ pushl %ebx # Save
+ addl 0x34(%ebp),%ebx # Add V86 SP
+ movl 0x30(%ebp),%edx # Load V86 flags
+ cmpb $0x9c,%al # PUSHF/PUSHFD?
+ je v86pushf # Yes
+ cmpb $0x9d,%al # POPF/POPFD?
+ je v86popf # Yes
+ cmpb $0xcd,%al # INT imm8?
+ je v86intn # Yes
+ cmpb $0xcf,%al # IRET/IRETD?
+ je v86iret # Yes
+ popl %ebx # Restore
+ popa # Restore
+ jmp except # Handle exception
+v86mon.4: movl %edx,0x30(%ebp) # Save V86 flags
+v86mon.5: popl %edx # V86 SS adjustment
+ subl %edx,%ebx # Save V86
+ movl %ebx,0x34(%ebp) # SP
+v86mon.6: subl %edi,%esi # From linear
+ movl %esi,0x28(%ebp) # Save V86 IP
+ popa # Restore
+ leal 0x8(%esp,1),%esp # Discard int no, error
+ iret # To V86 mode
+#
+# Emulate CLI.
+#
+v86cli: andb $~0x2,0x31(%ebp) # Clear IF
+ jmp v86mon.6 # Finish up
+#
+# Emulate STI.
+#
+v86sti: orb $0x2,0x31(%ebp) # Set IF
+ jmp v86mon.6 # Finish up
+#
+# Emulate PUSHF/PUSHFD.
+#
+v86pushf: subl %ecx,%ebx # Adjust SP
+ cmpb $0x4,%cl # 32-bit
+ je v86pushf.1 # Yes
+ o16 # 16-bit
+v86pushf.1: movl %edx,(%ebx) # Save flags
+ jmp v86mon.5 # Finish up
+#
+# Emulate IRET/IRETD.
+#
+v86iret: movzwl (%ebx),%esi # Load V86 IP
+ movzwl 0x2(%ebx),%edi # Load V86 CS
+ leal 0x4(%ebx),%ebx # Adjust SP
+ movl %edi,0x2c(%ebp) # Save V86 CS
+ xorl %edi,%edi # No ESI adjustment
+#
+# Emulate POPF/POPFD (and remainder of IRET/IRETD).
+#
+v86popf: cmpb $0x4,%cl # 32-bit?
+ je v86popf.1 # Yes
+ movl %edx,%eax # Initialize
+ o16 # 16-bit
+v86popf.1: movl (%ebx),%eax # Load flags
+ addl %ecx,%ebx # Adjust SP
+ andl $V86_FLG,%eax # Merge
+ andl $~V86_FLG,%edx # the
+ orl %eax,%edx # flags
+ jmp v86mon.4 # Finish up
+#
+# Emulate INT imm8.
+#
+v86intn: lodsb # Get int no
+ subl %edi,%esi # From
+ shrl $0x4,%edi # linear
+ movw %dx,-0x2(%ebx) # Save flags
+ movw %di,-0x4(%ebx) # Save CS
+ leal -0x6(%ebx),%ebx # Adjust SP
+ movw %si,(%ebx) # Save IP
+ shll $0x2,%eax # Scale
+ movzwl (%eax),%esi # Load IP
+ movzwl 0x2(%eax),%edi # Load CS
+ movl %edi,0x2c(%ebp) # Save CS
+ xorl %edi,%edi # No ESI adjustment
+ andb $~0x3,%dh # Clear IF and TF
+ jmp v86mon.4 # Finish up
+#
+# Hardware interrupt jump table.
+#
+intx20: pushb $0x8 # Int 0x20: IRQ0
+ jmp int_hw # V86 int 0x8
+ pushb $0x9 # Int 0x21: IRQ1
+ jmp int_hw # V86 int 0x9
+ pushb $0xa # Int 0x22: IRQ2
+ jmp int_hw # V86 int 0xa
+ pushb $0xb # Int 0x23: IRQ3
+ jmp int_hw # V86 int 0xb
+ pushb $0xc # Int 0x24: IRQ4
+ jmp int_hw # V86 int 0xc
+ pushb $0xd # Int 0x25: IRQ5
+ jmp int_hw # V86 int 0xd
+ pushb $0xe # Int 0x26: IRQ6
+ jmp int_hw # V86 int 0xe
+ pushb $0xf # Int 0x27: IRQ7
+ jmp int_hw # V86 int 0xf
+.`ifdef' PC98
+ pushb $0x10 # Int 0x28: IRQ8
+ jmp int_hw # V86 int 0x10
+ pushb $0x11 # Int 0x29: IRQ9
+ jmp int_hw # V86 int 0x11
+ pushb $0x12 # Int 0x2a: IRQ10
+ jmp int_hw # V86 int 0x12
+ pushb $0x13 # Int 0x2b: IRQ11
+ jmp int_hw # V86 int 0x13
+ pushb $0x14 # Int 0x2c: IRQ12
+ jmp int_hw # V86 int 0x14
+ pushb $0x15 # Int 0x2d: IRQ13
+ jmp int_hw # V86 int 0x15
+ pushb $0x16 # Int 0x2e: IRQ14
+ jmp int_hw # V86 int 0x16
+ pushb $0x17 # Int 0x2f: IRQ15
+ jmp int_hw # V86 int 0x17
+.else
+ pushb $0x70 # Int 0x28: IRQ8
+ jmp int_hw # V86 int 0x70
+ pushb $0x71 # Int 0x29: IRQ9
+ jmp int_hw # V86 int 0x71
+ pushb $0x72 # Int 0x2a: IRQ10
+ jmp int_hw # V86 int 0x72
+ pushb $0x73 # Int 0x2b: IRQ11
+ jmp int_hw # V86 int 0x73
+ pushb $0x74 # Int 0x2c: IRQ12
+ jmp int_hw # V86 int 0x74
+ pushb $0x75 # Int 0x2d: IRQ13
+ jmp int_hw # V86 int 0x75
+ pushb $0x76 # Int 0x2e: IRQ14
+ jmp int_hw # V86 int 0x76
+ pushb $0x77 # Int 0x2f: IRQ15
+ jmp int_hw # V86 int 0x77
+.endif
+#
+# Reflect hardware interrupts.
+#
+int_hw: testb $0x2,0xe(%esp,1) # V86 mode?
+ jz intusr # No
+ pushl $SEL_SDATA # Address
+ popl %ds # data
+ xchgl %eax,(%esp,1) # Swap EAX, int no
+ pushl %ebp # Address
+ movl %esp,%ebp # stack frame
+ pushl %ebx # Save
+ shll $0x2,%eax # Get int
+ movl (%eax),%eax # vector
+ subl $0x6,0x14(%ebp) # Adjust V86 ESP
+ movzwl 0x18(%ebp),%ebx # V86 SS
+ shll $0x4,%ebx # * 0x10
+ addl 0x14(%ebp),%ebx # + V86 ESP
+ xchgw %ax,0x8(%ebp) # Swap V86 IP
+ rorl $0x10,%eax # Swap words
+ xchgw %ax,0xc(%ebp) # Swap V86 CS
+ roll $0x10,%eax # Swap words
+ movl %eax,(%ebx) # CS:IP for IRET
+ movl 0x10(%ebp),%eax # V86 flags
+ movw %ax,0x4(%ebx) # Flags for IRET
+ andb $~0x3,0x11(%ebp) # Clear IF, TF
+ popl %ebx # Restore
+ popl %ebp # saved
+ popl %eax # registers
+ iret # To V86 mode
+#
+# Invoke V86 interrupt from user mode, with arguments.
+#
+intx31: stc # Have btx_v86
+ pushl %eax # Missing int no
+#
+# Invoke V86 interrupt from user mode.
+#
+intusr: std # String ops dec
+ pushl %eax # Expand
+ pushl %eax # stack
+ pushl %eax # frame
+ pusha # Save
+ pushl %gs # Save
+ movl %esp,%eax # seg regs
+ pushl %fs # and
+ pushl %ds # point
+ pushl %es # to them
+ pushb $SEL_SDATA # Set up
+ popl %ds # to
+ pushl %ds # address
+ popl %es # data
+ movl $MEM_USR,%ebx # User base
+ movl %ebx,%edx # address
+ jc intusr.1 # If btx_v86
+ xorl %edx,%edx # Control flags
+ xorl %ebp,%ebp # btx_v86 pointer
+intusr.1: leal 0x50(%esp,1),%esi # Base of frame
+ pushl %esi # Save
+ addl -0x4(%esi),%ebx # User ESP
+ movl MEM_TSS+TSS_ESP1,%edi # Link stack pointer
+ leal -0x4(%edi),%edi # Adjust for push
+ xorl %ecx,%ecx # Zero
+ movb $0x5,%cl # Push exception
+ rep # frame on
+ movsl # link stack
+ xchgl %eax,%esi # Saved seg regs
+ movl 0x40(%esp,1),%eax # Get int no
+ testl %edx,%edx # Have btx_v86?
+ jz intusr.2 # No
+ movl (%ebx),%ebp # btx_v86 pointer
+ movb $0x4,%cl # Count
+ addl %ecx,%ebx # Adjust for pop
+ rep # Push saved seg regs
+ movsl # on link stack
+ addl %ebp,%edx # Flatten btx_v86 ptr
+ leal 0x14(%edx),%esi # Seg regs pointer
+ movl 0x4(%edx),%eax # Get int no/address
+ movzwl 0x2(%edx),%edx # Get control flags
+intusr.2: movl %ebp,(%edi) # Push btx_v86 and
+ movl %edi,MEM_TSS+TSS_ESP1 # save link stack ptr
+ popl %edi # Base of frame
+ xchgl %eax,%ebp # Save intno/address
+ movl 0x48(%esp,1),%eax # Get flags
+ testb $0x2,%dl # Simulate CALLF?
+ jnz intusr.3 # Yes
+ decl %ebx # Push flags
+ decl %ebx # on V86
+ movw %ax,(%ebx) # stack
+intusr.3: movb $0x4,%cl # Count
+ subl %ecx,%ebx # Push return address
+ movl $inthlt,(%ebx) # on V86 stack
+ rep # Copy seg regs to
+ movsl # exception frame
+ xchgl %eax,%ecx # Save flags
+ movl %ebx,%eax # User ESP
+ subl $V86_STK,%eax # Less bytes
+ ja intusr.4 # to
+ xorl %eax,%eax # keep
+intusr.4: shrl $0x4,%eax # Gives segment
+ stosl # Set SS
+ shll $0x4,%eax # To bytes
+ xchgl %eax,%ebx # Swap
+ subl %ebx,%eax # Gives offset
+ stosl # Set ESP
+ xchgl %eax,%ecx # Get flags
+ btsl $0x11,%eax # Set VM
+ andb $~0x3,%ah # Clear IF and TF
+ stosl # Set EFL
+ xchgl %eax,%ebp # Get int no/address
+ testb $0x1,%dl # Address?
+ jnz intusr.5 # Yes
+ shll $0x2,%eax # Scale
+ movl (%eax),%eax # Load int vector
+intusr.5: movl %eax,%ecx # Save
+ shrl $0x10,%eax # Gives segment
+ stosl # Set CS
+ movw %cx,%ax # Restore
+ stosl # Set EIP
+ leal 0x10(%esp,1),%esp # Discard seg regs
+ popa # Restore
+ iret # To V86 mode
+#
+# System Call.
+#
+intx30: cmpl $SYS_EXEC,%eax # Exec system call?
+ jne intx30.1 # No
+ pushl %ss # Set up
+ popl %es # all
+ pushl %es # segment
+ popl %ds # registers
+ pushl %ds # for the
+ popl %fs # program
+ pushl %fs # we're
+ popl %gs # invoking
+ movl $MEM_USR,%eax # User base address
+ addl 0xc(%esp,1),%eax # Change to user
+ leal 0x4(%eax),%esp # stack
+ movl %cr0,%eax # Turn
+ andl $~0x80000000,%eax # off
+ movl %eax,%cr0 # paging
+ xorl %eax,%eax # Flush
+ movl %eax,%cr3 # TLB
+ popl %eax # Call
+ call *%eax # program
+intx30.1: incb %ss:btx_hdr+0x7 # Flag reboot
+ jmp exit # Exit
+#
+# Dump structure [EBX] to [EDI], using format string [ESI].
+#
+dump.0: stosb # Save char
+dump: lodsb # Load char
+ testb %al,%al # End of string?
+ jz dump.10 # Yes
+ testb $0x80,%al # Control?
+ jz dump.0 # No
+ movb %al,%ch # Save control
+ movb $'=',%al # Append
+ stosb # '='
+ lodsb # Get offset
+ pushl %esi # Save
+ movsbl %al,%esi # To
+ addl %ebx,%esi # pointer
+ testb $DMP_X16,%ch # Dump word?
+ jz dump.1 # No
+ lodsw # Get and
+ call hex16 # dump it
+dump.1: testb $DMP_X32,%ch # Dump long?
+ jz dump.2 # No
+ lodsl # Get and
+ call hex32 # dump it
+dump.2: testb $DMP_MEM,%ch # Dump memory?
+ jz dump.8 # No
+ pushl %ds # Save
+ testb $0x2,0x52(%ebx) # V86 mode?
+ jnz dump.3 # Yes
+ verrl 0x4(%esi) # Readable selector?
+ jnz dump.3 # No
+ ldsl (%esi),%esi # Load pointer
+ jmp dump.4 # Join common code
+dump.3: lodsl # Set offset
+ xchgl %eax,%edx # Save
+ lodsl # Get segment
+ shll $0x4,%eax # * 0x10
+ addl %edx,%eax # + offset
+ xchgl %eax,%esi # Set pointer
+dump.4: movb $0x10,%cl # Bytes to dump
+dump.5: lodsb # Get byte and
+ call hex8 # dump it
+ decb %cl # Keep count
+ jz dump.7 # If done
+ movb $'-',%al # Separator
+ cmpb $0x8,%cl # Half way?
+ je dump.6 # Yes
+ movb $' ',%al # Use space
+dump.6: stosb # Save separator
+ jmp dump.5 # Continue
+dump.7: popl %ds # Restore
+dump.8: popl %esi # Restore
+ movb $0xa,%al # Line feed
+ testb $DMP_EOL,%ch # End of line?
+ jnz dump.9 # Yes
+ movb $' ',%al # Use spaces
+ stosb # Save one
+dump.9: jmp dump.0 # Continue
+dump.10: stosb # Terminate string
+ ret # To caller
+#
+# Convert EAX, AX, or AL to hex, saving the result to [EDI].
+#
+hex32: pushl %eax # Save
+ shrl $0x10,%eax # Do upper
+ call hex16 # 16
+ popl %eax # Restore
+hex16: call hex16.1 # Do upper 8
+hex16.1: xchgb %ah,%al # Save/restore
+hex8: pushl %eax # Save
+ shrb $0x4,%al # Do upper
+ call hex8.1 # 4
+ popl %eax # Restore
+hex8.1: andb $0xf,%al # Get lower 4
+ cmpb $0xa,%al # Convert
+ sbbb $0x69,%al # to hex
+ das # digit
+ orb $0x20,%al # To lower case
+ stosb # Save char
+ ret # (Recursive)
+#
+# Output zero-terminated string [ESI] to the console.
+#
+putstr.0: call putchr # Output char
+putstr: lodsb # Load char
+ testb %al,%al # End of string?
+ jnz putstr.0 # No
+ ret # To caller
+#
+# Output character AL to the console.
+#
+putchr: pusha # Save
+ xorl %ecx,%ecx # Zero for loops
+ movb $SCR_MAT,%ah # Mode/attribute
+ movl $BDA_POS,%ebx # BDA pointer
+ movw (%ebx),%dx # Cursor position
+.`ifdef' PC98
+ movl $0xa0000,%edi
+.else
+ movl $0xb8000,%edi # Regen buffer (color)
+ cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode?
+ jne putchr.1 # No
+ xorw %di,%di # Regen buffer (mono)
+.endif
+putchr.1: cmpb $0xa,%al # New line?
+ je putchr.2 # Yes
+.`ifdef' PC98
+ movw %dx,%cx
+ movb %al,(%edi,%ecx,1) # Write char
+ addl $0x2000,%ecx
+ movb %ah,(%edi,%ecx,1) # Write attr
+ addw $0x02,%dx
+ jmp putchr.3
+putchr.2: movw %dx,%ax
+ movb $SCR_COL*2,%dl
+ div %dl
+ incb %al
+ mul %dl
+ movw %ax,%dx
+putchr.3: cmpw $SCR_ROW*SCR_COL*2,%dx
+.else
+ xchgl %eax,%ecx # Save char
+ movb $SCR_COL,%al # Columns per row
+ mulb %dh # * row position
+ addb %dl,%al # + column
+ adcb $0x0,%ah # position
+ shll %eax # * 2
+ xchgl %eax,%ecx # Swap char, offset
+ movw %ax,(%edi,%ecx,1) # Write attr:char
+ incl %edx # Bump cursor
+ cmpb $SCR_COL,%dl # Beyond row?
+ jb putchr.3 # No
+putchr.2: xorb %dl,%dl # Zero column
+ incb %dh # Bump row
+putchr.3: cmpb $SCR_ROW,%dh # Beyond screen?
+.endif
+ jb putchr.4 # No
+ leal 2*SCR_COL(%edi),%esi # New top line
+ movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
+ rep # Scroll
+ movsl # screen
+ movb $' ',%al # Space
+.`ifdef' PC98
+ xorb %ah,%ah
+.endif
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+.`ifdef' PC98
+ movw $(SCR_ROW-1)*SCR_COL*2,%dx
+.else
+ movb $SCR_ROW-1,%dh # Bottom line
+.endif
+putchr.4: movw %dx,(%ebx) # Update position
+ popa # Restore
+ ret # To caller
+
+ .p2align 4
+#
+# Global descriptor table.
+#
+gdt: .word 0x0,0x0,0x0,0x0 # Null entry
+ .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
+ .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
+ .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
+ .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
+ .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
+ .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
+ .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
+gdt.1:
+#
+# Pseudo-descriptors.
+#
+gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT
+idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT
+ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT
+#
+# IDT construction control string.
+#
+idtctl: .byte 0x10, 0x8e # Int 0x0-0xf
+ .word 0x7dfb,intx00 # (exceptions)
+ .byte 0x10, 0x8e # Int 0x10
+ .word 0x1, intx10 # (exception)
+ .byte 0x10, 0x8e # Int 0x20-0x2f
+ .word 0xffff,intx20 # (hardware)
+ .byte 0x1, 0xee # int 0x30
+ .word 0x1, intx30 # (system call)
+ .byte 0x2, 0xee # Int 0x31-0x32
+ .word 0x1, intx31 # (V86, null)
+ .byte 0x0 # End of string
+#
+# Dump format string.
+#
+dmpfmt: .byte '\n' # "\n"
+ .ascii "int" # "int="
+ .byte 0x80|DMP_X32, 0x40 # "00000000 "
+ .ascii "err" # "err="
+ .byte 0x80|DMP_X32, 0x44 # "00000000 "
+ .ascii "efl" # "efl="
+ .byte 0x80|DMP_X32, 0x50 # "00000000 "
+ .ascii "eip" # "eip="
+ .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
+ .ascii "eax" # "eax="
+ .byte 0x80|DMP_X32, 0x34 # "00000000 "
+ .ascii "ebx" # "ebx="
+ .byte 0x80|DMP_X32, 0x28 # "00000000 "
+ .ascii "ecx" # "ecx="
+ .byte 0x80|DMP_X32, 0x30 # "00000000 "
+ .ascii "edx" # "edx="
+ .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
+ .ascii "esi" # "esi="
+ .byte 0x80|DMP_X32, 0x1c # "00000000 "
+ .ascii "edi" # "edi="
+ .byte 0x80|DMP_X32, 0x18 # "00000000 "
+ .ascii "ebp" # "ebp="
+ .byte 0x80|DMP_X32, 0x20 # "00000000 "
+ .ascii "esp" # "esp="
+ .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n"
+ .ascii "cs" # "cs="
+ .byte 0x80|DMP_X16, 0x4c # "0000 "
+ .ascii "ds" # "ds="
+ .byte 0x80|DMP_X16, 0xc # "0000 "
+ .ascii "es" # "es="
+ .byte 0x80|DMP_X16, 0x8 # "0000 "
+ .ascii " " # " "
+ .ascii "fs" # "fs="
+ .byte 0x80|DMP_X16, 0x10 # "0000 "
+ .ascii "gs" # "gs="
+ .byte 0x80|DMP_X16, 0x14 # "0000 "
+ .ascii "ss" # "ss="
+ .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n"
+ .ascii "cs:eip" # "cs:eip="
+ .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
+ .ascii "ss:esp" # "ss:esp="
+ .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n"
+ .asciz "System halted" # End
+#
+# End of BTX memory.
+#
+ .p2align 4
+break:
diff --git a/sys/boot/pc98/btx/btx/btx.m4 b/sys/boot/pc98/btx/btx/btx.m4
new file mode 100644
index 0000000..6526c6b
--- /dev/null
+++ b/sys/boot/pc98/btx/btx/btx.m4
@@ -0,0 +1,59 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btx.m4,v 1.1.1.1 1998/09/12 04:29:23 rnordier Exp $
+
+define(_al,0x0)dnl
+define(_cl,0x1)dnl
+define(_dl,0x2)dnl
+define(_bl,0x3)dnl
+define(_ah,0x4)dnl
+define(_ch,0x5)dnl
+define(_dh,0x6)dnl
+define(_bh,0x7)dnl
+
+define(_ax,0x0)dnl
+define(_cx,0x1)dnl
+define(_dx,0x2)dnl
+define(_bx,0x3)dnl
+define(_sp,0x4)dnl
+define(_bp,0x5)dnl
+define(_si,0x6)dnl
+define(_di,0x7)dnl
+
+define(_bx_si,0x0)dnl
+define(_bx_di,0x1)dnl
+define(_bp_si,0x2)dnl
+define(_bp_di,0x3)dnl
+define(_si_,0x4)dnl
+define(_di_,0x5)dnl
+define(_bp_,0x6)dnl
+define(_bx_,0x7)dnl
+
+define(o16,`.byte 0x66')dnl
+
+define(addwia,`.byte 0x5; .word $1')dnl
+define(lgdtwm,`.byte 0xf; .byte 0x1; .byte 0x16; .word $1')dnl
+define(lidtwm,`.byte 0xf; .byte 0x1; .byte 0x1e; .word $1')dnl
+define(cmpwmr,`.byte 0x3b; .byte ($2 << 0x3) | 0x6; .word $1')dnl
+define(cmpwir,`.byte 0x81; .byte 0xf8 | $2; .word $1')dnl
+define(movbr1,`.byte 0x88; .byte 0x40 | ($1 << 0x3) | $3; .byte $2')dnl
+define(movwr0,`.byte 0x89; .byte ($1 << 0x3) | $2')dnl
+define(leaw1r,`.byte 0x8d; .byte 0x40 | ($3 << 0x3) | $2; .byte $1')dnl
+define(movwir,`.byte 0xb8 | $2; .word $1')dnl
+define(movbi1,`.byte 0xc6; .byte 0x40 | $3; .byte $2; .byte $1')dnl
+define(callwi,`.byte 0xe8; .word $1 - . - 0x2')dnl
+define(jmpfwi,`.byte 0xea; .word $2; .word $1')dnl
+define(tstbim,`.byte 0xf6; .byte 0x6; .word $2; .byte $1')dnl
diff --git a/sys/boot/pc98/btx/btx/btx.s b/sys/boot/pc98/btx/btx/btx.s
new file mode 100644
index 0000000..b0bd4f2
--- /dev/null
+++ b/sys/boot/pc98/btx/btx/btx.s
@@ -0,0 +1,1071 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btx.s,v 1.9 1999/01/22 13:07:17 rnordier Exp $
+
+#
+# Memory layout.
+#
+ .set MEM_BTX,0x1000 # Start of BTX memory
+ .set MEM_ESP0,0x1800 # Supervisor stack
+ .set MEM_BUF,0x1800 # Scratch buffer
+ .set MEM_ESP1,0x1e00 # Link stack
+ .set MEM_IDT,0x1e00 # IDT
+ .set MEM_TSS,0x1f98 # TSS
+ .set MEM_MAP,0x2000 # I/O bit map
+ .set MEM_DIR,0x4000 # Page directory
+ .set MEM_TBL,0x5000 # Page tables
+ .set MEM_ORG,0x9000 # BTX code
+ .set MEM_USR,0xa000 # Start of user memory
+#
+# Paging control.
+#
+ .set PAG_SIZ,0x1000 # Page size
+ .set PAG_CNT,0x1000 # Pages to map
+#
+# Segment selectors.
+#
+ .set SEL_SCODE,0x8 # Supervisor code
+ .set SEL_SDATA,0x10 # Supervisor data
+ .set SEL_RCODE,0x18 # Real mode code
+ .set SEL_RDATA,0x20 # Real mode data
+ .set SEL_UCODE,0x28|3 # User code
+ .set SEL_UDATA,0x30|3 # User data
+ .set SEL_TSS,0x38 # TSS
+#
+# Task state segment fields.
+#
+ .set TSS_ESP0,0x4 # PL 0 ESP
+ .set TSS_SS0,0x8 # PL 0 SS
+ .set TSS_ESP1,0xc # PL 1 ESP
+ .set TSS_MAP,0x66 # I/O bit map base
+#
+# System calls.
+#
+ .set SYS_EXIT,0x0 # Exit
+ .set SYS_EXEC,0x1 # Exec
+#
+# V86 constants.
+#
+ .set V86_FLG,0x208eff # V86 flag mask
+ .set V86_STK,0x400 # V86 stack allowance
+#
+# Dump format control bytes.
+#
+ .set DMP_X16,0x1 # Word
+ .set DMP_X32,0x2 # Long
+ .set DMP_MEM,0x4 # Memory
+ .set DMP_EOL,0x8 # End of line
+#
+# Screen defaults and assumptions.
+#
+.`ifdef' PC98
+ .set SCR_MAT,0xe1 # Mode/attribute
+.else
+ .set SCR_MAT,0x7 # Mode/attribute
+.endif
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+#
+# BIOS Data Area locations.
+#
+.`ifdef' PC98
+ .set BDA_MEM,0xa1501 # Free memory
+ .set BDA_POS,0xa153e # Cursor position
+.else
+ .set BDA_MEM,0x413 # Free memory
+ .set BDA_SCR,0x449 # Video mode
+ .set BDA_POS,0x450 # Cursor position
+.endif
+#
+# Derivations, for brevity.
+#
+ .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0
+ .set _ESP1H,MEM_ESP1>>0x8 # Byte 1 of ESP1
+ .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base
+ .set _TSSLM,MEM_DIR-MEM_TSS-1 # TSS limit
+ .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit
+#
+# Code segment.
+#
+ .globl start
+start: # Start of code
+#
+# BTX header.
+#
+btx_hdr: .byte 0xeb # Machine ID
+ .byte 0xe # Header size
+ .ascii "BTX" # Magic
+ .byte 0x1 # Major version
+ .byte 0x0 # Minor version
+ .byte 0x0 # Flags
+ .word PAG_CNT-MEM_ORG>>0xc # Paging control
+ .word break-start # Text size
+ .long 0x0 # Entry address
+#
+# Initialization routine.
+#
+init: cli # Disable interrupts
+ xorl %eax,%eax # Zero/segment
+ movl %ax,%ss # Set up
+ movwir(MEM_ESP0,_sp) # stack
+ movl %ax,%es # Address
+ movl %ax,%ds # data
+ pushw $0x2 # Clear
+ popfw # flags
+#
+# Initialize memory.
+#
+ movwir(MEM_IDT,_di) # Memory to initialize
+ movwir((MEM_ORG-MEM_IDT)/2,_cx) # Words to zero
+ pushl %edi # Save
+ rep # Zero-fill
+ stosl # memory
+ popl %edi # Restore
+#
+# Create IDT.
+#
+ movwir(idtctl,_si) # Control string
+init.1: lodsb # Get entry
+ cwde # count
+ xchgl %eax,%ecx # as word
+ jecxz init.4 # If done
+ lodsb # Get segment
+ xchgl %eax,%edx # P:DPL:type
+ lodsl # Get control
+ xchgl %eax,%ebx # set
+ lodsl # Get handler offset
+ movb $SEL_SCODE,%dh # Segment selector
+init.2: shrl %ebx # Handle this int?
+ jnc init.3 # No
+ movwr0(_ax,_di_) # Set handler offset
+ movbr1(_dh,0x2,_di_) # and selector
+ movbr1(_dl,0x5,_di_) # Set P:DPL:type
+ addwia(0x4) # Next handler
+init.3: leaw1r(0x8,_di_,_di) # Next entry
+ loop init.2 # Till set done
+ jmp init.1 # Continue
+#
+# Initialize TSS.
+#
+init.4: movbi1(_ESP0H,TSS_ESP0+1,_di_) # Set ESP0
+ movbi1(SEL_SDATA,TSS_SS0,_di_) # Set SS0
+ movbi1(_ESP1H,TSS_ESP1+1,_di_) # Set ESP1
+ movbi1(_TSSIO,TSS_MAP,_di_) # Set I/O bit map base
+#
+# Create page directory.
+#
+ xorw %dx,%dx # Page
+ movb $PAG_SIZ>>0x8,%dh # size
+ xorw %ax,%ax # Zero
+ movwir(MEM_DIR,_di) # Page directory
+ movb $PAG_CNT>>0xa,%cl # Entries
+ movwir(MEM_TBL|0x7,_ax) # First entry
+init.5: stosw # Write entry
+ addl %edx,%eax # To next
+ loop init.5 # Till done
+#
+# Create page tables.
+#
+ movwir(MEM_TBL,_di) # Page table
+ movb $PAG_CNT>>0x8,%ch # Entries
+ xorl %eax,%eax # Start address
+init.6: movb $0x7,%al # Set U:W:P flags
+ cmpwmr(btx_hdr+0x8,_cx) # Standard user page?
+ jb init.7 # Yes
+ cmpwir(PAG_CNT-MEM_BTX>>0xc,_cx)# BTX memory?
+ jae init.7 # No or first page
+ andb $~0x2,%al # Clear W flag
+ cmpwir(PAG_CNT-MEM_USR>>0xc,_cx)# User page zero?
+ jne init.7 # No
+ tstbim(0x80,btx_hdr+0x7) # Unmap it?
+ jz init.7 # No
+ andb $~0x1,%al # Clear P flag
+init.7: stosw # Set entry
+ addw %dx,%ax # Next address
+ loop init.6 # Till done
+#
+# Bring up the system.
+#
+ movwir(0x2820,_bx) # Set protected mode
+ callwi(setpic) # IRQ offsets
+ lidtwm(idtdesc) # Set IDT
+ xorw %ax,%ax # Set base
+ movb $MEM_DIR>>0x8,%ah # of page
+ movl %eax,%cr3 # directory
+ lgdtwm(gdtdesc) # Set GDT
+ movl %cr0,%eax # Switch to
+ o16 # protected mode
+ orl $0x80000001,%eax # and enable
+ movl %eax,%cr0 # paging
+ jmpfwi(SEL_SCODE,init.8) # To 32-bit code
+init.8: xorl %ecx,%ecx # Zero
+ movb $SEL_SDATA,%cl # To 32-bit
+ movl %cx,%ss # stack
+#
+# Launch user task.
+#
+ movb $SEL_TSS,%cl # Set task
+ ltrl %ecx # register
+ movl $MEM_USR,%edx # User base address
+ movzwl %ss:BDA_MEM,%eax # Get free memory
+.`ifdef' PC98
+ andl $0x7,%eax
+ incl %eax
+ shll $0x11,%eax # To bytes
+.else
+ shll $0xa,%eax # To bytes
+.endif
+ subl $0x1000,%eax # Less arg space
+ subl %edx,%eax # Less base
+ movb $SEL_UDATA,%cl # User data selector
+ pushl %ecx # Set SS
+ pushl %eax # Set ESP
+ pushl $0x202 # Set flags (IF set)
+ pushl $SEL_UCODE # Set CS
+ pushl btx_hdr+0xc # Set EIP
+ pushl %ecx # Set GS
+ pushl %ecx # Set FS
+ pushl %ecx # Set DS
+ pushl %ecx # Set ES
+ pushl %edx # Set EAX
+ movb $0x7,%cl # Set remaining
+init.9: pushb $0x0 # general
+ loop init.9 # registers
+ popa # and initialize
+ popl %es # Initialize
+ popl %ds # user
+ popl %fs # segment
+ popl %gs # registers
+ iret # To user mode
+#
+# Exit routine.
+#
+exit: cli # Disable interrupts
+ movl $MEM_ESP0,%esp # Clear stack
+#
+# Turn off paging.
+#
+ movl %cr0,%eax # Get CR0
+ andl $~0x80000000,%eax # Disable
+ movl %eax,%cr0 # paging
+ xorl %ecx,%ecx # Zero
+ movl %ecx,%cr3 # Flush TLB
+#
+# To 16 bits.
+#
+ o16 # Reload
+ jmpfwi(SEL_RCODE,exit.1) # CS
+exit.1: movb $SEL_RDATA,%cl # 16-bit selector
+ movl %cx,%ss # Reload SS
+ movl %cx,%ds # Load
+ movl %cx,%es # remaining
+ movl %cx,%fs # segment
+ movl %cx,%gs # registers
+#
+# To real-address mode.
+#
+ decl %eax # Switch to
+ movl %eax,%cr0 # real mode
+ jmpfwi(0x0,exit.2) # Reload CS
+exit.2: xorl %eax,%eax # Real mode segment
+ movl %ax,%ss # Reload SS
+ movl %ax,%ds # Address data
+.`ifdef' PC98
+ movwir(0x1008,_bx) # Set real mode
+.else
+ movwir(0x7008,_bx) # Set real mode
+.endif
+ callwi(setpic) # IRQ offsets
+ lidtwm(ivtdesc) # Set IVT
+#
+# Reboot or await reset.
+#
+ sti # Enable interrupts
+ tstbim(0x1,btx_hdr+0x7) # Reboot?
+exit.3: jz exit.3 # No
+.`ifdef' PC98
+ movb $0xa0,%al
+ outb %al,$0x35
+ movb 0,%al
+ outb %al,$0xf0
+exit.4: jmp exit.4
+.else
+ int $0x19 # BIOS: Reboot
+.endif
+#
+# Set IRQ offsets by reprogramming 8259A PICs.
+#
+.`ifdef' PC98
+setpic: inb $0x02,%al # Save master
+ pushl %eax # IMR
+ inb $0x0a,%al # Save slave
+ pushl %eax # IMR
+ movb $0x11,%al # ICW1 to
+ outb %al,$0x00 # master,
+ outb %al,$0x08 # slave
+ movb %bl,%al # ICW2 to
+ outb %al,$0x02 # master
+ movb %bh,%al # ICW2 to
+ outb %al,$0x0a # slave
+ movb $0x80,%al # ICW3 to
+ outb %al,$0x02 # master
+ movb $0x7,%al # ICW3 to
+ outb %al,$0x0a # slave
+ movb $0x1d,%al # ICW4 to
+ outb %al,$0x02 # master,
+ movb $0x9,%al # ICW4 to
+ outb %al,$0x0a # slave
+ popl %eax # Restore slave
+ outb %al,$0x0a # IMR
+ popl %eax # Restore master
+ outb %al,$0x02 # IMR
+.else
+setpic: inb $0x21,%al # Save master
+ pushl %eax # IMR
+ inb $0xa1,%al # Save slave
+ pushl %eax # IMR
+ movb $0x11,%al # ICW1 to
+ outb %al,$0x20 # master,
+ outb %al,$0xa0 # slave
+ movb %bl,%al # ICW2 to
+ outb %al,$0x21 # master
+ movb %bh,%al # ICW2 to
+ outb %al,$0xa1 # slave
+ movb $0x4,%al # ICW3 to
+ outb %al,$0x21 # master
+ movb $0x2,%al # ICW3 to
+ outb %al,$0xa1 # slave
+ movb $0x1,%al # ICW4 to
+ outb %al,$0x21 # master,
+ outb %al,$0xa1 # slave
+ popl %eax # Restore slave
+ outb %al,$0xa1 # IMR
+ popl %eax # Restore master
+ outb %al,$0x21 # IMR
+.endif
+ ret # To caller
+#
+# Initiate return from V86 mode to user mode.
+#
+inthlt: hlt # To supervisor mode
+#
+# Exception jump table.
+#
+intx00: pushb $0x0 # Int 0x0: #DE
+ jmp ex_noc # Divide error
+ pushb $0x1 # Int 0x1: #DB
+ jmp ex_noc # Debug
+ pushb $0x3 # Int 0x3: #BP
+ jmp ex_noc # Breakpoint
+ pushb $0x4 # Int 0x4: #OF
+ jmp ex_noc # Overflow
+ pushb $0x5 # Int 0x5: #BR
+ jmp ex_noc # BOUND range exceeded
+ pushb $0x6 # Int 0x6: #UD
+ jmp ex_noc # Invalid opcode
+ pushb $0x7 # Int 0x7: #NM
+ jmp ex_noc # Device not available
+ pushb $0x8 # Int 0x8: #DF
+ jmp except # Double fault
+ pushb $0xa # Int 0xa: #TS
+ jmp except # Invalid TSS
+ pushb $0xb # Int 0xb: #NP
+ jmp except # Segment not present
+ pushb $0xc # Int 0xc: #SS
+ jmp except # Stack segment fault
+ pushb $0xd # Int 0xd: #GP
+ jmp ex_v86 # General protection
+ pushb $0xe # Int 0xe: #PF
+ jmp except # Page fault
+intx10: pushb $0x10 # Int 0x10: #MF
+ jmp ex_noc # Floating-point error
+#
+# Handle #GP exception.
+#
+ex_v86: testb $0x2,0x12(%esp,1) # V86 mode?
+ jz except # No
+ jmp v86mon # To monitor
+#
+# Save a zero error code.
+#
+ex_noc: pushl (%esp,1) # Duplicate int no
+ movb $0x0,0x4(%esp,1) # Fake error code
+#
+# Handle exception.
+#
+except: cld # String ops inc
+ pushl %ds # Save
+ pushl %es # most
+ pusha # registers
+ movb $0x6,%al # Push loop count
+ testb $0x2,0x3a(%esp,1) # V86 mode?
+ jnz except.1 # Yes
+ pushl %gs # Set GS
+ pushl %fs # Set FS
+ pushl %ds # Set DS
+ pushl %es # Set ES
+ movb $0x2,%al # Push loop count
+ cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode?
+ jne except.1 # No
+ pushl %ss # Set SS
+ leal 0x50(%esp,1),%eax # Set
+ pushl %eax # ESP
+ jmp except.2 # Join common code
+except.1: pushl 0x50(%esp,1) # Set GS, FS, DS, ES
+ decb %al # (if V86 mode), and
+ jne except.1 # SS, ESP
+except.2: pushl $SEL_SDATA # Set up
+ popl %ds # to
+ pushl %ds # address
+ popl %es # data
+ movl %esp,%ebx # Stack frame
+ movl $dmpfmt,%esi # Dump format string
+ movl $MEM_BUF,%edi # Buffer
+.`ifdef' PC98
+ pushl %eax
+ pushl %edx
+wait.1:
+ inb $0x60,%al
+ testb $0x04,%al
+ jz wait.1
+ movb $0xe0,%al
+ outb %al,$0x62
+wait.2:
+ inb $0x60,%al
+ testb $0x01,%al
+ jz wait.2
+ xorl %edx,%edx
+ inb $0x62,%al
+ movb %al,%dl
+ inb $0x62,%al
+ movb %al,%dh
+ inb $0x62,%al
+ inb $0x62,%al
+ inb $0x62,%al
+ movl %edx,%eax
+ shlw $1,%ax
+ movl $BDA_POS,%edx
+ movw %ax,(%edx)
+ popl %edx
+ popl %eax
+.endif
+ pushl %edi # Dump to
+ call dump # buffer
+ popl %esi # and
+ call putstr # display
+ leal 0x18(%esp,1),%esp # Discard frame
+ popa # Restore
+ popl %es # registers
+ popl %ds # saved
+ cmpb $0x3,(%esp,1) # Breakpoint?
+ je except.3 # Yes
+ jmp exit # Exit
+except.3: leal 0x8(%esp,1),%esp # Discard err, int no
+ iret # From interrupt
+#
+# Return to user mode from V86 mode.
+#
+intrtn: cld # String ops inc
+ pushl %ds # Address
+ popl %es # data
+ leal 0x3c(%ebp),%edx # V86 Segment registers
+ movl MEM_TSS+TSS_ESP1,%esi # Link stack pointer
+ lodsl # INT_V86 args pointer
+ movl %esi,%ebx # Saved exception frame
+ testl %eax,%eax # INT_V86 args?
+ jz intrtn.2 # No
+ movl $MEM_USR,%edi # User base
+ movl 0x1c(%esi),%ebx # User ESP
+ movl %eax,(%edi,%ebx,1) # Restore to user stack
+ leal 0x8(%edi,%eax,1),%edi # Arg segment registers
+ testb $0x4,-0x6(%edi) # Return flags?
+ jz intrtn.1 # No
+ movl 0x30(%ebp),%eax # Get V86 flags
+ movw %ax,0x18(%esi) # Set user flags
+intrtn.1: leal 0x10(%esi),%ebx # Saved exception frame
+ xchgl %edx,%esi # Segment registers
+ movb $0x4,%cl # Update seg regs
+ rep # in INT_V86
+ movsl # args
+intrtn.2: movl %edx,%esi # Segment registers
+ leal 0x28(%ebp),%edi # Set up seg
+ movb $0x4,%cl # regs for
+ rep # later
+ movsl # pop
+ movl %ebx,%esi # Restore exception
+ movb $0x5,%cl # frame to
+ rep # supervisor
+ movsl # stack
+ movl %esi,MEM_TSS+TSS_ESP1 # Link stack pointer
+ popa # Restore
+ leal 0x8(%esp,1),%esp # Discard err, int no
+ popl %es # Restore
+ popl %ds # user
+ popl %fs # segment
+ popl %gs # registers
+ iret # To user mode
+#
+# V86 monitor.
+#
+v86mon: cld # String ops inc
+ pushl $SEL_SDATA # Set up for
+ popl %ds # flat addressing
+ pusha # Save registers
+ movl %esp,%ebp # Address stack frame
+ movzwl 0x2c(%ebp),%edi # Load V86 CS
+ shll $0x4,%edi # To linear
+ movl 0x28(%ebp),%esi # Load V86 IP
+ addl %edi,%esi # Code pointer
+ xorl %ecx,%ecx # Zero
+ movb $0x2,%cl # 16-bit operands
+ xorl %eax,%eax # Zero
+v86mon.1: lodsb # Get opcode
+ cmpb $0x66,%al # Operand size prefix?
+ jne v86mon.2 # No
+ movb $0x4,%cl # 32-bit operands
+ jmp v86mon.1 # Continue
+v86mon.2: cmpb $0xf4,%al # HLT?
+ jne v86mon.3 # No
+ cmpl $inthlt+0x1,%esi # Is inthlt?
+ jne v86mon.6 # No (ignore)
+ jmp intrtn # Return to user mode
+v86mon.3: cmpb $0xfa,%al # CLI?
+ je v86cli # Yes
+ cmpb $0xfb,%al # STI?
+ je v86sti # Yes
+ movzwl 0x38(%ebp),%ebx # Load V86 SS
+ shll $0x4,%ebx # To offset
+ pushl %ebx # Save
+ addl 0x34(%ebp),%ebx # Add V86 SP
+ movl 0x30(%ebp),%edx # Load V86 flags
+ cmpb $0x9c,%al # PUSHF/PUSHFD?
+ je v86pushf # Yes
+ cmpb $0x9d,%al # POPF/POPFD?
+ je v86popf # Yes
+ cmpb $0xcd,%al # INT imm8?
+ je v86intn # Yes
+ cmpb $0xcf,%al # IRET/IRETD?
+ je v86iret # Yes
+ popl %ebx # Restore
+ popa # Restore
+ jmp except # Handle exception
+v86mon.4: movl %edx,0x30(%ebp) # Save V86 flags
+v86mon.5: popl %edx # V86 SS adjustment
+ subl %edx,%ebx # Save V86
+ movl %ebx,0x34(%ebp) # SP
+v86mon.6: subl %edi,%esi # From linear
+ movl %esi,0x28(%ebp) # Save V86 IP
+ popa # Restore
+ leal 0x8(%esp,1),%esp # Discard int no, error
+ iret # To V86 mode
+#
+# Emulate CLI.
+#
+v86cli: andb $~0x2,0x31(%ebp) # Clear IF
+ jmp v86mon.6 # Finish up
+#
+# Emulate STI.
+#
+v86sti: orb $0x2,0x31(%ebp) # Set IF
+ jmp v86mon.6 # Finish up
+#
+# Emulate PUSHF/PUSHFD.
+#
+v86pushf: subl %ecx,%ebx # Adjust SP
+ cmpb $0x4,%cl # 32-bit
+ je v86pushf.1 # Yes
+ o16 # 16-bit
+v86pushf.1: movl %edx,(%ebx) # Save flags
+ jmp v86mon.5 # Finish up
+#
+# Emulate IRET/IRETD.
+#
+v86iret: movzwl (%ebx),%esi # Load V86 IP
+ movzwl 0x2(%ebx),%edi # Load V86 CS
+ leal 0x4(%ebx),%ebx # Adjust SP
+ movl %edi,0x2c(%ebp) # Save V86 CS
+ xorl %edi,%edi # No ESI adjustment
+#
+# Emulate POPF/POPFD (and remainder of IRET/IRETD).
+#
+v86popf: cmpb $0x4,%cl # 32-bit?
+ je v86popf.1 # Yes
+ movl %edx,%eax # Initialize
+ o16 # 16-bit
+v86popf.1: movl (%ebx),%eax # Load flags
+ addl %ecx,%ebx # Adjust SP
+ andl $V86_FLG,%eax # Merge
+ andl $~V86_FLG,%edx # the
+ orl %eax,%edx # flags
+ jmp v86mon.4 # Finish up
+#
+# Emulate INT imm8.
+#
+v86intn: lodsb # Get int no
+ subl %edi,%esi # From
+ shrl $0x4,%edi # linear
+ movw %dx,-0x2(%ebx) # Save flags
+ movw %di,-0x4(%ebx) # Save CS
+ leal -0x6(%ebx),%ebx # Adjust SP
+ movw %si,(%ebx) # Save IP
+ shll $0x2,%eax # Scale
+ movzwl (%eax),%esi # Load IP
+ movzwl 0x2(%eax),%edi # Load CS
+ movl %edi,0x2c(%ebp) # Save CS
+ xorl %edi,%edi # No ESI adjustment
+ andb $~0x3,%dh # Clear IF and TF
+ jmp v86mon.4 # Finish up
+#
+# Hardware interrupt jump table.
+#
+intx20: pushb $0x8 # Int 0x20: IRQ0
+ jmp int_hw # V86 int 0x8
+ pushb $0x9 # Int 0x21: IRQ1
+ jmp int_hw # V86 int 0x9
+ pushb $0xa # Int 0x22: IRQ2
+ jmp int_hw # V86 int 0xa
+ pushb $0xb # Int 0x23: IRQ3
+ jmp int_hw # V86 int 0xb
+ pushb $0xc # Int 0x24: IRQ4
+ jmp int_hw # V86 int 0xc
+ pushb $0xd # Int 0x25: IRQ5
+ jmp int_hw # V86 int 0xd
+ pushb $0xe # Int 0x26: IRQ6
+ jmp int_hw # V86 int 0xe
+ pushb $0xf # Int 0x27: IRQ7
+ jmp int_hw # V86 int 0xf
+.`ifdef' PC98
+ pushb $0x10 # Int 0x28: IRQ8
+ jmp int_hw # V86 int 0x10
+ pushb $0x11 # Int 0x29: IRQ9
+ jmp int_hw # V86 int 0x11
+ pushb $0x12 # Int 0x2a: IRQ10
+ jmp int_hw # V86 int 0x12
+ pushb $0x13 # Int 0x2b: IRQ11
+ jmp int_hw # V86 int 0x13
+ pushb $0x14 # Int 0x2c: IRQ12
+ jmp int_hw # V86 int 0x14
+ pushb $0x15 # Int 0x2d: IRQ13
+ jmp int_hw # V86 int 0x15
+ pushb $0x16 # Int 0x2e: IRQ14
+ jmp int_hw # V86 int 0x16
+ pushb $0x17 # Int 0x2f: IRQ15
+ jmp int_hw # V86 int 0x17
+.else
+ pushb $0x70 # Int 0x28: IRQ8
+ jmp int_hw # V86 int 0x70
+ pushb $0x71 # Int 0x29: IRQ9
+ jmp int_hw # V86 int 0x71
+ pushb $0x72 # Int 0x2a: IRQ10
+ jmp int_hw # V86 int 0x72
+ pushb $0x73 # Int 0x2b: IRQ11
+ jmp int_hw # V86 int 0x73
+ pushb $0x74 # Int 0x2c: IRQ12
+ jmp int_hw # V86 int 0x74
+ pushb $0x75 # Int 0x2d: IRQ13
+ jmp int_hw # V86 int 0x75
+ pushb $0x76 # Int 0x2e: IRQ14
+ jmp int_hw # V86 int 0x76
+ pushb $0x77 # Int 0x2f: IRQ15
+ jmp int_hw # V86 int 0x77
+.endif
+#
+# Reflect hardware interrupts.
+#
+int_hw: testb $0x2,0xe(%esp,1) # V86 mode?
+ jz intusr # No
+ pushl $SEL_SDATA # Address
+ popl %ds # data
+ xchgl %eax,(%esp,1) # Swap EAX, int no
+ pushl %ebp # Address
+ movl %esp,%ebp # stack frame
+ pushl %ebx # Save
+ shll $0x2,%eax # Get int
+ movl (%eax),%eax # vector
+ subl $0x6,0x14(%ebp) # Adjust V86 ESP
+ movzwl 0x18(%ebp),%ebx # V86 SS
+ shll $0x4,%ebx # * 0x10
+ addl 0x14(%ebp),%ebx # + V86 ESP
+ xchgw %ax,0x8(%ebp) # Swap V86 IP
+ rorl $0x10,%eax # Swap words
+ xchgw %ax,0xc(%ebp) # Swap V86 CS
+ roll $0x10,%eax # Swap words
+ movl %eax,(%ebx) # CS:IP for IRET
+ movl 0x10(%ebp),%eax # V86 flags
+ movw %ax,0x4(%ebx) # Flags for IRET
+ andb $~0x3,0x11(%ebp) # Clear IF, TF
+ popl %ebx # Restore
+ popl %ebp # saved
+ popl %eax # registers
+ iret # To V86 mode
+#
+# Invoke V86 interrupt from user mode, with arguments.
+#
+intx31: stc # Have btx_v86
+ pushl %eax # Missing int no
+#
+# Invoke V86 interrupt from user mode.
+#
+intusr: std # String ops dec
+ pushl %eax # Expand
+ pushl %eax # stack
+ pushl %eax # frame
+ pusha # Save
+ pushl %gs # Save
+ movl %esp,%eax # seg regs
+ pushl %fs # and
+ pushl %ds # point
+ pushl %es # to them
+ pushb $SEL_SDATA # Set up
+ popl %ds # to
+ pushl %ds # address
+ popl %es # data
+ movl $MEM_USR,%ebx # User base
+ movl %ebx,%edx # address
+ jc intusr.1 # If btx_v86
+ xorl %edx,%edx # Control flags
+ xorl %ebp,%ebp # btx_v86 pointer
+intusr.1: leal 0x50(%esp,1),%esi # Base of frame
+ pushl %esi # Save
+ addl -0x4(%esi),%ebx # User ESP
+ movl MEM_TSS+TSS_ESP1,%edi # Link stack pointer
+ leal -0x4(%edi),%edi # Adjust for push
+ xorl %ecx,%ecx # Zero
+ movb $0x5,%cl # Push exception
+ rep # frame on
+ movsl # link stack
+ xchgl %eax,%esi # Saved seg regs
+ movl 0x40(%esp,1),%eax # Get int no
+ testl %edx,%edx # Have btx_v86?
+ jz intusr.2 # No
+ movl (%ebx),%ebp # btx_v86 pointer
+ movb $0x4,%cl # Count
+ addl %ecx,%ebx # Adjust for pop
+ rep # Push saved seg regs
+ movsl # on link stack
+ addl %ebp,%edx # Flatten btx_v86 ptr
+ leal 0x14(%edx),%esi # Seg regs pointer
+ movl 0x4(%edx),%eax # Get int no/address
+ movzwl 0x2(%edx),%edx # Get control flags
+intusr.2: movl %ebp,(%edi) # Push btx_v86 and
+ movl %edi,MEM_TSS+TSS_ESP1 # save link stack ptr
+ popl %edi # Base of frame
+ xchgl %eax,%ebp # Save intno/address
+ movl 0x48(%esp,1),%eax # Get flags
+ testb $0x2,%dl # Simulate CALLF?
+ jnz intusr.3 # Yes
+ decl %ebx # Push flags
+ decl %ebx # on V86
+ movw %ax,(%ebx) # stack
+intusr.3: movb $0x4,%cl # Count
+ subl %ecx,%ebx # Push return address
+ movl $inthlt,(%ebx) # on V86 stack
+ rep # Copy seg regs to
+ movsl # exception frame
+ xchgl %eax,%ecx # Save flags
+ movl %ebx,%eax # User ESP
+ subl $V86_STK,%eax # Less bytes
+ ja intusr.4 # to
+ xorl %eax,%eax # keep
+intusr.4: shrl $0x4,%eax # Gives segment
+ stosl # Set SS
+ shll $0x4,%eax # To bytes
+ xchgl %eax,%ebx # Swap
+ subl %ebx,%eax # Gives offset
+ stosl # Set ESP
+ xchgl %eax,%ecx # Get flags
+ btsl $0x11,%eax # Set VM
+ andb $~0x3,%ah # Clear IF and TF
+ stosl # Set EFL
+ xchgl %eax,%ebp # Get int no/address
+ testb $0x1,%dl # Address?
+ jnz intusr.5 # Yes
+ shll $0x2,%eax # Scale
+ movl (%eax),%eax # Load int vector
+intusr.5: movl %eax,%ecx # Save
+ shrl $0x10,%eax # Gives segment
+ stosl # Set CS
+ movw %cx,%ax # Restore
+ stosl # Set EIP
+ leal 0x10(%esp,1),%esp # Discard seg regs
+ popa # Restore
+ iret # To V86 mode
+#
+# System Call.
+#
+intx30: cmpl $SYS_EXEC,%eax # Exec system call?
+ jne intx30.1 # No
+ pushl %ss # Set up
+ popl %es # all
+ pushl %es # segment
+ popl %ds # registers
+ pushl %ds # for the
+ popl %fs # program
+ pushl %fs # we're
+ popl %gs # invoking
+ movl $MEM_USR,%eax # User base address
+ addl 0xc(%esp,1),%eax # Change to user
+ leal 0x4(%eax),%esp # stack
+ movl %cr0,%eax # Turn
+ andl $~0x80000000,%eax # off
+ movl %eax,%cr0 # paging
+ xorl %eax,%eax # Flush
+ movl %eax,%cr3 # TLB
+ popl %eax # Call
+ call *%eax # program
+intx30.1: incb %ss:btx_hdr+0x7 # Flag reboot
+ jmp exit # Exit
+#
+# Dump structure [EBX] to [EDI], using format string [ESI].
+#
+dump.0: stosb # Save char
+dump: lodsb # Load char
+ testb %al,%al # End of string?
+ jz dump.10 # Yes
+ testb $0x80,%al # Control?
+ jz dump.0 # No
+ movb %al,%ch # Save control
+ movb $'=',%al # Append
+ stosb # '='
+ lodsb # Get offset
+ pushl %esi # Save
+ movsbl %al,%esi # To
+ addl %ebx,%esi # pointer
+ testb $DMP_X16,%ch # Dump word?
+ jz dump.1 # No
+ lodsw # Get and
+ call hex16 # dump it
+dump.1: testb $DMP_X32,%ch # Dump long?
+ jz dump.2 # No
+ lodsl # Get and
+ call hex32 # dump it
+dump.2: testb $DMP_MEM,%ch # Dump memory?
+ jz dump.8 # No
+ pushl %ds # Save
+ testb $0x2,0x52(%ebx) # V86 mode?
+ jnz dump.3 # Yes
+ verrl 0x4(%esi) # Readable selector?
+ jnz dump.3 # No
+ ldsl (%esi),%esi # Load pointer
+ jmp dump.4 # Join common code
+dump.3: lodsl # Set offset
+ xchgl %eax,%edx # Save
+ lodsl # Get segment
+ shll $0x4,%eax # * 0x10
+ addl %edx,%eax # + offset
+ xchgl %eax,%esi # Set pointer
+dump.4: movb $0x10,%cl # Bytes to dump
+dump.5: lodsb # Get byte and
+ call hex8 # dump it
+ decb %cl # Keep count
+ jz dump.7 # If done
+ movb $'-',%al # Separator
+ cmpb $0x8,%cl # Half way?
+ je dump.6 # Yes
+ movb $' ',%al # Use space
+dump.6: stosb # Save separator
+ jmp dump.5 # Continue
+dump.7: popl %ds # Restore
+dump.8: popl %esi # Restore
+ movb $0xa,%al # Line feed
+ testb $DMP_EOL,%ch # End of line?
+ jnz dump.9 # Yes
+ movb $' ',%al # Use spaces
+ stosb # Save one
+dump.9: jmp dump.0 # Continue
+dump.10: stosb # Terminate string
+ ret # To caller
+#
+# Convert EAX, AX, or AL to hex, saving the result to [EDI].
+#
+hex32: pushl %eax # Save
+ shrl $0x10,%eax # Do upper
+ call hex16 # 16
+ popl %eax # Restore
+hex16: call hex16.1 # Do upper 8
+hex16.1: xchgb %ah,%al # Save/restore
+hex8: pushl %eax # Save
+ shrb $0x4,%al # Do upper
+ call hex8.1 # 4
+ popl %eax # Restore
+hex8.1: andb $0xf,%al # Get lower 4
+ cmpb $0xa,%al # Convert
+ sbbb $0x69,%al # to hex
+ das # digit
+ orb $0x20,%al # To lower case
+ stosb # Save char
+ ret # (Recursive)
+#
+# Output zero-terminated string [ESI] to the console.
+#
+putstr.0: call putchr # Output char
+putstr: lodsb # Load char
+ testb %al,%al # End of string?
+ jnz putstr.0 # No
+ ret # To caller
+#
+# Output character AL to the console.
+#
+putchr: pusha # Save
+ xorl %ecx,%ecx # Zero for loops
+ movb $SCR_MAT,%ah # Mode/attribute
+ movl $BDA_POS,%ebx # BDA pointer
+ movw (%ebx),%dx # Cursor position
+.`ifdef' PC98
+ movl $0xa0000,%edi
+.else
+ movl $0xb8000,%edi # Regen buffer (color)
+ cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode?
+ jne putchr.1 # No
+ xorw %di,%di # Regen buffer (mono)
+.endif
+putchr.1: cmpb $0xa,%al # New line?
+ je putchr.2 # Yes
+.`ifdef' PC98
+ movw %dx,%cx
+ movb %al,(%edi,%ecx,1) # Write char
+ addl $0x2000,%ecx
+ movb %ah,(%edi,%ecx,1) # Write attr
+ addw $0x02,%dx
+ jmp putchr.3
+putchr.2: movw %dx,%ax
+ movb $SCR_COL*2,%dl
+ div %dl
+ incb %al
+ mul %dl
+ movw %ax,%dx
+putchr.3: cmpw $SCR_ROW*SCR_COL*2,%dx
+.else
+ xchgl %eax,%ecx # Save char
+ movb $SCR_COL,%al # Columns per row
+ mulb %dh # * row position
+ addb %dl,%al # + column
+ adcb $0x0,%ah # position
+ shll %eax # * 2
+ xchgl %eax,%ecx # Swap char, offset
+ movw %ax,(%edi,%ecx,1) # Write attr:char
+ incl %edx # Bump cursor
+ cmpb $SCR_COL,%dl # Beyond row?
+ jb putchr.3 # No
+putchr.2: xorb %dl,%dl # Zero column
+ incb %dh # Bump row
+putchr.3: cmpb $SCR_ROW,%dh # Beyond screen?
+.endif
+ jb putchr.4 # No
+ leal 2*SCR_COL(%edi),%esi # New top line
+ movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
+ rep # Scroll
+ movsl # screen
+ movb $' ',%al # Space
+.`ifdef' PC98
+ xorb %ah,%ah
+.endif
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+.`ifdef' PC98
+ movw $(SCR_ROW-1)*SCR_COL*2,%dx
+.else
+ movb $SCR_ROW-1,%dh # Bottom line
+.endif
+putchr.4: movw %dx,(%ebx) # Update position
+ popa # Restore
+ ret # To caller
+
+ .p2align 4
+#
+# Global descriptor table.
+#
+gdt: .word 0x0,0x0,0x0,0x0 # Null entry
+ .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
+ .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
+ .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
+ .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
+ .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
+ .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
+ .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
+gdt.1:
+#
+# Pseudo-descriptors.
+#
+gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT
+idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT
+ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT
+#
+# IDT construction control string.
+#
+idtctl: .byte 0x10, 0x8e # Int 0x0-0xf
+ .word 0x7dfb,intx00 # (exceptions)
+ .byte 0x10, 0x8e # Int 0x10
+ .word 0x1, intx10 # (exception)
+ .byte 0x10, 0x8e # Int 0x20-0x2f
+ .word 0xffff,intx20 # (hardware)
+ .byte 0x1, 0xee # int 0x30
+ .word 0x1, intx30 # (system call)
+ .byte 0x2, 0xee # Int 0x31-0x32
+ .word 0x1, intx31 # (V86, null)
+ .byte 0x0 # End of string
+#
+# Dump format string.
+#
+dmpfmt: .byte '\n' # "\n"
+ .ascii "int" # "int="
+ .byte 0x80|DMP_X32, 0x40 # "00000000 "
+ .ascii "err" # "err="
+ .byte 0x80|DMP_X32, 0x44 # "00000000 "
+ .ascii "efl" # "efl="
+ .byte 0x80|DMP_X32, 0x50 # "00000000 "
+ .ascii "eip" # "eip="
+ .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
+ .ascii "eax" # "eax="
+ .byte 0x80|DMP_X32, 0x34 # "00000000 "
+ .ascii "ebx" # "ebx="
+ .byte 0x80|DMP_X32, 0x28 # "00000000 "
+ .ascii "ecx" # "ecx="
+ .byte 0x80|DMP_X32, 0x30 # "00000000 "
+ .ascii "edx" # "edx="
+ .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
+ .ascii "esi" # "esi="
+ .byte 0x80|DMP_X32, 0x1c # "00000000 "
+ .ascii "edi" # "edi="
+ .byte 0x80|DMP_X32, 0x18 # "00000000 "
+ .ascii "ebp" # "ebp="
+ .byte 0x80|DMP_X32, 0x20 # "00000000 "
+ .ascii "esp" # "esp="
+ .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n"
+ .ascii "cs" # "cs="
+ .byte 0x80|DMP_X16, 0x4c # "0000 "
+ .ascii "ds" # "ds="
+ .byte 0x80|DMP_X16, 0xc # "0000 "
+ .ascii "es" # "es="
+ .byte 0x80|DMP_X16, 0x8 # "0000 "
+ .ascii " " # " "
+ .ascii "fs" # "fs="
+ .byte 0x80|DMP_X16, 0x10 # "0000 "
+ .ascii "gs" # "gs="
+ .byte 0x80|DMP_X16, 0x14 # "0000 "
+ .ascii "ss" # "ss="
+ .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n"
+ .ascii "cs:eip" # "cs:eip="
+ .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
+ .ascii "ss:esp" # "ss:esp="
+ .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n"
+ .asciz "System halted" # End
+#
+# End of BTX memory.
+#
+ .p2align 4
+break:
diff --git a/sys/boot/pc98/btx/btxldr/Makefile b/sys/boot/pc98/btx/btxldr/Makefile
new file mode 100644
index 0000000..5bd155c
--- /dev/null
+++ b/sys/boot/pc98/btx/btxldr/Makefile
@@ -0,0 +1,26 @@
+# $Id: Makefile,v 1.6 1998/10/30 00:11:35 msmith Exp $
+
+ORG=0x100000
+#AFLAGS+= -x assembler-with-cpp
+
+#AFLAGS+= --defsym PC98=1 --defsym BTXLDR_VERBOSE=1
+AFLAGS+= --defsym PC98=1
+
+all: btxldr
+
+btxldr: btxldr.o
+.if ${OBJFORMAT} == aout
+ ${LD} -nostdlib -N -s -T ${ORG} -o btxldr.out btxldr.o
+ dd if=btxldr.out of=${.TARGET} ibs=32 skip=1
+.else
+ ${LD} -N -e start -Ttext ${ORG} -o btxldr.out btxldr.o
+ objcopy -S -O binary btxldr.out ${.TARGET}
+.endif
+
+btxldr.o: btxldr.s
+# ${CC} ${AFLAGS} -c -o ${.TARGET} ${.CURDIR}/btxldr.s
+ ${AS} ${AFLAGS} -o ${.TARGET} ${.CURDIR}/btxldr.s
+
+CLEANFILES+= btxldr btxldr.out btxldr.o
+
+.include <bsd.prog.mk>
diff --git a/sys/boot/pc98/btx/btxldr/btxldr.S b/sys/boot/pc98/btx/btxldr/btxldr.S
new file mode 100644
index 0000000..6217eb2
--- /dev/null
+++ b/sys/boot/pc98/btx/btxldr/btxldr.S
@@ -0,0 +1,459 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btxldr.s,v 1.5 1999/01/22 13:07:17 rnordier Exp $
+
+#
+# Prototype BTX loader program, written in a couple of hours. The
+# real thing should probably be more flexible, and in C.
+#
+
+#
+# Memory locations.
+#
+ .set MEM_STUB,0x600 # Real mode stub
+ .set MEM_ESP,0x1000 # New stack pointer
+ .set MEM_TBL,0x5000 # BTX page tables
+ .set MEM_ENTRY,0x9010 # BTX entry point
+ .set MEM_DATA,0x101000 # Data segment
+#
+# Segment selectors.
+#
+ .set SEL_SCODE,0x8 # 4GB code
+ .set SEL_SDATA,0x10 # 4GB data
+ .set SEL_RCODE,0x18 # 64K code
+ .set SEL_RDATA,0x20 # 64K data
+#
+# Paging constants.
+#
+ .set PAG_SIZ,0x1000 # Page size
+ .set PAG_ENT,0x4 # Page entry size
+#
+# Screen constants.
+#
+.ifdef PC98
+ .set SCR_MAT,0xe1 # Mode/attribute
+.else
+ .set SCR_MAT,0x7 # Mode/attribute
+.endif
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+#
+# BIOS Data Area locations.
+#
+.ifdef PC98
+ .set BDA_MEM,0xa1501 # Free memory
+ .set BDA_POS,0xa153e # Cursor position
+.else
+ .set BDA_MEM,0x413 # Free memory
+ .set BDA_SCR,0x449 # Video mode
+ .set BDA_POS,0x450 # Cursor position
+.endif
+#
+# Required by aout gas inadequacy.
+#
+ .set SIZ_STUB,0x1a # Size of stub
+#
+# We expect to be loaded by boot2 at 0x100000.
+#
+ .globl start
+#
+# BTX program loader for ELF clients.
+#
+start: cld # String ops inc
+.ifdef PC98
+ cli
+gdcwait.1: inb $0x60,%al
+ testb $0x04,%al
+ jz gdcwait.1
+ movb $0xe0,%al
+ outb %al,$0x62
+ nop
+gdcwait.2: inb $0x60,%al
+ testb $0x01,%al
+ jz gdcwait.2
+ inb $0x62,%al
+ movb %al,%dl
+ inb $0x62,%al
+ movb %al,%dh
+ inb $0x62,%al
+ inb $0x62,%al
+ inb $0x62,%al
+ shlw $1,%dx
+ movl $BDA_POS,%ebx
+ movw %dx,(%ebx)
+.endif
+ movl $m_logo,%esi # Identify
+ call putstr # ourselves
+ movzwl BDA_MEM,%eax # Get base memory
+.ifdef PC98
+ andl $0x7,%eax
+ incl %eax
+ shll $0x11,%eax # in bytes
+.else
+ shll $0xa,%eax # in bytes
+.endif
+ movl %eax,%ebp # Base of user stack
+ movl $m_mem,%esi # Display
+ call dhexout # amount of
+ call dputstr # base memory
+ lgdt gdtdesc # Load new GDT
+#
+# Relocate caller's arguments.
+#
+ movl $m_esp,%esi # Display
+ movl %esp,%eax # caller's
+ call dhexout # stack
+ call dputstr # pointer
+ movl $m_args,%esi # Format string
+ leal 0x4(%esp,1),%ebx # First argument
+ movl $0x6,%ecx # Count
+start.1: movl (%ebx),%eax # Get argument and
+ addl $0x4,%ebx # bump pointer
+ call dhexout # Display it
+ loop start.1 # Till done
+ call dputstr # End message
+ movl $0x48,%ecx # Allocate space
+ subl %ecx,%ebp # for bootinfo
+ movl 0x18(%esp,1),%esi # Source
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # it
+ movl %ebp,0x18(%esp,1) # Update pointer
+ movl $m_rel_bi,%esi # Display
+ movl %ebp,%eax # bootinfo
+ call dhexout # relocation
+ call dputstr # message
+ movl $0x18,%ecx # Allocate space
+ subl %ecx,%ebp # for arguments
+ leal 0x4(%esp,1),%esi # Source
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # them
+ movl $m_rel_args,%esi # Display
+ movl %ebp,%eax # argument
+ call dhexout # relocation
+ call dputstr # message
+#
+# Set up BTX kernel.
+#
+ movl $MEM_ESP,%esp # Set up new stack
+ movl $MEM_DATA,%ebx # Data segment
+ movl $m_vers,%esi # Display BTX
+ call putstr # version message
+ movb 0x5(%ebx),%al # Get major version
+ addb $'0',%al # Display
+ call putchr # it
+ movb $'.',%al # And a
+ call putchr # dot
+ movb 0x6(%ebx),%al # Get minor
+ xorb %ah,%ah # version
+ movb $0xa,%dl # Divide
+ divb %dl,%al # by 10
+ addb $'0',%al # Display
+ call putchr # tens
+ movb %ah,%al # Get units
+ addb $'0',%al # Display
+ call putchr # units
+ call putstr # End message
+ movl %ebx,%esi # BTX image
+ movzwl 0x8(%ebx),%edi # Compute
+ orl $PAG_SIZ/PAG_ENT-1,%edi # the
+ incl %edi # BTX
+ shll $0x2,%edi # load
+ addl $MEM_TBL,%edi # address
+ pushl %edi # Save
+ movzwl 0xa(%ebx),%ecx # Image size
+ pushl %ecx # Save
+ rep # Relocate
+ movsb # BTX
+ movl %esi,%ebx # Keep place
+ movl $m_rel_btx,%esi # Restore
+ popl %eax # parameters
+ call dhexout # and
+ popl %ebp # display
+ movl %ebp,%eax # the
+ call dhexout # relocation
+ call dputstr # message
+ addl $PAG_SIZ,%ebp # Display
+ movl $m_base,%esi # the
+ movl %ebp,%eax # user
+ call dhexout # base
+ call dputstr # address
+#
+# Set up ELF-format client program.
+#
+ cmpl $0x464c457f,(%ebx) # ELF magic number?
+ je start.3 # Yes
+ movl $e_fmt,%esi # Display error
+ call putstr # message
+start.2: jmp start.2 # Hang
+start.3: movl $m_elf,%esi # Display ELF
+ call dputstr # message
+ movl $m_segs,%esi # Format string
+ movl $0x2,%edi # Segment count
+ movl 0x1c(%ebx),%edx # Get e_phoff
+ addl %ebx,%edx # To pointer
+ movzwl 0x2c(%ebx),%ecx # Get e_phnum
+start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD?
+ jne start.6 # No
+ movl 0x4(%edx),%eax # Display
+ call dhexout # p_offset
+ movl 0x8(%edx),%eax # Display
+ call dhexout # p_vaddr
+ movl 0x10(%edx),%eax # Display
+ call dhexout # p_filesz
+ movl 0x14(%edx),%eax # Display
+ call dhexout # p_memsz
+ call dputstr # End message
+ pushl %esi # Save
+ pushl %edi # working
+ pushl %ecx # registers
+ movl 0x4(%edx),%esi # Get p_offset
+ addl %ebx,%esi # as pointer
+ movl 0x8(%edx),%edi # Get p_vaddr
+ addl %ebp,%edi # as pointer
+ movl 0x10(%edx),%ecx # Get p_filesz
+ rep # Set up
+ movsb # segment
+ movl 0x14(%edx),%ecx # Any bytes
+ subl 0x10(%edx),%ecx # to zero?
+ jz start.5 # No
+ xorb %al,%al # Then
+ rep # zero
+ stosb # them
+start.5: popl %ecx # Restore
+ popl %edi # working
+ popl %esi # registers
+ decl %edi # Segments to do
+ je start.7 # If none
+start.6: addl $0x20,%edx # To next entry
+ loop start.4 # Till done
+start.7: movl $m_done,%esi # Display done
+ call dputstr # message
+ movl $start.8,%esi # Real mode stub
+ movl $MEM_STUB,%edi # Destination
+ movl $SIZ_STUB,%ecx # Size
+ rep # Relocate
+ movsb # it
+ ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code
+start.8: xorl %eax,%eax # Data
+ movb $SEL_RDATA,%al # selector
+ movl %eax,%ss # Reload SS
+ movl %eax,%ds # Reset
+ movl %eax,%es # other
+ movl %eax,%fs # segment
+ movl %eax,%gs # limits
+ movl %cr0,%eax # Switch to
+ decl %eax # real
+ movl %eax,%cr0 # mode
+ .byte 0xea # Jump to
+ .word MEM_ENTRY # BTX entry
+ .word 0x0 # point
+start.9:
+#
+# Output message [ESI] followed by EAX in hex.
+#
+dhexout:
+.ifndef BTXLDR_VERBOSE
+ ret
+.endif
+hexout: pushl %eax # Save
+ call putstr # Display message
+ popl %eax # Restore
+ pushl %esi # Save
+ pushl %edi # caller's
+ movl $buf,%edi # Buffer
+ pushl %edi # Save
+ call hex32 # To hex
+ xorb %al,%al # Terminate
+ stosb # string
+ popl %esi # Restore
+hexout.1: lodsb # Get a char
+ cmpb $'0',%al # Leading zero?
+ je hexout.1 # Yes
+ testb %al,%al # End of string?
+ jne hexout.2 # No
+ decl %esi # Undo
+hexout.2: decl %esi # Adjust for inc
+ call putstr # Display hex
+ popl %edi # Restore
+ popl %esi # caller's
+ ret # To caller
+#
+# Output zero-terminated string [ESI] to the console.
+#
+dputstr:
+.ifndef BTXLDR_VERBOSE
+ ret
+.else
+ jmp putstr
+.endif
+putstr.0: call putchr # Output char
+putstr: lodsb # Load char
+ testb %al,%al # End of string?
+ jne putstr.0 # No
+ ret # To caller
+#
+# Output character AL to the console.
+#
+dputchr:
+.ifndef BTXLDR_VERBOSE
+ ret
+.endif
+putchr: pusha # Save
+ xorl %ecx,%ecx # Zero for loops
+ movb $SCR_MAT,%ah # Mode/attribute
+ movl $BDA_POS,%ebx # BDA pointer
+ movw (%ebx),%dx # Cursor position
+.ifdef PC98
+ movl $0xa0000,%edi # Regen buffer (color)
+.else
+ movl $0xb8000,%edi # Regen buffer (color)
+ cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode?
+ jne putchr.1 # No
+ xorw %di,%di # Regen buffer (mono)
+.endif
+putchr.1: cmpb $0xa,%al # New line?
+ je putchr.2 # Yes
+.ifdef PC98
+ movw %dx,%cx
+ movb %al,(%edi,%ecx,1) # Write char
+ addl $0x2000,%ecx
+ movb %ah,(%edi,%ecx,1) # Write attr
+ addw $0x2,%dx
+ jmp putchr.3
+putchr.2: movw %dx,%ax
+ movb $SCR_COL*2,%dl
+ div %dl
+ incb %al
+ mul %dl
+ movw %ax,%dx
+putchr.3: cmpw $SCR_COL*SCR_ROW*2,%dx
+.else
+ xchgl %eax,%ecx # Save char
+ movb $SCR_COL,%al # Columns per row
+ mulb %dh # * row position
+ addb %dl,%al # + column
+ adcb $0x0,%ah # position
+ shll %eax # * 2
+ xchgl %eax,%ecx # Swap char, offset
+ movw %ax,(%edi,%ecx,1) # Write attr:char
+ incl %edx # Bump cursor
+ cmpb $SCR_COL,%dl # Beyond row?
+ jb putchr.3 # No
+putchr.2: xorb %dl,%dl # Zero column
+ incb %dh # Bump row
+putchr.3: cmpb $SCR_ROW,%dh # Beyond screen?
+.endif
+ jb putchr.4 # No
+ leal 2*SCR_COL(%edi),%esi # New top line
+ movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
+ rep # Scroll
+ movsl # screen
+ movb $' ',%al # Space
+.ifdef PC98
+ xorb %ah,%ah
+.endif
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+.ifdef PC98
+ movw $(SCR_ROW-1)*SCR_COL*2,%dx
+putchr.4: movw %dx,(%ebx) # Update position
+ shrw $1,%dx
+gdcwait.3: inb $0x60,%al
+ testb $0x04,%al
+ jz gdcwait.3
+ movb $0x49,%al
+ outb %al,$0x62
+ movb %dl,%al
+ outb %al,$0x60
+ movb %dh,%al
+ outb %al,$0x60
+.else
+ movb $SCR_ROW-1,%dh # Bottom line
+putchr.4: movw %dx,(%ebx) # Update position
+.endif
+ popa # Restore
+ ret # To caller
+#
+# Convert EAX, AX, or AL to hex, saving the result to [EDI].
+#
+hex32: pushl %eax # Save
+ shrl $0x10,%eax # Do upper
+ call hex16 # 16
+ popl %eax # Restore
+hex16: call hex16.1 # Do upper 8
+hex16.1: xchgb %ah,%al # Save/restore
+hex8: pushl %eax # Save
+ shrb $0x4,%al # Do upper
+ call hex8.1 # 4
+ popl %eax # Restore
+hex8.1: andb $0xf,%al # Get lower 4
+ cmpb $0xa,%al # Convert
+ sbbb $0x69,%al # to hex
+ das # digit
+ orb $0x20,%al # To lower case
+ stosb # Save char
+ ret # (Recursive)
+
+ .data
+ .p2align 4
+#
+# Global descriptor table.
+#
+gdt: .word 0x0,0x0,0x0,0x0 # Null entry
+ .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
+ .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
+ .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
+ .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
+gdt.1:
+gdtdesc: .word gdt.1-gdt-1 # Limit
+ .long gdt # Base
+#
+# Messages.
+#
+m_logo: .asciz "\nBTX loader 1.00 "
+m_vers: .asciz "BTX version is \0\n"
+e_fmt: .asciz "Error: Client format not supported\n"
+#.ifdef BTXLDR_VERBOSE
+m_mem: .asciz "Starting in protected mode (base mem=\0)\n"
+m_esp: .asciz "Arguments passed (esp=\0):\n"
+m_args: .asciz"<howto="
+ .asciz" bootdev="
+ .asciz" junk="
+ .asciz" "
+ .asciz" "
+ .asciz" bootinfo=\0>\n"
+m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n"
+m_rel_args: .asciz "Relocated arguments (size=18) to \0\n"
+m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n"
+m_base: .asciz "Client base address is \0\n"
+m_elf: .asciz "Client format is ELF\n"
+m_segs: .asciz "text segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+ .asciz "data segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+m_done: .asciz "Loading complete\n"
+#.endif
+#
+# Uninitialized data area.
+#
+buf: # Scratch buffer
diff --git a/sys/boot/pc98/btx/btxldr/btxldr.s b/sys/boot/pc98/btx/btxldr/btxldr.s
new file mode 100644
index 0000000..6217eb2
--- /dev/null
+++ b/sys/boot/pc98/btx/btxldr/btxldr.s
@@ -0,0 +1,459 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btxldr.s,v 1.5 1999/01/22 13:07:17 rnordier Exp $
+
+#
+# Prototype BTX loader program, written in a couple of hours. The
+# real thing should probably be more flexible, and in C.
+#
+
+#
+# Memory locations.
+#
+ .set MEM_STUB,0x600 # Real mode stub
+ .set MEM_ESP,0x1000 # New stack pointer
+ .set MEM_TBL,0x5000 # BTX page tables
+ .set MEM_ENTRY,0x9010 # BTX entry point
+ .set MEM_DATA,0x101000 # Data segment
+#
+# Segment selectors.
+#
+ .set SEL_SCODE,0x8 # 4GB code
+ .set SEL_SDATA,0x10 # 4GB data
+ .set SEL_RCODE,0x18 # 64K code
+ .set SEL_RDATA,0x20 # 64K data
+#
+# Paging constants.
+#
+ .set PAG_SIZ,0x1000 # Page size
+ .set PAG_ENT,0x4 # Page entry size
+#
+# Screen constants.
+#
+.ifdef PC98
+ .set SCR_MAT,0xe1 # Mode/attribute
+.else
+ .set SCR_MAT,0x7 # Mode/attribute
+.endif
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+#
+# BIOS Data Area locations.
+#
+.ifdef PC98
+ .set BDA_MEM,0xa1501 # Free memory
+ .set BDA_POS,0xa153e # Cursor position
+.else
+ .set BDA_MEM,0x413 # Free memory
+ .set BDA_SCR,0x449 # Video mode
+ .set BDA_POS,0x450 # Cursor position
+.endif
+#
+# Required by aout gas inadequacy.
+#
+ .set SIZ_STUB,0x1a # Size of stub
+#
+# We expect to be loaded by boot2 at 0x100000.
+#
+ .globl start
+#
+# BTX program loader for ELF clients.
+#
+start: cld # String ops inc
+.ifdef PC98
+ cli
+gdcwait.1: inb $0x60,%al
+ testb $0x04,%al
+ jz gdcwait.1
+ movb $0xe0,%al
+ outb %al,$0x62
+ nop
+gdcwait.2: inb $0x60,%al
+ testb $0x01,%al
+ jz gdcwait.2
+ inb $0x62,%al
+ movb %al,%dl
+ inb $0x62,%al
+ movb %al,%dh
+ inb $0x62,%al
+ inb $0x62,%al
+ inb $0x62,%al
+ shlw $1,%dx
+ movl $BDA_POS,%ebx
+ movw %dx,(%ebx)
+.endif
+ movl $m_logo,%esi # Identify
+ call putstr # ourselves
+ movzwl BDA_MEM,%eax # Get base memory
+.ifdef PC98
+ andl $0x7,%eax
+ incl %eax
+ shll $0x11,%eax # in bytes
+.else
+ shll $0xa,%eax # in bytes
+.endif
+ movl %eax,%ebp # Base of user stack
+ movl $m_mem,%esi # Display
+ call dhexout # amount of
+ call dputstr # base memory
+ lgdt gdtdesc # Load new GDT
+#
+# Relocate caller's arguments.
+#
+ movl $m_esp,%esi # Display
+ movl %esp,%eax # caller's
+ call dhexout # stack
+ call dputstr # pointer
+ movl $m_args,%esi # Format string
+ leal 0x4(%esp,1),%ebx # First argument
+ movl $0x6,%ecx # Count
+start.1: movl (%ebx),%eax # Get argument and
+ addl $0x4,%ebx # bump pointer
+ call dhexout # Display it
+ loop start.1 # Till done
+ call dputstr # End message
+ movl $0x48,%ecx # Allocate space
+ subl %ecx,%ebp # for bootinfo
+ movl 0x18(%esp,1),%esi # Source
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # it
+ movl %ebp,0x18(%esp,1) # Update pointer
+ movl $m_rel_bi,%esi # Display
+ movl %ebp,%eax # bootinfo
+ call dhexout # relocation
+ call dputstr # message
+ movl $0x18,%ecx # Allocate space
+ subl %ecx,%ebp # for arguments
+ leal 0x4(%esp,1),%esi # Source
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # them
+ movl $m_rel_args,%esi # Display
+ movl %ebp,%eax # argument
+ call dhexout # relocation
+ call dputstr # message
+#
+# Set up BTX kernel.
+#
+ movl $MEM_ESP,%esp # Set up new stack
+ movl $MEM_DATA,%ebx # Data segment
+ movl $m_vers,%esi # Display BTX
+ call putstr # version message
+ movb 0x5(%ebx),%al # Get major version
+ addb $'0',%al # Display
+ call putchr # it
+ movb $'.',%al # And a
+ call putchr # dot
+ movb 0x6(%ebx),%al # Get minor
+ xorb %ah,%ah # version
+ movb $0xa,%dl # Divide
+ divb %dl,%al # by 10
+ addb $'0',%al # Display
+ call putchr # tens
+ movb %ah,%al # Get units
+ addb $'0',%al # Display
+ call putchr # units
+ call putstr # End message
+ movl %ebx,%esi # BTX image
+ movzwl 0x8(%ebx),%edi # Compute
+ orl $PAG_SIZ/PAG_ENT-1,%edi # the
+ incl %edi # BTX
+ shll $0x2,%edi # load
+ addl $MEM_TBL,%edi # address
+ pushl %edi # Save
+ movzwl 0xa(%ebx),%ecx # Image size
+ pushl %ecx # Save
+ rep # Relocate
+ movsb # BTX
+ movl %esi,%ebx # Keep place
+ movl $m_rel_btx,%esi # Restore
+ popl %eax # parameters
+ call dhexout # and
+ popl %ebp # display
+ movl %ebp,%eax # the
+ call dhexout # relocation
+ call dputstr # message
+ addl $PAG_SIZ,%ebp # Display
+ movl $m_base,%esi # the
+ movl %ebp,%eax # user
+ call dhexout # base
+ call dputstr # address
+#
+# Set up ELF-format client program.
+#
+ cmpl $0x464c457f,(%ebx) # ELF magic number?
+ je start.3 # Yes
+ movl $e_fmt,%esi # Display error
+ call putstr # message
+start.2: jmp start.2 # Hang
+start.3: movl $m_elf,%esi # Display ELF
+ call dputstr # message
+ movl $m_segs,%esi # Format string
+ movl $0x2,%edi # Segment count
+ movl 0x1c(%ebx),%edx # Get e_phoff
+ addl %ebx,%edx # To pointer
+ movzwl 0x2c(%ebx),%ecx # Get e_phnum
+start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD?
+ jne start.6 # No
+ movl 0x4(%edx),%eax # Display
+ call dhexout # p_offset
+ movl 0x8(%edx),%eax # Display
+ call dhexout # p_vaddr
+ movl 0x10(%edx),%eax # Display
+ call dhexout # p_filesz
+ movl 0x14(%edx),%eax # Display
+ call dhexout # p_memsz
+ call dputstr # End message
+ pushl %esi # Save
+ pushl %edi # working
+ pushl %ecx # registers
+ movl 0x4(%edx),%esi # Get p_offset
+ addl %ebx,%esi # as pointer
+ movl 0x8(%edx),%edi # Get p_vaddr
+ addl %ebp,%edi # as pointer
+ movl 0x10(%edx),%ecx # Get p_filesz
+ rep # Set up
+ movsb # segment
+ movl 0x14(%edx),%ecx # Any bytes
+ subl 0x10(%edx),%ecx # to zero?
+ jz start.5 # No
+ xorb %al,%al # Then
+ rep # zero
+ stosb # them
+start.5: popl %ecx # Restore
+ popl %edi # working
+ popl %esi # registers
+ decl %edi # Segments to do
+ je start.7 # If none
+start.6: addl $0x20,%edx # To next entry
+ loop start.4 # Till done
+start.7: movl $m_done,%esi # Display done
+ call dputstr # message
+ movl $start.8,%esi # Real mode stub
+ movl $MEM_STUB,%edi # Destination
+ movl $SIZ_STUB,%ecx # Size
+ rep # Relocate
+ movsb # it
+ ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code
+start.8: xorl %eax,%eax # Data
+ movb $SEL_RDATA,%al # selector
+ movl %eax,%ss # Reload SS
+ movl %eax,%ds # Reset
+ movl %eax,%es # other
+ movl %eax,%fs # segment
+ movl %eax,%gs # limits
+ movl %cr0,%eax # Switch to
+ decl %eax # real
+ movl %eax,%cr0 # mode
+ .byte 0xea # Jump to
+ .word MEM_ENTRY # BTX entry
+ .word 0x0 # point
+start.9:
+#
+# Output message [ESI] followed by EAX in hex.
+#
+dhexout:
+.ifndef BTXLDR_VERBOSE
+ ret
+.endif
+hexout: pushl %eax # Save
+ call putstr # Display message
+ popl %eax # Restore
+ pushl %esi # Save
+ pushl %edi # caller's
+ movl $buf,%edi # Buffer
+ pushl %edi # Save
+ call hex32 # To hex
+ xorb %al,%al # Terminate
+ stosb # string
+ popl %esi # Restore
+hexout.1: lodsb # Get a char
+ cmpb $'0',%al # Leading zero?
+ je hexout.1 # Yes
+ testb %al,%al # End of string?
+ jne hexout.2 # No
+ decl %esi # Undo
+hexout.2: decl %esi # Adjust for inc
+ call putstr # Display hex
+ popl %edi # Restore
+ popl %esi # caller's
+ ret # To caller
+#
+# Output zero-terminated string [ESI] to the console.
+#
+dputstr:
+.ifndef BTXLDR_VERBOSE
+ ret
+.else
+ jmp putstr
+.endif
+putstr.0: call putchr # Output char
+putstr: lodsb # Load char
+ testb %al,%al # End of string?
+ jne putstr.0 # No
+ ret # To caller
+#
+# Output character AL to the console.
+#
+dputchr:
+.ifndef BTXLDR_VERBOSE
+ ret
+.endif
+putchr: pusha # Save
+ xorl %ecx,%ecx # Zero for loops
+ movb $SCR_MAT,%ah # Mode/attribute
+ movl $BDA_POS,%ebx # BDA pointer
+ movw (%ebx),%dx # Cursor position
+.ifdef PC98
+ movl $0xa0000,%edi # Regen buffer (color)
+.else
+ movl $0xb8000,%edi # Regen buffer (color)
+ cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode?
+ jne putchr.1 # No
+ xorw %di,%di # Regen buffer (mono)
+.endif
+putchr.1: cmpb $0xa,%al # New line?
+ je putchr.2 # Yes
+.ifdef PC98
+ movw %dx,%cx
+ movb %al,(%edi,%ecx,1) # Write char
+ addl $0x2000,%ecx
+ movb %ah,(%edi,%ecx,1) # Write attr
+ addw $0x2,%dx
+ jmp putchr.3
+putchr.2: movw %dx,%ax
+ movb $SCR_COL*2,%dl
+ div %dl
+ incb %al
+ mul %dl
+ movw %ax,%dx
+putchr.3: cmpw $SCR_COL*SCR_ROW*2,%dx
+.else
+ xchgl %eax,%ecx # Save char
+ movb $SCR_COL,%al # Columns per row
+ mulb %dh # * row position
+ addb %dl,%al # + column
+ adcb $0x0,%ah # position
+ shll %eax # * 2
+ xchgl %eax,%ecx # Swap char, offset
+ movw %ax,(%edi,%ecx,1) # Write attr:char
+ incl %edx # Bump cursor
+ cmpb $SCR_COL,%dl # Beyond row?
+ jb putchr.3 # No
+putchr.2: xorb %dl,%dl # Zero column
+ incb %dh # Bump row
+putchr.3: cmpb $SCR_ROW,%dh # Beyond screen?
+.endif
+ jb putchr.4 # No
+ leal 2*SCR_COL(%edi),%esi # New top line
+ movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
+ rep # Scroll
+ movsl # screen
+ movb $' ',%al # Space
+.ifdef PC98
+ xorb %ah,%ah
+.endif
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+.ifdef PC98
+ movw $(SCR_ROW-1)*SCR_COL*2,%dx
+putchr.4: movw %dx,(%ebx) # Update position
+ shrw $1,%dx
+gdcwait.3: inb $0x60,%al
+ testb $0x04,%al
+ jz gdcwait.3
+ movb $0x49,%al
+ outb %al,$0x62
+ movb %dl,%al
+ outb %al,$0x60
+ movb %dh,%al
+ outb %al,$0x60
+.else
+ movb $SCR_ROW-1,%dh # Bottom line
+putchr.4: movw %dx,(%ebx) # Update position
+.endif
+ popa # Restore
+ ret # To caller
+#
+# Convert EAX, AX, or AL to hex, saving the result to [EDI].
+#
+hex32: pushl %eax # Save
+ shrl $0x10,%eax # Do upper
+ call hex16 # 16
+ popl %eax # Restore
+hex16: call hex16.1 # Do upper 8
+hex16.1: xchgb %ah,%al # Save/restore
+hex8: pushl %eax # Save
+ shrb $0x4,%al # Do upper
+ call hex8.1 # 4
+ popl %eax # Restore
+hex8.1: andb $0xf,%al # Get lower 4
+ cmpb $0xa,%al # Convert
+ sbbb $0x69,%al # to hex
+ das # digit
+ orb $0x20,%al # To lower case
+ stosb # Save char
+ ret # (Recursive)
+
+ .data
+ .p2align 4
+#
+# Global descriptor table.
+#
+gdt: .word 0x0,0x0,0x0,0x0 # Null entry
+ .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
+ .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
+ .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
+ .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
+gdt.1:
+gdtdesc: .word gdt.1-gdt-1 # Limit
+ .long gdt # Base
+#
+# Messages.
+#
+m_logo: .asciz "\nBTX loader 1.00 "
+m_vers: .asciz "BTX version is \0\n"
+e_fmt: .asciz "Error: Client format not supported\n"
+#.ifdef BTXLDR_VERBOSE
+m_mem: .asciz "Starting in protected mode (base mem=\0)\n"
+m_esp: .asciz "Arguments passed (esp=\0):\n"
+m_args: .asciz"<howto="
+ .asciz" bootdev="
+ .asciz" junk="
+ .asciz" "
+ .asciz" "
+ .asciz" bootinfo=\0>\n"
+m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n"
+m_rel_args: .asciz "Relocated arguments (size=18) to \0\n"
+m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n"
+m_base: .asciz "Client base address is \0\n"
+m_elf: .asciz "Client format is ELF\n"
+m_segs: .asciz "text segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+ .asciz "data segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+m_done: .asciz "Loading complete\n"
+#.endif
+#
+# Uninitialized data area.
+#
+buf: # Scratch buffer
diff --git a/sys/boot/pc98/btx/lib/Makefile b/sys/boot/pc98/btx/lib/Makefile
new file mode 100644
index 0000000..e47e653
--- /dev/null
+++ b/sys/boot/pc98/btx/lib/Makefile
@@ -0,0 +1,20 @@
+# $Id: Makefile,v 1.2 1998/10/11 11:27:48 rnordier Exp $
+
+OBJS= btxcsu.o btxsys.o btxv86.o
+AFLAGS+= -elf
+LDFLAGS+= -elf
+CLEANFILES+= crt0.o
+INTERNALLIB= true
+NOMAN= true
+NOPIC= true
+NOPROFILE= true
+
+all: crt0.o
+
+crt0.o: ${OBJS}
+ ${LD} ${LDFLAGS} -i -o ${.TARGET} ${OBJS}
+
+.include <bsd.lib.mk>
+
+.s.o:
+ ${AS} ${AFLAGS} -o ${.TARGET} ${.IMPSRC}
diff --git a/sys/boot/pc98/btx/lib/btxcsu.s b/sys/boot/pc98/btx/lib/btxcsu.s
new file mode 100644
index 0000000..28b878b
--- /dev/null
+++ b/sys/boot/pc98/btx/lib/btxcsu.s
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btxcsu.s,v 1.2 1998/10/04 21:15:45 rnordier Exp $
+
+#
+# BTX C startup code (ELF).
+#
+
+#
+# Globals.
+#
+ .global _start
+#
+# Constants.
+#
+ .set ARGADJ,0xfa0 # Argument adjustment
+#
+# Client entry point.
+#
+_start: movl %eax,__base # Set base address
+ movl %esp,%eax # Set
+ addl $ARGADJ,%eax # argument
+ movl %eax,__args # pointer
+ call main # Invoke client main()
+ call exit # Invoke client exit()
+#
+# Data.
+#
+ .comm __base,4 # Client base address
+ .comm __args,4 # Client arguments
diff --git a/sys/boot/pc98/btx/lib/btxsys.s b/sys/boot/pc98/btx/lib/btxsys.s
new file mode 100644
index 0000000..6273bfa
--- /dev/null
+++ b/sys/boot/pc98/btx/lib/btxsys.s
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btxsys.s,v 1.1 1998/09/14 10:37:00 rnordier Exp $
+
+#
+# BTX system calls.
+#
+
+#
+# Globals.
+#
+ .global __exit
+ .global __exec
+#
+# Constants.
+#
+ .set INT_SYS,0x30 # Interrupt number
+#
+# System call: exit
+#
+__exit: xorl %eax,%eax # BTX system
+ int $INT_SYS # call 0x0
+#
+# System call: exec
+#
+__exec: movl $0x1,%eax # BTX system
+ int $INT_SYS # call 0x1
diff --git a/sys/boot/pc98/btx/lib/btxv86.h b/sys/boot/pc98/btx/lib/btxv86.h
new file mode 100644
index 0000000..05708f2
--- /dev/null
+++ b/sys/boot/pc98/btx/lib/btxv86.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+/*
+ * $Id: btxv86.h,v 1.4 1998/10/02 20:52:26 msmith Exp $
+ */
+
+#ifndef _BTXV86_H_
+#define _BTXV86_H_
+
+#include <sys/types.h>
+
+#define V86_ADDR 0x10000 /* Segment:offset address */
+#define V86_CALLF 0x20000 /* Emulate far call */
+#define V86_FLAGS 0x40000 /* Return flags */
+
+struct __v86 {
+ uint32_t ctl; /* Control flags */
+ uint32_t addr; /* Interrupt number or address */
+ uint32_t es; /* V86 ES register */
+ uint32_t ds; /* V86 DS register */
+ uint32_t fs; /* V86 FS register */
+ uint32_t gs; /* V86 GS register */
+ uint32_t eax; /* V86 EAX register */
+ uint32_t ecx; /* V86 ECX register */
+ uint32_t edx; /* V86 EDX register */
+ uint32_t ebx; /* V86 EBX register */
+ uint32_t efl; /* V86 eflags register */
+ uint32_t ebp; /* V86 EBP register */
+ uint32_t esi; /* V86 ESI register */
+ uint32_t edi; /* V86 EDI register */
+};
+
+extern struct __v86 __v86; /* V86 interface structure */
+void __v86int(void);
+
+#define v86 __v86
+#define v86int __v86int
+
+extern u_int32_t __base;
+extern u_int32_t __args;
+
+#define PTOV(pa) ((caddr_t)(pa) - __base)
+#define VTOP(va) ((vm_offset_t)(va) + __base)
+#define VTOPSEG(va) (u_int16_t)(VTOP((caddr_t)va) >> 4)
+#define VTOPOFF(va) (u_int16_t)(VTOP((caddr_t)va) & 0xf)
+
+void __exit(int) __attribute__((__noreturn__));
+void __exec(caddr_t, ...);
+
+#endif /* !_BTXV86_H_ */
diff --git a/sys/boot/pc98/btx/lib/btxv86.s b/sys/boot/pc98/btx/lib/btxv86.s
new file mode 100644
index 0000000..14b7767
--- /dev/null
+++ b/sys/boot/pc98/btx/lib/btxv86.s
@@ -0,0 +1,85 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btxv86.s,v 1.2 1998/10/22 20:22:07 msmith Exp $
+
+#
+# BTX V86 interface.
+#
+
+#
+# Globals.
+#
+ .global __v86int
+#
+# Fields in V86 interface structure.
+#
+ .set V86_CTL,0x0 # Control flags
+ .set V86_ADDR,0x4 # Int number/address
+ .set V86_ES,0x8 # V86 ES
+ .set V86_DS,0xc # V86 DS
+ .set V86_FS,0x10 # V86 FS
+ .set V86_GS,0x14 # V86 GS
+ .set V86_EAX,0x18 # V86 EAX
+ .set V86_ECX,0x1c # V86 ECX
+ .set V86_EDX,0x20 # V86 EDX
+ .set V86_EBX,0x24 # V86 EBX
+ .set V86_EFL,0x28 # V86 eflags
+ .set V86_EBP,0x2c # V86 EBP
+ .set V86_ESI,0x30 # V86 ESI
+ .set V86_EDI,0x34 # V86 EDI
+#
+# Other constants.
+#
+ .set INT_V86,0x31 # Interrupt number
+ .set SIZ_V86,0x38 # Size of V86 structure
+#
+# V86 interface function.
+#
+__v86int: popl __v86ret # Save return address
+ pushl $__v86 # Push pointer
+ call __v86_swap # Load V86 registers
+ int $INT_V86 # To BTX
+ call __v86_swap # Load user registers
+ addl $0x4,%esp # Discard pointer
+ pushl __v86ret # Restore return address
+ ret # To user
+#
+# Swap V86 and user registers.
+#
+__v86_swap: xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP
+ xchgl %eax,V86_EAX(%ebp) # Swap EAX
+ xchgl %ecx,V86_ECX(%ebp) # Swap ECX
+ xchgl %edx,V86_EDX(%ebp) # Swap EDX
+ xchgl %ebx,V86_EBX(%ebp) # Swap EBX
+ pushl %eax # Save
+ pushf # Put eflags
+ popl %eax # in EAX
+ xchgl %eax,V86_EFL(%ebp) # Swap
+ pushl %eax # Put EAX
+ popf # in eflags
+ movl 0x8(%esp,1),%eax # Load EBP
+ xchgl %eax,V86_EBP(%ebp) # Swap
+ movl %eax,0x8(%esp,1) # Save EBP
+ popl %eax # Restore
+ xchgl %esi,V86_ESI(%ebp) # Swap ESI
+ xchgl %edi,V86_EDI(%ebp) # Swap EDI
+ xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP
+ ret # To caller
+#
+# V86 interface structure.
+#
+ .comm __v86,SIZ_V86
+ .comm __v86ret,4
diff --git a/sys/boot/pc98/libpc98/Makefile b/sys/boot/pc98/libpc98/Makefile
new file mode 100644
index 0000000..fad0149
--- /dev/null
+++ b/sys/boot/pc98/libpc98/Makefile
@@ -0,0 +1,42 @@
+# $Id: Makefile,v 1.13 1999/01/10 14:48:04 rnordier Exp $
+#
+LIB= pc98
+NOPIC=
+NOPROFILE=
+INTERNALLIB= true
+INTERNALSTATICLIB= true
+
+SRCS= aout_freebsd.c biosdisk.c biosmem.c biospnp.c biospci.c \
+ bootinfo.c comconsole.c devicename.c elf_freebsd.c gatea20.c \
+ i386_copy.c i386_module.c time.c vidconsole.c
+.PATH: ${.CURDIR}/../../i386/libi386
+
+CFLAGS+= -DPC98
+
+CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../btx/lib \
+ -I${.CURDIR}/../../.. -I. -I${.CURDIR}/../../i386/libi386
+
+BOOT_COMCONSOLE_PORT?= 0x238
+CFLAGS+= -DCOMPORT=${BOOT_COMCONSOLE_PORT}
+
+BOOT_COMCONSOLE_SPEED?= 9600
+CFLAGS+= -DCOMSPEED=${BOOT_COMCONSOLE_SPEED}
+
+# Make the disk code more talkative
+#CFLAGS+= -DDISK_DEBUG
+
+# Include simple terminal emulation (cons25-compatible)
+CFLAGS+= -DTERM_EMU
+
+# If it's not there, don't consider it a target
+.if exists(${.CURDIR}/../../../i386/include)
+beforedepend ${OBJS}: machine
+
+machine:
+ ln -sf ${.CURDIR}/../../../i386/include machine
+
+.endif
+
+CLEANFILES+= machine
+
+.include <bsd.lib.mk>
diff --git a/sys/boot/pc98/libpc98/biosdisk.c b/sys/boot/pc98/libpc98/biosdisk.c
new file mode 100644
index 0000000..cef10b8
--- /dev/null
+++ b/sys/boot/pc98/libpc98/biosdisk.c
@@ -0,0 +1,1017 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * 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 form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: biosdisk.c,v 1.23 1999/01/25 23:07:02 rnordier Exp $
+ */
+
+/*
+ * BIOS disk device handling.
+ *
+ * Ideas and algorithms from:
+ *
+ * - NetBSD libi386/biosdisk.c
+ * - FreeBSD biosboot/disk.c
+ *
+ * XXX Todo: add bad144 support.
+ */
+
+#include <stand.h>
+
+#include <sys/disklabel.h>
+#include <sys/diskslice.h>
+#include <sys/reboot.h>
+
+#include <stdarg.h>
+
+#include <bootstrap.h>
+#include <btxv86.h>
+#include "libi386.h"
+
+#define BIOSDISK_SECSIZE 512
+#define BUFSIZE (1 * BIOSDISK_SECSIZE)
+#define MAXBDDEV MAXDEV
+
+#define DT_ATAPI 0x10 /* disk type for ATAPI floppies */
+#define WDMAJOR 0 /* major numbers for devices we frontend for */
+#define WFDMAJOR 1
+#define FDMAJOR 2
+#define DAMAJOR 4
+
+#ifdef DISK_DEBUG
+# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __FUNCTION__ , ## args)
+#else
+# define DEBUG(fmt, args...)
+#endif
+
+struct open_disk {
+ int od_dkunit; /* disk unit number */
+ int od_unit; /* BIOS unit number */
+ int od_cyl; /* BIOS geometry */
+ int od_hds;
+ int od_sec;
+ int od_boff; /* block offset from beginning of BIOS disk */
+ int od_flags;
+#define BD_MODEMASK 0x3
+#define BD_MODEINT13 0x0
+#define BD_MODEEDD1 0x1
+#define BD_MODEEDD3 0x2
+#define BD_FLOPPY (1<<2)
+ struct disklabel od_disklabel;
+ struct dos_partition od_parttab[NDOSPART]; /* XXX needs to grow for extended partitions */
+#define BD_LABELOK (1<<3)
+#define BD_PARTTABOK (1<<4)
+};
+
+/*
+ * List of BIOS devices, translation from disk unit number to
+ * BIOS unit number.
+ */
+static struct bdinfo
+{
+ int bd_unit; /* BIOS unit number */
+ int bd_flags;
+ int bd_type; /* BIOS 'drive type' (floppy only) */
+#ifdef PC98
+ int bd_drive;
+#endif
+} bdinfo [MAXBDDEV];
+static int nbdinfo = 0;
+
+static int bd_getgeom(struct open_disk *od);
+static int bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest);
+
+static int bd_int13probe(struct bdinfo *bd);
+
+static void bd_printslice(struct open_disk *od, int offset, char *prefix);
+
+static int bd_init(void);
+static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize);
+static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize);
+static int bd_open(struct open_file *f, ...);
+static int bd_close(struct open_file *f);
+static void bd_print(int verbose);
+
+struct devsw biosdisk = {
+ "disk",
+ DEVT_DISK,
+ bd_init,
+ bd_strategy,
+ bd_open,
+ bd_close,
+ noioctl,
+ bd_print
+};
+
+static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev);
+static void bd_closedisk(struct open_disk *od);
+static int bd_bestslice(struct dos_partition *dptr);
+
+/*
+ * Translate between BIOS device numbers and our private unit numbers.
+ */
+int
+bd_bios2unit(int biosdev)
+{
+ int i;
+
+ DEBUG("looking for bios device 0x%x", biosdev);
+ for (i = 0; i < nbdinfo; i++) {
+ DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit);
+ if (bdinfo[i].bd_unit == biosdev)
+ return(i);
+ }
+ return(-1);
+}
+
+int
+bd_unit2bios(int unit)
+{
+ if ((unit >= 0) && (unit < nbdinfo))
+ return(bdinfo[unit].bd_unit);
+ return(-1);
+}
+
+/*
+ * Quiz the BIOS for disk devices, save a little info about them.
+ *
+ * XXX should we be consulting the BIOS equipment list, specifically
+ * the value at 0x475?
+ */
+static int
+bd_init(void)
+{
+ int base, unit;
+
+#ifdef PC98
+ int hd_drive=0, n=-0x10;
+ /* sequence 0x90, 0x80, 0xa0 */
+ for (base = 0x90; base <= 0xa0; base += n, n += 0x30) {
+ for (unit = base; (nbdinfo < MAXBDDEV) || ((unit & 0x0f) < 4); unit++) {
+ bdinfo[nbdinfo].bd_unit = unit;
+ bdinfo[nbdinfo].bd_flags = (unit & 0xf0) == 0x90 ? BD_FLOPPY : 0;
+
+ /* XXX add EDD probes */
+ if (!bd_int13probe(&bdinfo[nbdinfo]))
+ break;
+
+ if (bdinfo[nbdinfo].bd_flags & BD_FLOPPY){
+ bdinfo[nbdinfo].bd_drive = 'A' + (unit & 0xf);
+ if (*(u_char *)PTOV(0x5AE) & (1<<(unit & 0xf)))
+ /* available 1.44MB access */
+ bdinfo[nbdinfo].bd_unit = 0x30 + (unit & 0xf);
+ }
+ else
+ bdinfo[nbdinfo].bd_drive = 'C' + hd_drive++;
+ /* XXX we need "disk aliases" to make this simpler */
+ printf("BIOS drive %c: is disk%d\n",
+ bdinfo[nbdinfo].bd_drive, nbdinfo);
+ nbdinfo++;
+ }
+ }
+#else
+ /* sequence 0, 0x80 */
+ for (base = 0; base <= 0x80; base += 0x80) {
+ for (unit = base; (nbdinfo < MAXBDDEV); unit++) {
+ bdinfo[nbdinfo].bd_unit = unit;
+ bdinfo[nbdinfo].bd_flags = (unit < 0x80) ? BD_FLOPPY : 0;
+
+ /* XXX add EDD probes */
+ if (!bd_int13probe(&bdinfo[nbdinfo]))
+ break;
+
+ /* XXX we need "disk aliases" to make this simpler */
+ printf("BIOS drive %c: is disk%d\n",
+ (unit < 0x80) ? ('A' + unit) : ('C' + unit - 0x80), nbdinfo);
+ nbdinfo++;
+ }
+ }
+#endif
+ return(0);
+}
+
+/*
+ * Try to detect a device supported by the legacy int13 BIOS
+ */
+
+static int
+bd_int13probe(struct bdinfo *bd)
+{
+#ifdef PC98
+ int addr;
+ if (bd->bd_flags & BD_FLOPPY){
+ addr = 0xa155c;
+ }
+ else {
+ if ((bd->bd_unit & 0xf0) == 0x80)
+ addr = 0xa155d;
+ else
+ addr = 0xa1482;
+ }
+ if ( *(u_char *)PTOV(addr) & (1<<(bd->bd_unit & 0x0f))) {
+ bd->bd_flags |= BD_MODEINT13;
+ return(1);
+ }
+ return(0);
+#else
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x800;
+ v86.edx = bd->bd_unit;
+ v86int();
+
+ if (!(v86.efl & 0x1) && /* carry clear */
+ ((v86.edx & 0xff) > (bd->bd_unit & 0x7f))) { /* unit # OK */
+ bd->bd_flags |= BD_MODEINT13;
+ bd->bd_type = v86.ebx & 0xff;
+ return(1);
+ }
+#endif
+ return(0);
+}
+
+/*
+ * Print information about disks
+ */
+static void
+bd_print(int verbose)
+{
+ int i, j;
+ char line[80];
+ struct i386_devdesc dev;
+ struct open_disk *od;
+ struct dos_partition *dptr;
+
+ for (i = 0; i < nbdinfo; i++) {
+#ifdef PC98
+ sprintf(line, " disk%d: BIOS drive %c:\n", i,
+ bdinfo[i].bd_drive);
+#else
+ sprintf(line, " disk%d: BIOS drive %c:\n", i,
+ (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit) : ('C' + bdinfo[i].bd_unit - 0x80));
+#endif
+ pager_output(line);
+
+ /* try to open the whole disk */
+ dev.d_kind.biosdisk.unit = i;
+ dev.d_kind.biosdisk.slice = -1;
+ dev.d_kind.biosdisk.partition = -1;
+
+ if (!bd_opendisk(&od, &dev)) {
+
+ /* Do we have a partition table? */
+ if (od->od_flags & BD_PARTTABOK) {
+ dptr = &od->od_parttab[0];
+
+ /* Check for a "truly dedicated" disk */
+#ifdef PC98
+ for (j = 0; j < NDOSPART; j++) {
+ switch(dptr[j].dp_mid) {
+ case DOSMID_386BSD:
+ sprintf(line, " disk%ds%d", i, j + 1);
+ bd_printslice(od, dptr[j].dp_scyl * od->od_hds * od->od_sec + dptr[j].dp_shd * od->od_sec + dptr[j].dp_ssect, line);
+ break;
+ default:
+ }
+ }
+#else
+ if ((dptr[3].dp_typ == DOSPTYP_386BSD) &&
+ (dptr[3].dp_start == 0) &&
+ (dptr[3].dp_size == 50000)) {
+ sprintf(line, " disk%d", i);
+ bd_printslice(od, 0, line);
+ } else {
+ for (j = 0; j < NDOSPART; j++) {
+ switch(dptr[j].dp_typ) {
+ case DOSPTYP_386BSD:
+ sprintf(line, " disk%ds%d", i, j + 1);
+ bd_printslice(od, dptr[j].dp_start, line);
+ break;
+ default:
+ }
+ }
+
+ }
+#endif
+ }
+ bd_closedisk(od);
+ }
+ }
+}
+
+static void
+bd_printslice(struct open_disk *od, int offset, char *prefix)
+{
+ char line[80];
+ u_char buf[BIOSDISK_SECSIZE];
+ struct disklabel *lp;
+ int i;
+
+ /* read disklabel */
+ if (bd_read(od, offset + LABELSECTOR, 1, buf))
+ return;
+ lp =(struct disklabel *)(&buf[0]);
+ if (lp->d_magic != DISKMAGIC) {
+ sprintf(line, "bad disklabel\n");
+ pager_output(line);
+ return;
+ }
+
+ /* Print partitions */
+ for (i = 0; i < lp->d_npartitions; i++) {
+ if ((lp->d_partitions[i].p_fstype == FS_BSDFFS) || (lp->d_partitions[i].p_fstype == FS_SWAP) ||
+ ((lp->d_partitions[i].p_fstype == FS_UNUSED) &&
+ (od->od_flags & BD_FLOPPY) && (i == 0))) { /* Floppies often have bogus fstype, print 'a' */
+ sprintf(line, " %s%c: %s %.6dMB (%d - %d)\n", prefix, 'a' + i,
+ (lp->d_partitions[i].p_fstype == FS_SWAP) ? "swap" : "FFS",
+ lp->d_partitions[i].p_size / 2048, /* 512-byte sector assumption */
+ lp->d_partitions[i].p_offset, lp->d_partitions[i].p_offset + lp->d_partitions[i].p_size);
+ pager_output(line);
+ }
+ }
+}
+
+
+/*
+ * Attempt to open the disk described by (dev) for use by (f).
+ *
+ * Note that the philosophy here is "give them exactly what
+ * they ask for". This is necessary because being too "smart"
+ * about what the user might want leads to complications.
+ * (eg. given no slice or partition value, with a disk that is
+ * sliced - are they after the first BSD slice, or the DOS
+ * slice before it?)
+ */
+static int
+bd_open(struct open_file *f, ...)
+{
+ va_list ap;
+ struct i386_devdesc *dev;
+ struct open_disk *od;
+ int error;
+
+ va_start(ap, f);
+ dev = va_arg(ap, struct i386_devdesc *);
+ va_end(ap);
+ if ((error = bd_opendisk(&od, dev)))
+ return(error);
+
+ /*
+ * Save our context
+ */
+ ((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data = od;
+ DEBUG("open_disk %p, partition at 0x%x", od, od->od_boff);
+ return(0);
+}
+
+static int
+bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
+{
+ struct dos_partition *dptr;
+ struct disklabel *lp;
+ struct open_disk *od;
+ int sector, slice, i;
+ int error;
+ u_char buf[BUFSIZE];
+ daddr_t pref_slice[4];
+
+ if (dev->d_kind.biosdisk.unit >= nbdinfo) {
+ DEBUG("attempt to open nonexistent disk");
+ return(ENXIO);
+ }
+
+ od = (struct open_disk *)malloc(sizeof(struct open_disk));
+ if (!od) {
+ DEBUG("no memory");
+ return (ENOMEM);
+ }
+
+ /* Look up BIOS unit number, intialise open_disk structure */
+ od->od_dkunit = dev->d_kind.biosdisk.unit;
+ od->od_unit = bdinfo[od->od_dkunit].bd_unit;
+ od->od_flags = bdinfo[od->od_dkunit].bd_flags;
+ od->od_boff = 0;
+ error = 0;
+ DEBUG("open '%s', unit 0x%x slice %d partition %c",
+ i386_fmtdev(dev), dev->d_kind.biosdisk.unit,
+ dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition + 'a');
+
+ /* Get geometry for this open (removable device may have changed) */
+ if (bd_getgeom(od)) {
+ DEBUG("can't get geometry");
+ error = ENXIO;
+ goto out;
+ }
+
+ /*
+ * Following calculations attempt to determine the correct value
+ * for d->od_boff by looking for the slice and partition specified,
+ * or searching for reasonable defaults.
+ */
+
+ /*
+ * Find the slice in the DOS slice table.
+ */
+#ifdef PC98
+ if (od->od_flags & BD_FLOPPY) {
+ sector = 0;
+ goto unsliced;
+ }
+#endif
+ if (bd_read(od, 0, 1, buf)) {
+ DEBUG("error reading MBR");
+ error = EIO;
+ goto out;
+ }
+
+ /*
+ * Check the slice table magic.
+ */
+ if ((buf[0x1fe] != 0x55) || (buf[0x1ff] != 0xaa)) {
+ /* If a slice number was explicitly supplied, this is an error */
+ if (dev->d_kind.biosdisk.slice > 0) {
+ DEBUG("no slice table/MBR (no magic)");
+ error = ENOENT;
+ goto out;
+ }
+ sector = 0;
+ goto unsliced; /* may be a floppy */
+ }
+#ifdef PC98
+ if (bd_read(od, 1, 1, buf)) {
+ DEBUG("error reading MBR");
+ error = EIO;
+ goto out;
+ }
+#endif
+ bcopy(buf + DOSPARTOFF, &od->od_parttab, sizeof(struct dos_partition) * NDOSPART);
+ dptr = &od->od_parttab[0];
+ od->od_flags |= BD_PARTTABOK;
+
+ /* Is this a request for the whole disk? */
+ if (dev->d_kind.biosdisk.slice == -1) {
+ sector = 0;
+ goto unsliced;
+ }
+
+ /* Try to auto-detect the best slice; this should always give a slice number */
+ if (dev->d_kind.biosdisk.slice == 0)
+ dev->d_kind.biosdisk.slice = bd_bestslice(dptr);
+
+ switch (dev->d_kind.biosdisk.slice) {
+ case -1:
+ error = ENOENT;
+ goto out;
+ case 0:
+ sector = 0;
+ goto unsliced;
+ default:
+ break;
+ }
+
+ /*
+ * Accept the supplied slice number unequivocally (we may be looking
+ * at a DOS partition).
+ */
+ dptr += (dev->d_kind.biosdisk.slice - 1); /* we number 1-4, offsets are 0-3 */
+#ifdef PC98
+ sector = dptr->dp_scyl * od->od_hds * od->od_sec + dptr->dp_shd * od->od_sec + dptr->dp_ssect;
+ {
+ int end = dptr->dp_ecyl * od->od_hds * od->od_sec + dptr->dp_ehd * od->od_sec + dptr->dp_esect;
+ DEBUG("slice entry %d at %d, %d sectors", dev->d_kind.biosdisk.slice - 1, sector, end-sector);
+ }
+#else
+ sector = dptr->dp_start;
+ DEBUG("slice entry %d at %d, %d sectors", dev->d_kind.biosdisk.slice - 1, sector, dptr->dp_size);
+#endif
+
+ /*
+ * If we are looking at a BSD slice, and the partition is < 0, assume the 'a' partition
+ */
+#ifdef PC98
+ if ((dptr->dp_mid == DOSMID_386BSD) && (dev->d_kind.biosdisk.partition < 0))
+#else
+ if ((dptr->dp_typ == DOSPTYP_386BSD) && (dev->d_kind.biosdisk.partition < 0))
+#endif
+ dev->d_kind.biosdisk.partition = 0;
+
+ unsliced:
+ /*
+ * Now we have the slice offset, look for the partition in the disklabel if we have
+ * a partition to start with.
+ *
+ * XXX we might want to check the label checksum.
+ */
+ if (dev->d_kind.biosdisk.partition < 0) {
+ od->od_boff = sector; /* no partition, must be after the slice */
+ DEBUG("opening raw slice");
+ } else {
+ if (bd_read(od, sector + LABELSECTOR, 1, buf)) {
+ DEBUG("error reading disklabel");
+ error = EIO;
+ goto out;
+ }
+ DEBUG("copy %d bytes of label from %p to %p", sizeof(struct disklabel), buf + LABELOFFSET, &od->od_disklabel);
+ bcopy(buf + LABELOFFSET, &od->od_disklabel, sizeof(struct disklabel));
+ lp = &od->od_disklabel;
+ od->od_flags |= BD_LABELOK;
+
+ if (lp->d_magic != DISKMAGIC) {
+ DEBUG("no disklabel");
+ error = ENOENT;
+ goto out;
+ }
+ if (dev->d_kind.biosdisk.partition >= lp->d_npartitions) {
+ DEBUG("partition '%c' exceeds partitions in table (a-'%c')",
+ 'a' + dev->d_kind.biosdisk.partition, 'a' + lp->d_npartitions);
+ error = EPART;
+ goto out;
+
+ }
+
+ /* Complain if the partition type is wrong */
+ if ((lp->d_partitions[dev->d_kind.biosdisk.partition].p_fstype == FS_UNUSED) &&
+ !(od->od_flags & BD_FLOPPY)) /* Floppies often have bogus fstype */
+ DEBUG("warning, partition marked as unused");
+
+ od->od_boff = lp->d_partitions[dev->d_kind.biosdisk.partition].p_offset;
+ }
+
+ out:
+ if (error) {
+ free(od);
+ } else {
+ *odp = od; /* return the open disk */
+ }
+ return(error);
+}
+
+
+/*
+ * Search for a slice with the following preferences:
+ *
+ * 1: Active FreeBSD slice
+ * 2: Non-active FreeBSD slice
+ * 3: Active FAT/FAT32 slice
+ * 4: non-active FAT/FAT32 slice
+ */
+#define PREF_FBSD_ACT 0
+#define PREF_FBSD 1
+#define PREF_DOS_ACT 2
+#define PREF_DOS 3
+#define PREF_NONE 4
+
+static int
+bd_bestslice(struct dos_partition *dptr)
+{
+ int i;
+ int preflevel, pref;
+
+
+#ifndef PC98
+ /*
+ * Check for the historically bogus MBR found on true dedicated disks
+ */
+ if ((dptr[3].dp_typ == DOSPTYP_386BSD) &&
+ (dptr[3].dp_start == 0) &&
+ (dptr[3].dp_size == 50000))
+ return(0);
+#endif
+
+ preflevel = PREF_NONE;
+ pref = -1;
+
+ /*
+ * XXX No support here for 'extended' slices
+ */
+ for (i = 0; i < NDOSPART; i++) {
+#ifdef PC98
+ switch(dptr[i].dp_mid & 0x7f) {
+ case DOSMID_386BSD & 0x7f: /* FreeBSD */
+ if ((dptr[i].dp_mid & 0x80) && (preflevel > PREF_FBSD_ACT)) {
+ pref = i;
+ preflevel = PREF_FBSD_ACT;
+ } else if (preflevel > PREF_FBSD) {
+ pref = i;
+ preflevel = PREF_FBSD;
+ }
+ break;
+
+ case 0x11: /* DOS/Windows */
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x63:
+ if ((dptr[i].dp_mid & 0x80) && (preflevel > PREF_DOS_ACT)) {
+ pref = i;
+ preflevel = PREF_DOS_ACT;
+ } else if (preflevel > PREF_DOS) {
+ pref = i;
+ preflevel = PREF_DOS;
+ }
+ break;
+ }
+#else
+ switch(dptr[i].dp_typ) {
+ case DOSPTYP_386BSD: /* FreeBSD */
+ if ((dptr[i].dp_flag & 0x80) && (preflevel > PREF_FBSD_ACT)) {
+ pref = i;
+ preflevel = PREF_FBSD_ACT;
+ } else if (preflevel > PREF_FBSD) {
+ pref = i;
+ preflevel = PREF_FBSD;
+ }
+ break;
+
+ case 0x04: /* DOS/Windows */
+ case 0x06:
+ case 0x0b:
+ case 0x0c:
+ case 0x0e:
+ case 0x63:
+ if ((dptr[i].dp_flag & 0x80) && (preflevel > PREF_DOS_ACT)) {
+ pref = i;
+ preflevel = PREF_DOS_ACT;
+ } else if (preflevel > PREF_DOS) {
+ pref = i;
+ preflevel = PREF_DOS;
+ }
+ break;
+ }
+#endif
+ }
+ return(pref + 1); /* slices numbered 1-4 */
+}
+
+
+static int
+bd_close(struct open_file *f)
+{
+ struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data);
+
+ bd_closedisk(od);
+ return(0);
+}
+
+static void
+bd_closedisk(struct open_disk *od)
+{
+ DEBUG("open_disk %p", od);
+#if 0
+ /* XXX is this required? (especially if disk already open...) */
+ if (od->od_flags & BD_FLOPPY)
+ delay(3000000);
+#endif
+ free(od);
+}
+
+static int
+bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
+{
+ struct bcache_devdata bcd;
+
+ bcd.dv_strategy = bd_realstrategy;
+ bcd.dv_devdata = devdata;
+ return(bcache_strategy(&bcd, rw, dblk, size, buf, rsize));
+}
+
+static int
+bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
+{
+ struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data);
+ int blks;
+#ifdef BD_SUPPORT_FRAGS
+ char fragbuf[BIOSDISK_SECSIZE];
+ size_t fragsize;
+
+ fragsize = size % BIOSDISK_SECSIZE;
+#else
+ if (size % BIOSDISK_SECSIZE)
+ panic("bd_strategy: %d bytes I/O not multiple of block size", size);
+#endif
+
+ DEBUG("open_disk %p", od);
+
+ if (rw != F_READ)
+ return(EROFS);
+
+
+ blks = size / BIOSDISK_SECSIZE;
+ DEBUG("read %d from %d+%d to %p", blks, od->od_boff, dblk, buf);
+
+ if (rsize)
+ *rsize = 0;
+ if (blks && bd_read(od, dblk + od->od_boff, blks, buf)) {
+ DEBUG("read error");
+ return (EIO);
+ }
+#ifdef BD_SUPPORT_FRAGS
+ DEBUG("bd_strategy: frag read %d from %d+%d+d to %p",
+ fragsize, od->od_boff, dblk, blks, buf + (blks * BIOSDISK_SECSIZE));
+ if (fragsize && bd_read(od, dblk + od->od_boff + blks, 1, fragsize)) {
+ DEBUG("frag read error");
+ return(EIO);
+ }
+ bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize);
+#endif
+ if (rsize)
+ *rsize = size;
+ return (0);
+}
+
+/* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */
+#define FLOPPY_BOUNCEBUF 18
+
+static int
+bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
+{
+ int x, bpc, cyl, hd, sec, result, resid, cnt, retry, maxfer;
+ caddr_t p, xp, bbuf, breg;
+
+ bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */
+ resid = blks;
+ p = dest;
+
+ /* Decide whether we have to bounce */
+#ifdef PC98
+ if (((od->od_unit & 0xf0) == 0x90 || (od->od_unit & 0xf0) == 0x30) &&
+#else
+ if ((od->od_unit < 0x80) &&
+#endif
+ ((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16))) {
+
+ /*
+ * There is a 64k physical boundary somewhere in the destination buffer, so we have
+ * to arrange a suitable bounce buffer. Allocate a buffer twice as large as we
+ * need to. Use the bottom half unless there is a break there, in which case we
+ * use the top half.
+ */
+ x = min(FLOPPY_BOUNCEBUF, blks);
+ bbuf = malloc(x * 2 * BIOSDISK_SECSIZE);
+ if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(dest + x * BIOSDISK_SECSIZE) & 0xffff0000)) {
+ breg = bbuf;
+ } else {
+ breg = bbuf + x * BIOSDISK_SECSIZE;
+ }
+ maxfer = x; /* limit transfers to bounce region size */
+ } else {
+ bbuf = NULL;
+ maxfer = 0;
+ }
+
+ while (resid > 0) {
+ x = dblk;
+ cyl = x / bpc; /* block # / blocks per cylinder */
+ x %= bpc; /* block offset into cylinder */
+ hd = x / od->od_sec; /* offset / blocks per track */
+ sec = x % od->od_sec; /* offset into track */
+
+ /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */
+ x = min(od->od_sec - sec, resid);
+ if (maxfer > 0)
+ x = min(x, maxfer); /* fit bounce buffer */
+
+ /* where do we transfer to? */
+ xp = bbuf == NULL ? p : breg;
+
+ /* correct sector number for 1-based BIOS numbering */
+#ifdef PC98
+ if ((od->od_unit & 0xf0) == 0x30 || (od->od_unit & 0xf0) == 0x90)
+ sec++;
+#else
+ sec++;
+#endif
+
+ /* Loop retrying the operation a couple of times. The BIOS may also retry. */
+ for (retry = 0; retry < 3; retry++) {
+ /* if retrying, reset the drive */
+ if (retry > 0) {
+#ifdef PC98
+#else
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0;
+ v86.edx = od->od_unit;
+ v86int();
+#endif
+ }
+
+ /* build request XXX support EDD requests too */
+#ifdef PC98
+ v86.ctl = 0;
+ v86.addr = 0x1b;
+ if (od->od_flags & BD_FLOPPY) {
+ v86.eax = 0xd600 | od->od_unit;
+ v86.ecx = 0x0200 | (cyl & 0xff);
+ }
+ else {
+ v86.eax = 0x0600 | od->od_unit;
+ v86.ecx = cyl;
+ }
+ v86.edx = (hd << 8) | sec;
+ v86.ebx = x * BIOSDISK_SECSIZE;
+ v86.es = VTOPSEG(xp);
+ v86.ebp = VTOPOFF(xp);
+ v86int();
+#else
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x200 | x;
+ v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec;
+ v86.edx = (hd << 8) | od->od_unit;
+ v86.es = VTOPSEG(xp);
+ v86.ebx = VTOPOFF(xp);
+ v86int();
+#endif
+ result = (v86.efl & 0x1);
+ if (result == 0)
+ break;
+ }
+
+#ifdef PC98
+ DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, od->od_flags & BD_FLOPPY ? sec - 1 : sec, p, VTOP(p), result ? "failed" : "ok");
+ /* BUG here, cannot use v86 in printf because putchar uses it too */
+ DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x",
+ od->od_flags & BD_FLOPPY ? 0xd600 | od->od_unit : 0x0600 | od->od_unit,
+ od->od_flags & BD_FLOPPY ? 0x0200 | cyl : cyl, (hd << 8) | sec,
+ (v86.eax >> 8) & 0xff);
+#else
+ DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, sec - 1, p, VTOP(p), result ? "failed" : "ok");
+ /* BUG here, cannot use v86 in printf because putchar uses it too */
+ DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x",
+ 0x200 | x, ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec, (hd << 8) | od->od_unit, (v86.eax >> 8) & 0xff);
+#endif
+ if (result) {
+ if (bbuf != NULL)
+ free(bbuf);
+ return(-1);
+ }
+ if (bbuf != NULL)
+ bcopy(breg, p, x * BIOSDISK_SECSIZE);
+ p += (x * BIOSDISK_SECSIZE);
+ dblk += x;
+ resid -= x;
+ }
+
+/* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */
+ if (bbuf != NULL)
+ free(bbuf);
+ return(0);
+}
+
+static int
+bd_getgeom(struct open_disk *od)
+{
+
+#ifdef PC98
+ if (od->od_flags & BD_FLOPPY) {
+ od->od_cyl = 79;
+ od->od_hds = 2;
+ od->od_sec = (od->od_unit & 0xf0) == 0x30 ? 18 : 15;
+ }
+ else {
+ v86.ctl = 0;
+ v86.addr = 0x1b;
+ v86.eax = 0x8400 | od->od_unit;
+ v86int();
+
+ od->od_cyl = v86.ecx;
+ od->od_hds = (v86.edx >> 8) & 0xff;
+ od->od_sec = v86.edx & 0xff;
+ }
+#else
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x800;
+ v86.edx = od->od_unit;
+ v86int();
+
+ if ((v86.efl & 0x1) || /* carry set */
+ ((v86.edx & 0xff) <= (od->od_unit & 0x7f))) /* unit # bad */
+ return(1);
+
+ /* convert max cyl # -> # of cylinders */
+ od->od_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
+ /* convert max head # -> # of heads */
+ od->od_hds = ((v86.edx & 0xff00) >> 8) + 1;
+ od->od_sec = v86.ecx & 0x3f;
+#endif
+
+ DEBUG("unit 0x%x geometry %d/%d/%d", od->od_unit, od->od_cyl, od->od_hds, od->od_sec);
+ return(0);
+}
+
+/*
+ * Return a suitable dev_t value for (dev).
+ *
+ * In the case where it looks like (dev) is a SCSI disk, we allow the number of
+ * IDE disks to be specified in $num_ide_disks. There should be a Better Way.
+ */
+int
+bd_getdev(struct i386_devdesc *dev)
+{
+ struct open_disk *od;
+ int biosdev;
+ int major;
+ int rootdev;
+ char *nip, *cp;
+ int unitofs = 0, i, unit;
+
+ biosdev = bd_unit2bios(dev->d_kind.biosdisk.unit);
+ DEBUG("unit %d BIOS device %d", dev->d_kind.biosdisk.unit, biosdev);
+ if (biosdev == -1) /* not a BIOS device */
+ return(-1);
+ if (bd_opendisk(&od, dev) != 0) /* oops, not a viable device */
+ return(-1);
+
+#ifdef PC98
+ if ((biosdev & 0xf0) == 0x90 || (biosdev & 0xf0) == 0x30) {
+#else
+ if (biosdev < 0x80) {
+#endif
+ /* floppy (or emulated floppy) or ATAPI device */
+ if (bdinfo[dev->d_kind.biosdisk.unit].bd_type == DT_ATAPI) {
+ /* is an ATAPI disk */
+ major = WFDMAJOR;
+ } else {
+ /* is a floppy disk */
+ major = FDMAJOR;
+ }
+ } else {
+ /* harddisk */
+ if ((od->od_flags & BD_LABELOK) && (od->od_disklabel.d_type == DTYPE_SCSI)) {
+ /* label OK, disk labelled as SCSI */
+ major = DAMAJOR;
+ /* check for unit number correction hint, now deprecated */
+ if ((nip = getenv("num_ide_disks")) != NULL) {
+ i = strtol(nip, &cp, 0);
+ /* check for parse error */
+ if ((cp != nip) && (*cp == 0))
+ unitofs = i;
+ }
+ } else {
+ /* assume an IDE disk */
+ major = WDMAJOR;
+ }
+ }
+ /* XXX a better kludge to set the root disk unit number */
+ if ((nip = getenv("root_disk_unit")) != NULL) {
+ i = strtol(nip, &cp, 0);
+ /* check for parse error */
+ if ((cp != nip) && (*cp == 0))
+ unit = i;
+ } else {
+#ifdef PC98
+ unit = biosdev & 0xf; /* allow for #wd compenstation in da case */
+#else
+ unit = (biosdev & 0x7f) - unitofs; /* allow for #wd compenstation in da case */
+#endif
+ }
+
+ rootdev = MAKEBOOTDEV(major,
+ (dev->d_kind.biosdisk.slice + 1) >> 4, /* XXX slices may be wrong here */
+ (dev->d_kind.biosdisk.slice + 1) & 0xf,
+ unit,
+ dev->d_kind.biosdisk.partition);
+ DEBUG("dev is 0x%x\n", rootdev);
+ return(rootdev);
+}
+
+/*
+ * Fix (dev) so that it refers to the 'real' disk/slice/partition that it implies.
+ */
+int
+bd_fixupdev(struct i386_devdesc *dev)
+{
+ struct open_disk *od;
+
+ /*
+ * Open the disk. This will fix up the slice and partition fields.
+ */
+ if (bd_opendisk(&od, dev) != 0)
+ return(ENOENT);
+
+ bd_closedisk(od);
+}
diff --git a/sys/boot/pc98/libpc98/biosmem.c b/sys/boot/pc98/libpc98/biosmem.c
new file mode 100644
index 0000000..f473935
--- /dev/null
+++ b/sys/boot/pc98/libpc98/biosmem.c
@@ -0,0 +1,59 @@
+/*
+ * mjs copyright
+ */
+
+/*
+ * Obtain memory configuration information from the BIOS
+ *
+ * Note that we don't try too hard here; knowing the size of
+ * base memory and extended memory out to 16 or 64M is enough for
+ * the requirements of the bootstrap.
+ *
+ * We also maintain a pointer to the top of physical memory
+ * once called to allow rangechecking of load/copy requests.
+ */
+#include <stand.h>
+#include "btxv86.h"
+
+vm_offset_t memtop;
+
+/*
+ * Return base memory size in kB.
+ */
+int
+getbasemem(void)
+{
+#ifdef PC98
+ return ((*(u_char *)PTOV(0xA1501)&0x07)+1)*128;
+#else
+ v86.ctl = 0;
+ v86.addr = 0x12; /* int 0x12 */
+ v86int();
+
+ return(v86.eax & 0xffff);
+#endif
+}
+
+/*
+ * Return extended memory size in kB
+ */
+int
+getextmem(void)
+{
+ int extkb;
+
+#ifdef PC98
+ extkb = *(u_char *)PTOV(0xA1401)*128 + *(unsigned short *)PTOV(0xA1594)*1024;
+#else
+ v86.ctl = 0;
+ v86.addr = 0x15; /* int 0x15 function 0x88*/
+ v86.eax = 0x8800;
+ v86int();
+ extkb = v86.eax & 0xffff;
+#endif
+ /* Set memtop to actual top or 16M, whicheve is less */
+ memtop = min((0x100000 + (extkb * 1024)), (16 * 1024 * 1024));
+
+ return(extkb);
+}
+
diff --git a/sys/boot/pc98/libpc98/bootinfo.c b/sys/boot/pc98/libpc98/bootinfo.c
new file mode 100644
index 0000000..94b2b6f
--- /dev/null
+++ b/sys/boot/pc98/libpc98/bootinfo.c
@@ -0,0 +1,331 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * 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 form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: bootinfo.c,v 1.16 1999/01/24 00:12:04 msmith Exp $
+ */
+
+#include <stand.h>
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/linker.h>
+#include <machine/bootinfo.h>
+#include "bootstrap.h"
+#include "libi386.h"
+#include "btxv86.h"
+
+static struct bootinfo bi;
+#ifdef PC98
+extern struct bootinfo *initial_bootinfo;
+#endif
+
+/*
+ * Return a 'boothowto' value corresponding to the kernel arguments in
+ * (kargs) and any relevant environment variables.
+ */
+static struct
+{
+ char *ev;
+ int mask;
+} howto_names[] = {
+ {"boot_askname", RB_ASKNAME},
+ {"boot_userconfig", RB_CONFIG},
+ {"boot_ddb", RB_KDB},
+ {"boot_gdb", RB_GDB},
+ {"boot_single", RB_SINGLE},
+ {"boot_verbose", RB_VERBOSE},
+ {NULL, 0}
+};
+
+int
+bi_getboothowto(char *kargs)
+{
+ char *cp;
+ int howto;
+ int active;
+ int i;
+
+ /* Parse kargs */
+ howto = 0;
+ if (kargs != NULL) {
+ cp = kargs;
+ active = 0;
+ while (*cp != 0) {
+ if (!active && (*cp == '-')) {
+ active = 1;
+ } else if (active)
+ switch (*cp) {
+ case 'a':
+ howto |= RB_ASKNAME;
+ break;
+ case 'c':
+ howto |= RB_CONFIG;
+ break;
+ case 'd':
+ howto |= RB_KDB;
+ break;
+ case 'g':
+ howto |= RB_GDB;
+ break;
+ case 'h':
+ howto |= RB_SERIAL;
+ break;
+ case 'r':
+ howto |= RB_DFLTROOT;
+ break;
+ case 's':
+ howto |= RB_SINGLE;
+ break;
+ case 'v':
+ howto |= RB_VERBOSE;
+ break;
+ default:
+ active = 0;
+ break;
+ }
+ cp++;
+ }
+ }
+ /* get equivalents from the environment */
+ for (i = 0; howto_names[i].ev != NULL; i++)
+ if (getenv(howto_names[i].ev) != NULL)
+ howto |= howto_names[i].mask;
+ if (!strcmp(getenv("console"), "comconsole"))
+ howto |= RB_SERIAL;
+ return(howto);
+}
+
+/*
+ * Copy the environment into the load area starting at (addr).
+ * Each variable is formatted as <name>=<value>, with a single nul
+ * separating each variable, and a double nul terminating the environment.
+ */
+vm_offset_t
+bi_copyenv(vm_offset_t addr)
+{
+ struct env_var *ep;
+
+ /* traverse the environment */
+ for (ep = environ; ep != NULL; ep = ep->ev_next) {
+ i386_copyin(ep->ev_name, addr, strlen(ep->ev_name));
+ addr += strlen(ep->ev_name);
+ i386_copyin("=", addr, 1);
+ addr++;
+ if (ep->ev_value != NULL) {
+ i386_copyin(ep->ev_value, addr, strlen(ep->ev_value));
+ addr += strlen(ep->ev_value);
+ }
+ i386_copyin("", addr, 1);
+ addr++;
+ }
+ i386_copyin("", addr, 1);
+ addr++;
+ return(addr);
+}
+
+/*
+ * Copy module-related data into the load area, where it can be
+ * used as a directory for loaded modules.
+ *
+ * Module data is presented in a self-describing format. Each datum
+ * is preceeded by a 32-bit identifier and a 32-bit size field.
+ *
+ * Currently, the following data are saved:
+ *
+ * MOD_NAME (variable) module name (string)
+ * MOD_TYPE (variable) module type (string)
+ * MOD_ADDR sizeof(vm_offset_t) module load address
+ * MOD_SIZE sizeof(size_t) module size
+ * MOD_METADATA (variable) type-specific metadata
+ */
+#define COPY32(v, a) { \
+ u_int32_t x = (v); \
+ i386_copyin(&x, a, sizeof(x)); \
+ a += sizeof(x); \
+}
+
+#define MOD_STR(t, a, s) { \
+ COPY32(t, a); \
+ COPY32(strlen(s) + 1, a); \
+ i386_copyin(s, a, strlen(s) + 1); \
+ a += roundup(strlen(s) + 1, sizeof(u_long));\
+}
+
+#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s)
+#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s)
+
+#define MOD_VAR(t, a, s) { \
+ COPY32(t, a); \
+ COPY32(sizeof(s), a); \
+ i386_copyin(&s, a, sizeof(s)); \
+ a += roundup(sizeof(s), sizeof(u_long)); \
+}
+
+#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s)
+#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s)
+
+#define MOD_METADATA(a, mm) { \
+ COPY32(MODINFO_METADATA | mm->md_type, a); \
+ COPY32(mm->md_size, a); \
+ i386_copyin(mm->md_data, a, mm->md_size); \
+ a += roundup(mm->md_size, sizeof(u_long));\
+}
+
+#define MOD_END(a) { \
+ COPY32(MODINFO_END, a); \
+ COPY32(0, a); \
+}
+
+vm_offset_t
+bi_copymodules(vm_offset_t addr)
+{
+ struct loaded_module *mp;
+ struct module_metadata *md;
+
+ /* start with the first module on the list, should be the kernel */
+ for (mp = mod_findmodule(NULL, NULL); mp != NULL; mp = mp->m_next) {
+
+ MOD_NAME(addr, mp->m_name); /* this field must come first */
+ MOD_TYPE(addr, mp->m_type);
+ MOD_ADDR(addr, mp->m_addr);
+ MOD_SIZE(addr, mp->m_size);
+ for (md = mp->m_metadata; md != NULL; md = md->md_next)
+ if (!(md->md_type & MODINFOMD_NOCOPY))
+ MOD_METADATA(addr, md);
+ }
+ MOD_END(addr);
+ return(addr);
+}
+
+/*
+ * Load the information expected by an i386 kernel.
+ *
+ * - The 'boothowto' argument is constructed
+ * - The 'botdev' argument is constructed
+ * - The 'bootinfo' struct is constructed, and copied into the kernel space.
+ * - The kernel environment is copied into kernel space.
+ * - Module metadata are formatted and placed in kernel space.
+ */
+int
+bi_load(char *args, int *howtop, int *bootdevp, vm_offset_t *bip)
+{
+ struct loaded_module *xp;
+ struct i386_devdesc *rootdev;
+ vm_offset_t addr, bootinfo_addr;
+ char *rootdevname;
+ int bootdevnr;
+ u_int pad;
+ char *kernelname;
+ const char *kernelpath;
+#ifdef PC98
+ int i;
+#endif
+
+ *howtop = bi_getboothowto(args);
+
+ /*
+ * Allow the environment variable 'rootdev' to override the supplied device
+ * This should perhaps go to MI code and/or have $rootdev tested/set by
+ * MI code before launching the kernel.
+ */
+ rootdevname = getenv("rootdev");
+ i386_getdev((void **)(&rootdev), rootdevname, NULL);
+ if (rootdev == NULL) { /* bad $rootdev/$currdev */
+ printf("can't determine root device\n");
+ return(EINVAL);
+ }
+
+ switch(rootdev->d_type) {
+ case DEVT_DISK:
+ /* pass in the BIOS device number of the current disk */
+ bi.bi_bios_dev = bd_unit2bios(rootdev->d_kind.biosdisk.unit);
+ bootdevnr = bd_getdev(rootdev);
+ if (bootdevnr != -1)
+ break;
+ printf("root device %s invalid\n", i386_fmtdev(rootdev));
+ return(EINVAL);
+
+ default:
+ printf("aout_exec: WARNING - don't know how to boot from device type %d\n", rootdev->d_type);
+ }
+ free(rootdev);
+ *bootdevp = bootdevnr;
+
+ /* legacy bootinfo structure */
+ bi.bi_version = BOOTINFO_VERSION;
+ bi.bi_kernelname = 0; /* XXX char * -> kernel name */
+ bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */
+ bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */
+ /* bi.bi_bios_geom[] */
+#ifdef PC98
+ for(i = 0; i < N_BIOS_GEOM; i++)
+ bi.bi_bios_geom[i] = initial_bootinfo->bi_bios_geom[i];
+#endif
+ bi.bi_size = sizeof(bi);
+ bi.bi_memsizes_valid = 1;
+ bi.bi_basemem = getbasemem();
+ bi.bi_extmem = getextmem();
+
+ /* find the last module in the chain */
+ addr = 0;
+ for (xp = mod_findmodule(NULL, NULL); xp != NULL; xp = xp->m_next) {
+ if (addr < (xp->m_addr + xp->m_size))
+ addr = xp->m_addr + xp->m_size;
+ }
+ /* pad to a page boundary */
+ pad = (u_int)addr & PAGE_MASK;
+ if (pad != 0) {
+ pad = PAGE_SIZE - pad;
+ addr += pad;
+ }
+
+ /* copy our environment */
+ bi.bi_envp = addr;
+ addr = bi_copyenv(addr);
+
+ /* pad to a page boundary */
+ pad = (u_int)addr & PAGE_MASK;
+ if (pad != 0) {
+ pad = PAGE_SIZE - pad;
+ addr += pad;
+ }
+ /* copy module list and metadata */
+ bi.bi_modulep = addr;
+ addr = bi_copymodules(addr);
+
+ /* all done copying stuff in, save end of loaded object space */
+ bi.bi_kernend = addr;
+
+ *howtop |= RB_BOOTINFO; /* it's there now */
+
+ /*
+ * Get the kernel name, strip off any device prefix.
+ */
+ kernelname = getenv("kernelname");
+ i386_getdev(NULL, kernelname, &kernelpath);
+ bi.bi_kernelname = VTOP(kernelpath);
+ *bip = VTOP(&bi);
+
+ return(0);
+}
diff --git a/sys/boot/pc98/libpc98/comconsole.c b/sys/boot/pc98/libpc98/comconsole.c
new file mode 100644
index 0000000..82e4642
--- /dev/null
+++ b/sys/boot/pc98/libpc98/comconsole.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
+ *
+ * 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 form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: comconsole.c,v 1.6 1999/01/10 14:48:05 rnordier Exp $
+ */
+
+#include <stand.h>
+#include <bootstrap.h>
+#include <machine/cpufunc.h>
+#include "libi386.h"
+
+/* selected defines from ns16550.h */
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
+
+/* selected defines from sioreg.h */
+#define CFCR_DLAB 0x80
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+#define LSR_TXRDY 0x20
+#define LSR_RXRDY 0x01
+
+#define COMC_FMT 0x3 /* 8N1 */
+#define COMC_TXWAIT 0x40000 /* transmit timeout */
+#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */
+
+#ifndef COMPORT
+#ifdef PC98
+#define COMPORT 0x238
+#else
+#define COMPORT 0x3f8
+#endif
+#endif
+#ifndef COMSPEED
+#define COMSPEED 9600
+#endif
+
+static void comc_probe(struct console *cp);
+static int comc_init(int arg);
+static void comc_putchar(int c);
+static int comc_getchar(void);
+static int comc_ischar(void);
+
+static int comc_started;
+
+struct console comconsole = {
+ "comconsole",
+ "serial port",
+ 0,
+ comc_probe,
+ comc_init,
+ comc_putchar,
+ comc_getchar,
+ comc_ischar
+};
+
+static void
+comc_probe(struct console *cp)
+{
+ /* XXX check the BIOS equipment list? */
+ cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
+}
+
+static int
+comc_init(int arg)
+{
+ if (comc_started && arg == 0)
+ return 0;
+ comc_started = 1;
+
+ outb(COMPORT + com_cfcr, CFCR_DLAB | COMC_FMT);
+ outb(COMPORT + com_dlbl, COMC_BPS(COMSPEED) & 0xff);
+ outb(COMPORT + com_dlbh, COMC_BPS(COMSPEED) >> 8);
+ outb(COMPORT + com_cfcr, COMC_FMT);
+ outb(COMPORT + com_mcr, MCR_RTS | MCR_DTR);
+
+ do
+ inb(COMPORT + com_data);
+ while (inb(COMPORT + com_lsr) & LSR_RXRDY);
+
+ return(0);
+}
+
+static void
+comc_putchar(int c)
+{
+ int wait;
+
+ for (wait = COMC_TXWAIT; wait > 0; wait--)
+ if (inb(COMPORT + com_lsr) & LSR_TXRDY) {
+ outb(COMPORT + com_data, c);
+ break;
+ }
+}
+
+static int
+comc_getchar(void)
+{
+ return(comc_ischar() ? inb(COMPORT + com_data) : -1);
+}
+
+static int
+comc_ischar(void)
+{
+ return(inb(COMPORT + com_lsr) & LSR_RXRDY);
+}
diff --git a/sys/boot/pc98/libpc98/gatea20.c b/sys/boot/pc98/libpc98/gatea20.c
new file mode 100644
index 0000000..45e4410
--- /dev/null
+++ b/sys/boot/pc98/libpc98/gatea20.c
@@ -0,0 +1,57 @@
+/*
+ * $Id: gatea20.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $
+ * From: $NetBSD: gatea20.c,v 1.2 1997/10/29 00:32:49 fvdl Exp $
+ */
+
+/* extracted from freebsd:sys/i386/boot/biosboot/io.c */
+
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+
+#include <stand.h>
+
+#include "libi386.h"
+
+#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
+#define K_STATUS 0x64 /* keyboard status */
+#define K_CMD 0x64 /* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL 0x01 /* output buffer full */
+#define K_IBUF_FUL 0x02 /* input buffer full */
+
+#define KC_CMD_WIN 0xd0 /* read output port */
+#define KC_CMD_WOUT 0xd1 /* write output port */
+#define KB_A20 0x9f /* enable A20,
+ reset (!),
+ enable output buffer full interrupt
+ enable data line
+ disable clock line */
+
+/*
+ * Gate A20 for high memory
+ */
+static unsigned char x_20 = KB_A20;
+void gateA20()
+{
+ __asm("pushfl ; cli");
+#ifdef PC98
+ outb(0xf2, 0x00);
+ outb(0xf6, 0x02);
+#else /* IBM PC */
+#ifdef IBM_L40
+ outb(0x92, 0x2);
+#else IBM_L40
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ while (inb(K_STATUS) & K_OBUF_FUL)
+ (void)inb(K_RDWR);
+
+ outb(K_CMD, KC_CMD_WOUT);
+ delay(100);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ outb(K_RDWR, x_20);
+ delay(100);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+#endif IBM_L40
+#endif /* IBM PC */
+ __asm("popfl");
+}
diff --git a/sys/boot/pc98/libpc98/time.c b/sys/boot/pc98/libpc98/time.c
new file mode 100644
index 0000000..4643d65
--- /dev/null
+++ b/sys/boot/pc98/libpc98/time.c
@@ -0,0 +1,83 @@
+/*
+ * mjs copyright
+ */
+
+#include <stand.h>
+#include <btxv86.h>
+#ifdef PC98
+#include <machine/cpufunc.h>
+#endif
+
+/*
+ * Return the time in seconds since the beginning of the day.
+ *
+ * If we pass midnight, don't wrap back to 0.
+ *
+ * XXX uses undocumented BCD support from libstand.
+ */
+
+time_t
+time(time_t *t)
+{
+ static time_t lasttime, now;
+ int hr, min, sec;
+#ifdef PC98
+ unsigned char bios_time[6];
+#endif
+
+ v86.ctl = 0;
+#ifdef PC98
+ v86.addr = 0x1c; /* int 0x1c, function 0 */
+ v86.eax = 0x0000;
+ v86.es = VTOPSEG(bios_time);
+ v86.ebx = VTOPOFF(bios_time);
+#else
+ v86.addr = 0x1a; /* int 0x1a, function 2 */
+ v86.eax = 0x0200;
+#endif
+ v86int();
+
+#ifdef PC98
+ hr = bcd2bin(bios_time[3]);
+ min = bcd2bin(bios_time[4]);
+ sec = bcd2bin(bios_time[5]);
+#else
+ hr = bcd2bin((v86.ecx & 0xff00) >> 8); /* hour in %ch */
+ min = bcd2bin(v86.ecx & 0xff); /* minute in %cl */
+ sec = bcd2bin((v86.edx & 0xff00) >> 8); /* second in %dh */
+#endif
+
+ now = hr * 3600 + min * 60 + sec;
+ if (now < lasttime)
+ now += 24 * 3600;
+ lasttime = now;
+
+ if (t != NULL)
+ *t = now;
+ return(now);
+}
+
+/*
+ * Use the BIOS Wait function to pause for (period) microseconds.
+ *
+ * Resolution of this function is variable, but typically around
+ * 1ms.
+ */
+void
+delay(int period)
+{
+#ifdef PC98
+ int i;
+ period = (period + 500) / 1000;
+ for( ; period != 0 ; period--)
+ for(i=800;i != 0; i--)
+ outb(0x5f,0); /* wait 600ns */
+#else
+ v86.ctl = 0;
+ v86.addr = 0x15; /* int 0x15, function 0x86 */
+ v86.eax = 0x8600;
+ v86.ecx = period >> 16;
+ v86.edx = period & 0xffff;
+ v86int();
+#endif
+}
diff --git a/sys/boot/pc98/libpc98/vidconsole.c b/sys/boot/pc98/libpc98/vidconsole.c
new file mode 100644
index 0000000..1881024
--- /dev/null
+++ b/sys/boot/pc98/libpc98/vidconsole.c
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
+ * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
+ * 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 form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * From Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
+ *
+ * $Id: vidconsole.c,v 1.11 1999/01/04 18:45:08 peter Exp $
+ */
+
+#include <stand.h>
+#include <bootstrap.h>
+#include <btxv86.h>
+#include <machine/psl.h>
+#include "libi386.h"
+#ifdef PC98
+#include <machine/cpufunc.h>
+#endif
+
+#if KEYBOARD_PROBE
+#include <machine/cpufunc.h>
+
+static int probe_keyboard(void);
+#endif
+static void vidc_probe(struct console *cp);
+static int vidc_init(int arg);
+static void vidc_putchar(int c);
+static int vidc_getchar(void);
+static int vidc_ischar(void);
+
+static int vidc_started;
+
+#ifdef TERM_EMU
+void end_term();
+void bail_out(int c);
+void vidc_term_emu(int c);
+void get_pos(void);
+void curs_move(int x, int y);
+void write_char(int c, int fg, int bg);
+void scroll_up(int rows, int fg, int bg);
+void AB(void);
+void AF(void);
+void CD(void);
+void CM(void);
+void HO(void);
+void ME(void);
+
+static int args[2],argc,br;
+static int fg,bg,dig;
+static int fg_c,bg_c,curx,cury;
+static int esc;
+#endif
+
+#ifdef PC98
+static unsigned short *crtat, *Crtat;
+static int row = 25, col = 80;
+#ifdef TERM_EMU
+unsigned int at2pc98(unsigned int fg_at, unsigned int bg_at);
+#endif
+#endif
+
+struct console vidconsole = {
+ "vidconsole",
+ "internal video/keyboard",
+ 0,
+ vidc_probe,
+ vidc_init,
+ vidc_putchar,
+ vidc_getchar,
+ vidc_ischar
+};
+
+static void
+vidc_probe(struct console *cp)
+{
+
+ /* look for a keyboard */
+#if KEYBOARD_PROBE
+ if (probe_keyboard())
+#endif
+ {
+
+ cp->c_flags |= C_PRESENTIN;
+ }
+
+ /* XXX for now, always assume we can do BIOS screen output */
+ cp->c_flags |= C_PRESENTOUT;
+}
+
+static int
+vidc_init(int arg)
+{
+ int i;
+#ifdef PC98
+ int hw_cursor;
+#endif
+
+ if (vidc_started && arg == 0)
+ return;
+ vidc_started = 1;
+#ifdef PC98
+ Crtat = (unsigned short *)PTOV(0xA0000);
+ while((inb(0x60) & 0x04) == 0);
+ outb(0x62, 0xe0);
+ while((inb(0x60) & 0x01) == 0);
+ hw_cursor = inb(0x62);
+ hw_cursor |= (inb(0x62) << 8);
+ inb(0x62);
+ inb(0x62);
+ inb(0x62);
+ crtat = Crtat + hw_cursor;
+#endif
+#ifdef TERM_EMU
+ /* Init terminal emulator */
+ end_term();
+ get_pos();
+ curs_move(curx,cury);
+ fg_c=7;
+ bg_c=0;
+#endif
+ for(i = 0; i < 10 && vidc_ischar(); i++)
+ (void)vidc_getchar();
+ return(0); /* XXX reinit? */
+}
+
+static void
+vidc_biosputchar(int c)
+{
+#ifdef PC98
+ unsigned short *cp;
+ int i, pos;
+
+#ifdef TERM_EMU
+ *crtat = (c == 0x5c ? 0xfc : c);
+ *(crtat + 0x1000) = at2pc98(fg, bg);
+#else
+ switch(c) {
+ case '\b':
+ crtat--;
+ break;
+ case '\r':
+ crtat -= (crtat - Crtat) % col;
+ break;
+ case '\n':
+ crtat += col;
+ break;
+ default:
+ *crtat = (c == 0x5c ? 0xfc : c);
+ *(crtat++ + 0x1000) = 0xe1;
+ break;
+ }
+
+ if (crtat >= Crtat + col * row) {
+ cp = Crtat;
+ for (i = 1; i < row; i++) {
+ bcopy((void *)(cp+col), (void *)cp, col*2);
+ cp += col;
+ }
+ for (i = 0; i < col; i++) {
+ *cp++ = ' ';
+ }
+ crtat -= col;
+ }
+ pos = crtat - Crtat;
+ while((inb(0x60) & 0x04) == 0) {}
+ outb(0x62, 0x49);
+ outb(0x60, pos & 0xff);
+ outb(0x60, pos >> 8);
+#endif
+#else
+ v86.ctl = 0;
+ v86.addr = 0x10;
+ v86.eax = 0xe00 | (c & 0xff);
+ v86.ebx = 0x7;
+ v86int();
+#endif
+}
+
+static void
+vidc_rawputchar(int c)
+{
+ int i;
+
+ if(c == '\t')
+ /* lame tab expansion */
+ for (i = 0; i < 8; i++)
+ vidc_rawputchar(' ');
+ else {
+#ifndef TERM_EMU
+ vidc_biosputchar(c);
+#else
+ /* Emulate AH=0eh (teletype output) */
+ switch(c) {
+ case '\a':
+ vidc_biosputchar(c);
+ return;
+ case '\r':
+ curx=0;
+ curs_move(curx,cury);
+ return;
+ case '\n':
+ cury++;
+ if(cury>24) {
+ scroll_up(1,fg_c,bg_c);
+ cury--;
+ } else {
+ curs_move(curx,cury);
+ }
+ return;
+ case '\b':
+ if(curx>0) {
+ curx--;
+ curs_move(curx,cury);
+ /* write_char(' ',fg_c,bg_c); XXX destructive(!) */
+ return;
+ }
+ return;
+ default:
+ write_char(c,fg_c,bg_c);
+ curx++;
+ if(curx>79) {
+ curx=0;
+ cury++;
+ }
+ if(cury>24) {
+ curx=0;
+ scroll_up(1,fg_c,bg_c);
+ cury--;
+ }
+ }
+ curs_move(curx,cury);
+#endif
+ }
+}
+
+#ifdef TERM_EMU
+
+/* Get cursor position on the screen. Result is in edx. Sets
+ * curx and cury appropriately.
+ */
+void
+get_pos(void)
+{
+#ifdef PC98
+ int pos = crtat - Crtat;
+ curx = pos % col;
+ cury = pos / col;
+#else
+ v86.ctl = 0;
+ v86.addr = 0x10;
+ v86.eax = 0x0300;
+ v86.ebx = 0x0;
+ v86int();
+ curx=v86.edx & 0x00ff;
+ cury=(v86.edx & 0xff00)>>8;
+#endif
+}
+
+/* Move cursor to x rows and y cols (0-based). */
+void
+curs_move(int x, int y)
+{
+#ifdef PC98
+ int pos;
+ pos = x + y*col;
+ crtat = Crtat + pos;
+ pos = crtat - Crtat;
+ while((inb(0x60) & 0x04) == 0) {}
+ outb(0x62, 0x49);
+ outb(0x60, pos & 0xff);
+ outb(0x60, pos >> 8);
+ curx=x;
+ cury=y;
+#define isvisible(c) (((c)>32) && ((c)<255))
+ if(!isvisible(*crtat & 0x00ff)) {
+ write_char(' ',fg_c,bg_c);
+ }
+#else
+ v86.ctl = 0;
+ v86.addr = 0x10;
+ v86.eax = 0x0200;
+ v86.ebx = 0x0;
+ v86.edx = ((0x00ff & y)<<8)+(0x00ff & x);
+ v86int();
+ curx=x;
+ cury=y;
+ /* If there is ctrl char at this position, cursor would be invisible.
+ * Make it a space instead.
+ */
+ v86.ctl=0;
+ v86.addr = 0x10;
+ v86.eax = 0x0800;
+ v86.ebx= 0x0;
+ v86int();
+#define isvisible(c) (((c)>32) && ((c)<255))
+ if(!isvisible(v86.eax & 0x00ff)) {
+ write_char(' ',fg_c,bg_c);
+ }
+#endif
+}
+
+/* Scroll up the whole window by a number of rows. If rows==0,
+ * clear the window. fg and bg are attributes for the new lines
+ * inserted in the window.
+ */
+void
+scroll_up(int rows, int fg, int bg)
+{
+#ifdef PC98
+ unsigned short *cp;
+ int i;
+
+ if(rows==0) rows=25;
+ cp = Crtat;
+ for (i = rows ; i < row; i++) {
+ bcopy((void *)(cp+col), (void *)cp, col*2);
+ cp += col;
+ }
+ for (i = 0; i < col; i++) {
+ *(cp + 0x1000) = at2pc98(fg, bg);
+ *cp++ = ' ';
+ }
+#else
+ if(rows==0) rows=25;
+ v86.ctl = 0;
+ v86.addr = 0x10;
+ v86.eax = 0x0600+(0x00ff & rows);
+ v86.ebx = (bg<<12)+(fg<<8);
+ v86.ecx = 0x0;
+ v86.edx = 0x184f;
+ v86int();
+#endif
+}
+
+/* Write character and attribute at cursor position. */
+void
+write_char(int c, int fg, int bg)
+{
+#ifdef PC98
+ *crtat = c;
+ *(crtat + 0x1000) = at2pc98(fg, bg);
+#else
+ v86.ctl=0;
+ v86.addr = 0x10;
+ v86.eax = 0x0900+(0x00ff & c);
+ v86.ebx = (bg<<4)+fg;
+ v86.ecx = 0x1;
+ v86int();
+#endif
+}
+
+/* Calculate power of 10 */
+int
+pow10(int i)
+{
+ int res=1;
+
+ while(i-->0) {
+ res*=10;
+ }
+ return res;
+}
+
+/**************************************************************/
+/*
+ * Screen manipulation functions. They use accumulated data in
+ * args[] and argc variables.
+ *
+ */
+
+/* Set background color */
+void
+AB(void){
+ bg_c=args[0];
+ end_term();
+}
+
+/* Set foreground color */
+void
+AF(void)
+{
+ fg_c=args[0];
+ end_term();
+}
+
+/* Clear display from current position to end of screen */
+void
+CD(void)
+{
+ get_pos();
+#ifdef PC98
+ for(;crtat <= Crtat + col*row; crtat++){
+ *crtat = ' ';
+ *(crtat + 0x1000) = at2pc98(fg_c, bg_c);
+ }
+#else
+ v86.ctl = 0;
+ v86.addr = 0x10;
+ v86.eax = 0x0600;
+ v86.ebx = (bg_c<<4)+fg_c;
+ v86.ecx = v86.edx;
+ v86.edx = 0x184f;
+ v86int();
+#endif
+ curx=0;
+ curs_move(curx,cury);
+ end_term();
+}
+
+/* Absolute cursor move to args[0] rows and args[1] columns
+ * (the coordinates are 1-based).
+ */
+void
+CM(void)
+{
+ if(args[0]>0) args[0]--;
+ if(args[1]>0) args[1]--;
+ curs_move(args[1],args[0]);
+ end_term();
+}
+
+/* Home cursor (left top corner) */
+void
+HO(void)
+{
+ argc=1;
+ args[0]=args[1]=1;
+ CM();
+}
+
+/* Exit attribute mode (reset fore/back-ground colors to defaults) */
+void
+ME(void)
+{
+ fg_c=7;
+ bg_c=0;
+ end_term();
+}
+
+/* Clear internal state of the terminal emulation code */
+void
+end_term(void)
+{
+ esc=0;
+ argc=-1;
+ fg=bg=br=0;
+ args[0]=args[1]=0;
+ dig=0;
+}
+
+/* Gracefully exit ESC-sequence processing in case of misunderstanding */
+void
+bail_out(int c)
+{
+ char buf[6],*ch;
+
+ if(esc) vidc_rawputchar('\033');
+ if(br) vidc_rawputchar('[');
+ if(argc>-1) {
+ sprintf(buf,"%d",args[0]);
+ ch=buf;
+ while(*ch) vidc_rawputchar(*ch++);
+
+ if(argc>0) {
+ vidc_rawputchar(';');
+ sprintf(buf,"%d",args[1]);
+ ch=buf;
+ while(*ch) vidc_rawputchar(*ch++);
+ }
+ }
+ vidc_rawputchar(c);
+ end_term();
+}
+
+/* Emulate basic capabilities of cons25 terminal */
+void
+vidc_term_emu(int c)
+{
+
+ if(!esc) {
+ if(c=='\033') {
+ esc=1;
+ } else {
+ vidc_rawputchar(c);
+ }
+ return;
+ }
+
+ /* Do ESC sequences processing */
+ switch(c) {
+ case '\033':
+ /* ESC in ESC sequence - error */
+ bail_out(c);
+ break;
+ case '[':
+ /* Check if it's first char after ESC */
+ if(argc<0) {
+ br=1;
+ } else {
+ bail_out(c);
+ }
+ break;
+ case 'H':
+ /* Emulate \E[H (cursor home) and
+ * \E%d;%dH (cursor absolute move) */
+ if(br) {
+ switch(argc) {
+ case -1:
+ HO();
+ break;
+ case 1:
+ if(fg) args[0]+=pow10(dig)*3;
+ if(bg) args[0]+=pow10(dig)*4;
+ CM();
+ break;
+ default:
+ bail_out(c);
+ }
+ } else bail_out(c);
+ break;
+ case 'J':
+ /* Emulate \EJ (clear to end of screen) */
+ if(br && argc<0) {
+ CD();
+ } else bail_out(c);
+ break;
+ case ';':
+ /* perhaps args separator */
+ if(br && (argc>-1)) {
+ argc++;
+ } else bail_out(c);
+ break;
+ case 'm':
+ /* Change char attributes */
+ if(br) {
+ switch(argc) {
+ case -1:
+ ME();
+ break;
+ case 0:
+ if(fg) AF();
+ else AB();
+ break;
+ default:
+ bail_out(c);
+ }
+ } else bail_out(c);
+ break;
+ default:
+ if(isdigit(c)) {
+ /* Carefully collect numeric arguments */
+ /* XXX this is ugly. */
+ if(br) {
+ if(argc==-1) {
+ argc=0;
+ args[argc]=0;
+ dig=0;
+ /* in case we're in error... */
+ if(c=='3') {
+ fg=1;
+ return;
+ }
+ if(c=='4') {
+ bg=1;
+ return;
+ }
+ args[argc]=(int)(c-'0');
+ dig=1;
+ args[argc+1]=0;
+ } else {
+ args[argc]=args[argc]*10+(int)(c-'0');
+ if(argc==0) dig++;
+ }
+ } else bail_out(c);
+ } else bail_out(c);
+ break;
+ }
+}
+#endif
+
+static void
+vidc_putchar(int c)
+{
+#ifdef TERM_EMU
+ vidc_term_emu(c);
+#else
+ vidc_rawputchar(c);
+#endif
+}
+
+static int
+vidc_getchar(void)
+{
+ if (vidc_ischar()) {
+ v86.ctl = 0;
+#ifdef PC98
+ v86.addr = 0x18;
+#else
+ v86.addr = 0x16;
+#endif
+ v86.eax = 0x0;
+ v86int();
+ return(v86.eax & 0xff);
+ } else {
+ return(-1);
+ }
+}
+
+static int
+vidc_ischar(void)
+{
+#ifdef PC98
+ v86.ctl = 0;
+ v86.addr = 0x18;
+ v86.eax = 0x100;
+ v86int();
+ return((v86.ebx >> 8) & 0x1);
+#else
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x16;
+ v86.eax = 0x100;
+ v86int();
+ return(!(v86.efl & PSL_Z));
+#endif
+}
+
+#if KEYBOARD_PROBE
+#ifdef PC98
+static int
+probe_keyboard(void)
+{
+ return (*(u_char *)PTOV(0xA1481) & 0x48);
+}
+#else /* PC98 */
+#define PROBE_MAXRETRY 5
+#define PROBE_MAXWAIT 400
+#define IO_DUMMY 0x84
+#define IO_KBD 0x060 /* 8042 Keyboard */
+
+/* selected defines from kbdio.h */
+#define KBD_STATUS_PORT 4 /* status port, read */
+#define KBD_DATA_PORT 0 /* data port, read/write
+ * also used as keyboard command
+ * and mouse command port
+ */
+#define KBDC_ECHO 0x00ee
+#define KBDS_ANY_BUFFER_FULL 0x0001
+#define KBDS_INPUT_BUFFER_FULL 0x0002
+#define KBD_ECHO 0x00ee
+
+/* 7 microsec delay necessary for some keyboard controllers */
+static void
+delay7(void)
+{
+ /*
+ * I know this is broken, but no timer is available yet at this stage...
+ * See also comments in `delay1ms()'.
+ */
+ inb(IO_DUMMY); inb(IO_DUMMY);
+ inb(IO_DUMMY); inb(IO_DUMMY);
+ inb(IO_DUMMY); inb(IO_DUMMY);
+}
+
+/*
+ * This routine uses an inb to an unused port, the time to execute that
+ * inb is approximately 1.25uS. This value is pretty constant across
+ * all CPU's and all buses, with the exception of some PCI implentations
+ * that do not forward this I/O adress to the ISA bus as they know it
+ * is not a valid ISA bus address, those machines execute this inb in
+ * 60 nS :-(.
+ *
+ */
+static void
+delay1ms(void)
+{
+ int i = 800;
+ while (--i >= 0)
+ (void)inb(0x84);
+}
+
+/*
+ * We use the presence/absence of a keyboard to determine whether the internal
+ * console can be used for input.
+ *
+ * Perform a simple test on the keyboard; issue the ECHO command and see
+ * if the right answer is returned. We don't do anything as drastic as
+ * full keyboard reset; it will be too troublesome and take too much time.
+ */
+static int
+probe_keyboard(void)
+{
+ int retry = PROBE_MAXRETRY;
+ int wait;
+ int i;
+
+ while (--retry >= 0) {
+ /* flush any noise */
+ while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
+ delay7();
+ inb(IO_KBD + KBD_DATA_PORT);
+ delay1ms();
+ }
+
+ /* wait until the controller can accept a command */
+ for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
+ if (((i = inb(IO_KBD + KBD_STATUS_PORT))
+ & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0)
+ break;
+ if (i & KBDS_ANY_BUFFER_FULL) {
+ delay7();
+ inb(IO_KBD + KBD_DATA_PORT);
+ }
+ delay1ms();
+ }
+ if (wait <= 0)
+ continue;
+
+ /* send the ECHO command */
+ outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
+
+ /* wait for a response */
+ for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
+ if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)
+ break;
+ delay1ms();
+ }
+ if (wait <= 0)
+ continue;
+
+ delay7();
+ i = inb(IO_KBD + KBD_DATA_PORT);
+#ifdef PROBE_KBD_BEBUG
+ printf("probe_keyboard: got 0x%x.\n", i);
+#endif
+ if (i == KBD_ECHO) {
+ /* got the right answer */
+ return (0);
+ }
+ }
+
+ return (1);
+}
+#endif
+#endif /* KEYBOARD_PROBE */
+
+#ifdef TERM_EMU
+#ifdef PC98
+static u_char ibmpc_to_pc98[16] =
+ { 0x01,0x21,0x81,0xa1,0x41,0x61,0xc1,0xe1, 0x09,0x29,0x89,0xa9,0x49,0x69,0xc9,0xe9 };
+static u_char ibmpc_to_pc98rev[16] =
+ { 0x05,0x25,0x85,0xa5,0x45,0x65,0xc5,0xe5, 0x0d,0x2d,0x8d,0xad,0x4d,0x6d,0xcd,0xed };
+
+unsigned int
+at2pc98(unsigned int fg_at, unsigned int bg_at)
+{
+ unsigned int at;
+
+ if (bg_at) {
+ if (bg_at & 0x80) {
+ if (bg_at & 0x70) {
+ /* reverse & blink */
+ at = ibmpc_to_pc98rev[bg_at >> 4] | 0x02;
+ } else {
+ /* normal & blink */
+ at = ibmpc_to_pc98[fg_at] | 0x02;
+ }
+ } else {
+ /* reverse */
+ at = ibmpc_to_pc98rev[bg_at >> 4];
+ }
+ } else {
+ /* normal */
+ at = ibmpc_to_pc98[fg_at];
+ }
+ at |= ((fg_at|bg_at) << 8);
+ return (at);
+}
+#endif
+#endif
diff --git a/sys/boot/pc98/loader/Makefile b/sys/boot/pc98/loader/Makefile
new file mode 100644
index 0000000..c1b4770
--- /dev/null
+++ b/sys/boot/pc98/loader/Makefile
@@ -0,0 +1,117 @@
+# $Id: Makefile,v 1.28 1999/01/18 19:05:27 msmith Exp $
+
+BASE= loader
+PROG= ${BASE}
+NOMAN=
+STRIP=
+NEWVERSWHAT= "bootstrap loader"
+BINDIR?= /boot
+
+CFLAGS+= -DPC98
+
+# architecture-specific loader code
+SRCS= main.c conf.c
+.PATH: ${.CURDIR}/../../i386/loader
+
+# Enable PnP and ISA-PnP code.
+HAVE_PNP= yes
+HAVE_ISABUS= yes
+
+# Enable BootForth
+BOOT_FORTH= yes
+CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl
+.if exists(${.OBJDIR}/../../ficl/libficl.a)
+LIBFICL= ${.OBJDIR}/../../ficl/libficl.a
+.else
+LIBFICL= ${.CURDIR}/../../ficl/libficl.a
+.endif
+
+# Always add MI sources
+.PATH: ${.CURDIR}/../../common
+.include <${.CURDIR}/../../common/Makefile.inc>
+CFLAGS+= -I${.CURDIR}/../../common
+CFLAGS+= -I${.CURDIR}/../../.. -I. -I${.CURDIR}/../../i386
+
+CLEANFILES+= vers.c vers.o ${BASE}.list ${BASE}.bin ${BASE}.sym ${BASE}.help
+
+CFLAGS+= -Wall
+LDFLAGS= -nostdlib -static -Ttext 0x1000
+
+# pc98 standalone support library
+LIBPC98= ${.OBJDIR}/../libpc98/libpc98.a
+CFLAGS+= -I${.CURDIR}/..
+
+# where to get libstand from
+LIBSTAND= -lstand
+#LIBSTAND= ${.CURDIR}/../../../lib/libstand/libstand.a
+#CFLAGS+= -I${.CURDIR}/../../../lib/libstand/
+
+# BTX components
+.if exists(${.OBJDIR}/../btx)
+BTXDIR= ${.OBJDIR}/../btx
+.else
+BTXDIR= ${.CURDIR}/../btx
+.endif
+BTXLDR= ${BTXDIR}/btxldr/btxldr
+BTXKERN= ${BTXDIR}/btx/btx
+BTXCRT= ${BTXDIR}/lib/crt0.o
+CFLAGS+= -I${.CURDIR}/../btx/lib
+
+# BTX is expecting ELF components
+CFLAGS+= -elf
+
+# New linker set code
+CFLAGS+= -DNEW_LINKER_SET
+
+# Debug me!
+#CFLAGS+= -g
+#LDFLAGS+= -g
+
+vers.o:
+ sh ${.CURDIR}/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
+ ${CC} -c vers.c
+
+${BASE}: ${BASE}.bin ${BTXLDR} ${BTXKERN} ${BTXCRT} ${BASE}.help
+ btxld -v -f aout -e 0x100000 -o ${.TARGET} -l ${BTXLDR} -b ${BTXKERN} \
+ ${BASE}.bin
+# /usr/bin/kzip ${.TARGET}
+# mv ${.TARGET}.kz ${.TARGET}
+
+${BASE}.bin: ${BASE}.sym
+ cp ${.ALLSRC} ${.TARGET}
+ strip ${.TARGET}
+
+${BASE}.help: help.common help.pc98
+ cat ${.ALLSRC} | awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET}
+
+beforeinstall:
+.if exists(${DESTDIR}/boot/loader)
+ mv ${DESTDIR}/boot/loader ${DESTDIR}/boot/loader.old
+.endif
+.if exists(${.OBJDIR}/loader.help)
+ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${.OBJDIR}/${BASE}.help ${DESTDIR}/boot
+.else
+ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${.CURDIR}/${BASE}.help ${DESTDIR}/boot
+.endif
+
+# Cannot use ${OBJS} above this line
+.include <bsd.prog.mk>
+
+${BASE}.sym: ${OBJS} ${LIBPC98} ${LIBSTAND} ${LIBFICL} vers.o
+ ${CC} ${LDFLAGS} -o ${.TARGET} ${BTXCRT} ${OBJS} vers.o \
+ ${LIBFICL} ${LIBSTAND} ${LIBPC98} ${LIBSTAND}
+
+# If it's not there, don't consider it a target
+.if exists(${.CURDIR}/../../../i386/include)
+beforedepend ${OBJS}: machine
+
+machine:
+ ln -sf ${.CURDIR}/../../../i386/include machine
+
+.endif
+
+CLEANFILES+= machine
+
+
diff --git a/sys/boot/pc98/loader/help.pc98 b/sys/boot/pc98/loader/help.pc98
new file mode 100644
index 0000000..4e4ec8b
--- /dev/null
+++ b/sys/boot/pc98/loader/help.pc98
@@ -0,0 +1,46 @@
+################################################################################
+# Treboot DReboot the system
+
+ reboot
+
+ Causes the system to immediately reboot.
+
+################################################################################
+# Theap DDisplay memory management statistics
+
+ heap
+
+ Requests debugging output from the heap manager. For debugging use
+ only.
+
+################################################################################
+# Tset Snum_ide_disks DSet the number of IDE disks
+
+ NOTE: this variable is deprecated, use root_disk_unit instead.
+
+ set num_ide_disks=<value>
+
+ When booting from a SCSI disk on a system with one or more IDE disks,
+ and where the IDE disks are the default boot device, it is necessary
+ to tell the kernel how many IDE disks there are in order to have it
+ correctly locate the SCSI disk you are booting from.
+
+################################################################################
+# Tset Sboot_userconfig DStart Userconfig
+
+ set boot_userconfig
+
+ Requests that the kernel's interactive device configuration program
+ be run when the kernel is booted.
+
+################################################################################
+# Tset Sroot_disk_unit DForce the root disk unit number.
+
+ set root_disk_unit=<value>
+
+ If the code which detects the disk unit number for the root disk is
+ confused, eg. by a mix of SCSI and IDE disks, or IDE disks with
+ gaps in the sequence (eg. no primary slave), the unit number can be
+ forced by setting this variable.
+
+################################################################################
diff --git a/sys/boot/pc98/loader/main.c b/sys/boot/pc98/loader/main.c
new file mode 100644
index 0000000..8ee752a
--- /dev/null
+++ b/sys/boot/pc98/loader/main.c
@@ -0,0 +1,244 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * 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 form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: main.c,v 1.14 1998/11/02 23:28:11 msmith Exp $
+ */
+
+/*
+ * MD bootstrap main() and assorted miscellaneous
+ * commands.
+ */
+
+#include <stand.h>
+#include <string.h>
+#include <machine/bootinfo.h>
+#include <sys/reboot.h>
+
+#include "bootstrap.h"
+#include "../../i386/libi386/libi386.h"
+#include "btxv86.h"
+
+/* Arguments passed in from the boot1/boot2 loader */
+static struct
+{
+ u_int32_t howto;
+ u_int32_t bootdev;
+ u_int32_t res0;
+ u_int32_t res1;
+ u_int32_t res2;
+ u_int32_t bootinfo;
+} *kargs;
+
+static u_int32_t initial_howto;
+static u_int32_t initial_bootdev;
+#ifdef PC98
+struct bootinfo *initial_bootinfo;
+#else
+static struct bootinfo *initial_bootinfo;
+#endif
+
+struct arch_switch archsw; /* MI/MD interface boundary */
+
+static void extract_currdev(void);
+static int isa_inb(int port);
+static void isa_outb(int port, int value);
+
+/* from vers.c */
+extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
+
+/* XXX debugging */
+extern char end[];
+
+void
+main(void)
+{
+ int i;
+
+ /* Pick up arguments */
+ kargs = (void *)__args;
+ initial_howto = kargs->howto;
+ initial_bootdev = kargs->bootdev;
+ initial_bootinfo = (struct bootinfo *)PTOV(kargs->bootinfo);
+
+ /*
+ * Initialise the heap as early as possible. Once this is done, malloc() is usable.
+ *
+ * XXX better to locate end of memory and use that
+ */
+ setheap((void *)end, (void *)(end + (384 * 1024)));
+
+ /*
+ * XXX Chicken-and-egg problem; we want to have console output early, but some
+ * console attributes may depend on reading from eg. the boot device, which we
+ * can't do yet.
+ *
+ * We can use printf() etc. once this is done.
+ * If the previous boot stage has requested a serial console, prefer that.
+ */
+ if (initial_howto & RB_SERIAL)
+ setenv("console", "comconsole", 1);
+ cons_probe();
+
+ /*
+ * Initialise the block cache
+ */
+ bcache_init(32, 512); /* 16k cache XXX tune this */
+
+ /*
+ * March through the device switch probing for things.
+ */
+ for (i = 0; devsw[i] != NULL; i++)
+ if (devsw[i]->dv_init != NULL)
+ (devsw[i]->dv_init)();
+
+ printf("\n");
+ printf("%s, Revision %s %d/%dkB\n", bootprog_name, bootprog_rev, getbasemem(), getextmem());
+ printf("(%s, %s)\n", bootprog_maker, bootprog_date);
+
+ extract_currdev(); /* set $currdev and $loaddev */
+ setenv("LINES", "24", 1); /* optional */
+
+ archsw.arch_autoload = i386_autoload;
+ archsw.arch_getdev = i386_getdev;
+ archsw.arch_copyin = i386_copyin;
+ archsw.arch_copyout = i386_copyout;
+ archsw.arch_readin = i386_readin;
+ archsw.arch_isainb = isa_inb;
+ archsw.arch_isaoutb = isa_outb;
+
+ interact(); /* doesn't return */
+}
+
+/*
+ * Set the 'current device' by (if possible) recovering the boot device as
+ * supplied by the initial bootstrap.
+ *
+ * XXX should be extended for netbooting.
+ */
+static void
+extract_currdev(void)
+{
+ struct i386_devdesc currdev;
+ int major, biosdev;
+
+ /* We're booting from a BIOS disk, try to spiff this */
+ currdev.d_dev = devsw[0]; /* XXX presumes that biosdisk is first in devsw */
+ currdev.d_type = currdev.d_dev->dv_type;
+
+ if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) {
+ /* The passed-in boot device is bad */
+ currdev.d_kind.biosdisk.slice = -1;
+ currdev.d_kind.biosdisk.partition = 0;
+ biosdev = -1;
+ } else {
+ currdev.d_kind.biosdisk.slice = (B_ADAPTOR(initial_bootdev) << 4) + B_CONTROLLER(initial_bootdev) - 1;
+ currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev);
+ biosdev = initial_bootinfo->bi_bios_dev;
+ major = B_TYPE(initial_bootdev);
+
+ /*
+ * If we are booted by an old bootstrap, we have to guess at the BIOS
+ * unit number. We will loose if there is more than one disk type
+ * and we are not booting from the lowest-numbered disk type
+ * (ie. SCSI when IDE also exists).
+ */
+#ifdef PC98
+ if (major == 6)
+ biosdev = 0x30 + B_UNIT(initial_bootdev);
+ else
+ biosdev = (major << 3) + 0x80 + B_UNIT(initial_bootdev);
+#else
+ if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */
+ biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */
+#endif
+ }
+
+ if ((currdev.d_kind.biosdisk.unit = bd_bios2unit(biosdev)) == -1) {
+ printf("Can't work out which disk we are booting from.\n"
+ "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev);
+ currdev.d_kind.biosdisk.unit = 0;
+ }
+ env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&currdev), i386_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&currdev), env_noset, env_nounset);
+}
+
+COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
+
+static int
+command_reboot(int argc, char *argv[])
+{
+
+ printf("Rebooting...\n");
+ delay(1000000);
+ __exit(0);
+}
+
+/* provide this for panic, as it's not in the startup code */
+void
+exit(int code)
+{
+ __exit(code);
+}
+
+COMMAND_SET(heap, "heap", "show heap usage", command_heap);
+
+static int
+command_heap(int argc, char *argv[])
+{
+ mallocstats();
+ printf("heap base at %p, top at %p\n", end, sbrk(0));
+ return(CMD_OK);
+}
+
+/* ISA bus access functions for PnP, derived from <machine/cpufunc.h> */
+static int
+isa_inb(int port)
+{
+ u_char data;
+
+ if (__builtin_constant_p(port) &&
+ (((port) & 0xffff) < 0x100) &&
+ ((port) < 0x10000)) {
+ __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
+ } else {
+ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
+ }
+ return(data);
+}
+
+static void
+isa_outb(int port, int value)
+{
+ u_char al = value;
+
+ if (__builtin_constant_p(port) &&
+ (((port) & 0xffff) < 0x100) &&
+ ((port) < 0x10000)) {
+ __asm __volatile("outb %0,%1" : : "a" (al), "id" ((u_short)(port)));
+ } else {
+ __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
+ }
+}
+
diff --git a/sys/boot/pc98/loader/newvers.sh b/sys/boot/pc98/loader/newvers.sh
new file mode 100644
index 0000000..476913b
--- /dev/null
+++ b/sys/boot/pc98/loader/newvers.sh
@@ -0,0 +1,46 @@
+#!/bin/sh -
+#
+# $NetBSD: newvers.sh,v 1.1 1997/07/26 01:50:38 thorpej Exp $
+#
+# Copyright (c) 1984, 1986, 1990, 1993
+# The Regents of the University of California. 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 form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+#
+# @(#)newvers.sh 8.1 (Berkeley) 4/20/94
+
+LC_TIME=C; export LC_TIME
+u=${USER-root} h=`hostname` t=`date`
+#r=`head -n 6 $1 | tail -n 1 | awk -F: ' { print $1 } '`
+r=`awk -F: ' /^[0-9]\.[0-9]+:/ { print $1; exit }' $1`
+
+echo "char bootprog_name[] = \"FreeBSD/i386 ${2}\";" > vers.c
+echo "char bootprog_rev[] = \"${r}\";" >> vers.c
+echo "char bootprog_date[] = \"${t}\";" >> vers.c
+echo "char bootprog_maker[] = \"${u}@${h}\";" >> vers.c
diff --git a/sys/boot/pc98/loader/version b/sys/boot/pc98/loader/version
new file mode 100644
index 0000000..7cf6004
--- /dev/null
+++ b/sys/boot/pc98/loader/version
@@ -0,0 +1,8 @@
+$Id: version,v 1.2 1998/09/17 23:52:16 msmith Exp $
+
+NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this
+file is important. Make sure the current version number is on line 6.
+
+0.2: Initial integration with BTX
+0.1: Initial i386 version, inspiration and some structure from the
+ NetBSD version.
OpenPOWER on IntegriCloud