Index: head/sys/boot/pc98/Makefile =================================================================== --- head/sys/boot/pc98/Makefile +++ head/sys/boot/pc98/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= boot0 boot0.5 pc98boot btx boot2 cdboot kgzldr libpc98 loader + +.include Index: head/sys/boot/pc98/Makefile.inc =================================================================== --- head/sys/boot/pc98/Makefile.inc +++ head/sys/boot/pc98/Makefile.inc @@ -0,0 +1,29 @@ +# Common defines for all of /sys/boot/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}/sys/boot/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" Index: head/sys/boot/pc98/boot0.5/Makefile =================================================================== --- head/sys/boot/pc98/boot0.5/Makefile +++ head/sys/boot/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 Index: head/sys/boot/pc98/boot0.5/boot.s =================================================================== --- head/sys/boot/pc98/boot0.5/boot.s +++ head/sys/boot/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 Index: head/sys/boot/pc98/boot0.5/boot0.5.s =================================================================== --- head/sys/boot/pc98/boot0.5/boot0.5.s +++ head/sys/boot/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 Index: head/sys/boot/pc98/boot0.5/disk.s =================================================================== --- head/sys/boot/pc98/boot0.5/disk.s +++ head/sys/boot/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 Index: head/sys/boot/pc98/boot0.5/ldscript =================================================================== --- head/sys/boot/pc98/boot0.5/ldscript +++ head/sys/boot/pc98/boot0.5/ldscript @@ -0,0 +1,12 @@ +/* + * $FreeBSD$ + */ + +SECTIONS +{ + .text : { *(.text) } + .data : { *(.data) } + . = 0x1243; + .putssjis : { *(.putssjis) } + .bss : { *(.bss) } +} Index: head/sys/boot/pc98/boot0.5/putssjis.s =================================================================== --- head/sys/boot/pc98/boot0.5/putssjis.s +++ head/sys/boot/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 Index: head/sys/boot/pc98/boot0.5/selector.s =================================================================== --- head/sys/boot/pc98/boot0.5/selector.s +++ head/sys/boot/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 " " Index: head/sys/boot/pc98/boot0.5/start.s =================================================================== --- head/sys/boot/pc98/boot0.5/start.s +++ head/sys/boot/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 Index: head/sys/boot/pc98/boot0.5/support.s =================================================================== --- head/sys/boot/pc98/boot0.5/support.s +++ head/sys/boot/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 Index: head/sys/boot/pc98/boot0.5/syscons.s =================================================================== --- head/sys/boot/pc98/boot0.5/syscons.s +++ head/sys/boot/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 Index: head/sys/boot/pc98/boot0/Makefile =================================================================== --- head/sys/boot/pc98/boot0/Makefile +++ head/sys/boot/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 Index: head/sys/boot/pc98/boot0/boot0.s =================================================================== --- head/sys/boot/pc98/boot0/boot0.s +++ head/sys/boot/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 Index: head/sys/boot/pc98/boot2/Makefile =================================================================== --- head/sys/boot/pc98/boot2/Makefile +++ head/sys/boot/pc98/boot2/Makefile @@ -0,0 +1,116 @@ +# $FreeBSD$ + +.include + +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 + +.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 + +# XXX: clang integrated-as doesn't grok .codeNN directives yet +CFLAGS.boot1.S= ${CLANG_NO_IAS} Index: head/sys/boot/pc98/boot2/boot1.S =================================================================== --- head/sys/boot/pc98/boot2/boot1.S +++ head/sys/boot/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 Index: head/sys/boot/pc98/boot2/boot2.c =================================================================== --- head/sys/boot/pc98/boot2/boot2.c +++ head/sys/boot/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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +#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; + } +} Index: head/sys/boot/pc98/btx/Makefile =================================================================== --- head/sys/boot/pc98/btx/Makefile +++ head/sys/boot/pc98/btx/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= btx btxldr lib + +.include Index: head/sys/boot/pc98/btx/Makefile.inc =================================================================== --- head/sys/boot/pc98/btx/Makefile.inc +++ head/sys/boot/pc98/btx/Makefile.inc @@ -0,0 +1,3 @@ +# $FreeBSD$ + +.include "../Makefile.inc" Index: head/sys/boot/pc98/btx/btx/Makefile =================================================================== --- head/sys/boot/pc98/btx/btx/Makefile +++ head/sys/boot/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 + +# XXX: clang integrated-as doesn't grok .codeNN directives yet +CFLAGS.btx.S= ${CLANG_NO_IAS} Index: head/sys/boot/pc98/btx/btx/btx.S =================================================================== --- head/sys/boot/pc98/btx/btx/btx.S +++ head/sys/boot/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 + +/* + * 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: Index: head/sys/boot/pc98/btx/btxldr/Makefile =================================================================== --- head/sys/boot/pc98/btx/btxldr/Makefile +++ head/sys/boot/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 + +# XXX: clang integrated-as doesn't grok .codeNN directives yet +CFLAGS.btxldr.S= ${CLANG_NO_IAS} Index: head/sys/boot/pc98/btx/btxldr/btxldr.S =================================================================== --- head/sys/boot/pc98/btx/btxldr/btxldr.S +++ head/sys/boot/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 + +/* + * 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"\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 Index: head/sys/boot/pc98/btx/lib/Makefile =================================================================== --- head/sys/boot/pc98/btx/lib/Makefile +++ head/sys/boot/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 Index: head/sys/boot/pc98/btx/lib/btxcsu.S =================================================================== --- head/sys/boot/pc98/btx/lib/btxcsu.S +++ head/sys/boot/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 + +# +# 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 Index: head/sys/boot/pc98/btx/lib/btxsys.s =================================================================== --- head/sys/boot/pc98/btx/lib/btxsys.s +++ head/sys/boot/pc98/btx/lib/btxsys.s @@ -0,0 +1,40 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $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 Index: head/sys/boot/pc98/btx/lib/btxv86.h =================================================================== --- head/sys/boot/pc98/btx/lib/btxv86.h +++ head/sys/boot/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 +#include + +#define V86_ADDR 0x10000 /* Segment:offset address */ +#define V86_CALLF 0x20000 /* Emulate far call */ +#define V86_FLAGS 0x40000 /* Return flags */ + +struct __v86 { + uint32_t ctl; /* Control flags */ + uint32_t addr; /* Interrupt number or address */ + uint32_t es; /* V86 ES register */ + uint32_t ds; /* V86 DS register */ + uint32_t fs; /* V86 FS register */ + uint32_t gs; /* V86 GS register */ + uint32_t eax; /* V86 EAX register */ + uint32_t ecx; /* V86 ECX register */ + uint32_t edx; /* V86 EDX register */ + uint32_t ebx; /* V86 EBX register */ + uint32_t efl; /* V86 eflags register */ + uint32_t ebp; /* V86 EBP register */ + uint32_t esi; /* V86 ESI register */ + uint32_t edi; /* V86 EDI register */ +}; + +extern struct __v86 __v86; /* V86 interface structure */ +void __v86int(void); + +#define v86 __v86 +#define v86int __v86int + +extern u_int32_t __base; +extern u_int32_t __args; + +#define PTOV(pa) ((caddr_t)(pa) - __base) +#define VTOP(va) ((vm_offset_t)(va) + __base) +#define VTOPSEG(va) (u_int16_t)(VTOP((caddr_t)va) >> 4) +#define VTOPOFF(va) (u_int16_t)(VTOP((caddr_t)va) & 0xf) + +#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_ */ Index: head/sys/boot/pc98/btx/lib/btxv86.s =================================================================== --- head/sys/boot/pc98/btx/lib/btxv86.s +++ head/sys/boot/pc98/btx/lib/btxv86.s @@ -0,0 +1,85 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $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 Index: head/sys/boot/pc98/cdboot/Makefile =================================================================== --- head/sys/boot/pc98/cdboot/Makefile +++ head/sys/boot/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 + +# XXX: clang integrated-as doesn't grok .codeNN directives yet +CFLAGS.cdboot.S= ${CLANG_NO_IAS} Index: head/sys/boot/pc98/cdboot/cdboot.S =================================================================== --- head/sys/boot/pc98/cdboot/cdboot.S +++ head/sys/boot/pc98/cdboot/cdboot.S @@ -0,0 +1,805 @@ +# +# Copyright (c) 2006 TAKAHASHI Yoshihiro +# Copyright (c) 2001 John Baldwin +# 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 + +# +# 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 Index: head/sys/boot/pc98/kgzldr/Makefile =================================================================== --- head/sys/boot/pc98/kgzldr/Makefile +++ head/sys/boot/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 Index: head/sys/boot/pc98/kgzldr/crt.s =================================================================== --- head/sys/boot/pc98/kgzldr/crt.s +++ head/sys/boot/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 Index: head/sys/boot/pc98/libpc98/Makefile =================================================================== --- head/sys/boot/pc98/libpc98/Makefile +++ head/sys/boot/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 Index: head/sys/boot/pc98/libpc98/bioscd.c =================================================================== --- head/sys/boot/pc98/libpc98/bioscd.c +++ head/sys/boot/pc98/libpc98/bioscd.c @@ -0,0 +1,420 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2001 John H. Baldwin + * 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 +__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 + +#include +#include + +#include + +#include +#include +#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); +} Index: head/sys/boot/pc98/libpc98/biosdisk.c =================================================================== --- head/sys/boot/pc98/libpc98/biosdisk.c +++ head/sys/boot/pc98/libpc98/biosdisk.c @@ -0,0 +1,1120 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * BIOS disk device handling. + * + * Ideas and algorithms from: + * + * - NetBSD libi386/biosdisk.c + * - FreeBSD biosboot/disk.c + * + */ + +#include + +#include +#include +#include + +#include + +#include +#include +#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); +} Index: head/sys/boot/pc98/libpc98/biosmem.c =================================================================== --- head/sys/boot/pc98/libpc98/biosmem.c +++ head/sys/boot/pc98/libpc98/biosmem.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Obtain memory configuration information from the BIOS + */ +#include +#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; + } +} Index: head/sys/boot/pc98/libpc98/biossmap.c =================================================================== --- head/sys/boot/pc98/libpc98/biossmap.c +++ head/sys/boot/pc98/libpc98/biossmap.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2006 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include "libi386.h" + +void +bios_addsmapdata(struct preloaded_file *kfp) +{ + +} Index: head/sys/boot/pc98/libpc98/comconsole.c =================================================================== --- head/sys/boot/pc98/libpc98/comconsole.c +++ head/sys/boot/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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#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)); +} Index: head/sys/boot/pc98/libpc98/libpc98.h =================================================================== --- head/sys/boot/pc98/libpc98/libpc98.h +++ head/sys/boot/pc98/libpc98/libpc98.h @@ -0,0 +1,29 @@ +/*- + * Copyright (c) 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$ + */ + +void set_machine_type(void); Index: head/sys/boot/pc98/libpc98/pc98_sys.c =================================================================== --- head/sys/boot/pc98/libpc98/pc98_sys.c +++ head/sys/boot/pc98/libpc98/pc98_sys.c @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 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. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#define _KERNEL +#include + +/* + * 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; +} Index: head/sys/boot/pc98/libpc98/time.c =================================================================== --- head/sys/boot/pc98/libpc98/time.c +++ head/sys/boot/pc98/libpc98/time.c @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#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 */ +} Index: head/sys/boot/pc98/libpc98/vidconsole.c =================================================================== --- head/sys/boot/pc98/libpc98/vidconsole.c +++ head/sys/boot/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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include "libi386.h" + +#if KEYBOARD_PROBE +#include + +static int probe_keyboard(void); +#endif +static void vidc_probe(struct console *cp); +static int vidc_init(int arg); +static void vidc_putchar(int c); +static int vidc_getchar(void); +static int vidc_ischar(void); + +static int vidc_started; + +#ifdef TERM_EMU +#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 */ Index: head/sys/boot/pc98/loader/Makefile =================================================================== --- head/sys/boot/pc98/loader/Makefile +++ head/sys/boot/pc98/loader/Makefile @@ -0,0 +1,99 @@ +# $FreeBSD$ + +.include +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 + +${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 Index: head/sys/boot/pc98/loader/conf.c =================================================================== --- head/sys/boot/pc98/loader/conf.c +++ head/sys/boot/pc98/loader/conf.c @@ -0,0 +1,116 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#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 +}; Index: head/sys/boot/pc98/loader/help.pc98 =================================================================== --- head/sys/boot/pc98/loader/help.pc98 +++ head/sys/boot/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= + + 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= + + 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. + +################################################################################ Index: head/sys/boot/pc98/loader/main.c =================================================================== --- head/sys/boot/pc98/loader/main.c +++ head/sys/boot/pc98/loader/main.c @@ -0,0 +1,322 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * MD bootstrap main() and assorted miscellaneous + * commands. + */ + +#include +#include +#include +#include +#include +#include +#include + +#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); +} Index: head/sys/boot/pc98/pc98boot/Makefile =================================================================== --- head/sys/boot/pc98/pc98boot/Makefile +++ head/sys/boot/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 Index: head/usr.sbin/makefs/ffs.c =================================================================== --- head/usr.sbin/makefs/ffs.c +++ head/usr.sbin/makefs/ffs.c @@ -973,7 +973,7 @@ errno = bwrite(bp); if (errno != 0) goto bad_ffs_write_file; - brelse(bp); + brelse(bp, 0); if (!isfile) p += chunk; } Index: head/usr.sbin/makefs/ffs/buf.h =================================================================== --- head/usr.sbin/makefs/ffs/buf.h +++ head/usr.sbin/makefs/ffs/buf.h @@ -1,4 +1,4 @@ -/* $NetBSD: buf.h,v 1.2 2001/11/02 03:12:49 lukem Exp $ */ +/* $NetBSD: buf.h,v 1.3 2001/11/02 03:12:49 lukem Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -43,6 +43,15 @@ #include #include +struct ucred; + +struct vnode { + int fd; + void *fs; + void *v_data; + int offset; +}; + struct buf { void * b_data; long b_bufsize; @@ -56,10 +65,11 @@ }; void bcleanup(void); -int bread(int, struct fs *, daddr_t, int, struct buf **); -void brelse(struct buf *); +int bread(struct vnode *, daddr_t, int, struct ucred *, + struct buf **); +void brelse(struct buf *, int); int bwrite(struct buf *); -struct buf * getblk(int, struct fs *, daddr_t, int); +struct buf * getblk(struct vnode *, daddr_t, int, int, int, int); #define bdwrite(bp) bwrite(bp) #define clrbuf(bp) memset((bp)->b_data, 0, (u_int)(bp)->b_bcount) Index: head/usr.sbin/makefs/ffs/buf.c =================================================================== --- head/usr.sbin/makefs/ffs/buf.c +++ head/usr.sbin/makefs/ffs/buf.c @@ -1,4 +1,4 @@ -/* $NetBSD: buf.c,v 1.12 2004/06/20 22:20:18 jmc Exp $ */ +/* $NetBSD: buf.c,v 1.13 2004/06/20 22:20:18 jmc Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -60,10 +60,12 @@ TAILQ_HEAD(buftailhead,buf) buftail; int -bread(int fd, struct fs *fs, daddr_t blkno, int size, struct buf **bpp) +bread(struct vnode *vp, daddr_t blkno, int size, struct ucred *u1 __unused, + struct buf **bpp) { off_t offset; ssize_t rv; + struct fs *fs = vp->fs; assert (fs != NULL); assert (bpp != NULL); @@ -71,7 +73,7 @@ if (debug & DEBUG_BUF_BREAD) printf("bread: fs %p blkno %lld size %d\n", fs, (long long)blkno, size); - *bpp = getblk(fd, fs, blkno, size); + *bpp = getblk(vp, blkno, size, 0, 0, 0); offset = (*bpp)->b_blkno * sectorsize; /* XXX */ if (debug & DEBUG_BUF_BREAD) printf("bread: bp %p blkno %lld offset %lld bcount %ld\n", @@ -95,7 +97,7 @@ } void -brelse(struct buf *bp) +brelse(struct buf *bp, int u1 __unused) { assert (bp != NULL); @@ -174,12 +176,16 @@ } struct buf * -getblk(int fd, struct fs *fs, daddr_t blkno, int size) +getblk(struct vnode *vp, daddr_t blkno, int size, int u1 __unused, + int u2 __unused, int u3 __unused) { static int buftailinitted; struct buf *bp; void *n; + int fd = vp->fd; + struct fs *fs = vp->fs; + blkno += vp->offset; assert (fs != NULL); if (debug & DEBUG_BUF_GETBLK) printf("getblk: fs %p blkno %lld size %d\n", fs, Index: head/usr.sbin/makefs/ffs/ffs_alloc.c =================================================================== --- head/usr.sbin/makefs/ffs/ffs_alloc.c +++ head/usr.sbin/makefs/ffs/ffs_alloc.c @@ -297,19 +297,20 @@ int error, frags, allocsiz, i; struct fs *fs = ip->i_fs; const int needswap = UFS_FSNEEDSWAP(fs); + struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 }; if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) return (0); - error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)), - (int)fs->fs_cgsize, &bp); + error = bread(&vp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, + NULL, &bp); if (error) { - brelse(bp); + brelse(bp, 0); return (0); } cgp = (struct cg *)bp->b_data; if (!cg_chkmagic_swap(cgp, needswap) || (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) { - brelse(bp); + brelse(bp, 0); return (0); } if (size == fs->fs_bsize) { @@ -332,7 +333,7 @@ * allocated, and hacked up */ if (cgp->cg_cs.cs_nbfree == 0) { - brelse(bp); + brelse(bp, 0); return (0); } bno = ffs_alloccgblk(ip, bp, bpref); @@ -432,6 +433,7 @@ int i, error, cg, blk, frags, bbase; struct fs *fs = ip->i_fs; const int needswap = UFS_FSNEEDSWAP(fs); + struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 }; if (size > fs->fs_bsize || fragoff(fs, size) != 0 || fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) { @@ -444,15 +446,15 @@ (uintmax_t)ip->i_number); return; } - error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)), - (int)fs->fs_cgsize, &bp); + error = bread(&vp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, + NULL, &bp); if (error) { - brelse(bp); + brelse(bp, 0); return; } cgp = (struct cg *)bp->b_data; if (!cg_chkmagic_swap(cgp, needswap)) { - brelse(bp); + brelse(bp, 0); return; } cgbno = dtogd(fs, bno); Index: head/usr.sbin/makefs/ffs/ffs_balloc.c =================================================================== --- head/usr.sbin/makefs/ffs/ffs_balloc.c +++ head/usr.sbin/makefs/ffs/ffs_balloc.c @@ -89,6 +89,7 @@ int32_t *allocblk, allociblk[NIADDR + 1]; int32_t *allocib; const int needswap = UFS_FSNEEDSWAP(fs); + struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 }; lbn = lblkno(fs, offset); size = blkoff(fs, offset) + bufsize; @@ -132,10 +133,10 @@ */ if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, - fs->fs_bsize, bpp); + error = bread(&vp, lbn, fs->fs_bsize, NULL, + bpp); if (error) { - brelse(*bpp); + brelse(*bpp, 0); return (error); } } @@ -158,10 +159,10 @@ */ if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, - osize, bpp); + error = bread(&vp, lbn, osize, NULL, + bpp); if (error) { - brelse(*bpp); + brelse(*bpp, 0); return (error); } } @@ -188,7 +189,7 @@ if (error) return (error); if (bpp != NULL) { - bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize); + bp = getblk(&vp, lbn, nsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, newb); clrbuf(bp); *bpp = bp; @@ -226,7 +227,7 @@ return error; nb = newb; *allocblk++ = nb; - bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize); + bp = getblk(&vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, nb); clrbuf(bp); /* @@ -244,10 +245,9 @@ */ for (i = 1;;) { - error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn, - fs->fs_bsize, &bp); + error = bread(&vp, indirs[i].in_lbn, fs->fs_bsize, NULL, &bp); if (error) { - brelse(bp); + brelse(bp, 0); return error; } bap = (int32_t *)bp->b_data; @@ -256,20 +256,19 @@ break; i++; if (nb != 0) { - brelse(bp); + brelse(bp, 0); continue; } if (pref == 0) pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); if (error) { - brelse(bp); + brelse(bp, 0); return error; } nb = newb; *allocblk++ = nb; - nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn, - fs->fs_bsize); + nbp = getblk(&vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); clrbuf(nbp); /* @@ -278,7 +277,7 @@ */ if ((error = bwrite(nbp)) != 0) { - brelse(bp); + brelse(bp, 0); return error; } bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap); @@ -294,13 +293,13 @@ pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); if (error) { - brelse(bp); + brelse(bp, 0); return error; } nb = newb; *allocblk++ = nb; if (bpp != NULL) { - nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize); + nbp = getblk(&vp, lbn, fs->fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); clrbuf(nbp); *bpp = nbp; @@ -314,11 +313,11 @@ bwrite(bp); return (0); } - brelse(bp); + brelse(bp, 0); if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp); + error = bread(&vp, lbn, (int)fs->fs_bsize, NULL, &nbp); if (error) { - brelse(nbp); + brelse(nbp, 0); return error; } *bpp = nbp; @@ -340,6 +339,7 @@ int64_t *allocblk, allociblk[NIADDR + 1]; int64_t *allocib; const int needswap = UFS_FSNEEDSWAP(fs); + struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 }; lbn = lblkno(fs, offset); size = blkoff(fs, offset) + bufsize; @@ -383,10 +383,10 @@ */ if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, - fs->fs_bsize, bpp); + error = bread(&vp, lbn, fs->fs_bsize, NULL, + bpp); if (error) { - brelse(*bpp); + brelse(*bpp, 0); return (error); } } @@ -409,10 +409,10 @@ */ if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, - osize, bpp); + error = bread(&vp, lbn, osize, NULL, + bpp); if (error) { - brelse(*bpp); + brelse(*bpp, 0); return (error); } } @@ -439,7 +439,7 @@ if (error) return (error); if (bpp != NULL) { - bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize); + bp = getblk(&vp, lbn, nsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, newb); clrbuf(bp); *bpp = bp; @@ -477,7 +477,7 @@ return error; nb = newb; *allocblk++ = nb; - bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize); + bp = getblk(&vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, nb); clrbuf(bp); /* @@ -495,10 +495,9 @@ */ for (i = 1;;) { - error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn, - fs->fs_bsize, &bp); + error = bread(&vp, indirs[i].in_lbn, fs->fs_bsize, NULL, &bp); if (error) { - brelse(bp); + brelse(bp, 0); return error; } bap = (int64_t *)bp->b_data; @@ -507,20 +506,19 @@ break; i++; if (nb != 0) { - brelse(bp); + brelse(bp, 0); continue; } if (pref == 0) pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); if (error) { - brelse(bp); + brelse(bp, 0); return error; } nb = newb; *allocblk++ = nb; - nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn, - fs->fs_bsize); + nbp = getblk(&vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); clrbuf(nbp); /* @@ -529,7 +527,7 @@ */ if ((error = bwrite(nbp)) != 0) { - brelse(bp); + brelse(bp, 0); return error; } bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap); @@ -545,13 +543,13 @@ pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); if (error) { - brelse(bp); + brelse(bp, 0); return error; } nb = newb; *allocblk++ = nb; if (bpp != NULL) { - nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize); + nbp = getblk(&vp, lbn, fs->fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); clrbuf(nbp); *bpp = nbp; @@ -565,11 +563,11 @@ bwrite(bp); return (0); } - brelse(bp); + brelse(bp, 0); if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp); + error = bread(&vp, lbn, (int)fs->fs_bsize, NULL, &nbp); if (error) { - brelse(nbp); + brelse(nbp, 0); return error; } *bpp = nbp;