summaryrefslogtreecommitdiffstats
path: root/stand/pc98
diff options
context:
space:
mode:
authorkevans <kevans@FreeBSD.org>2018-02-12 01:08:44 +0000
committerkevans <kevans@FreeBSD.org>2018-02-12 01:08:44 +0000
commit7d97ee5b28b409c00bfaf12daf5ab497a6038b9d (patch)
tree245306b754606bcf49c0ff17b131b58609b6c7a6 /stand/pc98
parent43b278e1b66cf4de337a17034087ea785031bd6f (diff)
downloadFreeBSD-src-7d97ee5b28b409c00bfaf12daf5ab497a6038b9d.zip
FreeBSD-src-7d97ee5b28b409c00bfaf12daf5ab497a6038b9d.tar.gz
MFC r325834,r325997,326502: Move sys/boot to stand/
This is effectively a direct commit to stable/11, due to differences between stable/11 and head. Changes to DTS in sys/boot/fdt/dts were often accompanied by kernel changes. Many of these were also risc-v updates that likely had many more dependencies to MFC. Because of this, sys/boot/fdt/dts remains as-is while everything else in sys/boot relocates to stand/. r325834: Move sys/boot to stand. Fix all references to new location r325997: Remove empty directories. r326502: Document the sys/boot -> stand move in hier.7 and the top-level README.
Diffstat (limited to 'stand/pc98')
-rw-r--r--stand/pc98/Makefile5
-rw-r--r--stand/pc98/Makefile.inc29
-rw-r--r--stand/pc98/boot0.5/Makefile26
-rw-r--r--stand/pc98/boot0.5/boot.s174
-rw-r--r--stand/pc98/boot0.5/boot0.5.s293
-rw-r--r--stand/pc98/boot0.5/disk.s296
-rw-r--r--stand/pc98/boot0.5/ldscript12
-rw-r--r--stand/pc98/boot0.5/putssjis.s137
-rw-r--r--stand/pc98/boot0.5/selector.s450
-rw-r--r--stand/pc98/boot0.5/start.s73
-rw-r--r--stand/pc98/boot0.5/support.s94
-rw-r--r--stand/pc98/boot0.5/syscons.s253
-rw-r--r--stand/pc98/boot0/Makefile19
-rw-r--r--stand/pc98/boot0/boot0.s108
-rw-r--r--stand/pc98/boot2/Makefile116
-rw-r--r--stand/pc98/boot2/boot1.S395
-rw-r--r--stand/pc98/boot2/boot2.c803
-rw-r--r--stand/pc98/btx/Makefile5
-rw-r--r--stand/pc98/btx/Makefile.inc3
-rw-r--r--stand/pc98/btx/btx/Makefile33
-rw-r--r--stand/pc98/btx/btx/btx.S1104
-rw-r--r--stand/pc98/btx/btxldr/Makefile21
-rw-r--r--stand/pc98/btx/btxldr/btxldr.S430
-rw-r--r--stand/pc98/btx/lib/Makefile10
-rw-r--r--stand/pc98/btx/lib/btxcsu.S49
-rw-r--r--stand/pc98/btx/lib/btxsys.s40
-rw-r--r--stand/pc98/btx/lib/btxv86.h67
-rw-r--r--stand/pc98/btx/lib/btxv86.s85
-rw-r--r--stand/pc98/cdboot/Makefile18
-rw-r--r--stand/pc98/cdboot/cdboot.S805
-rw-r--r--stand/pc98/kgzldr/Makefile20
-rw-r--r--stand/pc98/kgzldr/crt.s89
-rw-r--r--stand/pc98/libpc98/Makefile51
-rw-r--r--stand/pc98/libpc98/bioscd.c420
-rw-r--r--stand/pc98/libpc98/biosdisk.c1120
-rw-r--r--stand/pc98/libpc98/biosmem.c64
-rw-r--r--stand/pc98/libpc98/biossmap.c38
-rw-r--r--stand/pc98/libpc98/comconsole.c367
-rw-r--r--stand/pc98/libpc98/libpc98.h29
-rw-r--r--stand/pc98/libpc98/pc98_sys.c78
-rw-r--r--stand/pc98/libpc98/time.c98
-rw-r--r--stand/pc98/libpc98/vidconsole.c596
-rw-r--r--stand/pc98/loader/Makefile99
-rw-r--r--stand/pc98/loader/conf.c116
-rw-r--r--stand/pc98/loader/help.pc9838
-rw-r--r--stand/pc98/loader/main.c322
-rw-r--r--stand/pc98/pc98boot/Makefile25
47 files changed, 9523 insertions, 0 deletions
diff --git a/stand/pc98/Makefile b/stand/pc98/Makefile
new file mode 100644
index 0000000..e8f9dbf
--- /dev/null
+++ b/stand/pc98/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SUBDIR= boot0 boot0.5 pc98boot btx boot2 cdboot kgzldr libpc98 loader
+
+.include <bsd.subdir.mk>
diff --git a/stand/pc98/Makefile.inc b/stand/pc98/Makefile.inc
new file mode 100644
index 0000000..d766303
--- /dev/null
+++ b/stand/pc98/Makefile.inc
@@ -0,0 +1,29 @@
+# Common defines for all of /stand/pc98/
+#
+# $FreeBSD$
+
+BINDIR?= /boot
+
+LOADER_ADDRESS?=0x200000
+CFLAGS+= -march=i386 -ffreestanding
+CFLAGS.gcc+= -mpreferred-stack-boundary=2
+CFLAGS+= ${CFLAGS_NO_SIMD} -msoft-float
+CFLAGS+= -Os -DPC98
+LDFLAGS+= -nostdlib
+
+# 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
+
+# compact binary with no padding between text, data, bss
+LDSCRIPT= ${SRCTOP}/stand/i386/boot.ldscript
+LDFLAGS_BIN=-e start -Ttext ${ORG} -Wl,-T,${LDSCRIPT},-S,--oformat,binary
+LD_FLAGS_BIN=-static -T ${LDSCRIPT} --gc-sections
+
+.include "../Makefile.inc"
diff --git a/stand/pc98/boot0.5/Makefile b/stand/pc98/boot0.5/Makefile
new file mode 100644
index 0000000..ec40fe5
--- /dev/null
+++ b/stand/pc98/boot0.5/Makefile
@@ -0,0 +1,26 @@
+# $FreeBSD$
+
+PROG= ${BOOT}.out
+INTERNALPROG=
+FILES= ${BOOT}
+MAN=
+SRCS= start.s boot.s boot0.5.s disk.s selector.s support.s syscons.s \
+ putssjis.s
+CLEANFILES= ${BOOT} ${BOOT}.bin
+
+BOOT= boot0.5
+
+# The base address that we the boot0 code to to run it. Don't change this
+# unless you are glutton for punishment.
+BOOT_BOOT0_ORG?= 0x0000
+
+LDFLAGS=-e start -Ttext ${BOOT_BOOT0_ORG} -Wl,-N,-T,${.CURDIR}/ldscript
+
+# The size of boot0.5 must be 7168 bytes
+${BOOT}: ${BOOT}.bin
+ cat ${BOOT}.bin /dev/zero | ${DD} of=${BOOT} bs=1 count=7168
+
+${BOOT}.bin: ${BOOT}.out
+ ${OBJCOPY} -S -O binary ${BOOT}.out ${.TARGET}
+
+.include <bsd.prog.mk>
diff --git a/stand/pc98/boot0.5/boot.s b/stand/pc98/boot0.5/boot.s
new file mode 100644
index 0000000..9d11206
--- /dev/null
+++ b/stand/pc98/boot0.5/boot.s
@@ -0,0 +1,174 @@
+# Copyright (c) KATO Takenori, 1999, 2000.
+#
+# All rights reserved. Unpublished rights reserved under the copyright
+# laws of Japan.
+#
+# 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.
+#
+# 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.
+#
+# $FreeBSD$
+#
+
+ .code16
+
+ .text
+ .global boot
+#
+# Read bootstrap program and jump to it.
+#
+boot:
+ # Step 1: Save parameters
+ movw curdevice, %si
+ movb daua(%si), %al
+ movb %al, b_daua
+ shlw %si
+ movw secsize(%si), %ax
+ movw %ax, b_secsize
+
+ movw curpartition, %si
+ movb partnum(%si), %al # %al = real partition number
+ xorb %ah, %ah
+ movw %ax, b_partn # save real parttion number
+ movb $5, %cl
+ shlw %cl, %si # %si = offset to parttable
+ addw $4, %si
+ movb parttable(%si), %al # IPLS
+ movb %al, b_sector
+ incw %si
+ movb parttable(%si), %al # IPLH
+ movb %al, b_head
+ incw %si # IPLC
+ movw parttable(%si), %ax
+ movw %ax, b_cylinder
+
+ # Step 2: Calculate the segment address of the bootstrap routine
+ movw $0x1d00, %ax
+ movw b_secsize, %cx
+ shrw %cx
+ shrw %cx
+ subw %cx, %ax
+ subw $0x100, %ax
+ movw %ax, b_bootseg
+
+ # Step 3: Read bootstrap code
+ movb $6, %ah
+ movb b_daua, %al
+ movw b_secsize, %bx
+ shlw %bx # 2 sectors
+ movw b_cylinder, %cx
+ movb b_head, %dh
+ movb b_sector, %dl
+ movw b_bootseg, %es
+ xorw %bp, %bp
+ int $0x1b
+ jc boot_error
+
+ # Step 4: Set DA/UA into BIOS work area
+ xorw %ax, %ax
+ movw %ax, %es
+ movw $0x584, %bx # DISK_BOOT
+ movb b_daua, %dl
+ call write_biosparam
+
+ call sc_clean
+ # Step 5: Set registers
+ # %ah: 00
+ # %al: DA/UA
+ # %bx: Sector size * 2
+ # %cx: cylinder number of boot partition
+ # %si: pointer to partition table
+ movw b_partn, %ax
+ movb $5, %cl
+ shl %cl, %ax # %ax = partition number * 32
+ addw b_secsize, %ax
+ movw %ax, %si # %si = pointer to partition table
+ movw b_cylinder, %cx # %cx = cylinder
+ movb b_head, %dh # %dh = head
+ movb b_sector, %dl # %dl = sector
+ movw b_bootseg, %es # %es = boot segment
+ movb b_daua, %al # %al = DA/UA
+ movw b_secsize, %bx
+ shlw %bx # %bx = sector size * 2
+ cli
+ movw %cs:iniss, %ss # Restore stack pointer
+ movw %cs:inisp, %sp
+ push %es # Boot segment
+ xorw %bp, %bp
+ push %bp # 0
+ movw %ax, %di # Save %ax
+ xorw %ax, %ax
+ movw %ax, %ds # %ds = 0
+ movw %di, %ax # Restore %ax
+ xorb %ah, %ah # %ah = 0
+ xorw %di, %di # %di = 0
+ sti
+
+ # Jump to bootstrap code
+ lret
+ # NOTREACHED
+
+boot_error:
+ ret
+
+#
+# Try to boot from default partition.
+#
+ .global trydefault
+trydefault:
+ movw ndevice, %cx
+ xorw %si, %si
+trydefault_loop:
+ movw %si, curdevice
+ push %cx
+ push %si
+ call read_ipl
+ pop %si
+ pop %cx
+ cmpb $0x80, defpartflag
+ jne nodefpart
+ # Default partition is defined.
+ push %cx
+ movw npartition, %cx
+srch_part:
+ movw %cx, %bx
+ decw %bx
+ movb defpartnum, %al # %al = real partition number
+ cmpb partnum(%bx), %al
+ jne not_match
+ movw %bx, curpartition # Store partition number
+ call boot
+not_match:
+ loop srch_part
+ pop %cx
+nodefpart:
+ incw %si
+ loop trydefault_loop
+ ret
+
+ .data
+b_daua: .byte 0 # DA/UA
+b_head: .byte 0 # SYSH
+b_sector: .byte 0 # SYSS
+b_cylinder: .word 0 # SYSC
+b_bootseg: .word 0
+b_secsize: .word 0
+b_partn: .word 0 # Real partition number
diff --git a/stand/pc98/boot0.5/boot0.5.s b/stand/pc98/boot0.5/boot0.5.s
new file mode 100644
index 0000000..f878006
--- /dev/null
+++ b/stand/pc98/boot0.5/boot0.5.s
@@ -0,0 +1,293 @@
+# Copyright (c) KATO Takenori, 1999, 2000, 2007.
+#
+# All rights reserved. Unpublished rights reserved under the copyright
+# laws of Japan.
+#
+# 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.
+#
+# 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.
+#
+# $FreeBSD$
+#
+ .global main
+ .code16
+
+ .text
+main:
+ # Check hireso mode
+ movw $0x501, %bx # BIOS_FLAG
+ call read_biosparam
+ testb $0x08, %dl
+ jz normalmode
+ movb $1, ishireso
+normalmode:
+ call sc_init
+
+ # Display title and copyright.
+ movw $title, %di
+ call sc_puts
+ xorw %cx, %cx
+ movw $1, %dx
+ call sc_goto
+ movw $copyright, %di
+ call sc_puts
+
+ # Scan hard drives
+ xorw %si, %si # number of partition
+ call scan_sasi # SASI/IDE
+ call scan_scsi # SCSI
+ movw %si, ndevice
+ orw %si, %si
+ jnz drives_found
+ jmp exit # No hard drives
+
+drives_found:
+ # Setup sector size dependent parameters
+ movw %si, %cx # %cx = number of devices
+setup_loop:
+ movw %cx, %di
+ decw %di
+ shlw %di
+ movw secsize(%di), %ax
+ cmpw $1024, %ax
+ je setup_1024
+ cmpw $512, %ax
+ je setup_512
+ # 256 bytes/sector
+ movw $0x100, partoff(%di)
+ movw $0x0fa, defflagoff(%di)
+ movw $0x0fb, defpartoff(%di)
+ movw $8, maxpart(%di)
+ jmp setup_secsize_end
+ # 1024 bytes/sector
+setup_1024:
+ # XXX Fix me!
+ movw $0x400, partoff(%di)
+ movw $0x3fa, defflagoff(%di)
+ movw $0x3fb, defpartoff(%di)
+ movb $32, maxpart(%di)
+ jmp setup_secsize_end
+ # 512 bytes/sector
+setup_512:
+ movw $0x200, partoff(%di)
+ movw $0x1fa, defflagoff(%di)
+ movw $0x1fb, defpartoff(%di)
+ movb $16, maxpart(%di)
+setup_secsize_end:
+ loop setup_loop
+
+ # For debug with floppy, fake the parameter.
+ movw $0x584, %bx # DISK_BOOT
+ call read_biosparam
+ andb $0xf0, %dl
+ cmpb $0x90, %ah
+ jne boot_from_hdd
+ movb daua, %dl
+ call write_biosparam
+
+boot_from_hdd:
+ movw $500, %cx
+wait_0_5:
+ call wait1ms
+ loop wait_0_5
+
+ # If the TAB is pressed, don't try to boot from default partition
+ xorw %di, %di # flag
+wait_key_release:
+ call sc_iskeypress
+ orw %ax, %ax
+ jz key_release # KBD buffer empty.
+ call sc_getc
+ cmpb $0x0f, %ah # TAB
+ jne wait_key_release
+ # TAB pressed
+ movw $1, %di
+ jmp wait_key_release
+key_release:
+ orw %di, %di
+ jnz dont_try_default # TAB pressed.
+ call trydefault
+ # Default partition not found.
+dont_try_default:
+ call show_usage
+ call showdevices
+ call selector
+exit:
+ ret
+#
+# Display usage
+#
+show_usage:
+ movw $44, %cx
+ movw $3, %dx
+ call sc_goto
+ movw $msg_usage1, %di
+ call sc_puts
+ movw $44, %cx
+ movw $4, %dx
+ call sc_goto
+ movw $msg_usage2, %di
+ call sc_puts
+ movw $44, %cx
+ movw $5, %dx
+ call sc_goto
+ movw $msg_usage3, %di
+ call sc_puts
+ movw $44, %cx
+ movw $7, %dx
+ call sc_goto
+ movw $msg_usage4, %di
+ call sc_puts
+ movw $44, %cx
+ movw $8, %dx
+ call sc_goto
+ movw $msg_usage5, %di
+ call sc_puts
+ movw $44, %cx
+ movw $9, %dx
+ call sc_goto
+ movw $msg_usage6, %di
+ call sc_puts
+ movw $44, %cx
+ movw $10, %dx
+ call sc_goto
+ movw $msg_usage7, %di
+ call sc_puts
+ movw $44, %cx
+ movw $11, %dx
+ call sc_goto
+ movw $msg_usage8, %di
+ call sc_puts
+ movw $44, %cx
+ movw $16, %dx
+ call sc_goto
+ movw $msg_usage9, %di
+ call sc_puts
+ movw $44, %cx
+ movw $17, %dx
+ call sc_goto
+ movw $msg_usage10, %di
+ call sc_puts
+ movw $44, %cx
+ movw $18, %dx
+ call sc_goto
+ movw $msg_usage11, %di
+ call sc_puts
+ movw $44, %cx
+ movw $19, %dx
+ call sc_goto
+ movw $msg_usage12, %di
+ call sc_puts
+ ret
+
+#
+# Display device list
+#
+showdevices:
+ movw $2, %cx
+ movw $4, %dx
+ call sc_goto
+ movw $msg_device, %di
+ call sc_puts
+ xorw %si, %si # %si = device number
+ movw ndevice, %cx # %cx = number of devices
+showdev_loop:
+ push %cx
+ movw $2, %cx
+ movw $5, %dx
+ addw %si, %dx
+ call sc_goto
+ # Check DA
+ movb daua(%si), %al
+ push %ax
+ andb $0xf0, %al
+ cmpb $0x80, %al
+ je show_sasi
+ cmpb $0xa0, %al
+ je show_scsi
+ # unknown device
+ movw $msg_unknown, %di
+ call sc_puts
+ jmp showunit
+ # SASI
+show_sasi:
+ movw $msg_sasi, %di
+ call sc_puts
+ jmp showunit
+ # SCSI
+show_scsi:
+ movw $msg_scsi, %di
+ call sc_puts
+ # Display unit number.
+showunit:
+ pop %ax
+ andb $0x0f, %al
+ addb $'0', %al
+ call sc_putc
+ incw %si
+ pop %cx
+ loop showdev_loop
+ movw ndevice, %dx
+ addw $5, %dx
+ movw $2, %cx
+ call sc_goto
+ movw $msg_exitmenu, %di
+ call sc_puts
+ ret
+
+ .data
+ .global curdevice, ndevice
+ndevice: .word 0 # number of device
+curdevice: .word 0 # current device
+
+ .global ishireso
+ishireso: .byte 0
+
+title: .asciz "PC98 Boot Selector Version 1.2"
+copyright: .ascii "(C)Copyright 1999-2007 KATO Takenori. "
+ .asciz "All rights reserved."
+msg_device: .asciz "Device"
+msg_sasi: .asciz "SASI/IDE unit "
+msg_scsi: .asciz "SCSI ID "
+msg_unknown: .asciz "unknown unit "
+msg_exitmenu: .asciz "Exit this menu"
+msg_usage1: .asciz "Device list"
+msg_usage2: .asciz "UP, DOWN: select boot device"
+msg_usage3: .asciz "RETURN: move to slice list"
+msg_usage4: .asciz "Slice list"
+msg_usage5: .asciz "UP, DOWN: select boot slice"
+msg_usage6: .asciz "RETURN: boot"
+msg_usage7: .asciz "SPACE: toggle default"
+msg_usage8: .asciz "ESC: move to device list"
+msg_usage9: .asciz "LEGEND"
+msg_usage10: .asciz ">>: selected device/slice"
+msg_usage11: .asciz "*: default slice to boot"
+msg_usage12: .asciz "!: unbootable slice"
+
+ .bss
+ .global daua, secsize, defflagoff, defpartoff
+ .global maxpart, partoff
+daua: .space 12 # DA/DU list
+secsize: .space 12 * 2 # Sector soize
+defflagoff: .space 12 * 2
+defpartoff: .space 12 * 2
+maxpart: .space 12 * 2
+partoff: .space 12 * 2
diff --git a/stand/pc98/boot0.5/disk.s b/stand/pc98/boot0.5/disk.s
new file mode 100644
index 0000000..6e80348
--- /dev/null
+++ b/stand/pc98/boot0.5/disk.s
@@ -0,0 +1,296 @@
+# Copyright (c) KATO Takenori, 1999, 2000.
+#
+# All rights reserved. Unpublished rights reserved under the copyright
+# laws of Japan.
+#
+# 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.
+#
+# 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.
+#
+# $FreeBSD$
+#
+
+ .code16
+ .text
+#
+# Check magic number at the end of the sector 0
+#
+check_magic:
+ movw curdevice, %si
+ shlw %si
+ movw secsize(%si), %bx
+ decw %bx
+ decw %bx
+ movw iplbuf(%bx), %ax
+ cmpw $0xaa55, %ax
+ je magic_ok
+ movw $1, %ax
+ ret
+magic_ok:
+ xorw %ax, %ax
+ ret
+
+#
+# Copy partition table from buffer to parttable.
+#
+setup_partition:
+ push %cs
+ pop %es
+ movw curdevice, %bx
+ shlw %bx
+ movw maxpart(%bx), %cx # %cx = max num of partitions
+ movw partoff(%bx), %di
+ movw %di, %bx # %bx = offset to partition table
+ xorw %dx, %dx # %dx = partition number
+setup_partition_loop:
+ push %cx
+ movw %dx, %si
+ movb $5, %cl
+ shlw %cl, %si
+ addw %bx, %si
+ movb iplbuf(%si), %al
+ orb %al, %al
+ jz unused_partition
+ addw $iplbuf, %si
+ movw npartition, %ax
+ movw %ax, %di
+ movb $5, %cl
+ shlw %cl, %di
+ addw $parttable, %di
+ movw $32, %cx
+ rep
+ movsb
+ movw %ax, %di
+ addw $partnum, %di
+ movb %dl, (%di)
+ incw npartition
+unused_partition:
+ incw %dx
+ pop %cx
+ loop setup_partition_loop
+ ret
+
+#
+# Read IPL and partition table in the current device.
+#
+ .global read_ipl
+read_ipl:
+ movw curdevice, %ax
+ movw %ax, %si # %si = device number
+ movw %ax, %di
+ shlw %di
+
+ movw %cs, %ax
+ movw %ax, %es
+ movb $6, %ah
+ movb daua(%si), %al
+ movw $0x400, %bx
+ xorw %cx, %cx
+ xorw %dx, %dx
+ movw $iplbuf, %bp
+ int $0x1b
+ jc read_ipl_error
+ movw defflagoff(%di), %bx
+ movb iplbuf(%bx), %al
+ movb %al, defpartflag
+ incw %bx
+ movb iplbuf(%bx), %al
+ movb %al, defpartnum
+ movw $0, npartition
+ call check_magic
+ orw %ax, %ax
+ jnz no_magic
+ call setup_partition
+no_magic:
+ xorw %ax, %ax
+read_ipl_error:
+ xorw %bx, %bx
+ movw %bx, %es
+ ret
+
+#
+# Restore IPL from the buffer
+#
+ .global write_ipl
+write_ipl:
+ movw curdevice, %ax
+ movw %ax, %si
+ movw %ax, %di
+ shlw %di
+
+ # Restore default boot partition info.
+ movw defflagoff(%di), %bx
+ movb defpartflag, %al
+ movb %al, iplbuf(%bx)
+ incw %bx
+ movb defpartnum, %al
+ movb %al, iplbuf(%bx)
+
+ movw %cs, %ax
+ movw %ax, %es
+ movb $5, %ah
+ movb daua(%si), %al
+ movw secsize(%di), %bx
+ xorw %cx, %cx
+ xorw %dx, %dx
+ movw $iplbuf, %bp
+ int $0x1b
+ jc write_ipl_error
+ xorw %ax, %ax
+write_ipl_error:
+ xorw %bx, %bx
+ movw %bx, %es
+ ret
+
+#
+# Scan HDD devices
+#
+ .global scan_sasi, scan_scsi
+ # Scan SASI disk
+scan_sasi:
+ # SASI Disk
+ movw $4, %cx
+ movw $0x0001, %ax # %ah = unit number, %al = for bit operation
+
+sasi_loop:
+ movw %si, %di
+ shlw %di
+ movw $0x55d, %bx # DISK_EQUIP
+ call read_biosparam
+ testb %al, %dl
+ jz no_sasi_unit
+ movb $0x80, %dh
+ addb %ah, %dh # %dh = DA/UA
+ movb %dh, daua(%si) # Store DA/UA
+
+ # Try new sense command
+ push %ax
+ push %cx
+ movb %dh, %al
+ movb $0x84, %ah
+ int $0x1b
+ pop %cx
+ pop %ax
+ jc err_newsense
+ movw %bx, %dx
+ jmp found_sasi_unit
+
+err_newsense:
+ movw $0x457, %bx # capacity & sector size of IDE HDD
+ call read_biosparam
+ orb %ah, %ah
+ jz sasi_1
+ cmpb $1, %ah
+ jz sasi_2
+
+ # SASI #3/#4
+ movw $512, %dx # XXX
+ jmp found_sasi_unit
+
+sasi_1:
+ # SASI #1
+ testb $0x80, %dl
+ jz sasi_256
+ jmp sasi_512
+sasi_2:
+ # SASI #2
+ testb $0x40, %dl
+ jz sasi_256
+ jmp sasi_512
+
+sasi_256:
+ movw $256, %dx
+ jmp found_sasi_unit
+sasi_512:
+ movw $512, %dx
+found_sasi_unit:
+ movw %dx, secsize(%di)
+ incw %si
+no_sasi_unit:
+ incb %ah
+ shlb %al
+ loop sasi_loop
+ ret
+
+#
+# Scan SCSI disk
+# SI number of disks
+# destroyed: %ax, %bx, %cx, %dx
+scan_scsi:
+ movw $8, %cx
+ movw $0x0001, %ax # %ah = ID number, %al = for bit operation
+scsi_loop:
+ # Check whether drive exist.
+ movw %si, %di
+ shlw %di
+ movw $0x482, %bx # DISK_EQUIPS
+ call read_biosparam
+ testb %al, %dl
+ jz no_scsi_unit
+ xorw %bx, %bx
+ movb %ah, %bl
+ shlw %bx
+ shlw %bx
+ addw $0x460, %bx # SCSI parameter block
+ call read_biosparam
+ orb %dl, %dl
+ jz no_scsi_unit
+
+ # SCSI harddrive found.
+ movb $0xa0, %dh
+ addb %ah, %dh
+ movb %dh, daua(%si)
+
+ # Check sector size.
+ addw $3, %bx
+ call read_biosparam
+ andb $0x30, %dl
+ cmpb $0x20, %dl
+ je scsi_1024
+ cmpb $0x10, %dl
+ je scsi_512
+ movw $256, %dx
+ jmp found_scsi
+scsi_1024:
+ movw $1024, %dx
+ jmp found_scsi
+scsi_512:
+ movw $512, %dx
+found_scsi:
+ movw %dx, secsize(%di)
+ incw %si
+no_scsi_unit:
+ incb %ah
+ shlb %al
+ loop scsi_loop
+ ret
+
+ .data
+ .global defpartflag, defpartnum, npartition
+defpartflag: .byte 0
+defpartnum: .byte 0
+npartition: .word 0 # number of partitions
+
+ .bss
+ .global partnum, parttable
+iplbuf: .space 0x400 # Read buffer for IPL
+partnum: .space 32 # Index of parttable
+parttable: .space 1024 # Copy of valid partition table
diff --git a/stand/pc98/boot0.5/ldscript b/stand/pc98/boot0.5/ldscript
new file mode 100644
index 0000000..49044ab
--- /dev/null
+++ b/stand/pc98/boot0.5/ldscript
@@ -0,0 +1,12 @@
+/*
+ * $FreeBSD$
+ */
+
+SECTIONS
+{
+ .text : { *(.text) }
+ .data : { *(.data) }
+ . = 0x1243;
+ .putssjis : { *(.putssjis) }
+ .bss : { *(.bss) }
+}
diff --git a/stand/pc98/boot0.5/putssjis.s b/stand/pc98/boot0.5/putssjis.s
new file mode 100644
index 0000000..221b9e6
--- /dev/null
+++ b/stand/pc98/boot0.5/putssjis.s
@@ -0,0 +1,137 @@
+# Copyright (c) KATO Takenori, 2007.
+#
+# All rights reserved. Unpublished rights reserved under the copyright
+# laws of Japan.
+#
+# 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.
+#
+# 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.
+#
+# $FreeBSD$
+#
+
+ .code16
+ .section .putssjis, "awx", @progbits
+
+ #
+ # Display string with Shift-JIS support
+ # %si: address of string, %di: T-VRAM address, %cx: count
+ #
+
+ # Absolute address of putssjis_entry must be 0x1243.
+putssjis_entry:
+ push %es
+ push %ax
+ # Setup the T-VRAM segement address.
+ xorw %ax, %ax
+ movw %ax, %es
+ movw $0xa000, %ax
+ testb $0x08, %es:0x501
+ jz normalmode
+ movw $0xe000, %ax
+normalmode:
+ movw %ax, %es
+
+putssjis_loop:
+ lodsw
+ call check_sjis
+ jc put_2byte_char
+
+ # 1 byte character
+ xorb %ah, %ah
+ testb $0xe0, %al # Check control code.
+ jnz put_1byte_char
+ movb $0x20, %al # Convert control code into the space.
+put_1byte_char:
+ stosw
+ decw %si
+ jmp putssjis_loop_end
+
+put_2byte_char:
+ subb $0x20, %al
+
+ # Check 2byte "hankaku"
+ cmp $0x09, %al
+ je put_2byte_hankaku
+ cmp $0x0a, %al
+ je put_2byte_hankaku
+ cmp $0x0b, %al
+ je put_2byte_hankaku
+ jmp put_2byte_zenkaku
+
+put_2byte_hankaku:
+ stosw
+ jmp putssjis_loop_end
+
+put_2byte_zenkaku:
+ stosw
+ orb $0x80, %ah
+ stosw
+ decw %cx
+
+putssjis_loop_end:
+ loop putssjis_loop
+
+ pop %ax
+ pop %es
+ ret
+
+ # Check 2-byte code.
+check_sjis:
+ cmpb $0x80, %al
+ jbe found_ank_kana
+ cmpb $0xa0, %al
+ jb found_2byte_char
+ cmpb $0xe0, %al
+ jb found_ank_kana
+ cmpb $0xf0, %al
+ jae found_ank_kana
+ jmp found_2byte_char
+found_ank_kana:
+ clc
+ ret
+
+found_2byte_char:
+ # Convert Shift-JIS into JIS.
+ cmpb $0x9f, %al
+ ja sjis_h_2 # Upper > 0x9f
+ subb $0x71, %al # Upper -= 0x71
+ jmp sjis_lower
+sjis_h_2:
+ subb $0xb1, %al # Upper -= 0xb1
+sjis_lower:
+ salb %al # Upper *= 2
+ incb %al # Upper += 1
+
+ cmpb $0x7f, %ah
+ jbe sjis_l_2
+ decb %ah # Lower -= 1 if lower > 0x7f
+sjis_l_2:
+ cmpb $0x9e, %ah
+ jb sjis_l_3
+ subb $0x7d, %ah # Lower -= 0x7d
+ incb %al # Upper += 1
+ jmp check_2byte_end
+sjis_l_3:
+ subb $0x1f, %ah # Lower -= 0x1f
+check_2byte_end:
+ stc
+ ret
diff --git a/stand/pc98/boot0.5/selector.s b/stand/pc98/boot0.5/selector.s
new file mode 100644
index 0000000..9d98ef8
--- /dev/null
+++ b/stand/pc98/boot0.5/selector.s
@@ -0,0 +1,450 @@
+# Copyright (c) KATO Takenori, 1999, 2000, 2007.
+#
+# All rights reserved. Unpublished rights reserved under the copyright
+# laws of Japan.
+#
+# 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.
+#
+# 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.
+#
+# $FreeBSD$
+#
+
+ .code16
+
+ .text
+#
+# Display partition table.
+#
+showpartitions:
+ # Clear partition table area
+ movw $16, %cx
+clear_part:
+ push %cx
+ movw %cx, %dx
+ decw %dx
+ addw $5, %dx
+ movw $20, %cx
+ call sc_goto
+ movw $msg_spc, %di
+ call sc_puts
+ pop %cx
+ loop clear_part
+
+ # Check `Exit' menu
+ movw curdevice, %ax
+ cmpw ndevice, %ax
+ je no_slice
+
+ # XXX Move this to a suitable place!
+ movw $22, %cx
+ movw $4, %dx
+ call sc_goto
+ movw $msg_slice, %di
+ call sc_puts
+
+ # Check the number of partitions
+ movw npartition, %cx
+ orw %cx, %cx
+ jnz partitionexist
+no_slice:
+ # Just show the `no slice' message.
+ movw $22, %cx
+ movw $5, %dx
+ call sc_goto
+ movw $msg_noslice, %di
+ call sc_puts
+ ret
+partitionexist:
+ xorw %si, %si # %si = partition number
+showpart_loop:
+ push %cx # %cx = number of partitions
+ movw $22, %cx
+ movw %si, %dx
+ addw $5, %dx
+ call sc_goto
+ movw %si, %di
+ movb $5, %cl
+ shlw %cl, %di
+ addw $0x10, %di # SYSM field
+ # SYSM: space filled string. Don't use sc_puts.
+ movw $16, %cx
+showpart_name:
+ push %cx
+ movb parttable(%di), %al
+ call sc_putc
+ incw %di
+ pop %cx
+ loop showpart_name
+ incw %si
+ pop %cx
+ loop showpart_loop
+ ret
+
+#
+# Show default slice indicator
+# If the default boot slice exists, `*' indicator will be showed.
+#
+showdefaultslicemark:
+ cmpb $0x80, defpartflag
+ je defpartexist
+ ret
+defpartexist:
+ movw npartition, %cx
+defslice_loop:
+ movw %cx, %bx
+ decw %bx
+ push %cx
+ push %bx
+ movw $40, %cx
+ movw %bx, %dx
+ addw $5, %dx
+ call sc_goto
+
+ pop %bx
+ pop %cx
+ movb defpartnum, %al
+ cmpb partnum(%bx), %al
+ jne nomatch
+ movb $'*', %al
+ call sc_putc
+ jmp defslice_done
+nomatch:
+ movb $' ', %al
+ call sc_putc
+defslice_done:
+ loop defslice_loop
+ ret
+
+#
+# Hide default slice indicator
+#
+hidedefaultslicemark:
+ movw $16, %cx
+hidedefslice_loop:
+ push %cx
+ movw %cx, %dx
+ addw $4, %dx
+ movw $40, %cx
+ call sc_goto
+ movb $' ', %al
+ call sc_putc
+ pop %cx
+ loop hidedefslice_loop
+ ret
+
+#
+# Toggle default slice
+#
+toggle_default:
+ cmpb $0x80, defpartflag
+ jne set_default
+ # Clear default
+ movb $0, defpartflag
+ call write_ipl # Restore
+ call hidedefaultslicemark
+ ret
+ # Set default slice
+set_default:
+ movw curpartition, %si
+ movb partnum(%si), %al # %al = real partition number
+ movb $5, %cl
+ shlw %cl, %si
+ # Default slice must be bootable
+ testb $0x80, parttable(%si)
+ jnz curpart_bootable
+ # Current partition is not bootable.
+ ret
+curpart_bootable:
+ movb $0x80, defpartflag
+ movb %al, defpartnum
+ call write_ipl # Restore
+ call showdefaultslicemark
+ ret
+
+#
+# Show/hide cursor
+#
+show_devcurs:
+ xorw %cx, %cx
+ movw curdevice, %dx
+ addw $5, %dx
+ call sc_goto
+ movb $'>', %al
+ call sc_putc
+ movb $'>', %al
+ call sc_putc
+ ret
+
+hide_devcurs:
+ xorw %cx, %cx
+ movw curdevice, %dx
+ addw $5, %dx
+ call sc_goto
+ movb $' ', %al
+ call sc_putc
+ movb $' ', %al
+ call sc_putc
+ ret
+
+show_slicecurs:
+ movw $20, %cx
+ movw curpartition, %dx
+ addw $5, %dx
+ call sc_goto
+ movb $'>', %al
+ call sc_putc
+ movb $'>', %al
+ call sc_putc
+ ret
+
+hide_slicecurs:
+ movw $20, %cx
+ movw curpartition, %dx
+ addw $5, %dx
+ call sc_goto
+ movb $' ', %al
+ call sc_putc
+ movb $' ', %al
+ call sc_putc
+ ret
+
+isforceboot:
+ xorw %cx, %cx
+ movw $20, %dx
+ call sc_goto
+ movw $msg_force, %di
+ call sc_puts
+ call sc_getc
+ push %ax
+ xorw %cx, %cx
+ movw $20, %dx
+ call sc_goto
+ movw $msg_forceclr, %di
+ call sc_puts
+ pop %ax
+ cmpb $0x15, %ah
+ je force_yes
+ xorw %ax, %ax
+ ret
+force_yes:
+ movw $1, %ax
+ ret
+
+#
+# Main loop for device mode
+#
+devmode:
+ call read_ipl
+ call hidedefaultslicemark
+ call showpartitions
+ call showdefaultslicemark
+ call show_devcurs
+
+ movw $2, %cx
+ movw $4, %dx
+ call sc_goto
+ movb $0xe5, %al
+ movw $6, %cx
+ call sc_setattr
+ movw $22, %cx
+ movw $4, %dx
+ call sc_goto
+ movb $0xe1, %al
+ movw $5, %cx
+ call sc_setattr
+ movw $44, %cx
+ movw $3, %dx
+ call sc_goto
+ movb $0xe5, %al
+ movw $11, %cx
+ call sc_setattr
+ movw $44, %cx
+ movw $7, %dx
+ call sc_goto
+ movb $0xe1, %al
+ movw $10, %cx
+ call sc_setattr
+
+devmode_loop:
+ call sc_getc
+ movw ndevice, %bx
+ cmpb $0x3a, %ah # UP
+ je dev_up
+ cmpb $0x3d, %ah # DOWN
+ je dev_down
+ cmpb $0x3c, %ah # RIGHT
+ je dev_right
+ cmpb $0x1c, %ah # RETURN
+ jne devmode_loop
+ cmpw curdevice, %bx
+ jne dev_right
+ movw $3, mode # N88-BASIC
+ ret
+
+ # XXX
+ .space 5, 0x90
+ ret # Dummy ret @0x9ab
+
+dev_up:
+ cmpw $0, curdevice
+ je devmode_loop
+ call hide_devcurs
+ decw curdevice
+ call read_ipl
+ call hidedefaultslicemark
+ call showpartitions
+ call showdefaultslicemark
+ call show_devcurs
+ jmp devmode_loop
+dev_down:
+ cmpw curdevice, %bx
+ je devmode_loop
+ call hide_devcurs
+ incw curdevice
+ call read_ipl
+ call hidedefaultslicemark
+ call showpartitions
+ call showdefaultslicemark
+ call show_devcurs
+ jmp devmode_loop
+dev_right:
+ cmpw curdevice, %bx
+ je devmode_loop
+ movw $1, mode # Slice mode
+ ret
+
+#
+# main loop for slice mode
+#
+slicemode:
+ movw $0, curpartition
+ call show_slicecurs
+ movw $2, %cx
+ movw $4, %dx
+ call sc_goto
+ movb $0xe1, %al
+ movw $6, %cx
+ call sc_setattr
+ movw $22, %cx
+ movw $4, %dx
+ call sc_goto
+ movb $0xe5, %al
+ movw $5, %cx
+ call sc_setattr
+ movw $44, %cx
+ movw $3, %dx
+ call sc_goto
+ movb $0xe1, %al
+ movw $11, %cx
+ call sc_setattr
+ movw $44, %cx
+ movw $7, %dx
+ call sc_goto
+ movb $0xe5, %al
+ movw $10, %cx
+ call sc_setattr
+
+slicemode_loop:
+ call sc_getc
+ cmpb $0x3a, %ah # UP
+ je slice_up
+ cmpb $0x3d, %ah # DOWN
+ je slice_down
+ cmpb $0x3b, %ah # LEFT
+ je slice_esc
+ cmpb $0x00, %ah # ESC
+ je slice_esc
+ cmpb $0x1c, %ah # RETURN
+ je slice_ret
+ cmpb $0x34, %ah # SPC
+ je slice_spc
+ cmpb $0x62, %ah # f1
+ je slice_spc
+ jmp slicemode_loop
+slice_up:
+ cmpw $0, curpartition
+ je slicemode_loop
+ call hide_slicecurs
+ decw curpartition
+ call show_slicecurs
+ jmp slicemode_loop
+slice_down:
+ movw curpartition, %bx
+ movw npartition, %ax
+ decw %ax
+ cmpw %bx, %ax
+ je slicemode_loop
+ call hide_slicecurs
+ incw curpartition
+ call show_slicecurs
+ jmp slicemode_loop
+slice_esc:
+ movw $0, mode # Device mode
+ ret
+slice_spc:
+ call toggle_default
+ jmp slicemode_loop
+slice_ret:
+ # Test bit 7 of mid
+ movw curpartition, %si
+ movb $5, %cl
+ shlw %cl, %si
+ testb $0x80, parttable(%si)
+ jnz bootable_slice
+ call isforceboot
+ orw %ax, %ax
+ jz slicemode_loop
+bootable_slice:
+ call boot
+ jmp slicemode_loop
+
+#
+# Main loop
+#
+ .global selector
+selector:
+ movw $0, curdevice # trydefault may change the curdevice.
+ movw $0, mode
+
+selector_loop:
+ cmpw $0, mode
+ je status_dev
+ cmpw $1, mode
+ je status_slice
+ ret
+status_dev:
+ call devmode
+ jmp selector_loop
+status_slice:
+ call slicemode
+ jmp selector_loop
+
+ .data
+ .global curpartition
+curpartition: .word 0 # current patition
+mode: .word 0
+
+msg_spc: .asciz " "
+msg_slice: .asciz "Slice"
+msg_noslice: .asciz "no slice"
+msg_force: .asciz "This slice is not bootable. Continue? (Y / [N])"
+msg_forceclr: .asciz " "
diff --git a/stand/pc98/boot0.5/start.s b/stand/pc98/boot0.5/start.s
new file mode 100644
index 0000000..008ae66
--- /dev/null
+++ b/stand/pc98/boot0.5/start.s
@@ -0,0 +1,73 @@
+# Copyright (c) KATO Takenori, 1999, 2000, 2007.
+#
+# All rights reserved. Unpublished rights reserved under the copyright
+# laws of Japan.
+#
+# 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.
+#
+# 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.
+#
+# $FreeBSD$
+#
+ .global start
+ .code16
+
+ .text
+start:
+ jmp start1
+
+ # Magic
+ .org 0x053, 0x20
+ .byte 0x4e, 0x45, 0x43
+
+ .org 0x8f
+ .byte 0x32, 0x2e, 0x37, 0x30
+
+ .org 0x2d4
+start1:
+ # The instruction 'call 0x9ab' can be here. See also selector.s.
+ nop
+ nop
+ nop
+ cli
+ movw %cs, %ax
+ movw %ax, %ds
+ movw %ss, iniss
+ movw %sp, inisp
+ movw %ax, %ss
+ movw $0xfffe, %sp
+ sti
+ xorw %ax, %ax
+ movw %ax, %es
+ call main
+
+ cli
+ movw %cs:iniss, %ss
+ movw %cs:inisp, %sp
+ sti
+ int $0x1e
+ # NOTREACHED
+ lret
+
+ .data
+ .global iniss, inisp
+iniss: .word 0
+inisp: .word 0
diff --git a/stand/pc98/boot0.5/support.s b/stand/pc98/boot0.5/support.s
new file mode 100644
index 0000000..df1115b
--- /dev/null
+++ b/stand/pc98/boot0.5/support.s
@@ -0,0 +1,94 @@
+# Copyright (c) KATO Takenori, 1999, 2000.
+#
+# All rights reserved. Unpublished rights reserved under the copyright
+# laws of Japan.
+#
+# 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.
+#
+# 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.
+#
+# $FreeBSD$
+#
+
+ .code16
+
+ .text
+#
+# Wait 1ms
+#
+ .global wait1ms
+wait1ms:
+ push %cx
+ movw $800, %cx
+wait_loop:
+ outb %al, $0x5f
+ loop wait_loop
+ pop %cx
+ ret
+
+#
+# Read one byte from BIOS parameter block
+# %bx offset
+# %dl value
+#
+ .global read_biosparam
+read_biosparam:
+ movb %es:(%bx), %dl
+ ret
+
+#
+# Write one byte to BIOS parameter block
+# %bx offset
+# %dl value
+#
+ .global write_biosparam
+write_biosparam:
+ movb %dl, %es:(%bx)
+ ret
+
+#
+# beep
+#
+ .global beep_on, beep_off, beep
+beep_on:
+ movb $0x17, %ah
+ int $0x18
+ ret
+
+beep_off:
+ movb $0x18, %ah
+ int $0x18
+ ret
+
+beep:
+ push %cx
+ call beep_on
+ movw $100, %cx
+beep_loop1:
+ call wait1ms
+ loop beep_loop1
+ call beep_off
+ movw $50, %cx
+beep_loop2:
+ call wait1ms
+ loop beep_loop2
+ pop %cx
+ ret
diff --git a/stand/pc98/boot0.5/syscons.s b/stand/pc98/boot0.5/syscons.s
new file mode 100644
index 0000000..150b835
--- /dev/null
+++ b/stand/pc98/boot0.5/syscons.s
@@ -0,0 +1,253 @@
+# Copyright (c) KATO Takenori, 1999, 2000.
+#
+# All rights reserved. Unpublished rights reserved under the copyright
+# laws of Japan.
+#
+# 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.
+#
+# 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.
+#
+# $FreeBSD$
+#
+
+ .code16
+
+ .text
+#
+# %al character code
+# destroyed: %al, %bx
+#
+put_character:
+ movw $0xe000, %bx
+ movb ishireso, %ah
+ orb %ah, %ah
+ jne hireso_ch
+ movw $0xa000, %bx
+hireso_ch:
+ movw %bx, %es
+ xorb %ah, %ah
+ movw curpos, %bx
+ movw %ax, %es:(%bx)
+ xorw %ax, %ax
+ movw %ax, %es
+ ret
+
+#
+# %al attribute
+# destroyed: %ah, %cx
+#
+set_attribute:
+ movw $0xe200, %bx
+ movb ishireso, %ah
+ orb %ah, %ah
+ jne hireso_ch
+ movw $0xa200, %bx
+hireso_attr:
+ movw %bx, %es
+ xorb %ah, %ah
+ movw curpos, %bx
+ movw %ax, %es:(%bx)
+ xorw %bx, %bx
+ movw %bx, %es
+ ret
+
+#
+# Put a character
+# %al: character code
+# destroyed: %ah, %bx, %cx
+#
+ .global sc_putc
+sc_putc:
+ call put_character
+ incw curpos
+ incw curpos
+ cmpw $4000, curpos
+ jng putc_end
+ movw $0, curpos
+putc_end:
+ ret
+
+#
+# Put a null terminated string
+# %di: pointer to string
+# destroyed: %ah, %cx, %di
+#
+ .global sc_puts
+sc_puts:
+ movb (%di), %al
+ orb %al, %al
+ jz puts_end
+ call sc_putc
+ incw %di
+ jmp sc_puts
+puts_end:
+ ret
+
+#
+# Change the current cursor position
+# %cx: X
+# %dx: Y
+# destroyed: %ax, %bx
+#
+ .global sc_goto
+sc_goto:
+ movw %dx, %ax # AX=Y
+ shlw %ax # AX=Y*64
+ shlw %ax
+ shlw %ax
+ shlw %ax
+ shlw %ax
+ shlw %ax
+ movw %dx, %bx # BX=Y
+ shlw %bx # BX=Y*16
+ shlw %bx
+ shlw %bx
+ shlw %bx
+ addw %bx, %ax # AX=Y*64+Y*16=Y*80
+ addw %cx, %ax
+ shlw %ax
+ movw %ax, curpos
+ ret
+
+#
+# Clear screen
+# destroyed: %ax, %bx
+#
+ .global sc_clean
+sc_clean:
+ movb $0x16, %ah
+ movw $0xe120, %dx
+ int $0x18 # KBD/CRT BIOS
+ movw $0, curpos
+ ret
+
+#
+# Set sttribute code
+# %al: attribute
+# %cx: count
+# destroyed: %ax, %bx, %cx
+#
+ .global sc_setattr
+sc_setattr:
+ call set_attribute
+ incw curpos
+ incw curpos
+ loop sc_setattr
+
+#
+# Sense the state of shift key
+# destroyed: %ax
+#
+ .global sc_getshiftkey
+sc_getshiftkey:
+ movb $2, %ah # Sense KB_SHIFT_COD
+ int $0x18 # KBD/CRT BIOS
+ xorb %ah, %ah
+ ret
+
+#
+# Check KBD buffer
+#
+ .global sc_iskeypress
+sc_iskeypress:
+ mov $1, %ah
+ int $0x18 # KBD/CRT BIOS
+ testb $1, %bh
+ jz no_key
+ movw $1, %ax
+ ret
+no_key:
+ xorw %ax, %ax
+ ret
+
+#
+# Read from KBD
+#
+ .global sc_getc
+sc_getc:
+ xorb %ah, %ah
+ int $0x18
+ ret
+
+#
+# Initialize CRT (normal mode)
+#
+init_screen_normal:
+ # Disable graphic screen
+ movb $0x41, %ah
+ int $0x18
+ # Init graphic screen
+ movb $0x42, %al
+ movb $0xc0, %ch
+ int $0x18
+ # 80x25 mode
+ movw $0x0a00, %ax
+ int $0x18
+ ret
+
+#
+# Initialize CRT (hireso mode)
+#
+init_screen_hireso:
+ # Init RAM window
+ movb $8, %al
+ outb %al, $0x91
+ movb $0x0a, %al
+ outb %al, $0x93
+ # 80x31 mode
+ movw $0x0a00, %ax
+ int $0x18
+ ret
+
+#
+# Initialize screen (internal)
+#
+init_screen:
+ movb ishireso, %ah
+ orb %ah, %ah
+ jne hireso_ini
+ call init_screen_normal
+ jmp init_next
+hireso_ini:
+ call init_screen_hireso
+init_next:
+ movb $0x0c, %ah
+ int $0x18
+ # cursor home and off
+ xorw %dx, %dx
+ movb $0x13, %ah
+ int $0x18
+ movb $0x12, %ah
+ int $0x18
+ ret
+
+#
+# Initialize screeen
+#
+ .global sc_init
+sc_init:
+ call init_screen
+ call sc_clean
+ movw $0, curpos
+ ret
+
+ .data
+curpos: .word 0 # Current cursor position
diff --git a/stand/pc98/boot0/Makefile b/stand/pc98/boot0/Makefile
new file mode 100644
index 0000000..d348f60
--- /dev/null
+++ b/stand/pc98/boot0/Makefile
@@ -0,0 +1,19 @@
+# $FreeBSD$
+
+PROG= ${BOOT}
+INTERNALPROG=
+FILES= ${BOOT}
+MAN=
+SRCS= ${BOOT}.s
+CLEANFILES= ${BOOT}
+
+BOOT= boot0
+
+# The base address that we the boot0 code to to run it. Don't change this
+# unless you are glutton for punishment.
+BOOT_BOOT0_ORG?= 0x0000
+ORG=${BOOT_BOOT0_ORG}
+
+LDFLAGS=${LDFLAGS_BIN}
+
+.include <bsd.prog.mk>
diff --git a/stand/pc98/boot0/boot0.s b/stand/pc98/boot0/boot0.s
new file mode 100644
index 0000000..508e252
--- /dev/null
+++ b/stand/pc98/boot0/boot0.s
@@ -0,0 +1,108 @@
+# Copyright (c) KATO Takenori, 1999, 2000.
+#
+# All rights reserved. Unpublished rights reserved under the copyright
+# laws of Japan.
+#
+# 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.
+#
+# $FreeBSD$
+
+ .globl start
+ .code16
+start:
+ jmp main
+
+ .org 4
+ .ascii "IPL1"
+ .byte 0, 0, 0
+
+ .globl start
+main:
+ xor %ax, %ax
+ mov %ax, %ds
+ mov (0x584), %al # DA/UA
+ mov %al, %ah
+ and $0xf0, %ah
+ cmp $0x90, %ah
+ je fdd
+
+ # hdd
+ mov $6, %ah
+ mov $0x3000, %bx
+ mov %bx, %es
+ mov $0x2000, %bx
+ xor %cx, %cx
+ xor %dx, %dx
+ xor %bp, %bp
+ int $0x1b
+ jc error_hdd
+
+ push %ax
+ mov %es, %ax
+ add $0x40, %ax
+ mov %ax, %es
+ pop %ax
+ push %es
+ push %bp
+ lret
+
+ # fdd
+fdd:
+ xor %di, %di
+fdd_retry:
+ mov $0xd6, %ah
+ mov $0x3000, %bx
+ mov %bx, %es
+ mov $0x2000, %bx
+ mov $0x0200, %cx
+ mov $0x0001, %dx
+ xor %bp, %bp
+ int $0x1b
+ jc error
+ push %ax
+ mov %es, %ax
+ add $0x40, %ax
+ mov %ax, %es
+ pop %ax
+ push %es
+ push %bp
+ lret
+
+error:
+ or %di, %di
+ jnz error_hdd
+ and $0x0f, %al
+ or $0x30, %al
+ jmp fdd_retry
+
+error_hdd:
+ jmp error
+
+ .org 0x1fa
+ .byte 0 # defflag_off
+ .byte 0 # defpart_off
+ .byte 1 # menu version
+ .byte 0
+ .word 0xaa55
diff --git a/stand/pc98/boot2/Makefile b/stand/pc98/boot2/Makefile
new file mode 100644
index 0000000..2db0590
--- /dev/null
+++ b/stand/pc98/boot2/Makefile
@@ -0,0 +1,116 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+FILES= boot boot1 boot2
+
+NM?= nm
+
+BOOT_COMCONSOLE_PORT?= 0x238
+BOOT_COMCONSOLE_SPEED?= 9600
+B2SIOFMT?= 0x3
+
+REL1= 0x700
+ORG1= 0
+ORG2= 0x2000
+
+# Decide level of UFS support.
+BOOT2_UFS?= UFS1_AND_UFS2
+#BOOT2_UFS?= UFS2_ONLY
+#BOOT2_UFS?= UFS1_ONLY
+
+CFLAGS= -fomit-frame-pointer \
+ -mrtd \
+ -mregparm=3 \
+ -D${BOOT2_UFS} \
+ -DFLAGS=${BOOT_BOOT1_FLAGS} \
+ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \
+ -DSIOFMT=${B2SIOFMT} \
+ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \
+ -I${.CURDIR}/../../.. \
+ -I${.CURDIR}/../../i386/boot2 \
+ -I${.CURDIR}/../../common \
+ -I${.CURDIR}/../btx/lib -I. \
+ -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \
+ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
+ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \
+ -Winline
+
+CFLAGS.gcc+= -Os \
+ -fno-guess-branch-probability \
+ -fno-unit-at-a-time \
+ --param max-inline-insns-single=100
+.if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} <= 40201
+CFLAGS.gcc+= -mno-align-long-strings
+.endif
+
+# Set machine type to PC98_SYSTEM_PARAMETER
+#CFLAGS+= -DSET_MACHINE_TYPE
+
+# Initialize the bi_bios_geom using the BIOS geometry
+#CFLAGS+= -DGET_BIOSGEOM
+
+CFLAGS.clang+= -Oz ${CLANG_OPT_SMALL}
+
+LD_FLAGS=${LD_FLAGS_BIN}
+
+# Pick up ../Makefile.inc early.
+.include <bsd.init.mk>
+
+.PATH: ${.CURDIR}/../../i386/boot2
+
+CLEANFILES= boot
+
+boot: boot1 boot2
+ cat boot1 boot2 > boot
+
+CLEANFILES+= boot1 boot1.out boot1.o
+
+boot1: boot1.out
+ ${OBJCOPY} -S -O binary boot1.out ${.TARGET}
+
+boot1.out: boot1.o
+ ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} boot1.o
+
+CLEANFILES+= boot2 boot2.ld boot2.ldr boot2.bin boot2.out boot2.o \
+ boot2.s boot2.s.tmp boot2.h sio.o
+
+boot2: boot2.ld
+ @set -- `ls -l boot2.ld`; x=$$((7680-$$5)); \
+ echo "$$x bytes available"; test $$x -ge 0
+ ${DD} if=boot2.ld of=${.TARGET} obs=7680 conv=osync
+
+boot2.ld: boot2.ldr boot2.bin ${BTXKERN}
+ btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l boot2.ldr \
+ -o ${.TARGET} -P 1 boot2.bin
+
+boot2.ldr:
+ ${DD} if=/dev/zero of=${.TARGET} bs=276 count=1
+
+boot2.bin: boot2.out
+ ${OBJCOPY} -S -O binary boot2.out ${.TARGET}
+
+boot2.out: ${BTXCRT} boot2.o sio.o
+ ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC}
+
+boot2.o: boot2.s
+ ${CC} ${ACFLAGS} -c boot2.s
+
+SRCS= boot2.c boot2.h
+
+boot2.s: boot2.c boot2.h ${.CURDIR}/../../common/ufsread.c
+ ${CC} ${CFLAGS} -S -o boot2.s.tmp ${.CURDIR}/boot2.c
+ sed -e '/align/d' -e '/nop/d' < boot2.s.tmp > boot2.s
+ rm -f boot2.s.tmp
+
+boot2.h: boot1.out
+ ${NM} -t d ${.ALLSRC} | awk '/([0-9])+ T (read|putc)/ \
+ { x = $$1 - ORG1; \
+ printf("#define %sORG %#x\n", toupper($$3), REL1 + x) }' \
+ ORG1=`printf "%d" ${ORG1}` \
+ REL1=`printf "%d" ${REL1}` > ${.TARGET}
+
+.include <bsd.prog.mk>
+
+# XXX: clang integrated-as doesn't grok .codeNN directives yet
+CFLAGS.boot1.S= ${CLANG_NO_IAS}
diff --git a/stand/pc98/boot2/boot1.S b/stand/pc98/boot2/boot1.S
new file mode 100644
index 0000000..5c97206
--- /dev/null
+++ b/stand/pc98/boot2/boot1.S
@@ -0,0 +1,395 @@
+/*-
+ * Copyright (c) 2008-2009 TAKAHASHI Yoshihiro
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/* Memory Locations */
+ .set STACK_OFF,0x6000 # Stack offset
+ .set LOAD_SIZE,8192 # Load size
+ .set DAUA,0x0584 # DA/UA
+ .set MEM_REL,0x700 # Relocation address
+ .set MEM_ARG,0x900 # Arguments
+ .set MEM_BUF,0x8cec # Load area
+ .set MEM_BTX,0x9000 # BTX start
+ .set MEM_JMP,0x9010 # BTX entry point
+ .set MEM_USR,0xa000 # Client start
+
+/* PC98 machine type from sys/pc98/pc98/pc98_machdep.h */
+ .set MEM_SYS, 0xa100 # System common area segment
+ .set PC98_MACHINE_TYPE, 0x0620 # PC98 machine type
+ .set EPSON_ID, 0x0624 # EPSON machine id
+
+ .set M_NEC_PC98, 0x0001
+ .set M_EPSON_PC98, 0x0002
+ .set M_NOT_H98, 0x0010
+ .set M_H98, 0x0020
+ .set M_NOTE, 0x0040
+ .set M_NORMAL, 0x1000
+ .set M_8M, 0x8000
+
+/* Partition Constants */
+ .set PRT_OFF,0x1be # Partition offset
+
+/* Misc. Constants */
+ .set SIZ_PAG,0x1000 # Page size
+ .set SIZ_SEC,0x200 # Sector size
+
+ .set NSECT,0x10
+
+ .globl start
+ .globl read
+ .globl putc
+ .code16
+
+start: jmp main
+
+boot_cyl: .org 4
+ .ascii "IPL1 "
+
+main: cld
+
+ /* Setup the stack */
+ xor %si,%si
+ mov %si,%ss
+ mov $STACK_OFF,%sp
+
+ push %cx
+
+ /* Relocate ourself to MEM_REL */
+ push %cs
+ pop %ds
+ mov %si,%es
+ mov $MEM_REL,%di
+ mov $SIZ_SEC,%cx
+ rep
+ movsb
+
+ /* Transfer PC-9801 system common area */
+ xor %ax,%ax
+ mov %ax,%si
+ mov %ax,%ds
+ mov %ax,%di
+ mov $MEM_SYS,%ax
+ mov %ax,%es
+ mov $0x0600,%cx
+ rep
+ movsb
+
+ /* Transfer EPSON machine type */
+ mov $0xfd00,%ax
+ mov %ax,%ds
+ mov (0x804),%eax
+ and $0x00ffffff,%eax
+ mov %eax,%es:(EPSON_ID)
+
+ /* Set machine type to PC98_SYSTEM_PARAMETER */
+#ifdef SET_MACHINE_TYPE
+ call set_machine_type
+#else
+ mov $M_NEC_PC98+M_NOT_H98,%eax
+ mov %eax,%es:(PC98_MACHINE_TYPE)
+#endif
+
+ /* Setup graphic screen */
+ mov $0x42,%ah /* 640x400 */
+ mov $0xc0,%ch
+ int $0x18
+ mov $0x40,%ah /* graph on */
+ int $0x18
+
+ /* Setup text screen */
+ mov $0x0a00,%ax /* 80x25 */
+ int $0x18
+ mov $0x0c,%ah /* text on */
+ int $0x18
+ mov $0x13,%ah /* cursor home */
+ xor %dx,%dx
+ int $0x18
+ mov $0x11,%ah /* cursor on */
+ int $0x18
+
+ /* Setup keyboard */
+ mov $0x03,%ah
+ int $0x18
+
+ pop %cx
+
+ /* bootstrap passes */
+ xor %edi,%edi
+ mov %di,%ds
+ mov %di,%es
+ mov %cs,%bx
+ cmp $0x1fe0,%bx
+ jz boot_fd
+ cmp $0x1fc0,%bx
+ jnz boot_hd
+ xor %cx,%cx
+ mov (DAUA),%al
+ and $0xf0,%al
+ cmp $0x30,%al
+ jz boot_fd
+ cmp $0x90,%al
+ jnz boot_hd
+boot_fd: xor %cx,%cx
+ jmp boot_load
+boot_hd: test %cx,%cx
+ jnz boot_load
+ mov %cs:(boot_cyl),%cx
+boot_load: mov %cx,MEM_ARG /* Save cylinder number */
+ mov %cx,%di
+ xor %dx,%dx
+ mov $LOAD_SIZE,%bx
+ mov $MEM_BUF,%bp
+ push %cs
+ callw read
+ jc error
+
+ /* Transfer boot2.bin */
+ mov $MEM_BTX,%bx
+ mov 0xa(%bx),%si /* BTX size */
+ add %bx,%si /* start of boot2.bin */
+ mov $MEM_USR+SIZ_PAG*2,%di
+ mov $MEM_BTX+(NSECT-1)*SIZ_SEC,%cx
+ sub %si,%cx
+ rep
+ movsb
+
+ /* Enable A20 */
+ xor %ax,%ax
+ outb %al,$0xf2
+ mov $0x02,%al
+ outb %al,$0xf6
+
+ /* Start BTX */
+ ljmp $0x0000,$MEM_JMP
+
+/*
+ * Reads sectors from the disk.
+ * Call with:
+ *
+ * %bx - bytes to read
+ * %cx - cylinder
+ * %dh - head
+ * %dl - sector
+ * %edi - lba
+ * %es:(%bp) - buffer to read data into
+ */
+read: xor %ax,%ax
+ mov %ax,%ds
+ mov $0x06,%ah
+ mov (DAUA),%al
+ mov %ax,%si
+ and $0xf0,%al
+ cmp $0x30,%al /* 1.44MB FDD */
+ jz read_fd
+ cmp $0x90,%al /* 1MB FDD */
+ jz read_fd
+ cmp $0xa0,%al /* Is SCSI device? */
+ jnz read_load
+ push %cx
+ mov %si,%cx
+ and $0x0f,%cl
+ inc %cl
+ mov (0x482),%ah
+ shr %cl,%ah /* Is SCSI HDD? */
+ pop %cx
+ jc read_load
+ and $0xff7f,%si /* SCSI MO */
+ mov %di,%cx
+ shr $16,%edi
+ mov %di,%dx
+ jmp read_load
+read_fd: or $0xd000,%si
+ or $0x0200,%cx
+ inc %dx
+read_load: mov %si,%ax
+ int $0x1b
+ lret
+
+/*
+ * Print out the error message, wait for a keypress, and then reboot
+ * the machine.
+ */
+error: push %cs
+ pop %ds
+ mov $msg_eread,%si
+ call putstr
+ xor %ax,%ax /* Get keypress */
+ int $0x18
+ xor %ax,%ax /* CPU reset */
+ outb %al,$0xf0
+halt: hlt
+ jmp halt /* Spin */
+
+/*
+ * Display a null-terminated string.
+ */
+putstr.0: push %cs
+ callw putc
+putstr: lodsb
+ test %al,%al
+ jne putstr.0
+ ret
+
+/*
+ * Display a single char.
+ */
+putc: pusha
+ xor %dx,%dx
+ mov %dx,%ds
+ mov MEM_REL+cursor-start,%di
+ mov $0xa000,%bx
+ mov %bx,%es
+ mov $(80*2),%cx
+
+ cmp $0x08,%al
+ je putc.bs
+ cmp $0x0d,%al
+ je putc.cr
+ cmp $0x0a,%al
+ je putc.lf
+ cmp $0x5c,%al /* \ */
+ jne 1f
+ mov $0xfc,%al
+1: movb $0xe1,%es:0x2000(%di)
+ stosw
+ jmp putc.scr
+putc.bs: test %di,%di
+ jz putc.move
+ dec %di
+ dec %di
+ movb $0xe1,%es:0x2000(%di)
+ movw $0x20,%es:(%di)
+ jmp putc.move
+putc.cr: mov %di,%ax
+ div %cx
+ sub %dx,%di
+ jmp putc.move
+putc.lf: add %cx,%di
+putc.scr: cmp $(80*2*25),%di /* Scroll screen */
+ jb putc.move
+ push %ds
+ mov %bx,%ds
+ mov $(80*2),%si
+ xor %di,%di
+ mov $(80*24/2),%cx
+ rep
+ movsl
+ xor %ax,%ax
+ mov $0x20,%al
+ mov $80,%cl
+ rep
+ stosw
+ pop %ds
+ mov $(80*24*2),%di
+putc.move: mov %di,MEM_REL+cursor-start /* Move cursor */
+ mov $0x13,%ah
+ mov %di,%dx
+ int $0x18
+ popa
+ lret
+
+cursor: .word 0
+
+#ifdef SET_MACHINE_TYPE
+/*
+ * Set machine type to PC98_SYSTEM_PARAMETER.
+ */
+set_machine_type:
+ xor %edx,%edx
+ mov %dx,%ds
+// mov $MEM_SYS,%ax
+// mov %ax,%es
+
+ /* Wait V-SYNC */
+vsync.1: inb $0x60,%al
+ test $0x20,%al
+ jnz vsync.1
+vsync.2: inb $0x60,%al
+ test $0x20,%al
+ jz vsync.2
+
+ /* ANK 'A' font */
+ xor %al,%al
+ outb %al,$0xa1
+ mov $0x41,%al
+ outb %al,$0xa3
+
+ /* Get 'A' font from CG window */
+ push %ds
+ mov $0xa400,%ax
+ mov %ax,%ds
+ xor %eax,%eax
+ xor %bx,%bx
+ mov $4,%cx
+font.1: add (%bx),%eax
+ add $4,%bx
+ loop font.1
+ pop %ds
+ cmp $0x6efc58fc,%eax
+ jnz m_epson
+
+m_pc98: or $M_NEC_PC98,%edx
+ mov $0x0458,%bx
+ mov (%bx),%al
+ test $0x80,%al
+ jz m_not_h98
+ or $M_H98,%edx
+ jmp 1f
+m_epson: or $M_EPSON_PC98,%edx
+m_not_h98: or $M_NOT_H98,%edx
+
+1: inb $0x42,%al
+ test $0x20,%al
+ jz 1f
+ or $M_8M,%edx
+
+1: mov $0x0400,%bx
+ mov (%bx),%al
+ test $0x80,%al
+ jz 1f
+ or $M_NOTE,%edx
+
+1: mov $PC98_MACHINE_TYPE,%bx
+ mov %edx,%es:(%bx)
+ ret
+#endif
+
+/* Messages */
+
+msg_eread: .asciz "Error\r\n"
+
+ .org PRT_OFF,0x90
+
+/* Partition table */
+
+ .fill 0x30,0x1,0x0
+ .byte 0x80, 0x00, 0x01, 0x00
+ .byte 0xa5, 0xff, 0xff, 0xff
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x50, 0xc3, 0x00, 0x00
+
+ .word 0xaa55 # Magic number
diff --git a/stand/pc98/boot2/boot2.c b/stand/pc98/boot2/boot2.c
new file mode 100644
index 0000000..b582516
--- /dev/null
+++ b/stand/pc98/boot2/boot2.c
@@ -0,0 +1,803 @@
+/*-
+ * Copyright (c) 2008-2009 TAKAHASHI Yoshihiro
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/disklabel.h>
+#include <sys/diskpc98.h>
+#include <sys/dirent.h>
+#include <sys/reboot.h>
+
+#include <machine/bootinfo.h>
+#include <machine/cpufunc.h>
+#include <machine/elf.h>
+
+#include <stdarg.h>
+
+#include <a.out.h>
+
+#include <btxv86.h>
+
+#include "boot2.h"
+#include "lib.h"
+#include "paths.h"
+#include "rbx.h"
+
+/* Define to 0 to omit serial support */
+#ifndef SERIAL
+#define SERIAL 0
+#endif
+
+#define IO_KEYBOARD 1
+#define IO_SERIAL 2
+
+#if SERIAL
+#define DO_KBD (ioctrl & IO_KEYBOARD)
+#define DO_SIO (ioctrl & IO_SERIAL)
+#else
+#define DO_KBD (1)
+#define DO_SIO (0)
+#endif
+
+#define SECOND 1 /* Circa that many ticks in a second. */
+
+#define ARGS 0x900
+#define NOPT 14
+#define NDEV 3
+
+#define DRV_DISK 0xf0
+#define DRV_UNIT 0x0f
+
+#define TYPE_AD 0
+#define TYPE_DA 1
+#define TYPE_FD 2
+
+extern uint32_t _end;
+
+static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */
+static const unsigned char flags[NOPT] = {
+ RBX_DUAL,
+ RBX_SERIAL,
+ RBX_ASKNAME,
+ RBX_CDROM,
+ RBX_CONFIG,
+ RBX_KDB,
+ RBX_GDB,
+ RBX_MUTE,
+ RBX_NOINTR,
+ RBX_PAUSE,
+ RBX_QUIET,
+ RBX_DFLTROOT,
+ RBX_SINGLE,
+ RBX_VERBOSE
+};
+
+static const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
+static const unsigned char dev_maj[NDEV] = {30, 4, 2};
+static const unsigned char dev_daua[NDEV] = {0x80, 0xa0, 0x90};
+
+static struct dsk {
+ unsigned daua;
+ unsigned type;
+ unsigned disk;
+ unsigned unit;
+ unsigned head;
+ unsigned sec;
+ uint8_t slice;
+ uint8_t part;
+ unsigned start;
+} dsk;
+static char cmd[512], cmddup[512], knamebuf[1024];
+static const char *kname;
+uint32_t opts;
+static struct bootinfo bootinfo;
+#if SERIAL
+static int comspeed = SIOSPD;
+static uint8_t ioctrl = IO_KEYBOARD;
+#endif
+
+int main(void);
+void exit(int);
+static void load(void);
+static int parse(void);
+static int dskread(void *, unsigned, unsigned);
+static void printf(const char *,...);
+static void putchar(int);
+static int drvread(void *, unsigned);
+static int keyhit(unsigned);
+static int xputc(int);
+static int xgetc(int);
+static inline int getc(int);
+
+static void memcpy(void *, const void *, int);
+static void
+memcpy(void *dst, const void *src, int len)
+{
+ const char *s = src;
+ char *d = dst;
+
+ while (len--)
+ *d++ = *s++;
+}
+
+static inline int
+strcmp(const char *s1, const char *s2)
+{
+ for (; *s1 == *s2 && *s1; s1++, s2++);
+ return (unsigned char)*s1 - (unsigned char)*s2;
+}
+
+#define UFS_SMALL_CGBASE
+#include "ufsread.c"
+
+static inline int
+xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
+{
+ if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
+ printf("Invalid %s\n", "format");
+ return -1;
+ }
+ return 0;
+}
+
+static inline void
+getstr(void)
+{
+ char *s;
+ int c;
+
+ s = cmd;
+ for (;;) {
+ switch (c = xgetc(0)) {
+ case 0:
+ break;
+ case '\177':
+ case '\b':
+ if (s > cmd) {
+ s--;
+ printf("\b \b");
+ }
+ break;
+ case '\n':
+ case '\r':
+ *s = 0;
+ return;
+ default:
+ if (s - cmd < sizeof(cmd) - 1)
+ *s++ = c;
+ putchar(c);
+ }
+ }
+}
+
+static inline void
+putc(int c)
+{
+
+ v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
+ v86.addr = PUTCORG; /* call to putc in boot1 */
+ v86.eax = c;
+ v86int();
+ v86.ctl = V86_FLAGS;
+}
+
+static inline int
+is_scsi_hd(void)
+{
+
+ if ((*(u_char *)PTOV(0x482) >> dsk.unit) & 0x01)
+ return 1;
+
+ return 0;
+}
+
+static inline void
+fix_sector_size(void)
+{
+ u_char *p;
+
+ p = (u_char *)PTOV(0x460 + dsk.unit * 4); /* SCSI equipment parameter */
+
+ if ((p[0] & 0x1f) == 7) { /* SCSI MO */
+ if (!(p[3] & 0x30)) { /* 256B / sector */
+ p[3] |= 0x10; /* forced set 512B / sector */
+ p[3 + 0xa1000] |= 0x10;
+ }
+ }
+}
+
+static inline uint32_t
+get_diskinfo(void)
+{
+
+ if (dsk.disk == 0x30) { /* 1440KB FD */
+ /* 80 cylinders, 2 heads, 18 sectors */
+ return (80 << 16) | (2 << 8) | 18;
+ } else if (dsk.disk == 0x90) { /* 1200KB FD */
+ /* 80 cylinders, 2 heads, 15 sectors */
+ return (80 << 16) | (2 << 8) | 15;
+ } else if (dsk.disk == 0x80 || is_scsi_hd()) { /* IDE or SCSI HDD */
+ v86.addr = 0x1b;
+ v86.eax = 0x8400 | dsk.daua;
+ v86int();
+ return (v86.ecx << 16) | v86.edx;
+ }
+
+ /* SCSI MO or CD */
+ fix_sector_size(); /* SCSI MO */
+
+ /* other SCSI devices */
+ return (65535 << 16) | (8 << 8) | 32;
+}
+
+static void
+set_dsk(void)
+{
+ uint32_t di;
+
+ di = get_diskinfo();
+
+ dsk.head = (di >> 8) & 0xff;
+ dsk.sec = di & 0xff;
+ dsk.start = 0;
+}
+
+#ifdef GET_BIOSGEOM
+static uint32_t
+bd_getbigeom(int bunit)
+{
+ int hds = 0;
+ int unit = 0x80; /* IDE HDD */
+ u_int addr = 0x55d;
+
+ while (unit < 0xa7) {
+ if (*(u_char *)PTOV(addr) & (1 << (unit & 0x0f)))
+ if (hds++ == bunit)
+ break;
+
+ if (unit >= 0xA0) {
+ int media = ((unsigned *)PTOV(0x460))[unit & 0x0F] & 0x1F;
+
+ if (media == 7 && hds++ == bunit) /* SCSI MO */
+ return(0xFFFE0820); /* C:65535 H:8 S:32 */
+ }
+ if (++unit == 0x84) {
+ unit = 0xA0; /* SCSI HDD */
+ addr = 0x482;
+ }
+ }
+ if (unit == 0xa7)
+ return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */
+ v86.addr = 0x1b;
+ v86.eax = 0x8400 | unit;
+ v86int();
+ if (V86_CY(v86.efl))
+ return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */
+ return ((v86.ecx & 0xffff) << 16) | (v86.edx & 0xffff);
+}
+#endif
+
+static int
+check_slice(void)
+{
+ struct pc98_partition *dp;
+ char *sec;
+ unsigned i, cyl;
+
+ sec = dmadat->secbuf;
+ cyl = *(uint16_t *)PTOV(ARGS);
+ set_dsk();
+
+ if (dsk.type == TYPE_FD)
+ return (WHOLE_DISK_SLICE);
+ if (drvread(sec, PC98_BBSECTOR))
+ return (WHOLE_DISK_SLICE); /* Read error */
+ dp = (void *)(sec + PC98_PARTOFF);
+ for (i = 0; i < PC98_NPARTS; i++) {
+ if (dp[i].dp_mid == DOSMID_386BSD) {
+ if (dp[i].dp_scyl <= cyl && cyl <= dp[i].dp_ecyl)
+ return (BASE_SLICE + i);
+ }
+ }
+
+ return (WHOLE_DISK_SLICE);
+}
+
+int
+main(void)
+{
+#ifdef GET_BIOSGEOM
+ int i;
+#endif
+ uint8_t autoboot;
+ ufs_ino_t ino;
+ size_t nbyte;
+
+ dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
+ v86.ctl = V86_FLAGS;
+ v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
+ dsk.daua = *(uint8_t *)PTOV(0x584);
+ dsk.disk = dsk.daua & DRV_DISK;
+ dsk.unit = dsk.daua & DRV_UNIT;
+ if (dsk.disk == 0x80)
+ dsk.type = TYPE_AD;
+ else if (dsk.disk == 0xa0)
+ dsk.type = TYPE_DA;
+ else /* if (dsk.disk == 0x30 || dsk.disk == 0x90) */
+ dsk.type = TYPE_FD;
+ dsk.slice = check_slice();
+#ifdef GET_BIOSGEOM
+ for (i = 0; i < N_BIOS_GEOM; i++)
+ bootinfo.bi_bios_geom[i] = bd_getbigeom(i);
+#endif
+ bootinfo.bi_version = BOOTINFO_VERSION;
+ bootinfo.bi_size = sizeof(bootinfo);
+
+ /* Process configuration file */
+
+ autoboot = 1;
+
+ if ((ino = lookup(PATH_CONFIG)) ||
+ (ino = lookup(PATH_DOTCONFIG))) {
+ nbyte = fsread(ino, cmd, sizeof(cmd) - 1);
+ cmd[nbyte] = '\0';
+ }
+
+ if (*cmd) {
+ memcpy(cmddup, cmd, sizeof(cmd));
+ if (parse())
+ autoboot = 0;
+ if (!OPT_CHECK(RBX_QUIET))
+ printf("%s: %s", PATH_CONFIG, cmddup);
+ /* Do not process this command twice */
+ *cmd = 0;
+ }
+
+ /*
+ * Try to exec stage 3 boot loader. If interrupted by a keypress,
+ * or in case of failure, try to load a kernel directly instead.
+ */
+
+ if (!kname) {
+ kname = PATH_LOADER;
+ if (autoboot && !keyhit(3*SECOND)) {
+ load();
+ kname = PATH_KERNEL;
+ }
+ }
+
+ /* Present the user with the boot2 prompt. */
+
+ for (;;) {
+ if (!autoboot || !OPT_CHECK(RBX_QUIET))
+ printf("\nFreeBSD/pc98 boot\n"
+ "Default: %u:%s(%u,%c)%s\n"
+ "boot: ",
+ dsk.unit, dev_nm[dsk.type], dsk.unit,
+ 'a' + dsk.part, kname);
+ if (DO_SIO)
+ sio_flush();
+ if (!autoboot || keyhit(3*SECOND))
+ getstr();
+ else if (!autoboot || !OPT_CHECK(RBX_QUIET))
+ putchar('\n');
+ autoboot = 0;
+ if (parse())
+ putchar('\a');
+ else
+ load();
+ }
+}
+
+/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
+void
+exit(int x)
+{
+}
+
+static void
+load(void)
+{
+ union {
+ struct exec ex;
+ Elf32_Ehdr eh;
+ } hdr;
+ static Elf32_Phdr ep[2];
+ static Elf32_Shdr es[2];
+ caddr_t p;
+ ufs_ino_t ino;
+ uint32_t addr;
+ int k;
+ uint8_t i, j;
+
+ if (!(ino = lookup(kname))) {
+ if (!ls)
+ printf("No %s\n", kname);
+ return;
+ }
+ if (xfsread(ino, &hdr, sizeof(hdr)))
+ return;
+
+ if (N_GETMAGIC(hdr.ex) == ZMAGIC) {
+ addr = hdr.ex.a_entry & 0xffffff;
+ p = PTOV(addr);
+ fs_off = PAGE_SIZE;
+ if (xfsread(ino, p, hdr.ex.a_text))
+ return;
+ p += roundup2(hdr.ex.a_text, PAGE_SIZE);
+ if (xfsread(ino, p, hdr.ex.a_data))
+ return;
+ } else if (IS_ELF(hdr.eh)) {
+ fs_off = hdr.eh.e_phoff;
+ for (j = k = 0; k < hdr.eh.e_phnum && j < 2; k++) {
+ if (xfsread(ino, ep + j, sizeof(ep[0])))
+ return;
+ if (ep[j].p_type == PT_LOAD)
+ j++;
+ }
+ for (i = 0; i < 2; i++) {
+ p = PTOV(ep[i].p_paddr & 0xffffff);
+ fs_off = ep[i].p_offset;
+ if (xfsread(ino, p, ep[i].p_filesz))
+ return;
+ }
+ p += roundup2(ep[1].p_memsz, PAGE_SIZE);
+ bootinfo.bi_symtab = VTOP(p);
+ if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
+ fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
+ (hdr.eh.e_shstrndx + 1);
+ if (xfsread(ino, &es, sizeof(es)))
+ return;
+ for (i = 0; i < 2; i++) {
+ *(Elf32_Word *)p = es[i].sh_size;
+ p += sizeof(es[i].sh_size);
+ fs_off = es[i].sh_offset;
+ if (xfsread(ino, p, es[i].sh_size))
+ return;
+ p += es[i].sh_size;
+ }
+ }
+ addr = hdr.eh.e_entry & 0xffffff;
+ bootinfo.bi_esymtab = VTOP(p);
+ } else {
+ printf("Invalid %s\n", "format");
+ return;
+ }
+
+ bootinfo.bi_kernelname = VTOP(kname);
+ bootinfo.bi_bios_dev = dsk.daua;
+ __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
+ MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part),
+ 0, 0, 0, VTOP(&bootinfo));
+}
+
+static int
+parse()
+{
+ char *arg = cmd;
+ char *ep, *p, *q;
+ const char *cp;
+ unsigned int drv;
+ int c, i, j;
+ size_t k;
+
+ while ((c = *arg++)) {
+ if (c == ' ' || c == '\t' || c == '\n')
+ continue;
+ for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
+ ep = p;
+ if (*p)
+ *p++ = 0;
+ if (c == '-') {
+ while ((c = *arg++)) {
+ if (c == 'P') {
+ if (*(uint8_t *)PTOV(0x481) & 0x48) {
+ cp = "yes";
+ } else {
+ opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL);
+ cp = "no";
+ }
+ printf("Keyboard: %s\n", cp);
+ continue;
+#if SERIAL
+ } else if (c == 'S') {
+ j = 0;
+ while ((unsigned int)(i = *arg++ - '0') <= 9)
+ j = j * 10 + i;
+ if (j > 0 && i == -'0') {
+ comspeed = j;
+ break;
+ }
+ /* Fall through to error below ('S' not in optstr[]). */
+#endif
+ }
+ for (i = 0; c != optstr[i]; i++)
+ if (i == NOPT - 1)
+ return -1;
+ opts ^= OPT_SET(flags[i]);
+ }
+#if SERIAL
+ ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
+ OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
+ if (DO_SIO) {
+ if (sio_init(115200 / comspeed) != 0)
+ ioctrl &= ~IO_SERIAL;
+ }
+#endif
+ } else {
+ for (q = arg--; *q && *q != '('; q++);
+ if (*q) {
+ drv = -1;
+ if (arg[1] == ':') {
+ drv = *arg - '0';
+ if (drv > 9)
+ return (-1);
+ arg += 2;
+ }
+ if (q - arg != 2)
+ return -1;
+ for (i = 0; arg[0] != dev_nm[i][0] ||
+ arg[1] != dev_nm[i][1]; i++)
+ if (i == NDEV - 1)
+ return -1;
+ dsk.type = i;
+ arg += 3;
+ dsk.unit = *arg - '0';
+ if (arg[1] != ',' || dsk.unit > 9)
+ return -1;
+ arg += 2;
+ dsk.slice = WHOLE_DISK_SLICE;
+ if (arg[1] == ',') {
+ dsk.slice = *arg - '0' + 1;
+ if (dsk.slice > PC98_NPARTS + 1)
+ return -1;
+ arg += 2;
+ }
+ if (arg[1] != ')')
+ return -1;
+ dsk.part = *arg - 'a';
+ if (dsk.part > 7)
+ return (-1);
+ arg += 2;
+ if (drv == -1)
+ drv = dsk.unit;
+ dsk.disk = dev_daua[dsk.type];
+ dsk.daua = dsk.disk | dsk.unit;
+ dsk_meta = 0;
+ }
+ k = ep - arg;
+ if (k > 0) {
+ if (k >= sizeof(knamebuf))
+ return -1;
+ memcpy(knamebuf, arg, k + 1);
+ kname = knamebuf;
+ }
+ }
+ arg = p;
+ }
+ return 0;
+}
+
+static int
+dskread(void *buf, unsigned lba, unsigned nblk)
+{
+ struct pc98_partition *dp;
+ struct disklabel *d;
+ char *sec;
+ unsigned i;
+ uint8_t sl;
+ u_char *p;
+ const char *reason;
+
+ if (!dsk_meta) {
+ sec = dmadat->secbuf;
+ set_dsk();
+ if (dsk.type == TYPE_FD)
+ goto unsliced;
+ if (drvread(sec, PC98_BBSECTOR))
+ return -1;
+ dp = (void *)(sec + PC98_PARTOFF);
+ sl = dsk.slice;
+ if (sl < BASE_SLICE) {
+ for (i = 0; i < PC98_NPARTS; i++)
+ if (dp[i].dp_mid == DOSMID_386BSD) {
+ sl = BASE_SLICE + i;
+ break;
+ }
+ dsk.slice = sl;
+ }
+ if (sl != WHOLE_DISK_SLICE) {
+ dp += sl - BASE_SLICE;
+ if (dp->dp_mid != DOSMID_386BSD) {
+ reason = "slice";
+ goto error;
+ }
+ dsk.start = dp->dp_scyl * dsk.head * dsk.sec +
+ dp->dp_shd * dsk.sec + dp->dp_ssect;
+ }
+ if (drvread(sec, dsk.start + LABELSECTOR))
+ return -1;
+ d = (void *)(sec + LABELOFFSET);
+ if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
+ if (dsk.part != RAW_PART) {
+ reason = "label";
+ goto error;
+ }
+ } else {
+ if (dsk.part >= d->d_npartitions ||
+ !d->d_partitions[dsk.part].p_size) {
+ reason = "partition";
+ goto error;
+ }
+ dsk.start += d->d_partitions[dsk.part].p_offset;
+ dsk.start -= d->d_partitions[RAW_PART].p_offset;
+ }
+ unsliced: ;
+ }
+ for (p = buf; nblk; p += 512, lba++, nblk--) {
+ if ((i = drvread(p, dsk.start + lba)))
+ return i;
+ }
+ return 0;
+error:
+ printf("Invalid %s\n", reason);
+ return -1;
+}
+
+static void
+printf(const char *fmt,...)
+{
+ va_list ap;
+ static char buf[10];
+ char *s;
+ unsigned u;
+ int c;
+
+ va_start(ap, fmt);
+ while ((c = *fmt++)) {
+ if (c == '%') {
+ c = *fmt++;
+ switch (c) {
+ case 'c':
+ putchar(va_arg(ap, int));
+ continue;
+ case 's':
+ for (s = va_arg(ap, char *); *s; s++)
+ putchar(*s);
+ continue;
+ case 'u':
+ u = va_arg(ap, unsigned);
+ s = buf;
+ do
+ *s++ = '0' + u % 10U;
+ while (u /= 10U);
+ while (--s >= buf)
+ putchar(*s);
+ continue;
+ }
+ }
+ putchar(c);
+ }
+ va_end(ap);
+ return;
+}
+
+static void
+putchar(int c)
+{
+ if (c == '\n')
+ xputc('\r');
+ xputc(c);
+}
+
+static int
+drvread(void *buf, unsigned lba)
+{
+ static unsigned c = 0x2d5c7c2f;
+ unsigned bpc, x, cyl, head, sec;
+
+ bpc = dsk.sec * dsk.head;
+ cyl = lba / bpc;
+ x = lba % bpc;
+ head = x / dsk.sec;
+ sec = x % dsk.sec;
+
+ if (!OPT_CHECK(RBX_QUIET)) {
+ xputc(c = c << 8 | c >> 24);
+ xputc('\b');
+ }
+ v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
+ v86.addr = READORG; /* call to read in boot1 */
+ v86.ecx = cyl;
+ v86.edx = (head << 8) | sec;
+ v86.edi = lba;
+ v86.ebx = 512;
+ v86.es = VTOPSEG(buf);
+ v86.ebp = VTOPOFF(buf);
+ v86int();
+ v86.ctl = V86_FLAGS;
+ if (V86_CY(v86.efl)) {
+ printf("error %u c/h/s %u/%u/%u lba %u\n", v86.eax >> 8 & 0xff,
+ cyl, head, sec, lba);
+ return -1;
+ }
+ return 0;
+}
+
+static inline void
+delay(void)
+{
+ int i;
+
+ i = 800;
+ do {
+ outb(0x5f, 0); /* about 600ns */
+ } while (--i >= 0);
+}
+
+static int
+keyhit(unsigned sec)
+{
+ unsigned i;
+
+ if (OPT_CHECK(RBX_NOINTR))
+ return 0;
+ for (i = 0; i < sec * 1000; i++) {
+ if (xgetc(1))
+ return 1;
+ delay();
+ }
+ return 0;
+}
+
+static int
+xputc(int c)
+{
+ if (DO_KBD)
+ putc(c);
+ if (DO_SIO)
+ sio_putc(c);
+ return c;
+}
+
+static int
+getc(int fn)
+{
+ v86.addr = 0x18;
+ v86.eax = fn << 8;
+ v86int();
+ if (fn)
+ return (v86.ebx >> 8) & 0x01;
+ else
+ return v86.eax & 0xff;
+}
+
+static int
+xgetc(int fn)
+{
+ if (OPT_CHECK(RBX_NOINTR))
+ return 0;
+ for (;;) {
+ if (DO_KBD && getc(1))
+ return fn ? 1 : getc(0);
+ if (DO_SIO && sio_ischar())
+ return fn ? 1 : sio_getc();
+ if (fn)
+ return 0;
+ }
+}
diff --git a/stand/pc98/btx/Makefile b/stand/pc98/btx/Makefile
new file mode 100644
index 0000000..39f78ed
--- /dev/null
+++ b/stand/pc98/btx/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SUBDIR= btx btxldr lib
+
+.include <bsd.subdir.mk>
diff --git a/stand/pc98/btx/Makefile.inc b/stand/pc98/btx/Makefile.inc
new file mode 100644
index 0000000..265f86d
--- /dev/null
+++ b/stand/pc98/btx/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include "../Makefile.inc"
diff --git a/stand/pc98/btx/btx/Makefile b/stand/pc98/btx/btx/Makefile
new file mode 100644
index 0000000..2755460
--- /dev/null
+++ b/stand/pc98/btx/btx/Makefile
@@ -0,0 +1,33 @@
+# $FreeBSD$
+
+PROG= btx
+INTERNALPROG=
+MAN=
+SRCS= btx.S
+
+.if defined(BOOT_BTX_NOHANG)
+BOOT_BTX_FLAGS=0x1
+.else
+BOOT_BTX_FLAGS=0x0
+.endif
+
+CFLAGS+=-DBTX_FLAGS=${BOOT_BTX_FLAGS}
+CFLAGS+=-I${.CURDIR}/../../../i386/common
+
+.if defined(BTX_SERIAL)
+BOOT_COMCONSOLE_PORT?= 0x238
+BOOT_COMCONSOLE_SPEED?= 9600
+B2SIOFMT?= 0x3
+
+CFLAGS+=-DBTX_SERIAL -DSIOPRT=${BOOT_COMCONSOLE_PORT} \
+ -DSIOFMT=${B2SIOFMT} -DSIOSPD=${BOOT_COMCONSOLE_SPEED}
+.endif
+
+ORG= 0x9000
+
+LDFLAGS=${LDFLAGS_BIN}
+
+.include <bsd.prog.mk>
+
+# XXX: clang integrated-as doesn't grok .codeNN directives yet
+CFLAGS.btx.S= ${CLANG_NO_IAS}
diff --git a/stand/pc98/btx/btx/btx.S b/stand/pc98/btx/btx/btx.S
new file mode 100644
index 0000000..e8710d3
--- /dev/null
+++ b/stand/pc98/btx/btx/btx.S
@@ -0,0 +1,1104 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <bootargs.h>
+
+/*
+ * Memory layout.
+ */
+ .set MEM_BTX,0x1000 # Start of BTX memory
+ .set MEM_ESP0,0x1800 # Supervisor stack
+ .set MEM_BUF,0x1800 # Scratch buffer
+ .set MEM_ESPR,0x5e00 # Real mode stack
+ .set MEM_IDT,0x5e00 # IDT
+ .set MEM_TSS,0x5f98 # TSS
+ .set MEM_MAP,0x6000 # I/O bit map
+ .set MEM_TSS_END,0x7fff # End of TSS
+ .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
+/*
+ * Fields in %eflags.
+ */
+ .set PSL_RESERVED_DEFAULT,0x00000002
+ .set PSL_T,0x00000100 # Trap flag
+ .set PSL_I,0x00000200 # Interrupt enable flag
+ .set PSL_VM,0x00020000 # Virtual 8086 mode flag
+ .set PSL_AC,0x00040000 # Alignment check flag
+/*
+ * 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_MAP,0x66 # I/O bit map base
+/*
+ * System calls.
+ */
+ .set SYS_EXIT,0x0 # Exit
+ .set SYS_EXEC,0x1 # Exec
+/*
+ * 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
+/*
+ * V86 control flags.
+ */
+ .set V86F_ADDR,0x10000 # Segment:offset address
+ .set V86F_CALLF,0x20000 # Emulate far call
+ .set V86F_FLAGS,0x40000 # Return flags
+/*
+ * 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.
+ */
+ .set SCR_MAT,0xe1 # Mode/attribute
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+/*
+ * BIOS Data Area locations.
+ */
+ .set BDA_MEM,0x501 # Free memory
+ .set BDA_POS,0x53e # Cursor position
+/*
+ * Derivations, for brevity.
+ */
+ .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0
+ .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base
+ .set _TSSLM,MEM_TSS_END-MEM_TSS # TSS limit
+ .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit
+/*
+ * Code segment.
+ */
+ .globl start
+ .code16
+start: # Start of code
+/*
+ * BTX header.
+ */
+btx_hdr: .byte 0xeb # Machine ID
+ .byte 0xe # Header size
+ .ascii "BTX" # Magic
+ .byte 0x1 # Major version
+ .byte 0x2 # Minor version
+ .byte BTX_FLAGS # Flags
+ .word PAG_CNT-MEM_ORG>>0xc # Paging control
+ .word break-start # Text size
+ .long 0x0 # Entry address
+/*
+ * Initialization routine.
+ */
+init: cli # Disable interrupts
+ xor %ax,%ax # Zero/segment
+ mov %ax,%ss # Set up
+ mov $MEM_ESP0,%sp # stack
+ mov %ax,%es # Address
+ mov %ax,%ds # data
+ pushl $0x2 # Clear
+ popfl # flags
+/*
+ * Initialize memory.
+ */
+ mov $MEM_IDT,%di # Memory to initialize
+ mov $(MEM_ORG-MEM_IDT)/2,%cx # Words to zero
+ rep # Zero-fill
+ stosw # memory
+/*
+ * Update real mode IDT for reflecting hardware interrupts.
+ */
+ mov $intr20,%bx # Address first handler
+ mov $0x10,%cx # Number of handlers
+ mov $0x20*4,%di # First real mode IDT entry
+init.0: mov %bx,(%di) # Store IP
+ inc %di # Address next
+ inc %di # entry
+ stosw # Store CS
+ add $4,%bx # Next handler
+ loop init.0 # Next IRQ
+/*
+ * Create IDT.
+ */
+ mov $MEM_IDT,%di
+ mov $idtctl,%si # Control string
+init.1: lodsb # Get entry
+ cbw # count
+ xchg %ax,%cx # as word
+ jcxz init.4 # If done
+ lodsb # Get segment
+ xchg %ax,%dx # P:DPL:type
+ lodsw # Get control
+ xchg %ax,%bx # set
+ lodsw # Get handler offset
+ mov $SEL_SCODE,%dh # Segment selector
+init.2: shr %bx # Handle this int?
+ jnc init.3 # No
+ mov %ax,(%di) # Set handler offset
+ mov %dh,0x2(%di) # and selector
+ mov %dl,0x5(%di) # Set P:DPL:type
+ add $0x4,%ax # Next handler
+init.3: lea 0x8(%di),%di # Next entry
+ loop init.2 # Till set done
+ jmp init.1 # Continue
+/*
+ * Initialize TSS.
+ */
+init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0
+ movb $SEL_SDATA,TSS_SS0(%di) # Set SS0
+ movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base
+/*
+ * Bring up the system.
+ */
+ mov $0x2820,%bx # Set protected mode
+ callw setpic # IRQ offsets
+ lidt idtdesc # Set IDT
+ lgdt gdtdesc # Set GDT
+ mov %cr0,%eax # Switch to protected
+ inc %ax # mode
+ mov %eax,%cr0 #
+ ljmp $SEL_SCODE,$init.8 # To 32-bit code
+ .code32
+init.8: xorl %ecx,%ecx # Zero
+ movb $SEL_SDATA,%cl # To 32-bit
+ movw %cx,%ss # stack
+/*
+ * Launch user task.
+ */
+ movb $SEL_TSS,%cl # Set task
+ ltr %cx # register
+ movl $MEM_USR,%edx # User base address
+ movzwl %ss:BDA_MEM,%eax # Get free memory
+ andl $0x7,%eax
+ incl %eax
+ shll $0x11,%eax # To bytes
+ subl $ARGSPACE,%eax # Less arg space
+ subl %edx,%eax # Less base
+ movb $SEL_UDATA,%cl # User data selector
+ pushl %ecx # Set SS
+ pushl %eax # Set ESP
+ push $0x202 # Set flags (IF set)
+ push $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: push $0x0 # general
+ loop init.9 # registers
+#ifdef BTX_SERIAL
+ call sio_init # setup the serial console
+#endif
+ 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
+/*
+ * Restore the GDT in case we caught a kernel trap.
+ */
+ lgdt %cs:gdtdesc # Set GDT
+/*
+ * To 16 bits.
+ */
+ ljmpw $SEL_RCODE,$exit.1 # Reload CS
+ .code16
+exit.1: mov $SEL_RDATA,%cl # 16-bit selector
+ mov %cx,%ss # Reload SS
+ mov %cx,%ds # Load
+ mov %cx,%es # remaining
+ mov %cx,%fs # segment
+ mov %cx,%gs # registers
+/*
+ * To real-address mode.
+ */
+ dec %ax # Switch to
+ mov %eax,%cr0 # real mode
+ ljmp $0x0,$exit.2 # Reload CS
+exit.2: xor %ax,%ax # Real mode segment
+ mov %ax,%ss # Reload SS
+ mov %ax,%ds # Address data
+ mov $0x1008,%bx # Set real mode
+ callw setpic # IRQ offsets
+ lidt ivtdesc # Set IVT
+/*
+ * Reboot or await reset.
+ */
+ sti # Enable interrupts
+ testb $0x1,btx_hdr+0x7 # Reboot?
+exit.3: jz exit.3 # No
+ movb $0xa0,%al
+ outb %al,$0x35
+ movb $0x00,%al
+ outb %al,$0xf0 # reboot the machine
+exit.4: jmp exit.4
+/*
+ * Set IRQ offsets by reprogramming 8259A PICs.
+ */
+setpic: in $0x02,%al # Save master
+ push %ax # IMR
+ in $0x0a,%al # Save slave
+ push %ax # 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
+ pop %ax # Restore slave
+ outb %al,$0x0a # IMR
+ pop %ax # Restore master
+ outb %al,$0x02 # IMR
+ retw # To caller
+ .code32
+/*
+ * Exception jump table.
+ */
+intx00: push $0x0 # Int 0x0: #DE
+ jmp ex_noc # Divide error
+ push $0x1 # Int 0x1: #DB
+ jmp ex_noc # Debug
+ push $0x3 # Int 0x3: #BP
+ jmp ex_noc # Breakpoint
+ push $0x4 # Int 0x4: #OF
+ jmp ex_noc # Overflow
+ push $0x5 # Int 0x5: #BR
+ jmp ex_noc # BOUND range exceeded
+ push $0x6 # Int 0x6: #UD
+ jmp ex_noc # Invalid opcode
+ push $0x7 # Int 0x7: #NM
+ jmp ex_noc # Device not available
+ push $0x8 # Int 0x8: #DF
+ jmp except # Double fault
+ push $0xa # Int 0xa: #TS
+ jmp except # Invalid TSS
+ push $0xb # Int 0xb: #NP
+ jmp except # Segment not present
+ push $0xc # Int 0xc: #SS
+ jmp except # Stack segment fault
+ push $0xd # Int 0xd: #GP
+ jmp except # General protection
+ push $0xe # Int 0xe: #PF
+ jmp except # Page fault
+intx10: push $0x10 # Int 0x10: #MF
+ jmp ex_noc # Floating-point error
+/*
+ * 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
+ pushl %gs # Set GS
+ pushl %fs # Set FS
+ pushl %ds # Set DS
+ pushl %es # Set ES
+ cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode?
+ jne except.1 # No
+ pushl %ss # Set SS
+ jmp except.2 # Join common code
+except.1: pushl 0x50(%esp,1) # Set SS
+except.2: pushl 0x50(%esp,1) # Set ESP
+ push $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
+ 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
+ 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
+ cmpb $0x1,(%esp,1) # Debug?
+ jne except.2a # No
+ testl $PSL_T,0x10(%esp,1) # Trap flag set?
+ jnz except.3 # Yes
+except.2a: jmp exit # Exit
+except.3: leal 0x8(%esp,1),%esp # Discard err, int no
+ iret # From interrupt
+
+/*
+ * Reboot the machine by setting the reboot flag and exiting
+ */
+reboot: orb $0x1,btx_hdr+0x7 # Set the reboot flag
+ jmp exit # Terminate BTX and reboot
+
+/*
+ * Protected Mode Hardware interrupt jump table.
+ */
+intx20: push $0x8 # Int 0x20: IRQ0
+ jmp int_hw # V86 int 0x8
+ push $0x9 # Int 0x21: IRQ1
+ jmp int_hw # V86 int 0x9
+ push $0xa # Int 0x22: IRQ2
+ jmp int_hw # V86 int 0xa
+ push $0xb # Int 0x23: IRQ3
+ jmp int_hw # V86 int 0xb
+ push $0xc # Int 0x24: IRQ4
+ jmp int_hw # V86 int 0xc
+ push $0xd # Int 0x25: IRQ5
+ jmp int_hw # V86 int 0xd
+ push $0xe # Int 0x26: IRQ6
+ jmp int_hw # V86 int 0xe
+ push $0xf # Int 0x27: IRQ7
+ jmp int_hw # V86 int 0xf
+ push $0x10 # Int 0x28: IRQ8
+ jmp int_hw # V86 int 0x10
+ push $0x11 # Int 0x29: IRQ9
+ jmp int_hw # V86 int 0x11
+ push $0x12 # Int 0x2a: IRQ10
+ jmp int_hw # V86 int 0x12
+ push $0x13 # Int 0x2b: IRQ11
+ jmp int_hw # V86 int 0x13
+ push $0x14 # Int 0x2c: IRQ12
+ jmp int_hw # V86 int 0x14
+ push $0x15 # Int 0x2d: IRQ13
+ jmp int_hw # V86 int 0x15
+ push $0x16 # Int 0x2e: IRQ14
+ jmp int_hw # V86 int 0x16
+ push $0x17 # Int 0x2f: IRQ15
+ jmp int_hw # V86 int 0x17
+
+/*
+ * Invoke real mode interrupt/function call from user mode with arguments.
+ */
+intx31: pushl $-1 # Dummy int no for btx_v86
+/*
+ * Invoke real mode interrupt/function call from protected mode.
+ *
+ * We place a trampoline on the user stack that will return to rret_tramp
+ * which will reenter protected mode and then finally return to the user
+ * client.
+ *
+ * Kernel frame %esi points to: Real mode stack frame at MEM_ESPR:
+ *
+ * -0x00 user %ss -0x04 kernel %esp (with full frame)
+ * -0x04 user %esp -0x08 btx_v86 pointer
+ * -0x08 user %eflags -0x0c flags (only used if interrupt)
+ * -0x0c user %cs -0x10 real mode CS:IP return trampoline
+ * -0x10 user %eip -0x12 real mode flags
+ * -0x14 int no -0x16 real mode CS:IP (target)
+ * -0x18 %eax
+ * -0x1c %ecx
+ * -0x20 %edx
+ * -0x24 %ebx
+ * -0x28 %esp
+ * -0x2c %ebp
+ * -0x30 %esi
+ * -0x34 %edi
+ * -0x38 %gs
+ * -0x3c %fs
+ * -0x40 %ds
+ * -0x44 %es
+ * -0x48 zero %eax (hardware int only)
+ * -0x4c zero %ecx (hardware int only)
+ * -0x50 zero %edx (hardware int only)
+ * -0x54 zero %ebx (hardware int only)
+ * -0x58 zero %esp (hardware int only)
+ * -0x5c zero %ebp (hardware int only)
+ * -0x60 zero %esi (hardware int only)
+ * -0x64 zero %edi (hardware int only)
+ * -0x68 zero %gs (hardware int only)
+ * -0x6c zero %fs (hardware int only)
+ * -0x70 zero %ds (hardware int only)
+ * -0x74 zero %es (hardware int only)
+ */
+int_hw: cld # String ops inc
+ pusha # Save gp regs
+ pushl %gs # Save
+ pushl %fs # seg
+ pushl %ds # regs
+ pushl %es
+ push $SEL_SDATA # Set up
+ popl %ds # to
+ pushl %ds # address
+ popl %es # data
+ leal 0x44(%esp,1),%esi # Base of frame
+ movl %esp,MEM_ESPR-0x04 # Save kernel stack pointer
+ movl -0x14(%esi),%eax # Get Int no
+ cmpl $-1,%eax # Hardware interrupt?
+ jne intusr.1 # Yes
+/*
+ * v86 calls save the btx_v86 pointer on the real mode stack and read
+ * the address and flags from the btx_v86 structure. For interrupt
+ * handler invocations (VM86 INTx requests), disable interrupts,
+ * tracing, and alignment checking while the handler runs.
+ */
+ movl $MEM_USR,%ebx # User base
+ movl %ebx,%edx # address
+ addl -0x4(%esi),%ebx # User ESP
+ movl (%ebx),%ebp # btx_v86 pointer
+ addl %ebp,%edx # Flatten btx_v86 ptr
+ movl %edx,MEM_ESPR-0x08 # Save btx_v86 ptr
+ movl V86_ADDR(%edx),%eax # Get int no/address
+ movl V86_CTL(%edx),%edx # Get control flags
+ movl -0x08(%esi),%ebx # Save user flags in %ebx
+ testl $V86F_ADDR,%edx # Segment:offset?
+ jnz intusr.4 # Yes
+ andl $~(PSL_I|PSL_T|PSL_AC),%ebx # Disable interrupts, tracing,
+ # and alignment checking for
+ # interrupt handler
+ jmp intusr.3 # Skip hardware interrupt
+/*
+ * Hardware interrupts store a NULL btx_v86 pointer and use the
+ * address (interrupt number) from the stack with empty flags. Also,
+ * push a dummy frame of zeros onto the stack for all the general
+ * purpose and segment registers and clear %eflags. This gives the
+ * hardware interrupt handler a clean slate.
+ */
+intusr.1: xorl %edx,%edx # Control flags
+ movl %edx,MEM_ESPR-0x08 # NULL btx_v86 ptr
+ movl $12,%ecx # Frame is 12 dwords
+intusr.2: pushl $0x0 # Fill frame
+ loop intusr.2 # with zeros
+ movl $PSL_RESERVED_DEFAULT,%ebx # Set clean %eflags
+/*
+ * Look up real mode IDT entry for hardware interrupts and VM86 INTx
+ * requests.
+ */
+intusr.3: shll $0x2,%eax # Scale
+ movl (%eax),%eax # Load int vector
+ jmp intusr.5 # Skip CALLF test
+/*
+ * Panic if V86F_CALLF isn't set with V86F_ADDR.
+ */
+intusr.4: testl $V86F_CALLF,%edx # Far call?
+ jnz intusr.5 # Ok
+ movl %edx,0x30(%esp,1) # Place VM86 flags in int no
+ movl $badvm86,%esi # Display bad
+ call putstr # VM86 call
+ popl %es # Restore
+ popl %ds # seg
+ popl %fs # regs
+ popl %gs
+ popal # Restore gp regs
+ jmp ex_noc # Panic
+/*
+ * %eax now holds the segment:offset of the function.
+ * %ebx now holds the %eflags to pass to real mode.
+ * %edx now holds the V86F_* flags.
+ */
+intusr.5: movw %bx,MEM_ESPR-0x12 # Pass user flags to real mode
+ # target
+/*
+ * If this is a v86 call, copy the seg regs out of the btx_v86 structure.
+ */
+ movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr
+ jecxz intusr.6 # Skip for hardware ints
+ leal -0x44(%esi),%edi # %edi => kernel stack seg regs
+ pushl %esi # Save
+ leal V86_ES(%ecx),%esi # %esi => btx_v86 seg regs
+ movl $4,%ecx # Copy seg regs
+ rep # from btx_v86
+ movsl # to kernel stack
+ popl %esi # Restore
+intusr.6: movl -0x08(%esi),%ebx # Copy user flags to real
+ movl %ebx,MEM_ESPR-0x0c # mode return trampoline
+ movl $rret_tramp,%ebx # Set return trampoline
+ movl %ebx,MEM_ESPR-0x10 # CS:IP
+ movl %eax,MEM_ESPR-0x16 # Real mode target CS:IP
+ ljmpw $SEL_RCODE,$intusr.7 # Change to 16-bit segment
+ .code16
+intusr.7: movl %cr0,%eax # Leave
+ dec %al # protected
+ movl %eax,%cr0 # mode
+ ljmpw $0x0,$intusr.8
+intusr.8: xorw %ax,%ax # Reset %ds
+ movw %ax,%ds # and
+ movw %ax,%ss # %ss
+ lidt ivtdesc # Set IVT
+ popl %es # Restore
+ popl %ds # seg
+ popl %fs # regs
+ popl %gs
+ popal # Restore gp regs
+ movw $MEM_ESPR-0x16,%sp # Switch to real mode stack
+ iret # Call target routine
+/*
+ * For the return to real mode we setup a stack frame like this on the real
+ * mode stack. Note that callf calls won't pop off the flags, but we just
+ * ignore that by repositioning %sp to be just above the btx_v86 pointer
+ * so it is aligned. The stack is relative to MEM_ESPR.
+ *
+ * -0x04 kernel %esp
+ * -0x08 btx_v86
+ * -0x0c %eax
+ * -0x10 %ecx
+ * -0x14 %edx
+ * -0x18 %ebx
+ * -0x1c %esp
+ * -0x20 %ebp
+ * -0x24 %esi
+ * -0x28 %edi
+ * -0x2c %gs
+ * -0x30 %fs
+ * -0x34 %ds
+ * -0x38 %es
+ * -0x3c %eflags
+ */
+rret_tramp: movw $MEM_ESPR-0x08,%sp # Reset stack pointer
+ pushal # Save gp regs
+ pushl %gs # Save
+ pushl %fs # seg
+ pushl %ds # regs
+ pushl %es
+ pushfl # Save %eflags
+ cli # Disable interrupts
+ std # String ops dec
+ xorw %ax,%ax # Reset seg
+ movw %ax,%ds # regs
+ movw %ax,%es # (%ss is already 0)
+ lidt idtdesc # Set IDT
+ lgdt gdtdesc # Set GDT
+ mov %cr0,%eax # Switch to protected
+ inc %ax # mode
+ mov %eax,%cr0 #
+ ljmp $SEL_SCODE,$rret_tramp.1 # To 32-bit code
+ .code32
+rret_tramp.1: xorl %ecx,%ecx # Zero
+ movb $SEL_SDATA,%cl # Setup
+ movw %cx,%ss # 32-bit
+ movw %cx,%ds # seg
+ movw %cx,%es # regs
+ movl MEM_ESPR-0x04,%esp # Switch to kernel stack
+ leal 0x44(%esp,1),%esi # Base of frame
+ andb $~0x2,tss_desc+0x5 # Clear TSS busy
+ movb $SEL_TSS,%cl # Set task
+ ltr %cx # register
+/*
+ * Now we are back in protected mode. The kernel stack frame set up
+ * before entering real mode is still intact. For hardware interrupts,
+ * leave the frame unchanged.
+ */
+ cmpl $0,MEM_ESPR-0x08 # Leave saved regs unchanged
+ jz rret_tramp.3 # for hardware ints
+/*
+ * For V86 calls, copy the registers off of the real mode stack onto
+ * the kernel stack as we want their updated values. Also, initialize
+ * the segment registers on the kernel stack.
+ *
+ * Note that the %esp in the kernel stack after this is garbage, but popa
+ * ignores it, so we don't have to fix it up.
+ */
+ leal -0x18(%esi),%edi # Kernel stack GP regs
+ pushl %esi # Save
+ movl $MEM_ESPR-0x0c,%esi # Real mode stack GP regs
+ movl $8,%ecx # Copy GP regs from
+ rep # real mode stack
+ movsl # to kernel stack
+ movl $SEL_UDATA,%eax # Selector for data seg regs
+ movl $4,%ecx # Initialize %ds,
+ rep # %es, %fs, and
+ stosl # %gs
+/*
+ * For V86 calls, copy the saved seg regs on the real mode stack back
+ * over to the btx_v86 structure. Also, conditionally update the
+ * saved eflags on the kernel stack based on the flags from the user.
+ */
+ movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr
+ leal V86_GS(%ecx),%edi # %edi => btx_v86 seg regs
+ leal MEM_ESPR-0x2c,%esi # %esi => real mode seg regs
+ xchgl %ecx,%edx # Save btx_v86 ptr
+ movl $4,%ecx # Copy seg regs
+ rep # from real mode stack
+ movsl # to btx_v86
+ popl %esi # Restore
+ movl V86_CTL(%edx),%edx # Read V86 control flags
+ testl $V86F_FLAGS,%edx # User wants flags?
+ jz rret_tramp.3 # No
+ movl MEM_ESPR-0x3c,%eax # Read real mode flags
+ movw %ax,-0x08(%esi) # Update user flags (low 16)
+/*
+ * Return to the user task
+ */
+rret_tramp.3: popl %es # Restore
+ popl %ds # seg
+ popl %fs # regs
+ popl %gs
+ popal # Restore gp regs
+ addl $4,%esp # Discard int no
+ iret # Return to user 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
+ popl %eax # Call
+ call *%eax # program
+intx30.1: orb $0x1,%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
+ testl $PSL_VM,0x50(%ebx) # V86 mode?
+ jnz dump.3 # Yes
+ verr 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 $2,%dl # Num lines
+dump.4a: movb $0x10,%cl # Bytes to dump
+dump.5: lodsb # Get byte and
+ call hex8 # dump it
+ decb %cl # Keep count
+ jz dump.6a # 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.6a: decb %dl # Keep count
+ jz dump.7 # If done
+ movb $0xa,%al # Line feed
+ stosb # Save one
+ movb $7,%cl # Leading
+ movb $' ',%al # spaces
+dump.6b: stosb # Dump
+ decb %cl # spaces
+ jnz dump.6b
+ jmp dump.4a # Next line
+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
+#ifdef BTX_SERIAL
+ .set SIO_PRT,SIOPRT # Base port
+ .set SIO_FMT,SIOFMT # 8N1
+ .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD
+
+/*
+ * int sio_init(void)
+ */
+sio_init: movw $SIO_PRT+0x3,%dx # Data format reg
+ movb $SIO_FMT|0x80,%al # Set format
+ outb %al,(%dx) # and DLAB
+ pushl %edx # Save
+ subb $0x3,%dl # Divisor latch reg
+ movw $SIO_DIV,%ax # Set
+ outw %ax,(%dx) # BPS
+ popl %edx # Restore
+ movb $SIO_FMT,%al # Clear
+ outb %al,(%dx) # DLAB
+ incl %edx # Modem control reg
+ movb $0x3,%al # Set RTS,
+ outb %al,(%dx) # DTR
+ incl %edx # Line status reg
+ call sio_getc.1 # Get character
+
+/*
+ * int sio_flush(void)
+ */
+sio_flush: xorl %eax,%eax # Return value
+ xorl %ecx,%ecx # Timeout
+ movb $0x80,%ch # counter
+sio_flush.1: call sio_ischar # Check for character
+ jz sio_flush.2 # Till none
+ loop sio_flush.1 # or counter is zero
+ movb $1, %al # Exhausted all tries
+sio_flush.2: ret # To caller
+
+/*
+ * void sio_putc(int c)
+ */
+sio_putc: movw $SIO_PRT+0x5,%dx # Line status reg
+ xor %ecx,%ecx # Timeout
+ movb $0x40,%ch # counter
+sio_putc.1: inb (%dx),%al # Transmitter
+ testb $0x20,%al # buffer empty?
+ loopz sio_putc.1 # No
+ jz sio_putc.2 # If timeout
+ movb 0x4(%esp,1),%al # Get character
+ subb $0x5,%dl # Transmitter hold reg
+ outb %al,(%dx) # Write character
+sio_putc.2: ret $0x4 # To caller
+
+/*
+ * int sio_getc(void)
+ */
+sio_getc: call sio_ischar # Character available?
+ jz sio_getc # No
+sio_getc.1: subb $0x5,%dl # Receiver buffer reg
+ inb (%dx),%al # Read character
+ ret # To caller
+
+/*
+ * int sio_ischar(void)
+ */
+sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register
+ xorl %eax,%eax # Zero
+ inb (%dx),%al # Received data
+ andb $0x1,%al # ready?
+ ret # To caller
+
+/*
+ * Output character AL to the serial console.
+ */
+putchr: pusha # Save
+ cmpb $10, %al # is it a newline?
+ jne putchr.1 # no?, then leave
+ push $13 # output a carriage
+ call sio_putc # return first
+ movb $10, %al # restore %al
+putchr.1: pushl %eax # Push the character
+ # onto the stack
+ call sio_putc # Output the character
+ popa # Restore
+ ret # To caller
+#else
+/*
+ * 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
+ movl $0xa0000,%edi
+putchr.1: cmpb $0xa,%al # New line?
+ je putchr.2 # Yes
+ 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
+ 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 $0x20,%al # Space
+ xorb %ah,%ah
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+ movw $(SCR_ROW-1)*SCR_COL*2,%dx
+putchr.4: movw %dx,(%ebx) # Update position
+ popa # Restore
+ ret # To caller
+#endif
+
+ .code16
+/*
+ * Real Mode Hardware interrupt jump table.
+ */
+intr20: push $0x8 # Int 0x20: IRQ0
+ jmp int_hwr # V86 int 0x8
+ push $0x9 # Int 0x21: IRQ1
+ jmp int_hwr # V86 int 0x9
+ push $0xa # Int 0x22: IRQ2
+ jmp int_hwr # V86 int 0xa
+ push $0xb # Int 0x23: IRQ3
+ jmp int_hwr # V86 int 0xb
+ push $0xc # Int 0x24: IRQ4
+ jmp int_hwr # V86 int 0xc
+ push $0xd # Int 0x25: IRQ5
+ jmp int_hwr # V86 int 0xd
+ push $0xe # Int 0x26: IRQ6
+ jmp int_hwr # V86 int 0xe
+ push $0xf # Int 0x27: IRQ7
+ jmp int_hwr # V86 int 0xf
+ push $0x10 # Int 0x28: IRQ8
+ jmp int_hwr # V86 int 0x10
+ push $0x11 # Int 0x29: IRQ9
+ jmp int_hwr # V86 int 0x11
+ push $0x12 # Int 0x2a: IRQ10
+ jmp int_hwr # V86 int 0x12
+ push $0x13 # Int 0x2b: IRQ11
+ jmp int_hwr # V86 int 0x13
+ push $0x14 # Int 0x2c: IRQ12
+ jmp int_hwr # V86 int 0x14
+ push $0x15 # Int 0x2d: IRQ13
+ jmp int_hwr # V86 int 0x15
+ push $0x16 # Int 0x2e: IRQ14
+ jmp int_hwr # V86 int 0x16
+ push $0x17 # Int 0x2f: IRQ15
+ jmp int_hwr # V86 int 0x17
+/*
+ * Reflect hardware interrupts in real mode.
+ */
+int_hwr: push %ax # Save
+ push %ds # Save
+ push %bp # Save
+ mov %sp,%bp # Address stack frame
+ xchg %bx,6(%bp) # Swap BX, int no
+ xor %ax,%ax # Set %ds:%bx to
+ shl $2,%bx # point to
+ mov %ax,%ds # IDT entry
+ mov (%bx),%ax # Load IP
+ mov 2(%bx),%bx # Load CS
+ xchg %ax,4(%bp) # Swap saved %ax,%bx with
+ xchg %bx,6(%bp) # CS:IP of handler
+ pop %bp # Restore
+ pop %ds # Restore
+ lret # Jump to handler
+
+ .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
+tss_desc: .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 "BTX halted\n" # End
+/*
+ * Bad VM86 call panic
+ */
+badvm86: .asciz "Invalid VM86 Request\n"
+
+/*
+ * End of BTX memory.
+ */
+ .p2align 4
+break:
diff --git a/stand/pc98/btx/btxldr/Makefile b/stand/pc98/btx/btxldr/Makefile
new file mode 100644
index 0000000..47e83a0
--- /dev/null
+++ b/stand/pc98/btx/btxldr/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+PROG= btxldr
+INTERNALPROG=
+MAN=
+SRCS= btxldr.S
+
+CFLAGS+=-DLOADER_ADDRESS=${LOADER_ADDRESS}
+CFLAGS+=-I${.CURDIR}/../../../i386/common
+
+.if defined(BTXLDR_VERBOSE)
+CFLAGS+=-DBTXLDR_VERBOSE
+.endif
+
+ORG=${LOADER_ADDRESS}
+LDFLAGS=${LDFLAGS_BIN}
+
+.include <bsd.prog.mk>
+
+# XXX: clang integrated-as doesn't grok .codeNN directives yet
+CFLAGS.btxldr.S= ${CLANG_NO_IAS}
diff --git a/stand/pc98/btx/btxldr/btxldr.S b/stand/pc98/btx/btxldr/btxldr.S
new file mode 100644
index 0000000..9a6483f
--- /dev/null
+++ b/stand/pc98/btx/btxldr/btxldr.S
@@ -0,0 +1,430 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <bootargs.h>
+
+/*
+ * 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,start+0x1000 # 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.
+ */
+ .set SCR_MAT,0xe1 # Mode/attribute
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+/*
+ * BIOS Data Area locations.
+ */
+ .set BDA_MEM,0xa1501 # Free memory
+ .set BDA_POS,0xa153e # Cursor position
+/*
+ * Required by aout gas inadequacy.
+ */
+ .set SIZ_STUB,0x1a # Size of stub
+/*
+ * We expect to be loaded by boot2 at the origin defined in ./Makefile.
+ */
+ .globl start
+/*
+ * BTX program loader for ELF clients.
+ */
+start: cld # String ops inc
+ 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)
+ movl $m_logo,%esi # Identify
+ call putstr # ourselves
+ movzwl BDA_MEM,%eax # Get base memory
+ andl $0x7,%eax
+ incl %eax
+ shll $0x11,%eax # in bytes
+ movl %eax,%ebp # Base of user stack
+#ifdef BTXLDR_VERBOSE
+ movl $m_mem,%esi # Display
+ call hexout # amount of
+ call putstr # base memory
+#endif
+ lgdt gdtdesc # Load new GDT
+/*
+ * Relocate caller's arguments.
+ */
+#ifdef BTXLDR_VERBOSE
+ movl $m_esp,%esi # Display
+ movl %esp,%eax # caller
+ call hexout # stack
+ call putstr # pointer
+ movl $m_args,%esi # Format string
+ leal 0x4(%esp),%ebx # First argument
+ movl $0x6,%ecx # Count
+start.1: movl (%ebx),%eax # Get argument and
+ addl $0x4,%ebx # bump pointer
+ call hexout # Display it
+ loop start.1 # Till done
+ call putstr # End message
+#endif
+ movl BA_BOOTINFO+4(%esp),%esi # Source: bootinfo
+ cmpl $0x0, %esi # If the bootinfo pointer
+ je start_null_bi # is null, don't copy it
+ movl BI_SIZE(%esi),%ecx # Allocate space
+ subl %ecx,%ebp # for bootinfo
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # it
+ movl %ebp,BA_BOOTINFO+4(%esp) # Update pointer
+ movl %edi,%ebp # Restore base pointer
+#ifdef BTXLDR_VERBOSE
+ movl $m_rel_bi,%esi # Display
+ movl %ebp,%eax # bootinfo
+ call hexout # relocation
+ call putstr # message
+#endif
+start_null_bi: movl $BOOTARGS_SIZE,%ecx # Fixed size of arguments
+ testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data
+ jz start_fixed # Skip if the flag is not set
+ addl BOOTARGS_SIZE+4(%esp),%ecx # Add size of variable args
+start_fixed: subl $ARGOFF,%ebp # Place args at fixed offset
+ leal 0x4(%esp),%esi # Source
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # them
+#ifdef BTXLDR_VERBOSE
+ movl $m_rel_args,%esi # Display
+ movl %ebp,%eax # argument
+ call hexout # relocation
+ call putstr # message
+#endif
+/*
+ * 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 load address
+ movzwl 0xa(%ebx),%ecx # Image size
+#ifdef BTXLDR_VERBOSE
+ pushl %ecx # Save image size
+#endif
+ rep # Relocate
+ movsb # BTX
+ movl %esi,%ebx # Keep place
+#ifdef BTXLDR_VERBOSE
+ movl $m_rel_btx,%esi # Restore
+ popl %eax # parameters
+ call hexout # and
+#endif
+ popl %ebp # display
+#ifdef BTXLDR_VERBOSE
+ movl %ebp,%eax # the
+ call hexout # relocation
+ call putstr # message
+#endif
+ addl $PAG_SIZ,%ebp # Display
+#ifdef BTXLDR_VERBOSE
+ movl $m_base,%esi # the
+ movl %ebp,%eax # user
+ call hexout # base
+ call putstr # address
+#endif
+/*
+ * 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:
+#ifdef BTXLDR_VERBOSE
+ movl $m_elf,%esi # Display ELF
+ call putstr # message
+ movl $m_segs,%esi # Format string
+#endif
+ 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
+#ifdef BTXLDR_VERBOSE
+ movl 0x4(%edx),%eax # Display
+ call hexout # p_offset
+ movl 0x8(%edx),%eax # Display
+ call hexout # p_vaddr
+ movl 0x10(%edx),%eax # Display
+ call hexout # p_filesz
+ movl 0x14(%edx),%eax # Display
+ call hexout # p_memsz
+ call putstr # End message
+#endif
+ 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:
+#ifdef BTXLDR_VERBOSE
+ movl $m_done,%esi # Display done
+ call putstr # message
+#endif
+ movl $start.8,%esi # Real mode stub
+ movl $MEM_STUB,%edi # Destination
+ movl $start.9-start.8,%ecx # Size
+ rep # Relocate
+ movsb # it
+ ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code
+ .code16
+start.8: xorw %ax,%ax # Data
+ movb $SEL_RDATA,%al # selector
+ movw %ax,%ss # Reload SS
+ movw %ax,%ds # Reset
+ movw %ax,%es # other
+ movw %ax,%fs # segment
+ movw %ax,%gs # limits
+ movl %cr0,%eax # Switch to
+ decw %ax # real
+ movl %eax,%cr0 # mode
+ ljmp $0,$MEM_ENTRY # Jump to BTX entry point
+start.9:
+ .code32
+/*
+ * Output message [ESI] followed by EAX in hex.
+ */
+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.
+ */
+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.
+ */
+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
+ movl $0xa0000,%edi # Regen buffer (color)
+putchr.1: cmpb $0xa,%al # New line?
+ je putchr.2 # Yes
+ 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
+ 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
+ xorb %ah,%ah
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+ 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
+ popa # Restore
+ ret # To caller
+/*
+ * Convert EAX, AX, or AL to hex, saving the result to [EDI].
+ */
+hex32: pushl %eax # Save
+ shrl $0x10,%eax # Do upper
+ call hex16 # 16
+ popl %eax # Restore
+hex16: call hex16.1 # Do upper 8
+hex16.1: xchgb %ah,%al # Save/restore
+hex8: pushl %eax # Save
+ shrb $0x4,%al # Do upper
+ call hex8.1 # 4
+ popl %eax # Restore
+hex8.1: andb $0xf,%al # Get lower 4
+ cmpb $0xa,%al # Convert
+ sbbb $0x69,%al # to hex
+ das # digit
+ orb $0x20,%al # To lower case
+ stosb # Save char
+ ret # (Recursive)
+
+ .data
+ .p2align 4
+/*
+ * Global descriptor table.
+ */
+gdt: .word 0x0,0x0,0x0,0x0 # Null entry
+ .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
+ .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
+ .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
+ .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
+gdt.1:
+gdtdesc: .word gdt.1-gdt-1 # Limit
+ .long gdt # Base
+/*
+ * Messages.
+ */
+m_logo: .asciz " \nBTX loader 1.00 "
+m_vers: .asciz "BTX version is \0\n"
+e_fmt: .asciz "Error: Client format not supported\n"
+#ifdef BTXLDR_VERBOSE
+m_mem: .asciz "Starting in protected mode (base mem=\0)\n"
+m_esp: .asciz "Arguments passed (esp=\0):\n"
+m_args: .asciz"<howto="
+ .asciz" bootdev="
+ .asciz" junk="
+ .asciz" "
+ .asciz" "
+ .asciz" bootinfo=\0>\n"
+m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n"
+m_rel_args: .asciz "Relocated arguments (size=18) to \0\n"
+m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n"
+m_base: .asciz "Client base address is \0\n"
+m_elf: .asciz "Client format is ELF\n"
+m_segs: .asciz "text segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+ .asciz "data segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+m_done: .asciz "Loading complete\n"
+#endif
+/*
+ * Uninitialized data area.
+ */
+buf: # Scratch buffer
diff --git a/stand/pc98/btx/lib/Makefile b/stand/pc98/btx/lib/Makefile
new file mode 100644
index 0000000..e5876bc
--- /dev/null
+++ b/stand/pc98/btx/lib/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+PROG= crt0.o
+INTERNALPROG=
+MAN=
+SRCS= btxcsu.S btxsys.s btxv86.s
+CFLAGS+=-I${.CURDIR}/../../../i386/common
+LDFLAGS=-Wl,-r
+
+.include <bsd.prog.mk>
diff --git a/stand/pc98/btx/lib/btxcsu.S b/stand/pc98/btx/lib/btxcsu.S
new file mode 100644
index 0000000..c46f809
--- /dev/null
+++ b/stand/pc98/btx/lib/btxcsu.S
@@ -0,0 +1,49 @@
+#
+# 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.
+#
+
+# $FreeBSD$
+
+#include <bootargs.h>
+
+#
+# BTX C startup code (ELF).
+#
+
+#
+# Globals.
+#
+ .global _start
+#
+# Client entry point.
+#
+_start: cld
+ pushl %eax
+ movl $_edata,%edi
+ movl $_end,%ecx
+ subl %edi, %ecx
+ xorb %al, %al
+ rep
+ stosb
+ popl __base
+ 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/stand/pc98/btx/lib/btxsys.s b/stand/pc98/btx/lib/btxsys.s
new file mode 100644
index 0000000..9c77b42
--- /dev/null
+++ b/stand/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.
+#
+
+# $FreeBSD$
+
+#
+# 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/stand/pc98/btx/lib/btxv86.h b/stand/pc98/btx/lib/btxv86.h
new file mode 100644
index 0000000..27f6b34
--- /dev/null
+++ b/stand/pc98/btx/lib/btxv86.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/*
+ * $FreeBSD$
+ */
+
+#ifndef _BTXV86_H_
+#define _BTXV86_H_
+
+#include <sys/types.h>
+#include <machine/psl.h>
+
+#define V86_ADDR 0x10000 /* Segment:offset address */
+#define V86_CALLF 0x20000 /* Emulate far call */
+#define V86_FLAGS 0x40000 /* Return flags */
+
+struct __v86 {
+ uint32_t ctl; /* Control flags */
+ uint32_t addr; /* Interrupt number or address */
+ uint32_t es; /* V86 ES register */
+ uint32_t ds; /* V86 DS register */
+ uint32_t fs; /* V86 FS register */
+ uint32_t gs; /* V86 GS register */
+ uint32_t eax; /* V86 EAX register */
+ uint32_t ecx; /* V86 ECX register */
+ uint32_t edx; /* V86 EDX register */
+ uint32_t ebx; /* V86 EBX register */
+ uint32_t efl; /* V86 eflags register */
+ uint32_t ebp; /* V86 EBP register */
+ uint32_t esi; /* V86 ESI register */
+ uint32_t edi; /* V86 EDI register */
+};
+
+extern struct __v86 __v86; /* V86 interface structure */
+void __v86int(void);
+
+#define v86 __v86
+#define v86int __v86int
+
+extern u_int32_t __base;
+extern u_int32_t __args;
+
+#define PTOV(pa) ((caddr_t)(pa) - __base)
+#define VTOP(va) ((vm_offset_t)(va) + __base)
+#define VTOPSEG(va) (u_int16_t)(VTOP((caddr_t)va) >> 4)
+#define VTOPOFF(va) (u_int16_t)(VTOP((caddr_t)va) & 0xf)
+
+#define V86_CY(x) ((x) & PSL_C)
+#define V86_ZR(x) ((x) & PSL_Z)
+
+void __exit(int) __attribute__((__noreturn__));
+void __exec(caddr_t, ...);
+
+#endif /* !_BTXV86_H_ */
diff --git a/stand/pc98/btx/lib/btxv86.s b/stand/pc98/btx/lib/btxv86.s
new file mode 100644
index 0000000..0d7d111
--- /dev/null
+++ b/stand/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.
+#
+
+# $FreeBSD$
+
+#
+# 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/stand/pc98/cdboot/Makefile b/stand/pc98/cdboot/Makefile
new file mode 100644
index 0000000..ba94111
--- /dev/null
+++ b/stand/pc98/cdboot/Makefile
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+PROG= cdboot
+STRIP=
+BINMODE=${NOBINMODE}
+MAN=
+SRCS= ${PROG}.S
+
+CFLAGS+=-I${.CURDIR}/../../i386/common
+
+ORG= 0x0000
+
+LDFLAGS=${LDFLAGS_BIN}
+
+.include <bsd.prog.mk>
+
+# XXX: clang integrated-as doesn't grok .codeNN directives yet
+CFLAGS.cdboot.S= ${CLANG_NO_IAS}
diff --git a/stand/pc98/cdboot/cdboot.S b/stand/pc98/cdboot/cdboot.S
new file mode 100644
index 0000000..c97c02b
--- /dev/null
+++ b/stand/pc98/cdboot/cdboot.S
@@ -0,0 +1,805 @@
+#
+# Copyright (c) 2006 TAKAHASHI Yoshihiro <nyan@FreeBSD.org>
+# Copyright (c) 2001 John Baldwin <jhb@FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+# $FreeBSD$
+
+#
+# Basically, we first create a set of boot arguments to pass to the loaded
+# binary. Then we attempt to load /boot/loader from the CD we were booted
+# off of.
+#
+
+#include <bootargs.h>
+
+#
+# Memory locations.
+#
+ .set STACK_OFF,0x6000 # Stack offset
+ .set LOAD_SEG,0x0700 # Load segment
+ .set LOAD_SIZE,2048 # Load size
+ .set DAUA,0x0584 # DA/UA
+
+ .set MEM_PAGE_SIZE,0x1000 # memory page size, 4k
+ .set MEM_ARG,0x900 # Arguments at start
+ .set MEM_ARG_BTX,0xa100 # Where we move them to so the
+ # BTX client can see them
+ .set MEM_ARG_SIZE,0x18 # Size of the arguments
+ .set MEM_BTX_ADDRESS,0x9000 # where BTX lives
+ .set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute
+ .set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader
+ .set MEM_BTX_CLIENT,0xa000 # where BTX clients live
+#
+# PC98 machine type from sys/pc98/pc98/pc98_machdep.h
+#
+ .set MEM_SYS, 0xa100 # System common area segment
+ .set PC98_MACHINE_TYPE, 0x0620 # PC98 machine type
+ .set EPSON_ID, 0x0624 # EPSON machine id
+
+ .set M_NEC_PC98, 0x0001
+ .set M_EPSON_PC98, 0x0002
+ .set M_NOT_H98, 0x0010
+ .set M_H98, 0x0020
+ .set M_NOTE, 0x0040
+ .set M_NORMAL, 0x1000
+ .set M_8M, 0x8000
+#
+# Signature Constants
+#
+ .set SIG1_OFF,0x1fe # Signature offset
+ .set SIG2_OFF,0x7fe # Signature offset
+#
+# a.out header fields
+#
+ .set AOUT_TEXT,0x04 # text segment size
+ .set AOUT_DATA,0x08 # data segment size
+ .set AOUT_BSS,0x0c # zero'd BSS size
+ .set AOUT_SYMBOLS,0x10 # symbol table
+ .set AOUT_ENTRY,0x14 # entry point
+ .set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header
+#
+# Segment selectors.
+#
+ .set SEL_SDATA,0x8 # Supervisor data
+ .set SEL_RDATA,0x10 # Real mode data
+ .set SEL_SCODE,0x18 # PM-32 code
+ .set SEL_SCODE16,0x20 # PM-16 code
+#
+# BTX constants
+#
+ .set INT_SYS,0x30 # BTX syscall interrupt
+#
+# Constants for reading from the CD.
+#
+ .set ERROR_TIMEOUT,0x90 # BIOS timeout on read
+ .set NUM_RETRIES,3 # Num times to retry
+ .set SECTOR_SIZE,0x800 # size of a sector
+ .set SECTOR_SHIFT,11 # number of place to shift
+ .set BUFFER_LEN,0x100 # number of sectors in buffer
+ .set MAX_READ,0xf800 # max we can read at a time
+ .set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT
+ .set MEM_READ_BUFFER,0x9000 # buffer to read from CD
+ .set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor
+ .set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer
+ .set VOLDESC_LBA,0x10 # LBA of vol descriptor
+ .set VD_PRIMARY,1 # Primary VD
+ .set VD_END,255 # VD Terminator
+ .set VD_ROOTDIR,156 # Offset of Root Dir Record
+ .set DIR_LEN,0 # Offset of Dir Record length
+ .set DIR_EA_LEN,1 # Offset of EA length
+ .set DIR_EXTENT,2 # Offset of 64-bit LBA
+ .set DIR_SIZE,10 # Offset of 64-bit length
+ .set DIR_NAMELEN,32 # Offset of 8-bit name len
+ .set DIR_NAME,33 # Offset of dir name
+
+#
+# Program start.
+#
+ .code16
+ .globl start
+
+start: jmp main
+
+ .org 4
+ .ascii "IPL1 "
+
+main: cld
+
+ /* Setup the stack */
+ xor %ax,%ax
+ mov %ax,%ss
+ mov $STACK_OFF,%sp
+
+ push %ecx
+
+ /* Setup graphic screen */
+ mov $0x42,%ah # 640x400
+ mov $0xc0,%ch
+ int $0x18
+ mov $0x40,%ah # graph on
+ int $0x18
+
+ /* Setup text screen */
+ mov $0x0a00,%ax # 80x25
+ int $0x18
+ mov $0x0c,%ah # text on
+ int $0x18
+ mov $0x13,%ah # cursor home
+ xor %dx,%dx
+ int $0x18
+ mov $0x11,%ah # cursor on
+ int $0x18
+
+ /* Setup keyboard */
+ mov $0x03,%ah
+ int $0x18
+
+ /* Transfer PC-9801 system common area */
+ xor %ax,%ax
+ mov %ax,%si
+ mov %ax,%ds
+ mov %ax,%di
+ mov $MEM_SYS,%ax
+ mov %ax,%es
+ mov $0x0600,%cx
+ rep
+ movsb
+
+ /* Transfer EPSON machine type */
+ mov $0xfd00,%ax
+ mov %ax,%ds
+ mov (0x804),%eax
+ and $0x00ffffff,%eax
+ mov %eax,%es:(EPSON_ID)
+
+ /* Set machine type to PC98_SYSTEM_PARAMETER */
+ call machine_check
+
+ /* Load cdboot */
+ xor %ax,%ax
+ mov %ax,%ds
+ mov $0x06,%ah /* Read data */
+ mov (DAUA),%al /* Read drive */
+ pop %ecx /* cylinder */
+ xor %dx,%dx /* head / sector */
+ mov $LOAD_SEG,%bx /* Load address */
+ mov %bx,%es
+ xor %bp,%bp
+ mov $LOAD_SIZE,%bx /* Load size */
+ int $0x1b
+ mov $msg_readerr,%si
+ jc error
+
+ /* Jump to cdboot */
+ ljmp $LOAD_SEG,$cdboot
+
+#
+# Set machine type to PC98_SYSTEM_PARAMETER.
+#
+machine_check: xor %edx,%edx
+ mov %dx,%ds
+ mov $MEM_SYS,%ax
+ mov %ax,%es
+
+ /* Wait V-SYNC */
+vsync.1: inb $0x60,%al
+ test $0x20,%al
+ jnz vsync.1
+vsync.2: inb $0x60,%al
+ test $0x20,%al
+ jz vsync.2
+
+ /* ANK 'A' font */
+ xor %al,%al
+ outb %al,$0xa1
+ mov $0x41,%al
+ outb %al,$0xa3
+
+ /* Get 'A' font from CG window */
+ push %ds
+ mov $0xa400,%ax
+ mov %ax,%ds
+ xor %eax,%eax
+ xor %bx,%bx
+ mov $4,%cx
+font.1: add (%bx),%eax
+ add $4,%bx
+ loop font.1
+ pop %ds
+ cmp $0x6efc58fc,%eax
+ jnz m_epson
+
+m_pc98: or $M_NEC_PC98,%edx
+ mov $0x0458,%bx
+ mov (%bx),%al
+ test $0x80,%al
+ jz m_not_h98
+ or $M_H98,%edx
+ jmp 1f
+m_epson: or $M_EPSON_PC98,%edx
+m_not_h98: or $M_NOT_H98,%edx
+
+1: inb $0x42,%al
+ test $0x20,%al
+ jz 1f
+ or $M_8M,%edx
+
+1: mov $0x0400,%bx
+ mov (%bx),%al
+ test $0x80,%al
+ jz 1f
+ or $M_NOTE,%edx
+
+1: mov $PC98_MACHINE_TYPE,%bx
+ mov %edx,%es:(%bx)
+ ret
+
+#
+# Print out the error message at [SI], wait for a keypress, and then
+# reboot the machine.
+#
+error: call putstr
+ mov $msg_keypress,%si
+ call putstr
+ xor %ax,%ax # Get keypress
+ int $0x18
+ xor %ax,%ax # CPU reset
+ outb %al,$0xf0
+halt: hlt
+ jmp halt # Spin
+
+#
+# Display a null-terminated string at [SI].
+#
+# Trashes: AX, BX, CX, DX, SI, DI
+#
+putstr: push %ds
+ push %es
+ mov %cs,%ax
+ mov %ax,%ds
+ mov $0xa000,%ax
+ mov %ax,%es
+ mov cursor,%di
+ mov $0x00e1,%bx # Attribute
+ mov $160,%cx
+putstr.0: lodsb
+ testb %al,%al
+ jz putstr.done
+ cmp $0x0d,%al
+ jz putstr.cr
+ cmp $0x0a,%al
+ jz putstr.lf
+ mov %bl,%es:0x2000(%di)
+ stosb
+ inc %di
+ jmp putstr.move
+putstr.cr: xor %dx,%dx
+ mov %di,%ax
+ div %cx
+ sub %dx,%di
+ jmp putstr.move
+putstr.lf: add %cx,%di
+putstr.move: mov %di,%dx
+ mov $0x13,%ah # Move cursor
+ int $0x18
+ jmp putstr.0
+putstr.done: mov %di,cursor
+ pop %es
+ pop %ds
+ ret
+
+#
+# Display a single char at [AL], but don't move a cursor.
+#
+putc: push %es
+ push %di
+ push %bx
+ mov $0xa000,%bx
+ mov %bx,%es
+ mov cursor,%di
+ mov $0xe1,%bl # Attribute
+ mov %bl,%es:0x2000(%di)
+ stosb
+ pop %bx
+ pop %di
+ pop %es
+ ret
+
+msg_readerr: .asciz "Read Error\r\n"
+msg_keypress: .asciz "\r\nPress any key to reboot\r\n"
+
+/* Boot signature */
+
+ .org SIG1_OFF,0x90
+
+ .word 0xaa55 # Magic number
+
+#
+# cdboot
+#
+cdboot: mov %cs,%ax
+ mov %ax,%ds
+ xor %ax,%ax
+ mov %ax,%es
+ mov %es:(DAUA),%al # Save BIOS boot device
+ mov %al,drive
+ mov %cx,cylinder # Save BIOS boot cylinder
+
+ mov $msg_welcome,%si # %ds:(%si) -> welcome message
+ call putstr # display the welcome message
+#
+# Setup the arguments that the loader is expecting from boot[12]
+#
+ mov $msg_bootinfo,%si # %ds:(%si) -> boot args message
+ call putstr # display the message
+ mov $MEM_ARG,%bx # %ds:(%bx) -> boot args
+ mov %bx,%di # %es:(%di) -> boot args
+ xor %eax,%eax # zero %eax
+ mov $(MEM_ARG_SIZE/4),%cx # Size of arguments in 32-bit
+ # dwords
+ rep # Clear the arguments
+ stosl # to zero
+ mov drive,%dl # Store BIOS boot device
+ mov %dl,%es:0x4(%bx) # in kargs->bootdev
+ or $KARGS_FLAGS_CD,%es:0x8(%bx) # kargs->bootflags |=
+ # KARGS_FLAGS_CD
+#
+# Load Volume Descriptor
+#
+ mov $VOLDESC_LBA,%eax # Set LBA of first VD
+load_vd: push %eax # Save %eax
+ mov $1,%dh # One sector
+ mov $MEM_VOLDESC,%ebx # Destination
+ call read # Read it in
+ cmpb $VD_PRIMARY,%es:(%bx) # Primary VD?
+ je have_vd # Yes
+ pop %eax # Prepare to
+ inc %eax # try next
+ cmpb $VD_END,%es:(%bx) # Last VD?
+ jne load_vd # No, read next
+ mov $msg_novd,%si # No VD
+ jmp error # Halt
+have_vd: # Have Primary VD
+#
+# Try to look up the loader binary using the paths in the loader_paths
+# array.
+#
+ mov $loader_paths,%si # Point to start of array
+lookup_path: push %si # Save file name pointer
+ call lookup # Try to find file
+ pop %di # Restore file name pointer
+ jnc lookup_found # Found this file
+ push %es
+ mov %cs,%ax
+ mov %ax,%es
+ xor %al,%al # Look for next
+ mov $0xffff,%cx # path name by
+ repnz # scanning for
+ scasb # nul char
+ pop %es
+ mov %di,%si # Point %si at next path
+ mov (%si),%al # Get first char of next path
+ or %al,%al # Is it double nul?
+ jnz lookup_path # No, try it.
+ mov $msg_failed,%si # Failed message
+ jmp error # Halt
+lookup_found: # Found a loader file
+#
+# Load the binary into the buffer. Due to real mode addressing limitations
+# we have to read it in 64k chunks.
+#
+ mov %es:DIR_SIZE(%bx),%eax # Read file length
+ add $SECTOR_SIZE-1,%eax # Convert length to sectors
+ shr $SECTOR_SHIFT,%eax
+ cmp $BUFFER_LEN,%eax
+ jbe load_sizeok
+ mov $msg_load2big,%si # Error message
+ jmp error
+load_sizeok: movzbw %al,%cx # Num sectors to read
+ mov %es:DIR_EXTENT(%bx),%eax # Load extent
+ xor %edx,%edx
+ mov %es:DIR_EA_LEN(%bx),%dl
+ add %edx,%eax # Skip extended
+ mov $MEM_READ_BUFFER,%ebx # Read into the buffer
+load_loop: mov %cl,%dh
+ cmp $MAX_READ_SEC,%cl # Truncate to max read size
+ jbe load_notrunc
+ mov $MAX_READ_SEC,%dh
+load_notrunc: sub %dh,%cl # Update count
+ push %eax # Save
+ call read # Read it in
+ pop %eax # Restore
+ add $MAX_READ_SEC,%eax # Update LBA
+ add $MAX_READ,%ebx # Update dest addr
+ jcxz load_done # Done?
+ jmp load_loop # Keep going
+load_done:
+#
+# Turn on the A20 address line
+#
+ xor %ax,%ax # Turn A20 on
+ outb %al,$0xf2
+ mov $0x02,%al
+ outb %al,$0xf6
+#
+# Relocate the loader and BTX using a very lazy protected mode
+#
+ mov $msg_relocate,%si # Display the
+ call putstr # relocation message
+ mov %es:(MEM_READ_BUFFER+AOUT_ENTRY),%edi # %edi is the destination
+ mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi # %esi is
+ # the start of the text
+ # segment
+ mov %es:(MEM_READ_BUFFER+AOUT_TEXT),%ecx # %ecx = length of the text
+ # segment
+ push %edi # Save entry point for later
+ lgdt gdtdesc # setup our own gdt
+ cli # turn off interrupts
+ mov %cr0,%eax # Turn on
+ or $0x1,%al # protected
+ mov %eax,%cr0 # mode
+ ljmp $SEL_SCODE,$pm_start # long jump to clear the
+ # instruction pre-fetch queue
+ .code32
+pm_start: mov $SEL_SDATA,%ax # Initialize
+ mov %ax,%ds # %ds and
+ mov %ax,%es # %es to a flat selector
+ rep # Relocate the
+ movsb # text segment
+ add $(MEM_PAGE_SIZE - 1),%edi # pad %edi out to a new page
+ and $~(MEM_PAGE_SIZE - 1),%edi # for the data segment
+ mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment
+ rep # Relocate the
+ movsb # data segment
+ mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss
+ xor %eax,%eax # zero %eax
+ add $3,%cl # round %ecx up to
+ shr $2,%ecx # a multiple of 4
+ rep # zero the
+ stosl # bss
+ mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader
+ add $MEM_BTX_OFFSET,%esi # %esi -> BTX in the loader
+ mov $MEM_BTX_ADDRESS,%edi # %edi -> where BTX needs to go
+ movzwl 0xa(%esi),%ecx # %ecx -> length of BTX
+ rep # Relocate
+ movsb # BTX
+ ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM
+ .code16
+pm_16: mov $SEL_RDATA,%ax # Initialize
+ mov %ax,%ds # %ds and
+ mov %ax,%es # %es to a real mode selector
+ mov %cr0,%eax # Turn off
+ and $~0x1,%al # protected
+ mov %eax,%cr0 # mode
+ ljmp $LOAD_SEG,$pm_end # Long jump to clear the
+ # instruction pre-fetch queue
+pm_end: sti # Turn interrupts back on now
+#
+# Copy the BTX client to MEM_BTX_CLIENT
+#
+ mov %cs,%ax
+ mov %ax,%ds
+ xor %ax,%ax
+ mov %ax,%es
+ mov $MEM_BTX_CLIENT,%di # Prepare to relocate
+ mov $btx_client,%si # the simple btx client
+ mov $(btx_client_end-btx_client),%cx # length of btx client
+ rep # Relocate the
+ movsb # simple BTX client
+#
+# Copy the boot[12] args to where the BTX client can see them
+#
+ xor %ax,%ax
+ mov %ax,%ds
+ mov $MEM_ARG,%si # where the args are at now
+ mov $MEM_ARG_BTX,%di # where the args are moving to
+ mov $(MEM_ARG_SIZE/4),%cx # size of the arguments in longs
+ rep # Relocate
+ movsl # the words
+#
+# Save the entry point so the client can get to it later on
+#
+ pop %eax # Restore saved entry point
+ stosl # and add it to the end of
+ # the arguments
+#
+# Now we just start up BTX and let it do the rest
+#
+ mov $msg_jump,%si # Display the
+ call putstr # jump message
+ ljmp $0,$MEM_BTX_ENTRY # Jump to the BTX entry point
+
+#
+# Lookup the file in the path at [SI] from the root directory.
+#
+# Trashes: All but BX
+# Returns: CF = 0 (success), BX = pointer to record
+# CF = 1 (not found)
+#
+lookup: mov $VD_ROOTDIR+MEM_VOLDESC,%bx # Root directory record
+ push %bx
+ push %si
+ mov $msg_lookup,%si # Display lookup message
+ call putstr
+ pop %si
+ push %si
+ call putstr
+ mov $msg_lookup2,%si
+ call putstr
+ pop %si
+ pop %bx
+lookup_dir: lodsb # Get first char of path
+ cmp $0,%al # Are we done?
+ je lookup_done # Yes
+ cmp $'/',%al # Skip path separator.
+ je lookup_dir
+ dec %si # Undo lodsb side effect
+ call find_file # Lookup first path item
+ jnc lookup_dir # Try next component
+ mov $msg_lookupfail,%si # Not found message
+ push %bx
+ call putstr
+ pop %bx
+ stc # Set carry
+ ret
+lookup_done: mov $msg_lookupok,%si # Success message
+ push %bx
+ call putstr
+ pop %bx
+ clc # Clear carry
+ ret
+
+#
+# Lookup file at [SI] in directory whose record is at [BX].
+#
+# Trashes: All but returns
+# Returns: CF = 0 (success), BX = pointer to record, SI = next path item
+# CF = 1 (not found), SI = preserved
+#
+find_file: mov %es:DIR_EXTENT(%bx),%eax # Load extent
+ xor %edx,%edx
+ mov %es:DIR_EA_LEN(%bx),%dl
+ add %edx,%eax # Skip extended attributes
+ mov %eax,rec_lba # Save LBA
+ mov %es:DIR_SIZE(%bx),%eax # Save size
+ mov %eax,rec_size
+ xor %cl,%cl # Zero length
+ push %si # Save
+ff.namelen: inc %cl # Update length
+ lodsb # Read char
+ cmp $0,%al # Nul?
+ je ff.namedone # Yes
+ cmp $'/',%al # Path separator?
+ jnz ff.namelen # No, keep going
+ff.namedone: dec %cl # Adjust length and save
+ mov %cl,name_len
+ pop %si # Restore
+ff.load: mov rec_lba,%eax # Load LBA
+ mov $MEM_DIR,%ebx # Address buffer
+ mov $1,%dh # One sector
+ call read # Read directory block
+ incl rec_lba # Update LBA to next block
+ff.scan: mov %ebx,%edx # Check for EOF
+ sub $MEM_DIR,%edx
+ cmp %edx,rec_size
+ ja ff.scan.1
+ stc # EOF reached
+ ret
+ff.scan.1: cmpb $0,%es:DIR_LEN(%bx) # Last record in block?
+ je ff.nextblock
+ push %si # Save
+ movzbw %es:DIR_NAMELEN(%bx),%si # Find end of string
+ff.checkver: cmpb $'0',%es:DIR_NAME-1(%bx,%si) # Less than '0'?
+ jb ff.checkver.1
+ cmpb $'9',%es:DIR_NAME-1(%bx,%si) # Greater than '9'?
+ ja ff.checkver.1
+ dec %si # Next char
+ jnz ff.checkver
+ jmp ff.checklen # All numbers in name, so
+ # no version
+ff.checkver.1: movzbw %es:DIR_NAMELEN(%bx),%cx
+ cmp %cx,%si # Did we find any digits?
+ je ff.checkdot # No
+ cmpb $';',%es:DIR_NAME-1(%bx,%si) # Check for semicolon
+ jne ff.checkver.2
+ dec %si # Skip semicolon
+ mov %si,%cx
+ mov %cl,%es:DIR_NAMELEN(%bx) # Adjust length
+ jmp ff.checkdot
+ff.checkver.2: mov %cx,%si # Restore %si to end of string
+ff.checkdot: cmpb $'.',%es:DIR_NAME-1(%bx,%si) # Trailing dot?
+ jne ff.checklen # No
+ decb %es:DIR_NAMELEN(%bx) # Adjust length
+ff.checklen: pop %si # Restore
+ movzbw name_len,%cx # Load length of name
+ cmp %cl,%es:DIR_NAMELEN(%bx) # Does length match?
+ je ff.checkname # Yes, check name
+ff.nextrec: add %es:DIR_LEN(%bx),%bl # Next record
+ adc $0,%bh
+ jmp ff.scan
+ff.nextblock: subl $SECTOR_SIZE,rec_size # Adjust size
+ jnc ff.load # If subtract ok, keep going
+ ret # End of file, so not found
+ff.checkname: lea DIR_NAME(%bx),%di # Address name in record
+ push %si # Save
+ repe cmpsb # Compare name
+ je ff.match # We have a winner!
+ pop %si # Restore
+ jmp ff.nextrec # Keep looking.
+ff.match: add $2,%sp # Discard saved %si
+ clc # Clear carry
+ ret
+
+#
+# Load DH sectors starting at LBA EAX into [EBX].
+#
+# Trashes: EAX
+#
+read: push %es # Save
+ push %bp
+ push %dx
+ push %cx
+ push %ebx
+ mov %bx,%bp # Set destination address
+ and $0x000f,%bp
+ shr $4,%ebx
+ mov %bx,%es
+ xor %bx,%bx # Set read bytes
+ mov %dh,%bl
+ shl $SECTOR_SHIFT,%bx # 2048 bytes/sec
+ mov %ax,%cx # Set LBA
+ shr $16,%eax
+ mov %ax,%dx
+read.retry: mov $0x06,%ah # BIOS device read
+ mov drive,%al
+ and $0x7f,%al
+ call twiddle # Entertain the user
+ int $0x1b # Call BIOS
+ jc read.fail # Worked?
+ pop %ebx # Restore
+ pop %cx
+ pop %dx
+ pop %bp
+ pop %es
+ ret # Return
+read.fail: cmp $ERROR_TIMEOUT,%ah # Timeout?
+ je read.retry # Yes, Retry.
+read.error: mov %ah,%al # Save error
+ mov $hex_error,%di # Format it
+ call hex8 # as hex
+ mov $msg_badread,%si # Display Read error message
+ jmp error
+
+#
+# Output the "twiddle"
+#
+twiddle: push %ax # Save
+ push %bx # Save
+ mov twiddle_index,%al # Load index
+ mov $twiddle_chars,%bx # Address table
+ inc %al # Next
+ and $3,%al # char
+ mov %al,twiddle_index # Save index for next call
+ xlat # Get char
+ call putc # Output it
+ pop %bx # Restore
+ pop %ax # Restore
+ ret
+
+#
+# Convert AL to hex, saving the result to [EDI].
+#
+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
+ mov %al,(%di) # Save char
+ inc %di
+ ret # (Recursive)
+
+#
+# BTX client to start btxldr
+#
+ .code32
+btx_client: mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi
+ # %ds:(%esi) -> end
+ # of boot[12] args
+ mov $(MEM_ARG_SIZE/4),%ecx # Number of words to push
+ std # Go backwards
+push_arg: lodsl # Read argument
+ push %eax # Push it onto the stack
+ loop push_arg # Push all of the arguments
+ cld # In case anyone depends on this
+ pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of
+ # the loader
+ push %eax # Emulate a near call
+ mov $0x1,%eax # 'exec' system call
+ int $INT_SYS # BTX system call
+btx_client_end:
+ .code16
+
+ .p2align 4
+#
+# Global descriptor table.
+#
+gdt: .word 0x0,0x0,0x0,0x0 # Null entry
+ .word 0xffff,0x0000,0x9200,0x00cf # SEL_SDATA
+ .word 0xffff,0x0000,0x9200,0x0000 # SEL_RDATA
+ .word 0xffff,LOAD_SEG<<4,0x9a00,0x00cf # SEL_SCODE (32-bit)
+ .word 0xffff,LOAD_SEG<<4,0x9a00,0x008f # SEL_SCODE16 (16-bit)
+gdt.1:
+#
+# Pseudo-descriptors.
+#
+gdtdesc: .word gdt.1-gdt-1 # Limit
+ .long LOAD_SEG<<4 + gdt # Base
+
+#
+# BOOT device
+#
+drive: .byte 0
+cylinder: .word 0
+
+#
+# State for searching dir
+#
+rec_lba: .long 0x0 # LBA (adjusted for EA)
+rec_size: .long 0x0 # File size
+name_len: .byte 0x0 # Length of current name
+
+cursor: .word 0
+twiddle_index: .byte 0x0
+
+msg_welcome: .asciz "CD Loader 1.2\r\n\n"
+msg_bootinfo: .asciz "Building the boot loader arguments\r\n"
+msg_relocate: .asciz "Relocating the loader and the BTX\r\n"
+msg_jump: .asciz "Starting the BTX loader\r\n"
+msg_badread: .ascii "Read Error: 0x"
+hex_error: .asciz "00\r\n"
+msg_novd: .asciz "Could not find Primary Volume Descriptor\r\n"
+msg_lookup: .asciz "Looking up "
+msg_lookup2: .asciz "... "
+msg_lookupok: .asciz "Found\r\n"
+msg_lookupfail: .asciz "File not found\r\n"
+msg_load2big: .asciz "File too big\r\n"
+msg_failed: .asciz "Boot failed\r\n"
+twiddle_chars: .ascii "|/-\\"
+loader_paths: .asciz "/BOOT.PC98/LOADER"
+ .asciz "/boot.pc98/loader"
+ .asciz "/BOOT/LOADER"
+ .asciz "/boot/loader"
+ .byte 0
+
+/* Boot signature */
+
+ .org SIG2_OFF,0x90
+
+ .word 0xaa55 # Magic number
diff --git a/stand/pc98/kgzldr/Makefile b/stand/pc98/kgzldr/Makefile
new file mode 100644
index 0000000..0070d70
--- /dev/null
+++ b/stand/pc98/kgzldr/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+PROG= kgzldr.o
+STRIP=
+BINMODE=${LIBMODE}
+BINDIR= ${LIBDIR}
+MAN=
+
+SRCS= start.s boot.c inflate.c lib.c crt.s sio.s
+CFLAGS= -Os
+CFLAGS+=-DKZIP
+NO_SHARED=
+LDFLAGS=-Wl,-r
+.PATH: ${.CURDIR}/../../../kern
+.PATH: ${.CURDIR}/../../i386/kgzldr
+
+BOOT_COMCONSOLE_PORT?= 0x238
+AFLAGS+=--defsym SIO_PRT=${BOOT_COMCONSOLE_PORT}
+
+.include <bsd.prog.mk>
diff --git a/stand/pc98/kgzldr/crt.s b/stand/pc98/kgzldr/crt.s
new file mode 100644
index 0000000..35c1fc2
--- /dev/null
+++ b/stand/pc98/kgzldr/crt.s
@@ -0,0 +1,89 @@
+#
+# Copyright (c) 1999 Global Technology Associates, Inc.
+# 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: btx.s 1.10 1999/02/25 16:27:41 rnordier
+# $FreeBSD$
+#
+
+# Screen defaults and assumptions.
+
+ .set SCR_MAT,0xe1 # Mode/attribute
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+
+# BIOS Data Area locations.
+
+ .set BDA_POS,0x53e # Cursor position
+
+ .globl crt_putchr
+
+# void crt_putchr(int c)
+
+crt_putchr: movb 0x4(%esp,1),%al # Get character
+ 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
+ movl $0xa0000,%edi
+crt_putchr.1: cmpb $0xa,%al # New line?
+ je crt_putchr.2 # Yes
+ movw %dx,%cx
+ movb %al,(%edi,%ecx,1) # Write char
+ addl $0x2000,%ecx
+ movb %ah,(%edi,%ecx,1) # Write attr
+ addw $0x02,%dx
+ jmp crt_putchr.3
+crt_putchr.2: movw %dx,%ax
+ movb $SCR_COL*2,%dl
+ div %dl
+ incb %al
+ mul %dl
+ movw %ax,%dx
+crt_putchr.3: cmpw $SCR_ROW*SCR_COL*2,%dx
+ jb crt_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
+ xorb %ah,%ah
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+ movw $(SCR_ROW-1)*SCR_COL*2,%dx
+crt_putchr.4: movw %dx,(%ebx) # Update position
+ shrw $1,%dx
+crt_putchr.5: inb $0x60,%al # Move cursor
+ testb $0x04,%al
+ jz crt_putchr.5
+ movb $0x49,%al
+ outb %al,$0x62
+ movb %dl,%al
+ outb %al,$0x60
+ movb %dh,%al
+ outb %al,$0x60
+ popa # Restore
+ ret # To caller
diff --git a/stand/pc98/libpc98/Makefile b/stand/pc98/libpc98/Makefile
new file mode 100644
index 0000000..f3e27a4
--- /dev/null
+++ b/stand/pc98/libpc98/Makefile
@@ -0,0 +1,51 @@
+# $FreeBSD$
+#
+LIB= pc98
+INTERNALLIB=
+
+.PATH: ${.CURDIR}/../../i386/libi386
+
+SRCS= bioscd.c biosdisk.c biosmem.c biospnp.c \
+ biospci.c biossmap.c bootinfo.c bootinfo32.c \
+ comconsole.c devicename.c elf32_freebsd.c \
+ i386_copy.c i386_module.c nullconsole.c pc98_sys.c pxe.c pxetramp.s \
+ time.c vidconsole.c
+.PATH: ${.CURDIR}/../../zfs
+SRCS+= devicename_stubs.c
+
+# Enable PXE TFTP or NFS support, not both.
+.if defined(LOADER_TFTP_SUPPORT)
+CFLAGS+= -DLOADER_TFTP_SUPPORT
+.else
+CFLAGS+= -DLOADER_NFS_SUPPORT
+.endif
+
+BOOT_COMCONSOLE_PORT?= 0x238
+CFLAGS+= -DCOMPORT=${BOOT_COMCONSOLE_PORT}
+
+BOOT_COMCONSOLE_SPEED?= 9600
+CFLAGS+= -DCOMSPEED=${BOOT_COMCONSOLE_SPEED}
+
+.ifdef(BOOT_BIOSDISK_DEBUG)
+# Make the disk code more talkative
+CFLAGS+= -DDISK_DEBUG
+.endif
+
+# Include simple terminal emulation (cons25-compatible)
+CFLAGS+= -DTERM_EMU
+
+# XXX: make alloca() useable
+CFLAGS+= -Dalloca=__builtin_alloca
+
+CFLAGS+= -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/i386 \
+ -I${.CURDIR}/../../common \
+ -I${.CURDIR}/../btx/lib \
+ -I${.CURDIR}/../../i386/libi386 \
+ -I${.CURDIR}/../../.. -I.
+# the location of libstand
+CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/
+
+# Handle FreeBSD specific %b and %D printf format specifiers
+CFLAGS+= ${FORMAT_EXTENSIONS}
+
+.include <bsd.lib.mk>
diff --git a/stand/pc98/libpc98/bioscd.c b/stand/pc98/libpc98/bioscd.c
new file mode 100644
index 0000000..f259701
--- /dev/null
+++ b/stand/pc98/libpc98/bioscd.c
@@ -0,0 +1,420 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2001 John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * BIOS CD device handling for CD's that have been booted off of via no
+ * emulation booting as defined in the El Torito standard.
+ *
+ * Ideas and algorithms from:
+ *
+ * - FreeBSD libi386/biosdisk.c
+ *
+ */
+
+#include <stand.h>
+
+#include <sys/param.h>
+#include <machine/bootinfo.h>
+
+#include <stdarg.h>
+
+#include <bootstrap.h>
+#include <btxv86.h>
+#include "libi386.h"
+
+#define BIOSCD_SECSIZE 2048
+#define BUFSIZE (1 * BIOSCD_SECSIZE)
+#define MAXBCDEV 1
+
+/* Major numbers for devices we frontend for. */
+#define ACDMAJOR 117
+#define CDMAJOR 15
+
+#ifdef DISK_DEBUG
+# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
+#else
+# define DEBUG(fmt, args...)
+#endif
+
+struct specification_packet {
+ u_char sp_size;
+ u_char sp_bootmedia;
+ u_char sp_drive;
+ u_char sp_controller;
+ u_int sp_lba;
+ u_short sp_devicespec;
+ u_short sp_buffersegment;
+ u_short sp_loadsegment;
+ u_short sp_sectorcount;
+ u_short sp_cylsec;
+ u_char sp_head;
+};
+
+/*
+ * List of BIOS devices, translation from disk unit number to
+ * BIOS unit number.
+ */
+static struct bcinfo {
+ int bc_unit; /* BIOS unit number */
+ struct specification_packet bc_sp;
+ int bc_open; /* reference counter */
+ void *bc_bcache; /* buffer cache data */
+} bcinfo [MAXBCDEV];
+static int nbcinfo = 0;
+
+#define BC(dev) (bcinfo[(dev)->d_unit])
+
+static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest);
+static int bc_init(void);
+static int bc_strategy(void *devdata, int flag, daddr_t dblk,
+ size_t size, char *buf, size_t *rsize);
+static int bc_realstrategy(void *devdata, int flag, daddr_t dblk,
+ size_t size, char *buf, size_t *rsize);
+static int bc_open(struct open_file *f, ...);
+static int bc_close(struct open_file *f);
+static int bc_print(int verbose);
+
+struct devsw bioscd = {
+ "cd",
+ DEVT_CD,
+ bc_init,
+ bc_strategy,
+ bc_open,
+ bc_close,
+ noioctl,
+ bc_print,
+ NULL
+};
+
+/*
+ * Translate between BIOS device numbers and our private unit numbers.
+ */
+int
+bc_bios2unit(int biosdev)
+{
+ int i;
+
+ DEBUG("looking for bios device 0x%x", biosdev);
+ for (i = 0; i < nbcinfo; i++) {
+ DEBUG("bc unit %d is BIOS device 0x%x", i, bcinfo[i].bc_unit);
+ if (bcinfo[i].bc_unit == biosdev)
+ return(i);
+ }
+ return(-1);
+}
+
+int
+bc_unit2bios(int unit)
+{
+ if ((unit >= 0) && (unit < nbcinfo))
+ return(bcinfo[unit].bc_unit);
+ return(-1);
+}
+
+/*
+ * We can't quiz, we have to be told what device to use, so this functoin
+ * doesn't do anything. Instead, the loader calls bc_add() with the BIOS
+ * device number to add.
+ */
+static int
+bc_init(void)
+{
+
+ return (0);
+}
+
+int
+bc_add(int biosdev)
+{
+
+ if (nbcinfo >= MAXBCDEV)
+ return (-1);
+ bcinfo[nbcinfo].bc_unit = biosdev;
+
+ /* SCSI CD-ROM only */
+ if ((biosdev & 0xf0) != 0xa0)
+ return (-1);
+ if ((((uint32_t *)PTOV(0xA1460))[biosdev & 0x0f] & 0x1f) != 5)
+ return (-1);
+
+ printf("BIOS CD is cd%d\n", nbcinfo);
+ nbcinfo++;
+ bcache_add_dev(nbcinfo); /* register cd device in bcache */
+ return(0);
+}
+
+/*
+ * Print information about disks
+ */
+static int
+bc_print(int verbose)
+{
+ char line[80];
+ int i, ret = 0;
+
+ if (nbcinfo == 0)
+ return (0);
+
+ printf("%s devices:", bioscd.dv_name);
+ if ((ret = pager_output("\n")) != 0)
+ return (ret);
+
+ for (i = 0; i < nbcinfo; i++) {
+ sprintf(line, " cd%d: Device 0x%x\n", i,
+ bcinfo[i].bc_sp.sp_devicespec);
+ if ((ret = pager_output(line)) != 0)
+ break;
+ }
+ return (ret);
+}
+
+/*
+ * Attempt to open the disk described by (dev) for use by (f).
+ */
+static int
+bc_open(struct open_file *f, ...)
+{
+ va_list ap;
+ struct i386_devdesc *dev;
+
+ va_start(ap, f);
+ dev = va_arg(ap, struct i386_devdesc *);
+ va_end(ap);
+ if (dev->d_unit >= nbcinfo) {
+ DEBUG("attempt to open nonexistent disk");
+ return(ENXIO);
+ }
+
+ BC(dev).bc_open++;
+ if (BC(dev).bc_bcache == NULL)
+ BC(dev).bc_bcache = bcache_allocate();
+ return(0);
+}
+
+static int
+bc_close(struct open_file *f)
+{
+ struct i386_devdesc *dev;
+
+ dev = (struct i386_devdesc *)f->f_devdata;
+ BC(dev).bc_open--;
+ if (BC(dev).bc_open == 0) {
+ bcache_free(BC(dev).bc_bcache);
+ BC(dev).bc_bcache = NULL;
+ }
+ return(0);
+}
+
+static int
+bc_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
+ char *buf, size_t *rsize)
+{
+ struct bcache_devdata bcd;
+ struct i386_devdesc *dev;
+
+ dev = (struct i386_devdesc *)devdata;
+ bcd.dv_strategy = bc_realstrategy;
+ bcd.dv_devdata = devdata;
+ bcd.dv_cache = BC(dev).bc_bcache;
+
+ return (bcache_strategy(&bcd, rw, dblk, size, buf, rsize));
+}
+
+static int
+bc_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
+ char *buf, size_t *rsize)
+{
+ struct i386_devdesc *dev;
+ int unit;
+ int blks;
+#ifdef BD_SUPPORT_FRAGS
+ char fragbuf[BIOSCD_SECSIZE];
+ size_t fragsize;
+
+ fragsize = size % BIOSCD_SECSIZE;
+#else
+ if (size % BIOSCD_SECSIZE)
+ return (EINVAL);
+#endif
+
+ if (rw != F_READ)
+ return(EROFS);
+ dev = (struct i386_devdesc *)devdata;
+ unit = dev->d_unit;
+ blks = size / BIOSCD_SECSIZE;
+ if (dblk % (BIOSCD_SECSIZE / DEV_BSIZE) != 0)
+ return (EINVAL);
+ dblk /= (BIOSCD_SECSIZE / DEV_BSIZE);
+ DEBUG("read %d from %lld to %p", blks, dblk, buf);
+
+ if (rsize)
+ *rsize = 0;
+ if (blks && bc_read(unit, dblk, blks, buf)) {
+ DEBUG("read error");
+ return (EIO);
+ }
+#ifdef BD_SUPPORT_FRAGS
+ DEBUG("frag read %d from %lld+%d to %p",
+ fragsize, dblk, blks, buf + (blks * BIOSCD_SECSIZE));
+ if (fragsize && bc_read(unit, dblk + blks, 1, fragbuf)) {
+ DEBUG("frag read error");
+ return(EIO);
+ }
+ bcopy(fragbuf, buf + (blks * BIOSCD_SECSIZE), fragsize);
+#endif
+ if (rsize)
+ *rsize = size;
+ return (0);
+}
+
+/* Max number of sectors to bounce-buffer at a time. */
+#define CD_BOUNCEBUF 8
+
+static int
+bc_read(int unit, daddr_t dblk, int blks, caddr_t dest)
+{
+ u_int maxfer, resid, result, retry, x;
+ caddr_t bbuf, p, xp;
+ int biosdev;
+#ifdef DISK_DEBUG
+ int error;
+#endif
+
+ /* Just in case some idiot actually tries to read -1 blocks... */
+ if (blks < 0)
+ return (-1);
+
+ /* If nothing to do, just return succcess. */
+ if (blks == 0)
+ return (0);
+
+ /* Decide whether we have to bounce */
+ if (VTOP(dest) >> 20 != 0) {
+ /*
+ * The destination buffer is above first 1MB of
+ * physical memory so we have to arrange a suitable
+ * bounce buffer.
+ */
+ x = min(CD_BOUNCEBUF, (unsigned)blks);
+ bbuf = alloca(x * BIOSCD_SECSIZE);
+ maxfer = x;
+ } else {
+ bbuf = NULL;
+ maxfer = 0;
+ }
+
+ biosdev = bc_unit2bios(unit);
+ resid = blks;
+ p = dest;
+
+ while (resid > 0) {
+ if (bbuf)
+ xp = bbuf;
+ else
+ xp = p;
+ x = resid;
+ if (maxfer > 0)
+ x = min(x, maxfer);
+
+ /*
+ * 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) {
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x1b;
+ v86.eax = 0x0300 | biosdev;
+ v86int();
+ }
+
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x1b;
+ v86.eax = 0x0600 | (biosdev & 0x7f);
+ v86.ebx = x * BIOSCD_SECSIZE;
+ v86.ecx = dblk & 0xffff;
+ v86.edx = (dblk >> 16) & 0xffff;
+ v86.ebp = VTOPOFF(xp);
+ v86.es = VTOPSEG(xp);
+ v86int();
+ result = V86_CY(v86.efl);
+ if (result == 0)
+ break;
+ }
+
+#ifdef DISK_DEBUG
+ error = (v86.eax >> 8) & 0xff;
+#endif
+ DEBUG("%d sectors from %lld to %p (0x%x) %s", x, dblk, p,
+ VTOP(p), result ? "failed" : "ok");
+ DEBUG("unit %d status 0x%x", unit, error);
+ if (bbuf != NULL)
+ bcopy(bbuf, p, x * BIOSCD_SECSIZE);
+ p += (x * BIOSCD_SECSIZE);
+ dblk += x;
+ resid -= x;
+ }
+
+/* hexdump(dest, (blks * BIOSCD_SECSIZE)); */
+ return(0);
+}
+
+/*
+ * Return a suitable dev_t value for (dev).
+ */
+int
+bc_getdev(struct i386_devdesc *dev)
+{
+ int biosdev, unit, device;
+ int major;
+ int rootdev;
+
+ unit = dev->d_unit;
+ biosdev = bc_unit2bios(unit);
+ DEBUG("unit %d BIOS device %d", unit, biosdev);
+ if (biosdev == -1) /* not a BIOS device */
+ return(-1);
+
+ device = biosdev & 0xf0;
+ if (device == 0x80)
+ major = ACDMAJOR;
+ else if (device == 0xa0)
+ major = CDMAJOR;
+ else
+ return (-1);
+
+ unit = 0; /* XXX */
+
+ /* XXX: Assume partition 'a'. */
+ rootdev = MAKEBOOTDEV(major, 0, unit, 0);
+ DEBUG("dev is 0x%x\n", rootdev);
+ return(rootdev);
+}
diff --git a/stand/pc98/libpc98/biosdisk.c b/stand/pc98/libpc98/biosdisk.c
new file mode 100644
index 0000000..86a550d
--- /dev/null
+++ b/stand/pc98/libpc98/biosdisk.c
@@ -0,0 +1,1120 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * BIOS disk device handling.
+ *
+ * Ideas and algorithms from:
+ *
+ * - NetBSD libi386/biosdisk.c
+ * - FreeBSD biosboot/disk.c
+ *
+ */
+
+#include <stand.h>
+
+#include <sys/disklabel.h>
+#include <sys/diskpc98.h>
+#include <machine/bootinfo.h>
+
+#include <stdarg.h>
+
+#include <bootstrap.h>
+#include <btxv86.h>
+#include "libi386.h"
+
+#define BIOS_NUMDRIVES 0x475
+#define BIOSDISK_SECSIZE 512
+#define BUFSIZE (1 * BIOSDISK_SECSIZE)
+
+#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" , __func__ , ## 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_MODEINT13 0x0000
+#define BD_MODEEDD1 0x0001
+#define BD_MODEEDD3 0x0002
+#define BD_MODEMASK 0x0003
+#define BD_FLOPPY 0x0004
+#define BD_LABELOK 0x0008
+#define BD_PARTTABOK 0x0010
+#define BD_OPTICAL 0x0020
+ struct disklabel od_disklabel;
+ int od_nslices; /* slice count */
+ struct pc98_partition od_slicetab[PC98_NPARTS];
+};
+
+/*
+ * 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) */
+ int bd_da_unit; /* kernel unit number for da */
+ int bd_open; /* reference counter */
+ void *bd_bcache; /* buffer cache data */
+} bdinfo [MAXBDDEV];
+static int nbdinfo = 0;
+
+#define BD(dev) (bdinfo[(dev)->d_unit])
+
+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_write(struct open_disk *od, daddr_t dblk, int blks,
+ caddr_t dest);
+
+static int bd_int13probe(struct bdinfo *bd);
+
+static int bd_printslice(struct open_disk *od, struct pc98_partition *dp,
+ char *prefix, int verbose);
+static int bd_printbsdslice(struct open_disk *od, daddr_t offset,
+ char *prefix, int verbose);
+
+static int bd_init(void);
+static int bd_strategy(void *devdata, int flag, daddr_t dblk,
+ size_t size, char *buf, size_t *rsize);
+static int bd_realstrategy(void *devdata, int flag, daddr_t dblk,
+ size_t size, char *buf, size_t *rsize);
+static int bd_open(struct open_file *f, ...);
+static int bd_close(struct open_file *f);
+static int bd_print(int verbose);
+
+struct devsw biosdisk = {
+ "disk",
+ DEVT_DISK,
+ bd_init,
+ bd_strategy,
+ bd_open,
+ bd_close,
+ noioctl,
+ bd_print,
+ NULL
+};
+
+static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev);
+static void bd_closedisk(struct open_disk *od);
+static int bd_open_pc98(struct open_disk *od, struct i386_devdesc *dev);
+static int bd_bestslice(struct open_disk *od);
+static void bd_checkextended(struct open_disk *od, int slicenum);
+
+/*
+ * 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.
+ */
+static int
+bd_init(void)
+{
+ int base, unit;
+ int da_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_open = 0;
+ bdinfo[nbdinfo].bd_bcache = NULL;
+ bdinfo[nbdinfo].bd_unit = unit;
+ bdinfo[nbdinfo].bd_flags = (unit & 0xf0) == 0x90 ? BD_FLOPPY : 0;
+
+ if (!bd_int13probe(&bdinfo[nbdinfo])){
+ if (((unit & 0xf0) == 0x90 && (unit & 0x0f) < 4) ||
+ ((unit & 0xf0) == 0xa0 && (unit & 0x0f) < 6))
+ continue; /* Target IDs are not contiguous. */
+ else
+ break;
+ }
+
+ if (bdinfo[nbdinfo].bd_flags & BD_FLOPPY){
+ /* available 1.44MB access? */
+ if (*(u_char *)PTOV(0xA15AE) & (1<<(unit & 0xf))) {
+ /* boot media 1.2MB FD? */
+ if ((*(u_char *)PTOV(0xA1584) & 0xf0) != 0x90)
+ bdinfo[nbdinfo].bd_unit = 0x30 + (unit & 0xf);
+ }
+ }
+ else {
+ if ((unit & 0xF0) == 0xA0) /* SCSI HD or MO */
+ bdinfo[nbdinfo].bd_da_unit = da_drive++;
+ }
+ /* XXX we need "disk aliases" to make this simpler */
+ printf("BIOS drive %c: is disk%d\n",
+ 'A' + nbdinfo, nbdinfo);
+ nbdinfo++;
+ }
+ }
+ bcache_add_dev(nbdinfo);
+ return(0);
+}
+
+/*
+ * Try to detect a device supported by the legacy int13 BIOS
+ */
+static int
+bd_int13probe(struct bdinfo *bd)
+{
+ 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);
+ }
+ if ((bd->bd_unit & 0xF0) == 0xA0) {
+ int media = ((unsigned *)PTOV(0xA1460))[bd->bd_unit & 0x0F] & 0x1F;
+
+ if (media == 7) { /* MO */
+ bd->bd_flags |= BD_MODEINT13 | BD_OPTICAL;
+ return(1);
+ }
+ }
+ return(0);
+}
+
+/*
+ * Print information about disks
+ */
+static int
+bd_print(int verbose)
+{
+ int i, j, ret = 0;
+ char line[80];
+ struct i386_devdesc dev;
+ struct open_disk *od;
+ struct pc98_partition *dptr;
+
+ if (nbdinfo == 0)
+ return (0);
+
+ printf("%s devices:", biosdisk.dv_name);
+ if ((ret = pager_output("\n")) != 0)
+ return (ret);
+
+ for (i = 0; i < nbdinfo; i++) {
+ snprintf(line, sizeof(line), " disk%d: BIOS drive %c:\n",
+ i, 'A' + i);
+ if ((ret = pager_output(line)) != 0)
+ break;
+
+ /* try to open the whole disk */
+ dev.d_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_slicetab[0];
+
+ /* Check for a "dedicated" disk */
+ for (j = 0; j < od->od_nslices; j++) {
+ snprintf(line, sizeof(line), " disk%ds%d", i, j + 1);
+ if ((ret = bd_printslice(od, &dptr[j], line, verbose)) != 0)
+ break;
+ }
+ }
+ bd_closedisk(od);
+ if (ret != 0)
+ break;
+ }
+ }
+ return (ret);
+}
+
+/* Given a size in 512 byte sectors, convert it to a human-readable number. */
+static char *
+display_size(uint64_t size)
+{
+ static char buf[80];
+ char unit;
+
+ size /= 2;
+ unit = 'K';
+ if (size >= 10485760000LL) {
+ size /= 1073741824;
+ unit = 'T';
+ } else if (size >= 10240000) {
+ size /= 1048576;
+ unit = 'G';
+ } else if (size >= 10000) {
+ size /= 1024;
+ unit = 'M';
+ }
+ sprintf(buf, "%6ld%cB", (long)size, unit);
+ return (buf);
+}
+
+/*
+ * Print information about slices on a disk. For the size calculations we
+ * assume a 512 byte sector.
+ */
+static int
+bd_printslice(struct open_disk *od, struct pc98_partition *dp, char *prefix,
+ int verbose)
+{
+ int cylsecs, start, size;
+ char stats[80];
+ char line[80];
+
+ cylsecs = od->od_hds * od->od_sec;
+ start = dp->dp_scyl * cylsecs + dp->dp_shd * od->od_sec + dp->dp_ssect;
+ size = (dp->dp_ecyl - dp->dp_scyl + 1) * cylsecs;
+
+ if (verbose)
+ sprintf(stats, " %s (%d - %d)", display_size(size),
+ start, start + size);
+ else
+ stats[0] = '\0';
+
+ switch(dp->dp_mid & PC98_MID_MASK) {
+ case PC98_MID_386BSD:
+ return (bd_printbsdslice(od, start, prefix, verbose));
+ case 0x00: /* unused partition */
+ return (0);
+ case 0x01:
+ sprintf(line, "%s: FAT-12%s\n", prefix, stats);
+ break;
+ case 0x11:
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ sprintf(line, "%s: FAT-16%s\n", prefix, stats);
+ break;
+ default:
+ sprintf(line, "%s: Unknown fs: 0x%x %s\n", prefix, dp->dp_mid,
+ stats);
+ }
+ return (pager_output(line));
+}
+
+/*
+ * Print out each valid partition in the disklabel of a FreeBSD slice.
+ * For size calculations, we assume a 512 byte sector size.
+ */
+static int
+bd_printbsdslice(struct open_disk *od, daddr_t offset, char *prefix,
+ int verbose)
+{
+ char line[80];
+ char buf[BIOSDISK_SECSIZE];
+ struct disklabel *lp;
+ int i;
+
+ /* read disklabel */
+ if (bd_read(od, offset + LABELSECTOR, 1, buf))
+ return (0);
+ lp =(struct disklabel *)(&buf[0]);
+ if (lp->d_magic != DISKMAGIC) {
+ sprintf(line, "%s: FFS bad disklabel\n", prefix);
+ return (pager_output(line));
+ }
+
+ /* Print partitions */
+ for (i = 0; i < lp->d_npartitions; i++) {
+ /*
+ * For each partition, make sure we know what type of fs it is. If
+ * not, then skip it. However, since floppies often have bogus
+ * fstypes, print the 'a' partition on a floppy even if it is marked
+ * unused.
+ */
+ if ((lp->d_partitions[i].p_fstype == FS_BSDFFS) ||
+ (lp->d_partitions[i].p_fstype == FS_SWAP) ||
+ (lp->d_partitions[i].p_fstype == FS_VINUM) ||
+ ((lp->d_partitions[i].p_fstype == FS_UNUSED) &&
+ (od->od_flags & BD_FLOPPY) && (i == 0))) {
+
+ /* Only print out statistics in verbose mode */
+ if (verbose)
+ sprintf(line, " %s%c: %s %s (%d - %d)\n", prefix, 'a' + i,
+ (lp->d_partitions[i].p_fstype == FS_SWAP) ? "swap " :
+ (lp->d_partitions[i].p_fstype == FS_VINUM) ? "vinum" :
+ "FFS ",
+ display_size(lp->d_partitions[i].p_size),
+ lp->d_partitions[i].p_offset,
+ lp->d_partitions[i].p_offset + lp->d_partitions[i].p_size);
+ else
+ sprintf(line, " %s%c: %s\n", prefix, 'a' + i,
+ (lp->d_partitions[i].p_fstype == FS_SWAP) ? "swap" :
+ (lp->d_partitions[i].p_fstype == FS_VINUM) ? "vinum" :
+ "FFS");
+ if (pager_output(line))
+ return (1);
+ }
+ }
+ return (0);
+}
+
+
+/*
+ * 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);
+
+ BD(dev).bd_open++;
+ if (BD(dev).bd_bcache == NULL)
+ BD(dev).bd_bcache = bcache_allocate();
+
+ /*
+ * 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 open_disk *od;
+ int error;
+
+ if (dev->d_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_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 %d",
+ i386_fmtdev(dev), dev->d_unit,
+ dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition);
+
+ /* Get geometry for this open (removable device may have changed) */
+ if (bd_getgeom(od)) {
+ DEBUG("can't get geometry");
+ error = ENXIO;
+ goto out;
+ }
+
+ /* Determine disk layout. */
+ error = bd_open_pc98(od, dev);
+
+ out:
+ if (error) {
+ free(od);
+ } else {
+ *odp = od; /* return the open disk */
+ }
+ return(error);
+}
+
+static int
+bd_open_pc98(struct open_disk *od, struct i386_devdesc *dev)
+{
+ struct pc98_partition *dptr;
+ struct disklabel *lp;
+ int sector, slice, i;
+ char buf[BUFSIZE];
+
+ /*
+ * 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.
+ */
+ od->od_nslices = 0;
+ if (od->od_flags & BD_FLOPPY) {
+ sector = 0;
+ goto unsliced;
+ }
+ if (bd_read(od, 0, 1, buf)) {
+ DEBUG("error reading MBR");
+ return (EIO);
+ }
+
+ /*
+ * Check the slice table magic.
+ */
+ if (((u_char)buf[0x1fe] != 0x55) || ((u_char)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)");
+ return (ENOENT);
+ }
+ sector = 0;
+ goto unsliced; /* may be a floppy */
+ }
+ if (bd_read(od, 1, 1, buf)) {
+ DEBUG("error reading MBR");
+ return (EIO);
+ }
+
+ /*
+ * copy the partition table, then pick up any extended partitions.
+ */
+ bcopy(buf + PC98_PARTOFF, &od->od_slicetab,
+ sizeof(struct pc98_partition) * PC98_NPARTS);
+ od->od_nslices = PC98_NPARTS; /* extended slices start here */
+ od->od_flags |= BD_PARTTABOK;
+ dptr = &od->od_slicetab[0];
+
+ /* Is this a request for the whole disk? */
+ if (dev->d_kind.biosdisk.slice == -1) {
+ sector = 0;
+ goto unsliced;
+ }
+
+ /*
+ * if a slice number was supplied but not found, this is an error.
+ */
+ if (dev->d_kind.biosdisk.slice > 0) {
+ slice = dev->d_kind.biosdisk.slice - 1;
+ if (slice >= od->od_nslices) {
+ DEBUG("slice %d not found", slice);
+ return (ENOENT);
+ }
+ }
+
+ /* Try to auto-detect the best slice; this should always give a slice number */
+ if (dev->d_kind.biosdisk.slice == 0) {
+ slice = bd_bestslice(od);
+ if (slice == -1) {
+ return (ENOENT);
+ }
+ dev->d_kind.biosdisk.slice = slice;
+ }
+
+ dptr = &od->od_slicetab[0];
+ /*
+ * 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 */
+ 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);
+ }
+
+ /*
+ * If we are looking at a BSD slice, and the partition is < 0, assume the 'a' partition
+ */
+ if ((dptr->dp_mid == DOSMID_386BSD) && (dev->d_kind.biosdisk.partition < 0))
+ 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");
+ return (EIO);
+ }
+ 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");
+ return (ENOENT);
+ }
+ 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);
+ return (EPART);
+ }
+
+#ifdef DISK_DEBUG
+ /* Complain if the partition is unused unless this is a floppy. */
+ if ((lp->d_partitions[dev->d_kind.biosdisk.partition].p_fstype == FS_UNUSED) &&
+ !(od->od_flags & BD_FLOPPY))
+ DEBUG("warning, partition marked as unused");
+#endif
+
+ od->od_boff =
+ lp->d_partitions[dev->d_kind.biosdisk.partition].p_offset -
+ lp->d_partitions[RAW_PART].p_offset +
+ sector;
+ }
+ return (0);
+}
+
+/*
+ * Search for a slice with the following preferences:
+ *
+ * 1: Active FreeBSD slice
+ * 2: Non-active FreeBSD slice
+ * 3: Active Linux slice
+ * 4: non-active Linux slice
+ * 5: Active FAT/FAT32 slice
+ * 6: non-active FAT/FAT32 slice
+ */
+#define PREF_RAWDISK 0
+#define PREF_FBSD_ACT 1
+#define PREF_FBSD 2
+#define PREF_LINUX_ACT 3
+#define PREF_LINUX 4
+#define PREF_DOS_ACT 5
+#define PREF_DOS 6
+#define PREF_NONE 7
+
+/*
+ * slicelimit is in the range 0 .. PC98_NPARTS
+ */
+static int
+bd_bestslice(struct open_disk *od)
+{
+ struct pc98_partition *dp;
+ int pref, preflevel;
+ int i, prefslice;
+
+ prefslice = 0;
+ preflevel = PREF_NONE;
+
+ dp = &od->od_slicetab[0];
+ for (i = 0; i < od->od_nslices; i++, dp++) {
+ switch(dp->dp_mid & PC98_MID_MASK) {
+ case PC98_MID_386BSD: /* FreeBSD */
+ if ((dp->dp_mid & PC98_MID_BOOTABLE) &&
+ (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 ((dp->dp_mid & PC98_MID_BOOTABLE) &&
+ (preflevel > PREF_DOS_ACT)) {
+ pref = i;
+ preflevel = PREF_DOS_ACT;
+ } else if (preflevel > PREF_DOS) {
+ pref = i;
+ preflevel = PREF_DOS;
+ }
+ break;
+ }
+ }
+ return (prefslice);
+}
+
+static int
+bd_close(struct open_file *f)
+{
+ struct i386_devdesc *dev = f->f_devdata;
+ struct open_disk *od = (struct open_disk *)(dev->d_kind.biosdisk.data);
+
+ BD(dev).bd_open--;
+ if (BD(dev).bd_open == 0) {
+ bcache_free(BD(dev).bd_bcache);
+ BD(dev).bd_bcache = NULL;
+ }
+
+ 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,
+ char *buf, size_t *rsize)
+{
+ struct bcache_devdata bcd;
+ struct i386_devdesc *dev = devdata;
+ struct open_disk *od = (struct open_disk *)(dev->d_kind.biosdisk.data);
+
+ bcd.dv_strategy = bd_realstrategy;
+ bcd.dv_devdata = devdata;
+ bcd.dv_cache = BD(dev).bd_bcache;
+ return(bcache_strategy(&bcd, rw, dblk+od->od_boff, size, buf, rsize));
+}
+
+static int
+bd_realstrategy(void *devdata, int rw, daddr_t dblk,
+ size_t size, char *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);
+ blks = size / BIOSDISK_SECSIZE;
+ if (rsize)
+ *rsize = 0;
+
+ switch(rw){
+ case F_READ:
+ DEBUG("read %d from %d to %p", blks, dblk, buf);
+
+ if (blks && bd_read(od, dblk, blks, buf)) {
+ DEBUG("read error");
+ return (EIO);
+ }
+#ifdef BD_SUPPORT_FRAGS
+ DEBUG("bd_strategy: frag read %d from %d+%d to %p",
+ fragsize, dblk, blks, buf + (blks * BIOSDISK_SECSIZE));
+ if (fragsize && bd_read(od, dblk + blks, 1, fragsize)) {
+ DEBUG("frag read error");
+ return(EIO);
+ }
+ bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize);
+#endif
+ break;
+ case F_WRITE :
+ DEBUG("write %d from %d to %p", blks, dblk, buf);
+
+ if (blks && bd_write(od, dblk, blks, buf)) {
+ DEBUG("write error");
+ return (EIO);
+ }
+#ifdef BD_SUPPORT_FRAGS
+ if(fragsize) {
+ DEBUG("Attempted to write a frag");
+ return (EIO);
+ }
+#endif
+ break;
+ default:
+ /* DO NOTHING */
+ return (EROFS);
+ }
+
+ 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_chs_io(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest, int write)
+{
+ u_int x, bpc, cyl, hd, sec;
+
+ bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */
+ 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 */
+
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x1b;
+ if (write)
+ v86.eax = 0x0500 | od->od_unit;
+ else
+ v86.eax = 0x0600 | od->od_unit;
+ if (od->od_flags & BD_FLOPPY) {
+ v86.eax |= 0xd000;
+ v86.ecx = 0x0200 | (cyl & 0xff);
+ v86.edx = (hd << 8) | (sec + 1);
+ } else if (od->od_flags & BD_OPTICAL) {
+ v86.eax &= 0xFF7F;
+ v86.ecx = dblk & 0xFFFF;
+ v86.edx = dblk >> 16;
+ } else {
+ v86.ecx = cyl;
+ v86.edx = (hd << 8) | sec;
+ }
+ v86.ebx = blks * BIOSDISK_SECSIZE;
+ v86.es = VTOPSEG(dest);
+ v86.ebp = VTOPOFF(dest);
+ v86int();
+ return (V86_CY(v86.efl));
+}
+
+static int
+bd_io(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest, int write)
+{
+ u_int x, sec, result, resid, retry, maxfer;
+ caddr_t p, xp, bbuf, breg;
+
+ /* Just in case some idiot actually tries to read/write -1 blocks... */
+ if (blks < 0)
+ return (-1);
+
+ resid = blks;
+ p = dest;
+
+ /* Decide whether we have to bounce */
+ if (VTOP(dest) >> 20 != 0 ||
+ ((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16))) {
+
+ /*
+ * There is a 64k physical boundary somewhere in the
+ * destination buffer, or the destination buffer is above
+ * first 1MB of physical memory 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(od->od_sec, (unsigned)blks);
+ bbuf = alloca(x * 2 * BIOSDISK_SECSIZE);
+ if (((u_int32_t)VTOP(bbuf) & 0xffff0000) ==
+ ((u_int32_t)VTOP(bbuf + x * BIOSDISK_SECSIZE) & 0xffff0000)) {
+ breg = bbuf;
+ } else {
+ breg = bbuf + x * BIOSDISK_SECSIZE;
+ }
+ maxfer = x; /* limit transfers to bounce region size */
+ } else {
+ breg = bbuf = NULL;
+ maxfer = 0;
+ }
+
+ while (resid > 0) {
+ /*
+ * Play it safe and don't cross track boundaries.
+ * (XXX this is probably unnecessary)
+ */
+ sec = dblk % od->od_sec; /* offset into track */
+ 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;
+
+ /*
+ * Put your Data In, Put your Data out,
+ * Put your Data In, and shake it all about
+ */
+ if (write && bbuf != NULL)
+ bcopy(p, breg, x * BIOSDISK_SECSIZE);
+
+ /*
+ * 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) {
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x1b;
+ v86.eax = 0x0300 | od->od_unit;
+ v86int();
+ }
+
+ result = bd_chs_io(od, dblk, x, xp, write);
+ if (result == 0)
+ break;
+ }
+
+ if (write)
+ DEBUG("Write %d sector(s) from %p (0x%x) to %lld %s", x,
+ p, VTOP(p), dblk, result ? "failed" : "ok");
+ else
+ DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x,
+ dblk, p, VTOP(p), result ? "failed" : "ok");
+ if (result) {
+ return(-1);
+ }
+ if (!write && bbuf != NULL)
+ bcopy(breg, p, x * BIOSDISK_SECSIZE);
+ p += (x * BIOSDISK_SECSIZE);
+ dblk += x;
+ resid -= x;
+ }
+
+/* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */
+ return(0);
+}
+
+static int
+bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
+{
+
+ return (bd_io(od, dblk, blks, dest, 0));
+}
+
+static int
+bd_write(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
+{
+
+ return (bd_io(od, dblk, blks, dest, 1));
+}
+
+static int
+bd_getgeom(struct open_disk *od)
+{
+
+ 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 if (od->od_flags & BD_OPTICAL) {
+ od->od_cyl = 0xFFFE;
+ od->od_hds = 8;
+ od->od_sec = 32;
+ } else {
+ v86.ctl = V86_FLAGS;
+ 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;
+ if (V86_CY(v86.efl))
+ return(1);
+ }
+
+ DEBUG("unit 0x%x geometry %d/%d/%d", od->od_unit, od->od_cyl, od->od_hds, od->od_sec);
+ return(0);
+}
+
+/*
+ * Return the BIOS geometry of a given "fixed drive" in a format
+ * suitable for the legacy bootinfo structure. Since the kernel is
+ * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we
+ * prefer to get the information directly, rather than rely on being
+ * able to put it together from information already maintained for
+ * different purposes and for a probably different number of drives.
+ *
+ * For valid drives, the geometry is expected in the format (31..0)
+ * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are
+ * indicated by returning the geometry of a "1.2M" PC-format floppy
+ * disk. And, incidentally, what is returned is not the geometry as
+ * such but the highest valid cylinder, head, and sector numbers.
+ */
+u_int32_t
+bd_getbigeom(int bunit)
+{
+ int hds = 0;
+ int unit = 0x80; /* IDE HDD */
+ u_int addr = 0xA155d;
+
+ while (unit < 0xa7) {
+ if (*(u_char *)PTOV(addr) & (1 << (unit & 0x0f)))
+ if (hds++ == bunit)
+ break;
+
+ if (unit >= 0xA0) {
+ int media = ((unsigned *)PTOV(0xA1460))[unit & 0x0F] & 0x1F;
+
+ if (media == 7 && hds++ == bunit) /* SCSI MO */
+ return(0xFFFE0820); /* C:65535 H:8 S:32 */
+ }
+ if (++unit == 0x84) {
+ unit = 0xA0; /* SCSI HDD */
+ addr = 0xA1482;
+ }
+ }
+ if (unit == 0xa7)
+ return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x1b;
+ v86.eax = 0x8400 | unit;
+ v86int();
+ if (V86_CY(v86.efl))
+ return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */
+ return ((v86.ecx & 0xffff) << 16) | (v86.edx & 0xffff);
+}
+
+/*
+ * 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_unit);
+ DEBUG("unit %d BIOS device %d", dev->d_unit, biosdev);
+ if (biosdev == -1) /* not a BIOS device */
+ return(-1);
+ if (bd_opendisk(&od, dev) != 0) /* oops, not a viable device */
+ return(-1);
+
+ if ((biosdev & 0xf0) == 0x90 || (biosdev & 0xf0) == 0x30) {
+ /* floppy (or emulated floppy) or ATAPI device */
+ if (bdinfo[dev->d_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;
+ }
+ }
+ /* default root disk unit number */
+ if ((biosdev & 0xf0) == 0xa0)
+ unit = bdinfo[dev->d_unit].bd_da_unit;
+ else
+ unit = biosdev & 0xf;
+
+ /* 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;
+ }
+
+ rootdev = MAKEBOOTDEV(major, dev->d_kind.biosdisk.slice + 1, unit,
+ dev->d_kind.biosdisk.partition);
+ DEBUG("dev is 0x%x\n", rootdev);
+ return(rootdev);
+}
diff --git a/stand/pc98/libpc98/biosmem.c b/stand/pc98/libpc98/biosmem.c
new file mode 100644
index 0000000..c5a9b30
--- /dev/null
+++ b/stand/pc98/libpc98/biosmem.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Obtain memory configuration information from the BIOS
+ */
+#include <stand.h>
+#include "libi386.h"
+#include "btxv86.h"
+
+vm_offset_t memtop, memtop_copyin, high_heap_base;
+uint32_t bios_basemem, bios_extmem, high_heap_size;
+
+/*
+ * The minimum amount of memory to reserve in bios_extmem for the heap.
+ */
+#define HEAP_MIN (64 * 1024 * 1024)
+
+void
+bios_getmem(void)
+{
+
+ bios_basemem = ((*(u_char *)PTOV(0xA1501) & 0x07) + 1) * 128 * 1024;
+ bios_extmem = *(u_char *)PTOV(0xA1401) * 128 * 1024 +
+ *(u_int16_t *)PTOV(0xA1594) * 1024 * 1024;
+
+ /* Set memtop to actual top of memory */
+ memtop = memtop_copyin = 0x100000 + bios_extmem;
+
+ /*
+ * If we have extended memory, use the last 3MB of 'extended' memory
+ * as a high heap candidate.
+ */
+ if (bios_extmem >= HEAP_MIN) {
+ high_heap_size = HEAP_MIN;
+ high_heap_base = memtop - HEAP_MIN;
+ }
+}
diff --git a/stand/pc98/libpc98/biossmap.c b/stand/pc98/libpc98/biossmap.c
new file mode 100644
index 0000000..5a7a89f
--- /dev/null
+++ b/stand/pc98/libpc98/biossmap.c
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2006 TAKAHASHI Yoshihiro <nyan@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <sys/param.h>
+#include "libi386.h"
+
+void
+bios_addsmapdata(struct preloaded_file *kfp)
+{
+
+}
diff --git a/stand/pc98/libpc98/comconsole.c b/stand/pc98/libpc98/comconsole.c
new file mode 100644
index 0000000..1bf2d6a
--- /dev/null
+++ b/stand/pc98/libpc98/comconsole.c
@@ -0,0 +1,367 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <bootstrap.h>
+#include <machine/cpufunc.h>
+#include <dev/ic/ns16550.h>
+#include <dev/pci/pcireg.h>
+#include "libi386.h"
+
+#define COMC_FMT 0x3 /* 8N1 */
+#define COMC_TXWAIT 0x40000 /* transmit timeout */
+#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */
+#define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */
+
+#ifndef COMPORT
+#define COMPORT 0x238
+#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_getspeed(void);
+static int comc_ischar(void);
+static int comc_parseint(const char *string);
+static uint32_t comc_parse_pcidev(const char *string);
+static int comc_pcidev_set(struct env_var *ev, int flags,
+ const void *value);
+static int comc_pcidev_handle(uint32_t locator);
+static int comc_port_set(struct env_var *ev, int flags,
+ const void *value);
+static void comc_setup(int speed, int port);
+static int comc_speed_set(struct env_var *ev, int flags,
+ const void *value);
+
+static int comc_curspeed;
+static int comc_port = COMPORT;
+static uint32_t comc_locator;
+
+struct console comconsole = {
+ "comconsole",
+ "serial port",
+ 0,
+ comc_probe,
+ comc_init,
+ comc_putchar,
+ comc_getchar,
+ comc_ischar
+};
+
+static void
+comc_probe(struct console *cp)
+{
+ char intbuf[16];
+ char *cons, *env;
+ int speed, port;
+ uint32_t locator;
+
+ if (comc_curspeed == 0) {
+ comc_curspeed = COMSPEED;
+ /*
+ * Assume that the speed was set by an earlier boot loader if
+ * comconsole is already the preferred console.
+ */
+ cons = getenv("console");
+ if ((cons != NULL && strcmp(cons, comconsole.c_name) == 0) ||
+ getenv("boot_multicons") != NULL) {
+ comc_curspeed = comc_getspeed();
+ }
+
+ env = getenv("comconsole_speed");
+ if (env != NULL) {
+ speed = comc_parseint(env);
+ if (speed > 0)
+ comc_curspeed = speed;
+ }
+
+ sprintf(intbuf, "%d", comc_curspeed);
+ unsetenv("comconsole_speed");
+ env_setenv("comconsole_speed", EV_VOLATILE, intbuf, comc_speed_set,
+ env_nounset);
+
+ env = getenv("comconsole_port");
+ if (env != NULL) {
+ port = comc_parseint(env);
+ if (port > 0)
+ comc_port = port;
+ }
+
+ sprintf(intbuf, "%d", comc_port);
+ unsetenv("comconsole_port");
+ env_setenv("comconsole_port", EV_VOLATILE, intbuf, comc_port_set,
+ env_nounset);
+
+ env = getenv("comconsole_pcidev");
+ if (env != NULL) {
+ locator = comc_parse_pcidev(env);
+ if (locator != 0)
+ comc_pcidev_handle(locator);
+ }
+
+ unsetenv("comconsole_pcidev");
+ env_setenv("comconsole_pcidev", EV_VOLATILE, env, comc_pcidev_set,
+ env_nounset);
+ }
+ comc_setup(comc_curspeed, comc_port);
+}
+
+static int
+comc_init(int arg)
+{
+
+ comc_setup(comc_curspeed, comc_port);
+
+ if ((comconsole.c_flags & (C_PRESENTIN | C_PRESENTOUT)) ==
+ (C_PRESENTIN | C_PRESENTOUT))
+ return (CMD_OK);
+ return (CMD_ERROR);
+}
+
+static void
+comc_putchar(int c)
+{
+ int wait;
+
+ for (wait = COMC_TXWAIT; wait > 0; wait--)
+ if (inb(comc_port + com_lsr) & LSR_TXRDY) {
+ outb(comc_port + com_data, (u_char)c);
+ break;
+ }
+}
+
+static int
+comc_getchar(void)
+{
+ return (comc_ischar() ? inb(comc_port + com_data) : -1);
+}
+
+static int
+comc_ischar(void)
+{
+ return (inb(comc_port + com_lsr) & LSR_RXRDY);
+}
+
+static int
+comc_speed_set(struct env_var *ev, int flags, const void *value)
+{
+ int speed;
+
+ if (value == NULL || (speed = comc_parseint(value)) <= 0) {
+ printf("Invalid speed\n");
+ return (CMD_ERROR);
+ }
+
+ if (comc_curspeed != speed)
+ comc_setup(speed, comc_port);
+
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+
+ return (CMD_OK);
+}
+
+static int
+comc_port_set(struct env_var *ev, int flags, const void *value)
+{
+ int port;
+
+ if (value == NULL || (port = comc_parseint(value)) <= 0) {
+ printf("Invalid port\n");
+ return (CMD_ERROR);
+ }
+
+ if (comc_port != port)
+ comc_setup(comc_curspeed, port);
+
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+
+ return (CMD_OK);
+}
+
+/*
+ * Input: bus:dev:func[:bar]. If bar is not specified, it is 0x10.
+ * Output: bar[24:16] bus[15:8] dev[7:3] func[2:0]
+ */
+static uint32_t
+comc_parse_pcidev(const char *string)
+{
+ char *p, *p1;
+ uint8_t bus, dev, func, bar;
+ uint32_t locator;
+ int pres;
+
+ pres = strtol(string, &p, 0);
+ if (p == string || *p != ':' || pres < 0 )
+ return (0);
+ bus = pres;
+ p1 = ++p;
+
+ pres = strtol(p1, &p, 0);
+ if (p == string || *p != ':' || pres < 0 )
+ return (0);
+ dev = pres;
+ p1 = ++p;
+
+ pres = strtol(p1, &p, 0);
+ if (p == string || (*p != ':' && *p != '\0') || pres < 0 )
+ return (0);
+ func = pres;
+
+ if (*p == ':') {
+ p1 = ++p;
+ pres = strtol(p1, &p, 0);
+ if (p == string || *p != '\0' || pres <= 0 )
+ return (0);
+ bar = pres;
+ } else
+ bar = 0x10;
+
+ locator = (bar << 16) | biospci_locator(bus, dev, func);
+ return (locator);
+}
+
+static int
+comc_pcidev_handle(uint32_t locator)
+{
+ char intbuf[64];
+ uint32_t port;
+
+ if (biospci_read_config(locator & 0xffff,
+ (locator & 0xff0000) >> 16, 2, &port) == -1) {
+ printf("Cannot read bar at 0x%x\n", locator);
+ return (CMD_ERROR);
+ }
+ if (!PCI_BAR_IO(port)) {
+ printf("Memory bar at 0x%x\n", locator);
+ return (CMD_ERROR);
+ }
+ port &= PCIM_BAR_IO_BASE;
+
+ sprintf(intbuf, "%d", port);
+ unsetenv("comconsole_port");
+ env_setenv("comconsole_port", EV_VOLATILE, intbuf,
+ comc_port_set, env_nounset);
+
+ comc_setup(comc_curspeed, port);
+ comc_locator = locator;
+
+ return (CMD_OK);
+}
+
+static int
+comc_pcidev_set(struct env_var *ev, int flags, const void *value)
+{
+ uint32_t locator;
+ int error;
+
+ if (value == NULL || (locator = comc_parse_pcidev(value)) <= 0) {
+ printf("Invalid pcidev\n");
+ return (CMD_ERROR);
+ }
+ if ((comconsole.c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) != 0 &&
+ comc_locator != locator) {
+ error = comc_pcidev_handle(locator);
+ if (error != CMD_OK)
+ return (error);
+ }
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ return (CMD_OK);
+}
+
+static void
+comc_setup(int speed, int port)
+{
+ static int TRY_COUNT = 1000000;
+ char intbuf[64];
+ int tries;
+
+ unsetenv("hw.uart.console");
+ comc_curspeed = speed;
+ comc_port = port;
+ if ((comconsole.c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) == 0)
+ return;
+
+ outb(comc_port + com_cfcr, CFCR_DLAB | COMC_FMT);
+ outb(comc_port + com_dlbl, COMC_BPS(speed) & 0xff);
+ outb(comc_port + com_dlbh, COMC_BPS(speed) >> 8);
+ outb(comc_port + com_cfcr, COMC_FMT);
+ outb(comc_port + com_mcr, MCR_RTS | MCR_DTR);
+
+ tries = 0;
+ do
+ inb(comc_port + com_data);
+ while (inb(comc_port + com_lsr) & LSR_RXRDY && ++tries < TRY_COUNT);
+
+ if (tries < TRY_COUNT) {
+ comconsole.c_flags |= (C_PRESENTIN | C_PRESENTOUT);
+ sprintf(intbuf, "io:%d,br:%d", comc_port, comc_curspeed);
+ env_setenv("hw.uart.console", EV_VOLATILE, intbuf, NULL, NULL);
+ } else
+ comconsole.c_flags &= ~(C_PRESENTIN | C_PRESENTOUT);
+}
+
+static int
+comc_parseint(const char *speedstr)
+{
+ char *p;
+ int speed;
+
+ speed = strtol(speedstr, &p, 0);
+ if (p == speedstr || *p != '\0' || speed <= 0)
+ return (-1);
+
+ return (speed);
+}
+
+static int
+comc_getspeed(void)
+{
+ u_int divisor;
+ u_char dlbh;
+ u_char dlbl;
+ u_char cfcr;
+
+ cfcr = inb(comc_port + com_cfcr);
+ outb(comc_port + com_cfcr, CFCR_DLAB | cfcr);
+
+ dlbl = inb(comc_port + com_dlbl);
+ dlbh = inb(comc_port + com_dlbh);
+
+ outb(comc_port + com_cfcr, cfcr);
+
+ divisor = dlbh << 8 | dlbl;
+
+ /* XXX there should be more sanity checking. */
+ if (divisor == 0)
+ return (COMSPEED);
+ return (COMC_DIV2BPS(divisor));
+}
diff --git a/stand/pc98/libpc98/libpc98.h b/stand/pc98/libpc98/libpc98.h
new file mode 100644
index 0000000..78b07a1
--- /dev/null
+++ b/stand/pc98/libpc98/libpc98.h
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (c) 2009 TAKAHASHI Yoshihiro <nyan@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+void set_machine_type(void);
diff --git a/stand/pc98/libpc98/pc98_sys.c b/stand/pc98/libpc98/pc98_sys.c
new file mode 100644
index 0000000..7f66d02
--- /dev/null
+++ b/stand/pc98/libpc98/pc98_sys.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2009 TAKAHASHI Yoshihiro <nyan@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <btxv86.h>
+#include <machine/cpufunc.h>
+#define _KERNEL
+#include <pc98/pc98/pc98_machdep.h>
+
+/*
+ * Set machine type to PC98_SYSTEM_PARAMETER.
+ */
+void
+set_machine_type(void)
+{
+ int i;
+ u_long ret, data;
+
+ /* PC98_SYSTEM_PARAMETER (0x501) */
+ ret = ((*(u_char *)PTOV(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) */
+ for (i = data = 0; i < 4; i++)
+ data += *((u_long *)PTOV(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 ((*(u_char *)PTOV(0xA1400)) & 0x80)
+ ret |= M_NOTE;
+ if (ret & M_NEC_PC98) {
+ /* PC98_SYSTEM_PARAMETER(0x458) */
+ if ((*(u_char *)PTOV(0xA1458)) & 0x80)
+ ret |= M_H98;
+ else
+ ret |= M_NOT_H98;
+ } else
+ ret |= M_NOT_H98;
+
+ (*(u_long *)PTOV(0xA1620)) = ret;
+}
diff --git a/stand/pc98/libpc98/time.c b/stand/pc98/libpc98/time.c
new file mode 100644
index 0000000..5d832bb
--- /dev/null
+++ b/stand/pc98/libpc98/time.c
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <btxv86.h>
+#include <machine/cpufunc.h>
+#include "bootstrap.h"
+#include "libi386.h"
+
+static int bios_seconds(void);
+
+/*
+ * Return the BIOS time-of-day value.
+ *
+ * XXX uses undocumented BCD support from libstand.
+ */
+static int
+bios_seconds(void)
+{
+ int hr, minute, sec;
+ unsigned char bios_time[6];
+
+ v86.ctl = 0;
+ v86.addr = 0x1c; /* int 0x1c, function 0 */
+ v86.eax = 0x0000;
+ v86.es = VTOPSEG(bios_time);
+ v86.ebx = VTOPOFF(bios_time);
+ v86int();
+
+ hr = bcd2bin(bios_time[3]);
+ minute = bcd2bin(bios_time[4]);
+ sec = bcd2bin(bios_time[5]);
+
+ return (hr * 3600 + minute * 60 + sec);
+}
+
+/*
+ * Return the time in seconds since the beginning of the day.
+ */
+time_t
+time(time_t *t)
+{
+ static time_t lasttime;
+ time_t now;
+
+ now = bios_seconds();
+
+ 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)
+{
+ int i;
+
+ period = (period + 500) / 1000;
+ for( ; period != 0 ; period--)
+ for(i=800;i != 0; i--)
+ outb(0x5f,0); /* wait 600ns */
+}
diff --git a/stand/pc98/libpc98/vidconsole.c b/stand/pc98/libpc98/vidconsole.c
new file mode 100644
index 0000000..7cf81e8
--- /dev/null
+++ b/stand/pc98/libpc98/vidconsole.c
@@ -0,0 +1,596 @@
+/*-
+ * 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.
+ *
+ * Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <bootstrap.h>
+#include <btxv86.h>
+#include <machine/cpufunc.h>
+#include "libi386.h"
+
+#if KEYBOARD_PROBE
+#include <machine/cpufunc.h>
+
+static int probe_keyboard(void);
+#endif
+static void vidc_probe(struct console *cp);
+static int vidc_init(int arg);
+static void vidc_putchar(int c);
+static int vidc_getchar(void);
+static int vidc_ischar(void);
+
+static int vidc_started;
+
+#ifdef TERM_EMU
+#define MAXARGS 8
+#define DEFAULT_FGCOLOR 7
+#define DEFAULT_BGCOLOR 0
+
+void end_term(void);
+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 CD(void);
+void CM(void);
+void HO(void);
+
+static int args[MAXARGS], argc;
+static int fg_c, bg_c, curx, cury;
+static int esc;
+#endif
+
+static unsigned short *crtat, *Crtat;
+static int row = 25, col = 80;
+#ifdef TERM_EMU
+static u_int8_t ibmpc_to_pc98[256] = {
+ 0x01, 0x21, 0x81, 0xa1, 0x41, 0x61, 0xc1, 0xe1,
+ 0x09, 0x29, 0x89, 0xa9, 0x49, 0x69, 0xc9, 0xe9,
+ 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
+ 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
+ 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
+ 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
+ 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
+ 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
+ 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
+ 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
+ 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
+
+ 0x03, 0x23, 0x83, 0xa3, 0x43, 0x63, 0xc3, 0xe3,
+ 0x0b, 0x2b, 0x8b, 0xab, 0x4b, 0x6b, 0xcb, 0xeb,
+ 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+ 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+ 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+ 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+ 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+ 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+ 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
+ 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
+ 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
+ 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
+ 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
+ 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
+};
+#define at2pc98(fg_at, bg_at) ibmpc_to_pc98[((bg_at) << 4) | (fg_at)]
+#endif /* TERM_EMU */
+
+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, hw_cursor;
+
+ if (vidc_started && arg == 0)
+ return (0);
+ vidc_started = 1;
+ 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;
+#ifdef TERM_EMU
+ /* Init terminal emulator */
+ end_term();
+ get_pos();
+ curs_move(curx, cury);
+ fg_c = DEFAULT_FGCOLOR;
+ bg_c = DEFAULT_BGCOLOR;
+#endif
+ for (i = 0; i < 10 && vidc_ischar(); i++)
+ (void)vidc_getchar();
+ return (0); /* XXX reinit? */
+}
+
+static void
+beep(void)
+{
+
+ outb(0x37, 6);
+ delay(40000);
+ outb(0x37, 7);
+}
+
+#if 0
+static void
+vidc_biosputchar(int c)
+{
+ 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
+}
+#endif
+
+static void
+vidc_rawputchar(int c)
+{
+ int i;
+
+ if (c == '\t')
+ /* lame tab expansion */
+ for (i = 0; i < 8; i++)
+ vidc_rawputchar(' ');
+ else {
+ /* Emulate AH=0eh (teletype output) */
+ switch(c) {
+ case '\a':
+ beep();
+ 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);
+ }
+}
+
+#ifdef TERM_EMU
+
+/* Get cursor position on the screen. Result is in edx. Sets
+ * curx and cury appropriately.
+ */
+void
+get_pos(void)
+{
+ int pos = crtat - Crtat;
+
+ curx = pos % col;
+ cury = pos / col;
+}
+
+/* Move cursor to x rows and y cols (0-based). */
+void
+curs_move(int x, int y)
+{
+ 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);
+ }
+}
+
+/* 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 fgcol, int bgcol)
+{
+ 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(fgcol, bgcol);
+ *cp++ = ' ';
+ }
+}
+
+/* Write character and attribute at cursor position. */
+void
+write_char(int c, int fgcol, int bgcol)
+{
+
+ *crtat = (c == 0x5c ? 0xfc : (c & 0xff));
+ *(crtat + 0x1000) = at2pc98(fgcol, bgcol);
+}
+
+/**************************************************************/
+/*
+ * Screen manipulation functions. They use accumulated data in
+ * args[] and argc variables.
+ *
+ */
+
+/* Clear display from current position to end of screen */
+void
+CD(void)
+{
+ int pos;
+
+ get_pos();
+ for (pos = 0; crtat + pos <= Crtat + col * row; pos++) {
+ *(crtat + pos) = ' ';
+ *(crtat + pos + 0x1000) = at2pc98(fg_c, bg_c);
+ }
+ 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();
+}
+
+/* Clear internal state of the terminal emulation code */
+void
+end_term(void)
+{
+
+ esc = 0;
+ argc = -1;
+}
+
+/* Gracefully exit ESC-sequence processing in case of misunderstanding */
+void
+bail_out(int c)
+{
+ char buf[16], *ch;
+ int i;
+
+ if (esc) {
+ vidc_rawputchar('\033');
+ if (esc != '\033')
+ vidc_rawputchar(esc);
+ for (i = 0; i <= argc; ++i) {
+ sprintf(buf, "%d", args[i]);
+ ch = buf;
+ while (*ch)
+ vidc_rawputchar(*ch++);
+ }
+ }
+ vidc_rawputchar(c);
+ end_term();
+}
+
+static void
+get_arg(int c)
+{
+
+ if (argc < 0)
+ argc = 0;
+ args[argc] *= 10;
+ args[argc] += c - '0';
+}
+
+/* Emulate basic capabilities of cons25 terminal */
+void
+vidc_term_emu(int c)
+{
+ static int ansi_col[] = {
+ 0, 4, 2, 6, 1, 5, 3, 7,
+ };
+ int t;
+ int i;
+
+ switch (esc) {
+ case 0:
+ switch (c) {
+ case '\033':
+ esc = c;
+ break;
+ default:
+ vidc_rawputchar(c);
+ break;
+ }
+ break;
+
+ case '\033':
+ switch (c) {
+ case '[':
+ esc = c;
+ args[0] = 0;
+ argc = -1;
+ break;
+ default:
+ bail_out(c);
+ break;
+ }
+ break;
+
+ case '[':
+ switch (c) {
+ case ';':
+ if (argc < 0) /* XXX */
+ argc = 0;
+ else if (argc + 1 >= MAXARGS)
+ bail_out(c);
+ else
+ args[++argc] = 0;
+ break;
+ case 'H':
+ if (argc < 0)
+ HO();
+ else if (argc == 1)
+ CM();
+ else
+ bail_out(c);
+ break;
+ case 'J':
+ if (argc < 0)
+ CD();
+ else
+ bail_out(c);
+ break;
+ case 'm':
+ if (argc < 0) {
+ fg_c = DEFAULT_FGCOLOR;
+ bg_c = DEFAULT_BGCOLOR;
+ }
+ for (i = 0; i <= argc; ++i) {
+ switch (args[i]) {
+ case 0: /* back to normal */
+ fg_c = DEFAULT_FGCOLOR;
+ bg_c = DEFAULT_BGCOLOR;
+ break;
+ case 1: /* bold */
+ fg_c |= 0x8;
+ break;
+ case 4: /* underline */
+ case 5: /* blink */
+ bg_c |= 0x8;
+ break;
+ case 7: /* reverse */
+ t = fg_c;
+ fg_c = bg_c;
+ bg_c = t;
+ break;
+ case 30: case 31: case 32: case 33:
+ case 34: case 35: case 36: case 37:
+ fg_c = ansi_col[args[i] - 30];
+ break;
+ case 39: /* normal */
+ fg_c = DEFAULT_FGCOLOR;
+ break;
+ case 40: case 41: case 42: case 43:
+ case 44: case 45: case 46: case 47:
+ bg_c = ansi_col[args[i] - 40];
+ break;
+ case 49: /* normal */
+ bg_c = DEFAULT_BGCOLOR;
+ break;
+ }
+ }
+ end_term();
+ break;
+ default:
+ if (isdigit(c))
+ get_arg(c);
+ else
+ bail_out(c);
+ break;
+ }
+ break;
+
+ default:
+ 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;
+ v86.addr = 0x18;
+ v86.eax = 0x0;
+ v86int();
+ return (v86.eax & 0xff);
+ } else {
+ return (-1);
+ }
+}
+
+static int
+vidc_ischar(void)
+{
+
+ v86.ctl = 0;
+ v86.addr = 0x18;
+ v86.eax = 0x100;
+ v86int();
+ return ((v86.ebx >> 8) & 0x1);
+}
+
+#if KEYBOARD_PROBE
+static int
+probe_keyboard(void)
+{
+ return (*(u_char *)PTOV(0xA1481) & 0x48);
+}
+#endif /* KEYBOARD_PROBE */
diff --git a/stand/pc98/loader/Makefile b/stand/pc98/loader/Makefile
new file mode 100644
index 0000000..d75e8d0
--- /dev/null
+++ b/stand/pc98/loader/Makefile
@@ -0,0 +1,99 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+MK_SSP= no
+MAN=
+
+LOADER?= loader
+PROG= ${LOADER}.sym
+INTERNALPROG=
+NEWVERSWHAT= "bootstrap loader" pc98
+VERSION_FILE= ${.CURDIR}/../../i386/loader/version
+
+# architecture-specific loader code
+SRCS= main.c conf.c vers.c
+.PATH: ${.CURDIR}/../../i386/loader
+
+# Enable PXE TFTP or NFS support, not both.
+.if defined(LOADER_TFTP_SUPPORT)
+CFLAGS+= -DLOADER_TFTP_SUPPORT
+.else
+CFLAGS+= -DLOADER_NFS_SUPPORT
+.endif
+
+# Include bcache code.
+HAVE_BCACHE= yes
+
+# Enable PnP and ISA-PnP code.
+HAVE_PNP= yes
+HAVE_ISABUS= yes
+
+.if ${MK_FORTH} != "no"
+# Enable BootForth
+BOOT_FORTH= yes
+CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/i386
+LIBFICL= ${.OBJDIR}/../../ficl/libficl.a
+.endif
+
+.if defined(LOADER_BZIP2_SUPPORT)
+CFLAGS+= -DLOADER_BZIP2_SUPPORT
+.endif
+.if !defined(LOADER_NO_GZIP_SUPPORT)
+CFLAGS+= -DLOADER_GZIP_SUPPORT
+.endif
+
+# Always add MI sources
+.PATH: ${.CURDIR}/../../common
+.include "${.CURDIR}/../../common/Makefile.inc"
+CFLAGS+= -I${.CURDIR}/../../common
+CFLAGS+= -I${.CURDIR}/../../i386
+CFLAGS+= -I.
+
+CLEANFILES= ${LOADER} ${LOADER}.bin loader.help
+
+CFLAGS+= -Wall
+LDFLAGS= -static -Ttext 0x0
+
+# pc98 standalone support library
+LIBPC98= ${.OBJDIR}/../libpc98/libpc98.a
+CFLAGS+= -I${.CURDIR}/..
+
+LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a
+
+# BTX components
+CFLAGS+= -I${.CURDIR}/../btx/lib
+
+# Debug me!
+#CFLAGS+= -g
+#LDFLAGS+= -g
+
+# Pick up ../Makefile.inc early.
+.include <bsd.init.mk>
+
+${LOADER}: ${LOADER}.bin ${BTXLDR} ${BTXKERN}
+ btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \
+ -b ${BTXKERN} ${LOADER}.bin
+
+${LOADER}.bin: ${LOADER}.sym
+ cp ${.ALLSRC} ${.TARGET}
+ strip -R .comment -R .note ${.TARGET}
+
+loader.help: help.common help.pc98
+ cat ${.ALLSRC} | awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET}
+
+FILES= ${LOADER}
+# XXX INSTALLFLAGS_loader= -b
+FILESMODE_${LOADER}= ${BINMODE} -b
+
+.PATH: ${.CURDIR}/../../forth
+.include "${.CURDIR}/../../forth/Makefile.inc"
+
+FILES+= ${.CURDIR}/../../i386/loader/loader.rc menu.rc
+
+# XXX crt0.o needs to be first for pxeboot(8) to work
+OBJS= ${BTXCRT}
+
+DPADD= ${LIBFICL} ${LIBPC98} ${LIBSTAND}
+LDADD= ${LIBFICL} ${LIBPC98} ${LIBSTAND}
+
+.include <bsd.prog.mk>
diff --git a/stand/pc98/loader/conf.c b/stand/pc98/loader/conf.c
new file mode 100644
index 0000000..695c260
--- /dev/null
+++ b/stand/pc98/loader/conf.c
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <bootstrap.h>
+#include "libi386/libi386.h"
+
+/*
+ * We could use linker sets for some or all of these, but
+ * then we would have to control what ended up linked into
+ * the bootstrap. So it's easier to conditionalise things
+ * here.
+ *
+ * XXX rename these arrays to be consistent and less namespace-hostile
+ *
+ * XXX as libi386 and biosboot merge, some of these can become linker sets.
+ */
+
+/* Exported for libstand */
+struct devsw *devsw[] = {
+ &bioscd,
+ &biosdisk,
+#if defined(LOADER_NFS_SUPPORT) || defined(LOADER_TFTP_SUPPORT)
+ &pxedisk,
+#endif
+ NULL
+};
+
+struct fs_ops *file_system[] = {
+ &ufs_fsops,
+ &ext2fs_fsops,
+ &dosfs_fsops,
+ &cd9660_fsops,
+#ifdef LOADER_NFS_SUPPORT
+ &nfs_fsops,
+#endif
+#ifdef LOADER_TFTP_SUPPORT
+ &tftp_fsops,
+#endif
+#ifdef LOADER_GZIP_SUPPORT
+ &gzipfs_fsops,
+#endif
+#ifdef LOADER_BZIP2_SUPPORT
+ &bzipfs_fsops,
+#endif
+ &splitfs_fsops,
+ NULL
+};
+
+/* Exported for i386 only */
+/*
+ * Sort formats so that those that can detect based on arguments
+ * rather than reading the file go first.
+ */
+extern struct file_format i386_elf;
+extern struct file_format i386_elf_obj;
+
+struct file_format *file_formats[] = {
+ &i386_elf,
+ &i386_elf_obj,
+ NULL
+};
+
+/*
+ * Consoles
+ *
+ * We don't prototype these in libi386.h because they require
+ * data structures from bootstrap.h as well.
+ */
+extern struct console vidconsole;
+extern struct console comconsole;
+extern struct console nullconsole;
+
+struct console *consoles[] = {
+ &vidconsole,
+ &comconsole,
+ &nullconsole,
+ NULL
+};
+
+extern struct pnphandler isapnphandler;
+extern struct pnphandler biospnphandler;
+extern struct pnphandler biospcihandler;
+
+struct pnphandler *pnphandlers[] = {
+ &biospnphandler, /* should go first, as it may set isapnp_readport */
+ &isapnphandler,
+ &biospcihandler,
+ NULL
+};
diff --git a/stand/pc98/loader/help.pc98 b/stand/pc98/loader/help.pc98
new file mode 100644
index 0000000..4b9197c
--- /dev/null
+++ b/stand/pc98/loader/help.pc98
@@ -0,0 +1,38 @@
+################################################################################
+# Treboot DReboot the system
+
+ reboot
+
+ Causes the system to immediately reboot.
+
+################################################################################
+# Theap DDisplay memory management statistics
+
+ heap
+
+ Requests debugging output from the heap manager. For debugging use
+ only.
+
+################################################################################
+# Tset Snum_ide_disks DSet the number of IDE disks
+
+ NOTE: this variable is deprecated, use root_disk_unit instead.
+
+ set num_ide_disks=<value>
+
+ When booting from a SCSI disk on a system with one or more IDE disks,
+ and where the IDE disks are the default boot device, it is necessary
+ to tell the kernel how many IDE disks there are in order to have it
+ correctly locate the SCSI disk you are booting from.
+
+################################################################################
+# Tset Sroot_disk_unit DForce the root disk unit number.
+
+ set root_disk_unit=<value>
+
+ If the code which detects the disk unit number for the root disk is
+ confused, eg. by a mix of SCSI and IDE disks, or IDE disks with
+ gaps in the sequence (eg. no primary slave), the unit number can be
+ forced by setting this variable.
+
+################################################################################
diff --git a/stand/pc98/loader/main.c b/stand/pc98/loader/main.c
new file mode 100644
index 0000000..c31cc84
--- /dev/null
+++ b/stand/pc98/loader/main.c
@@ -0,0 +1,322 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * MD bootstrap main() and assorted miscellaneous
+ * commands.
+ */
+
+#include <stand.h>
+#include <stddef.h>
+#include <string.h>
+#include <machine/bootinfo.h>
+#include <machine/cpufunc.h>
+#include <sys/param.h>
+#include <sys/reboot.h>
+
+#include "bootstrap.h"
+#include "common/bootargs.h"
+#include "libi386/libi386.h"
+#include "libpc98/libpc98.h"
+#include "btxv86.h"
+
+CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE);
+CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO);
+CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS);
+CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE);
+
+/* Arguments passed in from the boot1/boot2 loader */
+static struct bootargs *kargs;
+
+static u_int32_t initial_howto;
+static u_int32_t initial_bootdev;
+static struct bootinfo *initial_bootinfo;
+
+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);
+void exit(int code);
+
+/* from vers.c */
+extern char bootprog_info[];
+
+/* XXX debugging */
+extern char end[];
+
+static void *heap_top;
+static void *heap_bottom;
+
+static uint64_t
+pc98_loadaddr(u_int type, void *data, uint64_t addr)
+{
+ struct stat st;
+
+ if (type == LOAD_ELF)
+ return (roundup(addr, PAGE_SIZE));
+
+ /* We cannot use 15M-16M area on pc98. */
+ if (type == LOAD_RAW && addr < 0x1000000 && stat(data, &st) == 0 &&
+ (st.st_size == -1 || addr + st.st_size > 0xf00000))
+ addr = 0x1000000;
+ return (addr);
+}
+
+int
+main(void)
+{
+ int i;
+
+ /* Set machine type to PC98_SYSTEM_PARAMETER. */
+ set_machine_type();
+
+ /* Pick up arguments */
+ kargs = (void *)__args;
+ initial_howto = kargs->howto;
+ initial_bootdev = kargs->bootdev;
+ initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL;
+
+ /* Initialize the v86 register set to a known-good state. */
+ bzero(&v86, sizeof(v86));
+ v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
+
+ /*
+ * Initialise the heap as early as possible. Once this is done, malloc() is usable.
+ */
+ bios_getmem();
+
+#if defined(LOADER_BZIP2_SUPPORT)
+ if (high_heap_size > 0) {
+ heap_top = PTOV(high_heap_base + high_heap_size);
+ heap_bottom = PTOV(high_heap_base);
+ if (high_heap_base < memtop_copyin)
+ memtop_copyin = high_heap_base;
+ } else
+#endif
+ {
+ heap_top = (void *)PTOV(bios_basemem);
+ heap_bottom = (void *)end;
+ }
+ setheap(heap_bottom, heap_top);
+
+ /*
+ * 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.
+ */
+ bi_setboothowto(initial_howto);
+ if (initial_howto & RB_MULTIPLE) {
+ if (initial_howto & RB_SERIAL)
+ setenv("console", "comconsole vidconsole", 1);
+ else
+ setenv("console", "vidconsole comconsole", 1);
+ } else if (initial_howto & RB_SERIAL)
+ setenv("console", "comconsole", 1);
+ else if (initial_howto & RB_MUTE)
+ setenv("console", "nullconsole", 1);
+ cons_probe();
+
+ /*
+ * Initialise the block cache. Set the upper limit.
+ */
+ bcache_init(32768, 512);
+
+ /*
+ * Special handling for PXE and CD booting.
+ */
+ if (kargs->bootinfo == 0) {
+ /*
+ * We only want the PXE disk to try to init itself in the below
+ * walk through devsw if we actually booted off of PXE.
+ */
+ if (kargs->bootflags & KARGS_FLAGS_PXE)
+ pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL);
+ else if (kargs->bootflags & KARGS_FLAGS_CD)
+ bc_add(initial_bootdev);
+ }
+
+ 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;
+ archsw.arch_loadaddr = pc98_loadaddr;
+
+ /*
+ * 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("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024);
+ if (initial_bootinfo != NULL) {
+ initial_bootinfo->bi_basemem = bios_basemem / 1024;
+ initial_bootinfo->bi_extmem = bios_extmem / 1024;
+ }
+
+ printf("\n%s", bootprog_info);
+
+ extract_currdev(); /* set $currdev and $loaddev */
+ setenv("LINES", "24", 1); /* optional */
+
+ interact(NULL); /* doesn't return */
+
+ /* if we ever get here, it is an error */
+ return (1);
+}
+
+/*
+ * 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 new_currdev;
+ int major;
+ int biosdev = -1;
+
+ /* Assume we are booting from a BIOS disk by default */
+ new_currdev.d_dev = &biosdisk;
+
+ /* new-style boot loaders such as pxeldr and cdldr */
+ if (kargs->bootinfo == 0) {
+ if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) {
+ /* we are booting from a CD with cdboot */
+ new_currdev.d_dev = &bioscd;
+ new_currdev.d_unit = bc_bios2unit(initial_bootdev);
+ } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) {
+ /* we are booting from pxeldr */
+ new_currdev.d_dev = &pxedisk;
+ new_currdev.d_unit = 0;
+ } else {
+ /* we don't know what our boot device is */
+ new_currdev.d_kind.biosdisk.slice = -1;
+ new_currdev.d_kind.biosdisk.partition = 0;
+ biosdev = -1;
+ }
+ } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) {
+ /* The passed-in boot device is bad */
+ new_currdev.d_kind.biosdisk.slice = -1;
+ new_currdev.d_kind.biosdisk.partition = 0;
+ biosdev = -1;
+ } else {
+ new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1;
+ new_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 lose 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).
+ */
+ if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) { /* biosdev doesn't match major */
+ if (B_TYPE(initial_bootdev) == 6)
+ biosdev = 0x30 + B_UNIT(initial_bootdev);
+ else
+ biosdev = (major << 3) + 0x80 + B_UNIT(initial_bootdev);
+ }
+ }
+ new_currdev.d_type = new_currdev.d_dev->dv_type;
+
+ /*
+ * If we are booting off of a BIOS disk and we didn't succeed in determining
+ * which one we booted off of, just use disk0: as a reasonable default.
+ */
+ if ((new_currdev.d_type == biosdisk.dv_type) &&
+ ((new_currdev.d_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);
+ new_currdev.d_unit = 0;
+ }
+
+ env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev),
+ i386_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset,
+ env_nounset);
+}
+
+COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
+
+static int
+command_reboot(int argc, char *argv[])
+{
+ int i;
+
+ for (i = 0; devsw[i] != NULL; ++i)
+ if (devsw[i]->dv_cleanup != NULL)
+ (devsw[i]->dv_cleanup)();
+
+ 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, upper limit at %p\n", heap_bottom,
+ sbrk(0), heap_top);
+ return(CMD_OK);
+}
+
+/* ISA bus access functions for PnP. */
+static int
+isa_inb(int port)
+{
+
+ return (inb(port));
+}
+
+static void
+isa_outb(int port, int value)
+{
+
+ outb(port, value);
+}
diff --git a/stand/pc98/pc98boot/Makefile b/stand/pc98/pc98boot/Makefile
new file mode 100644
index 0000000..f33b15f
--- /dev/null
+++ b/stand/pc98/pc98boot/Makefile
@@ -0,0 +1,25 @@
+# $FreeBSD$
+
+FILES= ${BOOT}
+CLEANFILES= ${BOOT} ${BOOT}.part
+
+BOOT= pc98boot
+
+.if exists(${.OBJDIR}/../boot0)
+BOOT0= ${.OBJDIR}/../boot0/boot0
+.else
+BOOT0= ${.CURDIR}/../boot0/boot0
+.endif
+.if exists(${.OBJDIR}/../boot0.5)
+BOOT05= ${.OBJDIR}/../boot0.5/boot0.5
+.else
+BOOT05= ${.CURDIR}/../boot0.5/boot0.5
+.endif
+
+${BOOT}: ${BOOT0} ${BOOT05} ${BOOT}.part
+ cat ${BOOT0} ${BOOT}.part ${BOOT05} > ${.TARGET}
+
+${BOOT}.part:
+ ${DD} if=/dev/zero of=${.TARGET} bs=512 count=1
+
+.include <bsd.prog.mk>
OpenPOWER on IntegriCloud