From c40db6cc734847f5d3013132b80d70a078c16615 Mon Sep 17 00:00:00 2001 From: kato Date: Wed, 3 Feb 1999 08:39:09 +0000 Subject: 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 --- sys/boot/Makefile | 2 +- sys/boot/common/isapnp.h | 6 +- sys/boot/pc98/Makefile | 5 + sys/boot/pc98/boot2/Makefile | 97 +++ sys/boot/pc98/boot2/README.serial.98 | 63 ++ sys/boot/pc98/boot2/asm.S | 244 ++++++++ sys/boot/pc98/boot2/asm.h | 144 +++++ sys/boot/pc98/boot2/bios.S | 456 +++++++++++++++ sys/boot/pc98/boot2/boot.c | 447 ++++++++++++++ sys/boot/pc98/boot2/boot.h | 109 ++++ sys/boot/pc98/boot2/boot2.S | 183 ++++++ sys/boot/pc98/boot2/disk.c | 330 +++++++++++ sys/boot/pc98/boot2/io.c | 429 ++++++++++++++ sys/boot/pc98/boot2/probe_keyboard.c | 39 ++ sys/boot/pc98/boot2/serial.S | 201 +++++++ sys/boot/pc98/boot2/start.S | 535 +++++++++++++++++ sys/boot/pc98/boot2/sys.c | 337 +++++++++++ sys/boot/pc98/boot2/table.c | 149 +++++ sys/boot/pc98/btx/Makefile | 5 + sys/boot/pc98/btx/btx/Makefile | 25 + sys/boot/pc98/btx/btx/btx.S | 1071 ++++++++++++++++++++++++++++++++++ sys/boot/pc98/btx/btx/btx.m4 | 59 ++ sys/boot/pc98/btx/btx/btx.s | 1071 ++++++++++++++++++++++++++++++++++ sys/boot/pc98/btx/btxldr/Makefile | 26 + sys/boot/pc98/btx/btxldr/btxldr.S | 459 +++++++++++++++ sys/boot/pc98/btx/btxldr/btxldr.s | 459 +++++++++++++++ sys/boot/pc98/btx/lib/Makefile | 20 + sys/boot/pc98/btx/lib/btxcsu.s | 43 ++ sys/boot/pc98/btx/lib/btxsys.s | 40 ++ sys/boot/pc98/btx/lib/btxv86.h | 63 ++ sys/boot/pc98/btx/lib/btxv86.s | 85 +++ sys/boot/pc98/libpc98/Makefile | 42 ++ sys/boot/pc98/libpc98/biosdisk.c | 1017 ++++++++++++++++++++++++++++++++ sys/boot/pc98/libpc98/biosmem.c | 59 ++ sys/boot/pc98/libpc98/bootinfo.c | 331 +++++++++++ sys/boot/pc98/libpc98/comconsole.c | 136 +++++ sys/boot/pc98/libpc98/gatea20.c | 57 ++ sys/boot/pc98/libpc98/time.c | 83 +++ sys/boot/pc98/libpc98/vidconsole.c | 800 +++++++++++++++++++++++++ sys/boot/pc98/loader/Makefile | 117 ++++ sys/boot/pc98/loader/help.pc98 | 46 ++ sys/boot/pc98/loader/main.c | 244 ++++++++ sys/boot/pc98/loader/newvers.sh | 46 ++ sys/boot/pc98/loader/version | 8 + 44 files changed, 10185 insertions(+), 3 deletions(-) create mode 100644 sys/boot/pc98/Makefile create mode 100644 sys/boot/pc98/boot2/Makefile create mode 100644 sys/boot/pc98/boot2/README.serial.98 create mode 100644 sys/boot/pc98/boot2/asm.S create mode 100644 sys/boot/pc98/boot2/asm.h create mode 100644 sys/boot/pc98/boot2/bios.S create mode 100644 sys/boot/pc98/boot2/boot.c create mode 100644 sys/boot/pc98/boot2/boot.h create mode 100644 sys/boot/pc98/boot2/boot2.S create mode 100644 sys/boot/pc98/boot2/disk.c create mode 100644 sys/boot/pc98/boot2/io.c create mode 100644 sys/boot/pc98/boot2/probe_keyboard.c create mode 100644 sys/boot/pc98/boot2/serial.S create mode 100644 sys/boot/pc98/boot2/start.S create mode 100644 sys/boot/pc98/boot2/sys.c create mode 100644 sys/boot/pc98/boot2/table.c create mode 100644 sys/boot/pc98/btx/Makefile create mode 100644 sys/boot/pc98/btx/btx/Makefile create mode 100644 sys/boot/pc98/btx/btx/btx.S create mode 100644 sys/boot/pc98/btx/btx/btx.m4 create mode 100644 sys/boot/pc98/btx/btx/btx.s create mode 100644 sys/boot/pc98/btx/btxldr/Makefile create mode 100644 sys/boot/pc98/btx/btxldr/btxldr.S create mode 100644 sys/boot/pc98/btx/btxldr/btxldr.s create mode 100644 sys/boot/pc98/btx/lib/Makefile create mode 100644 sys/boot/pc98/btx/lib/btxcsu.s create mode 100644 sys/boot/pc98/btx/lib/btxsys.s create mode 100644 sys/boot/pc98/btx/lib/btxv86.h create mode 100644 sys/boot/pc98/btx/lib/btxv86.s create mode 100644 sys/boot/pc98/libpc98/Makefile create mode 100644 sys/boot/pc98/libpc98/biosdisk.c create mode 100644 sys/boot/pc98/libpc98/biosmem.c create mode 100644 sys/boot/pc98/libpc98/bootinfo.c create mode 100644 sys/boot/pc98/libpc98/comconsole.c create mode 100644 sys/boot/pc98/libpc98/gatea20.c create mode 100644 sys/boot/pc98/libpc98/time.c create mode 100644 sys/boot/pc98/libpc98/vidconsole.c create mode 100644 sys/boot/pc98/loader/Makefile create mode 100644 sys/boot/pc98/loader/help.pc98 create mode 100644 sys/boot/pc98/loader/main.c create mode 100644 sys/boot/pc98/loader/newvers.sh create mode 100644 sys/boot/pc98/loader/version (limited to 'sys/boot') 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 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 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 +.include 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 . + * + * 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 +#include "boot.h" +#include +#include +#include + +#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 +#include + +#include +#include +#include + +#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 +#endif DO_BAD144 +#include +#include + +#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 ??? */ +#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 +#include +#ifdef PC98 +#include +#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 +#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 +#include + +#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 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 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 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"\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"\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 + +.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 + +#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 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 + * 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 + +#include +#include +#include + +#include + +#include +#include +#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 +#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 + * 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 +#include +#include +#include +#include +#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 =, 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 +#include +#include +#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 +#include + +#include + +#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 +#include +#ifdef PC98 +#include +#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 +#include +#include +#include +#include "libi386.h" +#ifdef PC98 +#include +#endif + +#if KEYBOARD_PROBE +#include + +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 + +${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= + + 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= + + 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 + * 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 +#include +#include +#include + +#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 */ +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. -- cgit v1.1