summaryrefslogtreecommitdiffstats
path: root/sys/boot/i386
diff options
context:
space:
mode:
Diffstat (limited to 'sys/boot/i386')
-rw-r--r--sys/boot/i386/Makefile5
-rw-r--r--sys/boot/i386/boot0/Makefile26
-rw-r--r--sys/boot/i386/boot0/boot0.m417
-rw-r--r--sys/boot/i386/boot0/boot0.s258
-rw-r--r--sys/boot/i386/boot2/Makefile53
-rw-r--r--sys/boot/i386/boot2/boot1.S236
-rw-r--r--sys/boot/i386/boot2/boot1.m44
-rw-r--r--sys/boot/i386/boot2/boot1.s178
-rw-r--r--sys/boot/i386/boot2/boot2.c304
-rw-r--r--sys/boot/i386/boot2/lib.h24
-rw-r--r--sys/boot/i386/boot2/sio.S80
-rw-r--r--sys/boot/i386/boot2/sio.s80
-rw-r--r--sys/boot/i386/btx/Makefile4
-rw-r--r--sys/boot/i386/btx/btx/Makefile11
-rw-r--r--sys/boot/i386/btx/btx/btx.S958
-rw-r--r--sys/boot/i386/btx/btx/btx.s123
-rw-r--r--sys/boot/i386/btx/btxldr/Makefile22
-rw-r--r--sys/boot/i386/btx/btxldr/btxldr.S384
-rw-r--r--sys/boot/i386/btx/btxldr/btxldr.s384
-rw-r--r--sys/boot/i386/btx/lib/Makefile20
-rw-r--r--sys/boot/i386/btx/lib/btxcsu.s43
-rw-r--r--sys/boot/i386/btx/lib/btxsys.s40
-rw-r--r--sys/boot/i386/btx/lib/btxv86.h63
-rw-r--r--sys/boot/i386/btx/lib/btxv86.s85
-rw-r--r--sys/boot/i386/gptboot/Makefile76
-rw-r--r--sys/boot/i386/gptboot/gptboot.c809
-rw-r--r--sys/boot/i386/libi386/Makefile39
-rw-r--r--sys/boot/i386/libi386/aout_freebsd.c83
-rw-r--r--sys/boot/i386/libi386/biosdisk.c832
-rw-r--r--sys/boot/i386/libi386/biosmem.c52
-rw-r--r--sys/boot/i386/libi386/biospci.c294
-rw-r--r--sys/boot/i386/libi386/biospnp.c289
-rw-r--r--sys/boot/i386/libi386/bootinfo.c325
-rw-r--r--sys/boot/i386/libi386/bootinfo32.c325
-rw-r--r--sys/boot/i386/libi386/bootinfo64.c325
-rw-r--r--sys/boot/i386/libi386/comconsole.c132
-rw-r--r--sys/boot/i386/libi386/devicename.c235
-rw-r--r--sys/boot/i386/libi386/elf32_freebsd.c90
-rw-r--r--sys/boot/i386/libi386/elf64_freebsd.c90
-rw-r--r--sys/boot/i386/libi386/elf_freebsd.c90
-rw-r--r--sys/boot/i386/libi386/gatea20.c52
-rw-r--r--sys/boot/i386/libi386/i386_copy.c63
-rw-r--r--sys/boot/i386/libi386/i386_module.c48
-rw-r--r--sys/boot/i386/libi386/libi386.h86
-rw-r--r--sys/boot/i386/libi386/pread.c79
-rw-r--r--sys/boot/i386/libi386/time.c56
-rw-r--r--sys/boot/i386/libi386/vidconsole.c627
-rw-r--r--sys/boot/i386/loader/Makefile126
-rw-r--r--sys/boot/i386/loader/conf.c96
-rw-r--r--sys/boot/i386/loader/help.i38646
-rw-r--r--sys/boot/i386/loader/loader.8753
-rw-r--r--sys/boot/i386/loader/main.c233
-rwxr-xr-xsys/boot/i386/loader/newvers.sh46
-rw-r--r--sys/boot/i386/loader/version11
54 files changed, 9399 insertions, 411 deletions
diff --git a/sys/boot/i386/Makefile b/sys/boot/i386/Makefile
new file mode 100644
index 0000000..06743b6
--- /dev/null
+++ b/sys/boot/i386/Makefile
@@ -0,0 +1,5 @@
+# $Id: Makefile,v 1.6 1998/10/12 02:05:44 rnordier Exp $
+
+SUBDIR= boot0 btx boot2 libi386 loader
+
+.include <bsd.subdir.mk>
diff --git a/sys/boot/i386/boot0/Makefile b/sys/boot/i386/boot0/Makefile
index b80d938..4e890da 100644
--- a/sys/boot/i386/boot0/Makefile
+++ b/sys/boot/i386/boot0/Makefile
@@ -1,19 +1,31 @@
-# $Id:$
+# $Id: Makefile,v 1.5 1998/10/17 14:20:25 rnordier Exp $
+
+PROG= boot0
+NOMAN=
+STRIP=
+BINDIR?= /boot
+BINMODE= 444
M4?= m4
-ORG= 0x600
+B0FLAGS=0x0
+B0TICKS=0xb6
-all: boot0
+ORG= 0x600
boot0: boot0.o
+.if ${OBJFORMAT} == aout
+ ${LD} -N -s -T ${ORG} -o boot0.out boot0.o
+ dd if=boot0.out of=${.TARGET} ibs=32 skip=1
+.else
${LD} -N -e start -Ttext ${ORG} -o boot0.out boot0.o
- /usr/libexec/elf/objcopy -S -O binary boot0.out ${.TARGET}
+ objcopy -S -O binary boot0.out ${.TARGET}
+.endif
boot0.o: boot0.m4 boot0.s
- (cd ${.CURDIR}; ${M4} boot0.m4 boot0.s) | \
- ${AS} ${AFLAGS} -o ${.TARGET}
+ (cd ${.CURDIR}; ${M4} -DFLAGS=${B0FLAGS} -DTICKS=${B0TICKS} \
+ boot0.m4 boot0.s) | ${AS} ${AFLAGS} -o ${.TARGET}
-CLEANFILES+= boot0 boot0.out boot0.o
+CLEANFILES+= boot0.out boot0.o
.include <bsd.prog.mk>
diff --git a/sys/boot/i386/boot0/boot0.m4 b/sys/boot/i386/boot0/boot0.m4
index c0a38b7..f0912a8 100644
--- a/sys/boot/i386/boot0/boot0.m4
+++ b/sys/boot/i386/boot0/boot0.m4
@@ -13,7 +13,7 @@
# purpose.
#
-# $Id:$
+# $Id: boot0.m4,v 1.2 1998/10/19 19:13:53 rnordier Exp $
define(_al,0x0)dnl
define(_cl,0x1)dnl
@@ -52,25 +52,22 @@ define(_bx_,0x7)dnl
define(o16,`.byte 0x66')dnl
define(addwia,`.byte 0x5; .word $1')dnl
-define(btwrm,`.byte 0xf; .byte 0xa3; .byte 0x6 | ($1 << 0x3); .word $2')dnl
-define(btswrm,`.byte 0xf; .byte 0xab; .byte 0x6 | ($1 << 0x3); .word $2')dnl
-define(cmpwmr,`.byte 0x3b; .byte ($2 << 0x3) | 0x6; .word $1')dnl
+define(btwr1,`.word 0xa30f; .byte 0x40 | ($1 << 0x3) | $3; .byte $2')dnl
+define(btswr1,`.word 0xab0f; .byte 0x40 | ($1 << 0x3) | $3; .byte $2')dnl
+define(cmpbmr,`.byte 0x3a; .byte 0x6 | ($2 << 0x3); .word $1')dnl
+define(cmpw1r,`.byte 0x3b; .byte 0x40 | ($3 << 0x3) | $2; .byte $1')dnl
define(cmpwi2,`.byte 0x81; .byte 0xb8 | $3; .word $2; .word $1')dnl
-define(cmpwir,`.byte 0x81; .byte 0xf8 | $2; .word $1')dnl
+define(addwir,`.byte 0x83; .byte 0xc0 | $2; .byte $1')dnl
define(movbr0,`.byte 0x88; .byte ($1 << 0x3) | $2')dnl
-define(movbrm,`.byte 0x88; .byte 0x6 | ($1 << 0x3); .word $2')dnl
define(movbr1,`.byte 0x88; .byte 0x40 | ($1 << 0x3) | $3; .byte $2')dnl
define(movwr1,`.byte 0x89; .byte 0x40 | ($1 << 0x3) | $3; .byte $2')dnl
define(movb0r,`.byte 0x8a; .byte ($2 << 0x3) | $1')dnl
-define(movbmr,`.byte 0x8a; .byte 0x6 | ($2 << 0x3); .word $1')dnl
define(movb1r,`.byte 0x8a; .byte 0x40 | ($3 << 0x3) | $2; .byte $1')dnl
define(movw1r,`.byte 0x8b; .byte 0x40 | ($3 << 0x3) | $2; .byte $1')dnl
define(movws1,`.byte 0x8c; .byte 0x40 | ($1 << 0x3) | $3; .byte $2')dnl
-define(leaw1r,`.byte 0x8d; .byte 0x40 | ($3 << 0x3) | $2; .byte $1')dnl
-define(movbma,`.byte 0xa0; .word $1')dnl
-define(movbam,`.byte 0xa2; .word $1')dnl
define(movwir,`.byte 0xb8 | $2; .word $1')dnl
define(movbi0,`.byte 0xc6; .byte $2; .byte $1')dnl
define(callwi,`.byte 0xe8; .word $1 - . - 0x2')dnl
define(jmpnwi,`.byte 0xe9; .word $1 - . - 0x2')dnl
+define(tstbi1,`.byte 0xf6; .byte 0x40 | $3; .byte $2; .byte $1')dnl
define(incb1,`.byte 0xfe; .byte 0x40 | $2; .byte $1')dnl
diff --git a/sys/boot/i386/boot0/boot0.s b/sys/boot/i386/boot0/boot0.s
index cc68d90..c02a7d7 100644
--- a/sys/boot/i386/boot0/boot0.s
+++ b/sys/boot/i386/boot0/boot0.s
@@ -13,19 +13,37 @@
# purpose.
#
-# $Id:$
+# $Id: boot0.s,v 1.7 1999/02/26 14:51:14 rnordier Exp $
# A 512-byte boot manager.
+ .set NHRDRV,0x475 # Number of hard drives
+ .set ORIGIN,0x600 # Execution address
+ .set DSKPKT,0x800 # Disk packet
+ .set FAKE,0x810 # Partition entry
.set LOAD,0x7c00 # Load address
- .set ORIGIN,0x600 # Relocation address
+
.set PRT_OFF,0x1be # Partition table
- .set FAKE,0x810 # Partition entry
- .set MNUOPT,0x81c # Menu options
+
+ .set TBL0SZ,0x3 # Table 0 size
+ .set TBL1SZ,0xa # Table 1 size
+
+ .set MAGIC,0xaa55 # Magic: bootable
+
+ .set KEY_ENTER,0x1c # Enter key scan code
+ .set KEY_F1,0x3b # F1 key scan code
+
+ .set _NXTDRV,-0x48 # Next drive
+ .set _OPT,-0x47 # Default option
+ .set _SETDRV,-0x46 # Drive to force
+ .set _FLAGS,-0x45 # Flags
+ .set _TICKS,-0x44 # Timeout ticks
+ .set _FAKE,0x10 # Fake partition entry
+ .set _MNUOPT,0x1c # Menu options
.globl start # Entry point
-start: cld # String ops inc
+start: cld # String ops inc
xorl %eax,%eax # Zero
movl %eax,%es # Address
movl %eax,%ds # data
@@ -36,182 +54,196 @@ start: cld # String ops inc
movwir(0x100,_cx) # Word count
rep # Relocate
movsl # code
+ movl %edi,%ebp # Address variables
movb $0x10,%cl # Words to clear
rep # Zero
- stosl # then
+ stosl # them
incb1(-0xe,_di_) # Sector number
jmpnwi(main-LOAD+ORIGIN) # To relocated code
-main: movbrm(_dl,FAKE) # Save drive number
+main: tstbi1(0x20,_FLAGS,_bp_) # Set drive?
+ jz main.0 # No
+ movb1r(_SETDRV,_bp_,_dl) # Drive to force
+main.0: movbr1(_dl,_FAKE,_bp_) # Save drive number
callwi(putn) # To new line
movwir(partbl,_bx) # Partition table
xorl %edx,%edx # Item
-main.1: movbr0(_dh,_bx_) # Mark inactive
- movb1r(0x4,_bx_,_al) # Load type
- movwir(table0,_di) # Exclusion table
- movb $0x3,%cl # Entries
+main.1: movb1r(0x4,_bx_,_al) # Load type
+ movwir(tables,_di) # Lookup tables
+ movb $TBL0SZ,%cl # Entries
repne # Exclude
scasb # partition?
je main.3 # Yes
- movb $0xa,%cl # Entries
+ movb $TBL1SZ,%cl # Entries
repne # Known
scasb # type?
jne main.2 # No
- leaw1r(0xa,_di_,_di) # Name table
-main.2: movwir(item,_si) # Display start
- callwi(putkey) # of menu item
- movl %edi,%esi # Set pointer
- lodsb # to
- cwde # partition
- add %eax,%esi # description
- callwi(puts) # Display it
- btswrm(_dx,MNUOPT) # Flag option enabled
-main.3: addb $0x10,%bl # Next entry
+ addwir(TBL1SZ,_di) # Adjust
+main.2: movb0r(_di_,_cl) # Partition
+ addl %ecx,%edi # description
+ callwi(putx) # Display it
+main.3: addwir(0x10,_bx) # Next entry
incl %edx # Next item
cmpb $0x4,%dl # Done?
jb main.1 # No
- movwir(prompt,_si) # Display
+ movb1r(_FAKE,_bp_,_al) # Drive number
+ subb $0x80-0x1,%al # Does next
+ cmpbmr(NHRDRV,_al) # drive exist?
+ jb main.4 # Yes
+ decb %al # Already drive 0?
+ jz main.5 # Yes
+ xorb %al,%al # Drive 0
+main.4: addb $'0'|0x80,%al # Save
+ movbr1(_al,_NXTDRV,_bp_) # it
+ movwir(drive,_di) # Display
+ callwi(putx) # item
+main.5: movwir(prompt,_si) # Display
callwi(putstr) # prompt
- movbmr(opt,_dl) # Display
+ movb1r(_OPT,_bp_,_dl) # Display
decl %esi # default
callwi(putkey) # key
xorb %ah,%ah # BIOS: Get
int $0x1a # system time
- movl %edx,%edi # Save
-main.4: movb $0x1,%ah # BIOS: Check
+ movl %edx,%edi # Save ticks
+main.6: movb $0x1,%ah # BIOS: Check
int $0x16 # for keypress
- jnz main.6 # Have one
+ jnz main.9 # Have one
xorb %ah,%ah # BIOS: Get
int $0x1a # system time
subl %edi,%edx # Elapsed time
- cmpwmr(ticks,_dx) # Timeout?
- jb main.4 # No
- jmp main.7 # Join common code
-main.5: movb $0x7,%al # Signal
+ cmpw1r(_TICKS,_bp_,_dx) # Timeout?
+ jb main.6 # No
+main.7: movb1r(_OPT,_bp_,_al) # Load default
+ jmp main.10 # Join common code
+main.8: movb $0x7,%al # Signal
callwi(putchr) # error
-main.6: xorb %ah,%ah # BIOS: Get
+main.9: xorb %ah,%ah # BIOS: Get
int $0x16 # keypress
movb %ah,%al # Scan code
- cmpb $0x1c,%al # Enter pressed?
- jne main.8 # No
-main.7: movbma(opt) # Load
- jmp main.9 # default
-main.8: subb $0x3b,%al # Less F1 scan code
- jb main.5 # Not a function key
-main.9: cmpb $0x4,%al # F1..F5?
- ja main.5 # No
- movwir(FAKE,_si) # Partition entry
- movb0r(_si_,_dl) # Load drive number
- jne main.10 # If not F5
- xorb $0x1,%dl # Toggle drive
- jmp main.11 # number
-main.10: cwtl # Option
- btwrm(_ax,MNUOPT) # enabled?
- jnc main.5 # No
- movbam(opt) # Save option
- shlb $0x4,%al # Point to
- addwia(partbl) # partition
- xchgl %esi,%eax # entry
- movbi0(0x80,_si_) # Flag active
- pushl %esi # Save
- movl %eax,%esi # Fake partition entry
+ cmpb $KEY_ENTER,%al # Enter pressed?
+ je main.7 # No
+ subb $KEY_F1,%al # Less F1 scan code
+ cmpb $0x4,%al # F1..F5?
+ ja main.8 # No
+main.10: cwtl # Option
+ btwr1(_ax,_MNUOPT,_bp_) # enabled?
+ jnc main.8 # No
+ movbr1(_al,_OPT,_bp_) # Save option
+ movwir(FAKE,_si) # Partition for write
+ movb0r(_si_,_dl) # Drive number
+ movl %esi,%ebx # Partition for read
+ cmpb $0x4,%al # F5 pressed?
+ pushfl # Save
+ je main.12 # Yes
+ movwir(partbl,_bx) # Partition table
+ pushl %ebx # Save
+main.11: movbr0(_ah,_bx_) # Mark inactive
+ addb $0x10,%bl # To next entry
+ cmpb $0xfe,%bl # Till
+ jb main.11 # done
+ popl %ebx # Restore
+ shlb $0x4,%al # Selected
+ addb %al,%bl # partition
+ movbi0(0x80,_bx_) # Flag active
+main.12: pushl %ebx # Save
+ tstbi1(0x40,_FLAGS,_bp_) # No updates?
+ jnz main.13 # Yes
movwir(start,_bx) # Data to write
movwir(0x301,_ax) # Write sector
callwi(intx13) # to disk
- popl %esi # Restore
- jc main.5 # If error
-main.11: movwir(LOAD,_bx) # Address for read
+main.13: popl %esi # Restore
+ popfl # Restore
+ jne main.14 # If not F5
+ movb1r(_NXTDRV,_bp_,_dl) # Next drive
+ subb $'0',%dl # number
+main.14: movwir(LOAD,_bx) # Address for read
movwir(0x201,_ax) # Read sector
callwi(intx13) # from disk
- jc main.5 # If error
- cmpwi2(0xaa55,0x1fe,_bx_) # Bootable?
- jne main.5 # No
- callwi(putn) # To next line
+ jc main.8 # If error
+ cmpwi2(MAGIC,0x1fe,_bx_) # Bootable?
+ jne main.8 # No
+ movwir(crlf,_si) # Leave some
+ callwi(puts) # space
jmp *%ebx # Invoke bootstrap
# Display routines
-putkey: movb $'F',%al # Display
+putkey: movb $'F',%al # Display
callwi(putchr) # 'F'
movb $'1',%al # Prepare
addb %dl,%al # digit
jmp putstr.1 # Display the rest
+putx: btswr1(_dx,_MNUOPT,_bp_) # Enable menu option
+ movwir(item,_si) # Display
+ callwi(putkey) # key
+ movl %edi,%esi # Display the rest
+
puts: callwi(putstr) # Display string
putn: movwir(crlf,_si) # To next line
-putstr: lodsb # Get byte
- testb $0x80,%al # End of string?
+putstr: lodsb # Get byte
+ testb $0x80,%al # End of string?
jnz putstr.2 # Yes
putstr.1: callwi(putchr) # Display char
jmp putstr # Continue
-putstr.2: andb $~0x80,%al # Clear MSB
+putstr.2: andb $~0x80,%al # Clear MSB
-putchr: pushl %ebx # Save
- movwir(0x7,_bx) # Page:attribute
+putchr: pushl %ebx # Save
+ movwir(0x7,_bx) # Page:attribute
movb $0xe,%ah # BIOS: Display
int $0x10 # character
popl %ebx # Restore
ret # To caller
-# Disk I/O
+# Disk I/O routine
-intx13: movb1r(0x1,_si_,_dh) # Load head
+intx13: cli # Disable interrupts
+ movb1r(0x1,_si_,_dh) # Load head
movw1r(0x2,_si_,_cx) # Load cylinder:sector
o16 # Load
movw1r(0x8,_si_,_di) # offset
- pushl %ecx # Save
- pushl %ebx # caller's
- movwir(0x55aa,_bx) # Magic
- pushl %eax # Save
- movb $0x41,%ah # BIOS: EDD extensions
- int $0x13 # present?
- popl %eax # Restore
- jc intx13.1 # No
- cmpwir(0xaa55,_bx) # Magic?
- jne intx13.1 # No
- testb $0x1,%cl # Use packet?
- jz intx13.1 # No
- orb $0x40,%ah # Use EDD
-intx13.1: popl %ebx # Restore
- popl %ecx # caller's
- testb $0x40,%ah # Use EDD?
- jz intx13.2 # No
- movwir(break,_si) # Packet pointer
+ movwir(DSKPKT,_si) # Packet pointer
movbi0(0x10,_si_) # Packet size
movbr1(_al,0x2,_si_) # Block count
movwr1(_bx,0x4,_si_) # Transfer
movws1(_es,0x6,_si_) # buffer
o16 # LBA
movwr1(_di,0x8,_si_) # address
- xorb %al,%al # Verify off
-intx13.2: int $0x13 # BIOS: Disk I/O
+ sti # Enable interrupts
+ tstbi1(0x80,_FLAGS,_bp_) # Use packet interface?
+ jz intx13.1 # No
+ orb $0x40,%ah # Use disk packet
+ decl %eax # Verify off
+intx13.1: int $0x13 # BIOS: Disk I/O
ret # To caller
# Menu strings
-crlf: .ascii "\r"; .byte '\n'|0x80
-item: .ascii " "; .byte ' '|0x80
+item: .ascii " "; .byte ' '|0x80
prompt: .ascii "\nDefault:"; .byte ' '|0x80
+crlf: .ascii "\r"; .byte '\n'|0x80
# Partition type tables
-table0: .byte 0x0, 0x5, 0xf
-table1: .byte 0x1, 0x4, 0x6, 0xb, 0xc, 0xe, 0x63, 0x83
+tables:
+ .byte 0x0, 0x5, 0xf
+
+ .byte 0x1, 0x4, 0x6, 0xb, 0xc, 0xe, 0x63, 0x83
.byte 0xa5, 0xa6
- .byte os_misc-.-1 # Unknown
- .byte os_dos-.-1 # DOS
- .byte os_dos-.-1 # DOS
- .byte os_dos-.-1 # DOS
- .byte os_dos-.-1 # Windows
- .byte os_dos-.-1 # Windows
- .byte os_dos-.-1 # Windows
- .byte os_unix-.-1 # UNIX
- .byte os_linux-.-1 # Linux
- .byte os_freebsd-.-1 # FreeBSD
- .byte os_bsd-.-1 # OpenBSD
+ .byte os_misc-. # Unknown
+ .byte os_dos-. # DOS
+ .byte os_dos-. # DOS
+ .byte os_dos-. # DOS
+ .byte os_dos-. # Windows
+ .byte os_dos-. # Windows
+ .byte os_dos-. # Windows
+ .byte os_unix-. # UNIX
+ .byte os_linux-. # Linux
+ .byte os_freebsd-. # FreeBSD
+ .byte os_bsd-. # OpenBSD
os_misc: .ascii "?"; .byte '?'|0x80
os_dos: .ascii "DO"; .byte 'S'|0x80
@@ -220,12 +252,14 @@ os_linux: .ascii "Linu"; .byte 'x'|0x80
os_freebsd: .ascii "Free"
os_bsd: .ascii "BS"; .byte 'D'|0x80
- .fill start+PRT_OFF-0x3-.,0x1,0x90
-
-opt: .byte 0x1 # Option
-ticks: .word 0xb6 # Delay
+ .org PRT_OFF-0xc,0x90
-partbl: .fill 0x40,0x1,0x0 # Partition table
- .word 0xaa55 # Magic number
+drive: .ascii "Drive "
+nxtdrv: .byte 0x0 # Next drive number
+opt: .byte 0x0 # Option
+setdrv: .byte 0x80 # Drive to force
+flags: .byte FLAGS # Flags
+ticks: .word TICKS # Delay
-break: # Uninitialized data
+partbl: .fill 0x40,0x1,0x0 # Partition table
+ .word MAGIC # Magic number
diff --git a/sys/boot/i386/boot2/Makefile b/sys/boot/i386/boot2/Makefile
index b52493f..d10aa12 100644
--- a/sys/boot/i386/boot2/Makefile
+++ b/sys/boot/i386/boot2/Makefile
@@ -1,7 +1,20 @@
-# $Id:$
+# $Id: Makefile,v 1.11 1999/01/10 14:48:03 rnordier Exp $
+
+PROG= boot2
+NOMAN=
+STRIP=
+BINDIR?= /boot
+BINMODE= 444
+CLEANFILES+= boot1 boot1.out boot1.o \
+ boot2.ldr boot2.bin boot2.ld boot2.out boot2.o \
+ sio.o
M4?= m4
+BOOT_COMCONSOLE_PORT?= 0x3f8
+BOOT_COMCONSOLE_SPEED?= 9600
+B2SIOFMT?= 0x3
+
.if exists(${.OBJDIR}/../btx)
BTX= ${.OBJDIR}/../btx
.else
@@ -11,8 +24,8 @@ BTX= ${.CURDIR}/../btx
ORG1= 0x7c00
ORG2= 0x1000
-CFLAGS= -elf -I${BTX}/lib -I. -fno-builtin \
- -O2 -malign-functions=0 -malign-jumps=0 -malign-loops=0 -mrtd \
+CFLAGS= -elf -I${.CURDIR}/../btx/lib -I. -fno-builtin \
+ -Os -malign-functions=0 -malign-jumps=0 -malign-loops=0 -mrtd \
-Wall -Waggregate-return -Wbad-function-cast -Wcast-align \
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings
@@ -22,30 +35,42 @@ LDFLAGS=-nostdlib -static -N
all: boot1 boot2
boot1: boot1.out
- /usr/libexec/elf/objcopy -S -O binary boot1.out ${.TARGET}
+ objcopy -S -O binary boot1.out ${.TARGET}
boot1.out: boot1.o
${LD} ${LDFLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} boot1.o
boot1.o: boot1.m4 boot1.s
- ${M4} boot1.m4 boot1.s | ${AS} ${AFLAGS} -o ${.TARGET}
+ (cd ${.CURDIR}; ${M4} boot1.m4 boot1.s) | \
+ ${AS} ${AFLAGS} -o ${.TARGET}
boot2: boot2.ldr boot2.bin
btxld -v -E ${ORG2} -f bin -b ${BTX}/btx/btx -l boot2.ldr \
- -o ${.TARGET} -P 1 boot2.bin
- @ls -l boot2 | awk '{ x = 7680 - $$5; print x " bytes free"; \
- if (x < 0) exit 1 }'
+ -o boot2.ld -P 1 boot2.bin
+ @ls -l boot2.ld | awk '{ x = 7680 - $$5; \
+ print x " bytes available"; if (x < 0) exit 1 }'
+ dd if=boot2.ld of=${.TARGET} obs=7680 conv=osync 2>/dev/null
boot2.ldr:
dd if=/dev/zero of=${.TARGET} bs=512 count=1 2>/dev/null
boot2.bin: boot2.out
- /usr/libexec/elf/objcopy -S -O binary boot2.out ${.TARGET}
+ objcopy -S -O binary boot2.out ${.TARGET}
-boot2.out: boot2.o
+boot2.out: boot2.o sio.o
${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} \
- ${BTX}/lib/crt0.o boot2.o
+ ${BTX}/lib/crt0.o boot2.o sio.o
+
+sio.o: sio.s
+ (cd ${.CURDIR}; ${M4} -DSIOPRT=${BOOT_COMCONSOLE_PORT} \
+ -DSIOFMT=${B2SIOFMT} \
+ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} sio.s) | \
+ ${AS} ${AFLAGS} -o ${.TARGET}
+
+install:
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ boot1 ${DESTDIR}${BINDIR}/boot1
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ boot2 ${DESTDIR}${BINDIR}/boot2
-clean:
- rm -f boot1 boot1.out boot1.o boot2 boot2.ldr boot2.bin \
- boot2.out boot2.o
+.include <bsd.prog.mk>
diff --git a/sys/boot/i386/boot2/boot1.S b/sys/boot/i386/boot2/boot1.S
new file mode 100644
index 0000000..3161b74
--- /dev/null
+++ b/sys/boot/i386/boot2/boot1.S
@@ -0,0 +1,236 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: boot1.s,v 1.7 1999/01/10 13:29:51 peter Exp $
+
+ .set MEM_REL,0x700 # Relocation address
+ .set MEM_ARG,0x900 # Arguments
+ .set MEM_ORG,0x7c00 # Origin
+ .set MEM_BUF,0x8c00 # Load area
+ .set MEM_BTX,0x9000 # BTX start
+ .set MEM_JMP,0x9010 # BTX entry point
+ .set MEM_USR,0xa000 # Client start
+
+ .set PRT_OFF,0x1be # Partition offset
+ .set PRT_NUM,0x4 # Partitions
+ .set PRT_BSD,0xa5 # Partition type
+
+ .set SIZ_PAG,0x1000 # Page size
+ .set SIZ_SEC,0x200 # Sector size
+
+ .globl start
+ .globl xread
+
+start: jmp main # Start recognizably
+
+ .org 0x4,0x90
+
+# External read from disk
+
+xread: pushl %ecx # Set
+ pushl %eax # LBA
+ pushl %es # Set transfer
+ pushl %ebx # buffer
+ pushl %edx # Set count:drive
+ callwi(read) # Read from disk
+ popl %edx # Pop all
+ popl %ebx # registers
+ popl %es # pushed, but
+ popl %ecx # preserve
+ popl %ecx # AX
+ lret # To far caller
+
+# Bootstrap
+
+main: cld # String ops inc
+ xorl %ecx,%ecx # Zero
+ movl %cx,%es # Address
+ movl %cx,%ds # data
+ movl %cx,%ss # Set up
+ movwir(start,_sp) # stack
+ movl %esp,%esi # Source
+ movwir(MEM_REL,_di) # Destination
+ incb %ch # Word count
+ rep # Copy
+ movsl # code
+ movwir(part4,_si) # Partition
+ cmpb $0x80,%dl # Hard drive?
+ jb main.4 # No
+ movb $0x1,%dh # Block count
+ callwi(nread) # Read MBR
+ movwir(0x1,_cx) # Two passes
+main.1: movwir(MEM_BUF+PRT_OFF,_si) # Partition table
+ movb $0x1,%dh # Partition
+main.2: cmpbi1(PRT_BSD,0x4,_si_) # Our partition type?
+ jne main.3 # No
+ jecxz main.5 # If second pass
+ tstbi0(0x80,_si_) # Active?
+ jnz main.5 # Yes
+main.3: addl $0x10,%esi # Next entry
+ incb %dh # Partition
+ cmpb $0x1+PRT_NUM,%dh # In table?
+ jb main.2 # Yes
+ decl %ecx # Do two
+ jecxz main.1 # passes
+ movwir(msg_part,_si) # Message
+ jmp error # Error
+main.4: xorl %edx,%edx # Partition:drive
+main.5: movwrm(_dx,MEM_ARG) # Save args
+ movb $0x10,%dh # Sector count
+ callwi(nread) # Read disk
+ movwir(MEM_BTX,_bx) # BTX
+ movw1r(0xa,_bx_,_si) # Point past
+ addl %ebx,%esi # it
+ movwir(MEM_USR+SIZ_PAG,_di) # Client page 1
+ movwir(MEM_BTX+0xe*SIZ_SEC,_cx) # Byte
+ subl %esi,%ecx # count
+ rep # Relocate
+ movsb # client
+ subl %edi,%ecx # Byte count
+ xorb %al,%al # Zero
+ rep # assumed
+ stosb # bss
+ callwi(seta20) # Enable A20
+ jmpnwi(start+MEM_JMP-MEM_ORG) # Start BTX
+
+# Enable A20
+
+seta20: cli # Disable interrupts
+seta20.1: inb $0x64,%al # Get status
+ testb $0x2,%al # Busy?
+ jnz seta20.1 # Yes
+ movb $0xd1,%al # Command: Write
+ outb %al,$0x64 # output port
+seta20.2: inb $0x64,%al # Get status
+ testb $0x2,%al # Busy?
+ jnz seta20.2 # Yes
+ movb $0xdf,%al # Enable
+ outb %al,$0x60 # A20
+ sti # Enable interrupts
+ ret # To caller
+
+# Local read from disk
+
+nread: movwir(MEM_BUF,_bx) # Transfer buffer
+ movw1r(0x8,_si_,_ax) # Get
+ movw1r(0xa,_si_,_cx) # LBA
+ pushl %cs # Read from
+ callwi(xread) # disk
+ jnc return # If success
+ movwir(msg_read,_si) # Message
+
+# Error exit
+
+error: callwi(putstr) # Display message
+ movwir(prompt,_si) # Display
+ callwi(putstr) # prompt
+ xorb %ah,%ah # BIOS: Get
+ int $0x16 # keypress
+ int $0x19 # BIOS: Reboot
+
+# Display string
+
+putstr.0: movwir(0x7,_bx) # Page:attribute
+ movb $0xe,%ah # BIOS: Display
+ int $0x10 # character
+putstr: lodsb # Get char
+ testb %al,%al # End of string?
+ jne putstr.0 # No
+
+ereturn: movb $0x1,%ah # Invalid
+ stc # argument
+return: ret # To caller
+
+# Read from disk
+
+read: movl %esp,%ebp # Address stack frame
+ pushl %edx # Save
+ movb $0x8,%ah # BIOS: Get drive
+ int $0x13 # parameters
+ movb %dh,%ch # Max head number
+ popl %edx # Restore
+ jc return # If error
+ andb $0x3f,%cl # Sectors per track
+ jz ereturn # If zero
+ cli # Disable interrupts
+ o16 # Get
+ movw1r(0x8,_bp_,_ax) # LBA
+ pushl %edx # Save
+ movzbw %cl,%bx # Divide by
+ xorw %dx,%dx # sectors
+ divw %bx,%ax # per track
+ movb %ch,%bl # Max head number
+ movb %dl,%ch # Sector number
+ incl %ebx # Divide by
+ xorb %dl,%dl # number
+ divw %bx,%ax # of heads
+ movb %dl,%bh # Head number
+ popl %edx # Restore
+ o16 # Cylinder number
+ cmpl $0x3ff,%eax # supportable?
+ sti # Enable interrupts
+ ja ereturn # No
+ xchgb %al,%ah # Set up cylinder
+ rorb $0x2,%al # number
+ orb %ch,%al # Merge
+ incl %eax # sector
+ xchgl %eax,%ecx # number
+ movb %bh,%dh # Head number
+ subb %ah,%al # Sectors this track
+ movb1r(0x3,_bp_,_ah) # Blocks to read
+ cmpb %ah,%al # To read
+ jb read.1 # this
+ movb %ah,%al # track
+read.1: movwir(0x5,_di) # Try count
+read.2: lesw1r(0x4,_bp_,_bx) # Transfer buffer
+ pushl %eax # Save
+ movb $0x2,%ah # BIOS: Read
+ int $0x13 # from disk
+ popl %ebx # Restore
+ jnc read.3 # If success
+ decl %edi # Retry?
+ jz read.5 # No
+ xorb %ah,%ah # BIOS: Reset
+ int $0x13 # disk system
+ xchgl %ebx,%eax # Block count
+ jmp read.2 # Continue
+read.3: movzbl %bl,%eax # Sectors read
+ addwr1(_ax,0x8,_bp_) # Adjust
+ jnc read.4 # LBA,
+ incw1(0xa,_bp_) # transfer
+read.4: shlb %bl # buffer
+ addbr1(_bl,0x5,_bp_) # pointer,
+ subbr1(_al,0x3,_bp_) # block count
+ ja read # If not done
+read.5: ret # To caller
+
+# Messages
+
+msg_read: .asciz "Read"
+msg_part: .asciz "Boot"
+
+prompt: .asciz " error\r\n"
+
+ .org PRT_OFF,0x90
+
+# Partition table
+
+ .fill 0x30,0x1,0x0
+part4: .byte 0x80, 0x00, 0x01, 0x00
+ .byte 0xa5, 0xff, 0xff, 0xff
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x50, 0xc3, 0x00, 0x00
+
+ .word 0xaa55 # Magic number
diff --git a/sys/boot/i386/boot2/boot1.m4 b/sys/boot/i386/boot2/boot1.m4
index fc221a1..06bdc97 100644
--- a/sys/boot/i386/boot2/boot1.m4
+++ b/sys/boot/i386/boot2/boot1.m4
@@ -13,7 +13,7 @@
# purpose.
#
-# $Id:$
+# $Id: boot1.m4,v 1.2 1998/11/05 20:52:25 rnordier Exp $
define(_al,0x0)dnl
define(_cl,0x1)dnl
@@ -60,3 +60,5 @@ define(movbi1,`.byte 0xc6; .byte 0x40 | $3; .byte $2; .byte $1')dnl
define(callwi,`.byte 0xe8; .word $1 - . - 0x2')dnl
define(jmpnwi,`.byte 0xe9; .word $1 - . - 0x2')dnl
define(tstbi0,`.byte 0xf6; .byte $2; .byte $1')dnl
+define(tstbim,`.byte 0xf6; .byte 0x6; .word $2; .byte $1')dnl
+define(incw1,`.byte 0xff; .byte 0x40 | $2; .byte $1')dnl
diff --git a/sys/boot/i386/boot2/boot1.s b/sys/boot/i386/boot2/boot1.s
index b84ddf3..3161b74 100644
--- a/sys/boot/i386/boot2/boot1.s
+++ b/sys/boot/i386/boot2/boot1.s
@@ -13,11 +13,10 @@
# purpose.
#
-# $Id:$
+# $Id: boot1.s,v 1.7 1999/01/10 13:29:51 peter Exp $
- .set MEM_REL,0x600 # Relocation address
- .set MEM_ARG,0x800 # Arguments
- .set MEM_PKT,0x810 # Disk packet
+ .set MEM_REL,0x700 # Relocation address
+ .set MEM_ARG,0x900 # Arguments
.set MEM_ORG,0x7c00 # Origin
.set MEM_BUF,0x8c00 # Load area
.set MEM_BTX,0x9000 # BTX start
@@ -38,65 +37,64 @@ start: jmp main # Start recognizably
.org 0x4,0x90
-xread: pushl %cs # Address
- popl %ds # data
-xread.1: movwir(MEM_PKT,_si) # Packet
- movbr1(_al,0x2,_si_) # Blocks to read
- o16 # Transfer
- movwr1(_bx,0x4,_si_) # buffer
- o16 # LBA
- movwr1(_cx,0x8,_si_) # address
+# External read from disk
+
+xread: pushl %ecx # Set
+ pushl %eax # LBA
+ pushl %es # Set transfer
+ pushl %ebx # buffer
+ pushl %edx # Set count:drive
callwi(read) # Read from disk
- lret # To caller
+ popl %edx # Pop all
+ popl %ebx # registers
+ popl %es # pushed, but
+ popl %ecx # preserve
+ popl %ecx # AX
+ lret # To far caller
+
+# Bootstrap
main: cld # String ops inc
- xorl %eax,%eax # Zero
- movl %ax,%es # Address
- movl %ax,%ds # data
- movl %ax,%ss # Set up
+ xorl %ecx,%ecx # Zero
+ movl %cx,%es # Address
+ movl %cx,%ds # data
+ movl %cx,%ss # Set up
movwir(start,_sp) # stack
movl %esp,%esi # Source
movwir(MEM_REL,_di) # Destination
- movwir(0x100,_cx) # Word count
+ incb %ch # Word count
rep # Copy
movsl # code
- movb $0x10,%cl # Words to clear
- rep # Zero
- stosl # them
- movbi1(0x10,-0x10,_di_) # Set packet size
+ movwir(part4,_si) # Partition
cmpb $0x80,%dl # Hard drive?
jb main.4 # No
- movwir(part4,_si) # Read master
- movb $0x1,%al # boot
- callwi(nread) # record
- xorl %eax,%eax # Pass number
+ movb $0x1,%dh # Block count
+ callwi(nread) # Read MBR
+ movwir(0x1,_cx) # Two passes
main.1: movwir(MEM_BUF+PRT_OFF,_si) # Partition table
movb $0x1,%dh # Partition
main.2: cmpbi1(PRT_BSD,0x4,_si_) # Our partition type?
jne main.3 # No
+ jecxz main.5 # If second pass
tstbi0(0x80,_si_) # Active?
jnz main.5 # Yes
- testb %al,%al # Second pass?
- jnz main.5 # Yes
main.3: addl $0x10,%esi # Next entry
incb %dh # Partition
- cmpb $0x1+PRT_NUM,%dh # Done?
- jb main.2 # No
- incl %eax # Pass
- cmpb $0x2,%al # Done?
- jb main.1 # No
+ cmpb $0x1+PRT_NUM,%dh # In table?
+ jb main.2 # Yes
+ decl %ecx # Do two
+ jecxz main.1 # passes
movwir(msg_part,_si) # Message
jmp error # Error
main.4: xorl %edx,%edx # Partition:drive
- movwir(part4,_si) # Partition pointer
main.5: movwrm(_dx,MEM_ARG) # Save args
- movb $0x10,%al # Sector count
+ movb $0x10,%dh # Sector count
callwi(nread) # Read disk
movwir(MEM_BTX,_bx) # BTX
movw1r(0xa,_bx_,_si) # Point past
addl %ebx,%esi # it
movwir(MEM_USR+SIZ_PAG,_di) # Client page 1
- movwir(MEM_BTX+0xd*SIZ_SEC,_cx) # Byte
+ movwir(MEM_BTX+0xe*SIZ_SEC,_cx) # Byte
subl %esi,%ecx # count
rep # Relocate
movsb # client
@@ -109,33 +107,34 @@ main.5: movwrm(_dx,MEM_ARG) # Save args
# Enable A20
-seta20: inb $0x64,%al # Get status
+seta20: cli # Disable interrupts
+seta20.1: inb $0x64,%al # Get status
testb $0x2,%al # Busy?
- jnz seta20 # Yes
+ jnz seta20.1 # Yes
movb $0xd1,%al # Command: Write
outb %al,$0x64 # output port
-seta20.1: inb $0x64,%al # Get status
+seta20.2: inb $0x64,%al # Get status
testb $0x2,%al # Busy?
- jnz seta20.1 # Yes
+ jnz seta20.2 # Yes
movb $0xdf,%al # Enable
outb %al,$0x60 # A20
+ sti # Enable interrupts
ret # To caller
-# Read from disk
+# Local read from disk
-nread: xorw %bx,%bx # Transfer
- movb $MEM_BUF>>0x8,%bh # buffer
- o16 # LBA
- movw1r(0x8,_si_,_cx) # address
+nread: movwir(MEM_BUF,_bx) # Transfer buffer
+ movw1r(0x8,_si_,_ax) # Get
+ movw1r(0xa,_si_,_cx) # LBA
pushl %cs # Read from
- callwi(xread.1) # disk
+ callwi(xread) # disk
jnc return # If success
movwir(msg_read,_si) # Message
# Error exit
error: callwi(putstr) # Display message
- movwir(msg_boot,_si) # Display
+ movwir(prompt,_si) # Display
callwi(putstr) # prompt
xorb %ah,%ah # BIOS: Get
int $0x16 # keypress
@@ -150,40 +149,24 @@ putstr: lodsb # Get char
testb %al,%al # End of string?
jne putstr.0 # No
-return: ret # Generic return
+ereturn: movb $0x1,%ah # Invalid
+ stc # argument
+return: ret # To caller
# Read from disk
-read: testb %dh,%dh # Try for extensions?
- jz read.3 # No
- movwir(0x55aa,_bx) # Magic
+read: movl %esp,%ebp # Address stack frame
pushl %edx # Save
- movb $0x41,%ah # BIOS: Check
- int $0x13 # extensions present
- popl %edx # Restore
- jc read.3 # If error
- cmpwir(0xaa55,_bx) # Magic?
- jne read.3 # No
- testb $0x1,%cl # Packet interface?
- jz read.3 # No
- movb $0x42,%ah # BIOS: Extended
- int $0x13 # read
- ret # To caller
-
-read.1: movb $0x1,%ah # Invalid
- stc # parameter
-read.2: ret # To caller
-
-read.3: pushl %edx # Save
movb $0x8,%ah # BIOS: Get drive
int $0x13 # parameters
movb %dh,%ch # Max head number
popl %edx # Restore
- jc read.2 # If error
+ jc return # If error
andb $0x3f,%cl # Sectors per track
- jz read.1 # If zero
+ jz ereturn # If zero
+ cli # Disable interrupts
o16 # Get
- movw1r(0x8,_si_,_ax) # LBA
+ movw1r(0x8,_bp_,_ax) # LBA
pushl %edx # Save
movzbw %cl,%bx # Divide by
xorw %dx,%dx # sectors
@@ -191,13 +174,14 @@ read.3: pushl %edx # Save
movb %ch,%bl # Max head number
movb %dl,%ch # Sector number
incl %ebx # Divide by
- xorb %dl,%dl # number of
- divw %bx,%ax # heads
+ xorb %dl,%dl # number
+ divw %bx,%ax # of heads
movb %dl,%bh # Head number
popl %edx # Restore
o16 # Cylinder number
cmpl $0x3ff,%eax # supportable?
- ja read.1 # No
+ sti # Enable interrupts
+ ja ereturn # No
xchgb %al,%ah # Set up cylinder
rorb $0x2,%al # number
orb %ch,%al # Merge
@@ -205,37 +189,39 @@ read.3: pushl %edx # Save
xchgl %eax,%ecx # number
movb %bh,%dh # Head number
subb %ah,%al # Sectors this track
- movb1r(0x2,_si_,_ah) # Blocks to read
+ movb1r(0x3,_bp_,_ah) # Blocks to read
cmpb %ah,%al # To read
- jb read.4 # this
+ jb read.1 # this
movb %ah,%al # track
-read.4: movwir(0x5,_bp) # Try count
-read.5: lesw1r(0x4,_si_,_bx) # Transfer buffer
+read.1: movwir(0x5,_di) # Try count
+read.2: lesw1r(0x4,_bp_,_bx) # Transfer buffer
pushl %eax # Save
- movb $0x2,%ah # BIOS: Conventional
- int $0x13 # read
+ movb $0x2,%ah # BIOS: Read
+ int $0x13 # from disk
popl %ebx # Restore
- jnc read.6 # If success
- decl %ebp # Retry?
- jz read.7 # No
+ jnc read.3 # If success
+ decl %edi # Retry?
+ jz read.5 # No
xorb %ah,%ah # BIOS: Reset
int $0x13 # disk system
- movl %ebx,%eax # Block count
- jmp read.5 # Continue
-read.6: movzbw %bl,%ax # Sectors read
- o16 # Adjust
- addwr1(_ax,0x8,_si_) # LBA,
- shlb %bl # buffer
- addbr1(_bl,0x5,_si_) # pointer,
- subbr1(_al,0x2,_si_) # block count
- ja read.3 # If not done
-read.7: ret # To caller
+ xchgl %ebx,%eax # Block count
+ jmp read.2 # Continue
+read.3: movzbl %bl,%eax # Sectors read
+ addwr1(_ax,0x8,_bp_) # Adjust
+ jnc read.4 # LBA,
+ incw1(0xa,_bp_) # transfer
+read.4: shlb %bl # buffer
+ addbr1(_bl,0x5,_bp_) # pointer,
+ subbr1(_al,0x3,_bp_) # block count
+ ja read # If not done
+read.5: ret # To caller
# Messages
-msg_read: .asciz "Read error"
-msg_part: .asciz "No bootable partition"
-msg_boot: .asciz "\r\nHit return to reboot: "
+msg_read: .asciz "Read"
+msg_part: .asciz "Boot"
+
+prompt: .asciz " error\r\n"
.org PRT_OFF,0x90
diff --git a/sys/boot/i386/boot2/boot2.c b/sys/boot/i386/boot2/boot2.c
index 25dd42a..b711c28 100644
--- a/sys/boot/i386/boot2/boot2.c
+++ b/sys/boot/i386/boot2/boot2.c
@@ -14,7 +14,7 @@
*/
/*
- * $Id:$
+ * $Id: boot2.c,v 1.22 1999/04/04 21:15:41 obrien Exp $
*/
#include <sys/param.h>
@@ -34,46 +34,61 @@
#include <btxv86.h>
+#include "lib.h"
+
#define RBX_ASKNAME 0x0 /* -a */
#define RBX_SINGLE 0x1 /* -s */
#define RBX_DFLTROOT 0x5 /* -r */
#define RBX_KDB 0x6 /* -d */
#define RBX_CONFIG 0xa /* -c */
#define RBX_VERBOSE 0xb /* -v */
+#define RBX_SERIAL 0xc /* -h */
#define RBX_CDROM 0xd /* -C */
#define RBX_GDB 0xf /* -g */
+#define RBX_DUAL 0x1d /* -D */
+#define RBX_PROBEKBD 0x1e /* -P */
+
+#define RBX_MASK 0xffff
#define PATH_CONFIG "/boot.config"
#define PATH_BOOT3 "/boot/loader"
#define PATH_KERNEL "/kernel"
-#define PATH_HELP "boot.help"
-#define ARGS 0x800
-#define NOPT 8
+#define ARGS 0x900
+#define NOPT 11
#define BSIZEMAX 8192
-#define NDEV 3
+#define NDEV 5
#define MEM_BASE 0x12
#define MEM_EXT 0x15
#define V86_CY(x) ((x) & 1)
#define V86_ZR(x) ((x) & 0x40)
+#define DRV_HARD 0x80
+#define DRV_MASK 0x7f
+
+#define MAJ_WD 0
+#define MAJ_WFD 1
+#define MAJ_FD 2
+#define MAJ_DA 4
+
extern uint32_t _end;
-static const char optstr[NOPT] = "aCcdgrsv";
+static const char optstr[NOPT] = "DhaCcdgPrsv";
static const unsigned char flags[NOPT] = {
+ RBX_DUAL,
+ RBX_SERIAL,
RBX_ASKNAME,
RBX_CDROM,
RBX_CONFIG,
RBX_KDB,
RBX_GDB,
+ RBX_PROBEKBD,
RBX_DFLTROOT,
RBX_SINGLE,
RBX_VERBOSE
};
-static const char *const dev_nm[] = {"fd", "wd", "da"};
-static const uint8_t dev_bios[] = {0, 0x80, 0x82};
-static const uint8_t dev_bsd[] = {2, 0, 4};
+static const char *const dev_nm[] = {"wd", " ", "fd", " ", "da"};
static struct dsk {
unsigned drive;
@@ -81,15 +96,17 @@ static struct dsk {
unsigned unit;
unsigned slice;
unsigned part;
+ unsigned start;
+ int init;
int meta;
} dsk;
static char cmd[512];
static char kname[1024];
-static char help[2048];
static uint32_t opts;
static struct bootinfo bootinfo;
static int ls;
static uint32_t fs_off;
+static uint8_t ioctrl = 0x1;
void exit(int);
static void load(const char *);
@@ -97,6 +114,7 @@ static int parse(char *);
static void readfile(const char *, void *, size_t);
static ino_t lookup(const char *);
static int fsfind(const char *, ino_t *);
+static int xfsread(ino_t, void *, size_t);
static ssize_t fsread(ino_t, void *, size_t);
static int dskread(void *, unsigned, unsigned);
static int printf(const char *,...);
@@ -110,19 +128,20 @@ static uint32_t memsize(int);
static uint32_t drvinfo(int);
static int drvread(void *, unsigned, unsigned);
static int keyhit(unsigned);
-static int putch(int);
-static int getch(void);
+static int xputc(int);
+static int xgetc(int);
+static void putc(int);
+static int getc(int);
int
main(void)
{
- int autoboot, helpon, i;
+ int autoboot, i;
+ v86.ctl = V86_FLAGS;
dsk.drive = *(uint8_t *)PTOV(ARGS);
- for (dsk.type = NDEV - 1;
- (i = dsk.drive - dev_bios[dsk.type]) < 0;
- dsk.type--);
- dsk.unit = i;
+ dsk.type = dsk.drive & DRV_HARD ? MAJ_WD : MAJ_FD;
+ dsk.unit = dsk.drive & DRV_MASK;
dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
bootinfo.bi_version = BOOTINFO_VERSION;
bootinfo.bi_size = sizeof(bootinfo);
@@ -132,11 +151,14 @@ main(void)
for (i = 0; i < N_BIOS_GEOM; i++)
bootinfo.bi_bios_geom[i] = drvinfo(i);
autoboot = 2;
- helpon = 1;
readfile(PATH_CONFIG, cmd, sizeof(cmd));
- if (parse(cmd))
- autoboot = 0;
- else if (!*kname) {
+ if (*cmd) {
+ printf("%s: %s", PATH_CONFIG, cmd);
+ if (parse(cmd))
+ autoboot = 0;
+ *cmd = 0;
+ }
+ if (autoboot && !*kname) {
if (autoboot == 2) {
memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
if (!keyhit(0x37)) {
@@ -147,19 +169,21 @@ main(void)
if (autoboot == 1)
memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
}
- readfile(PATH_HELP, help, sizeof(help));
for (;;) {
printf(" \n>> FreeBSD/i386 BOOT\n"
"Default: %u:%s(%u,%c)%s\n"
- "%s"
"boot: ",
- dsk.drive & 0x7f, dev_nm[dsk.type], dsk.unit,
- 'a' + dsk.part, kname, helpon ? help : "");
+ dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
+ 'a' + dsk.part, kname);
+ if (ioctrl & 0x2)
+ sio_flush();
if (!autoboot || keyhit(0x5a))
getstr(cmd, sizeof(cmd));
- autoboot = helpon = 0;
+ else
+ putchar('\n');
+ autoboot = 0;
if (parse(cmd))
- helpon = 1;
+ putchar('\a');
else
load(kname);
}
@@ -184,11 +208,12 @@ load(const char *fname)
uint32_t addr, x;
int fmt, i, j;
- if (!(ino = lookup(fname)) && !ls) {
- printf("No `%s'\n", fname);
+ if (!(ino = lookup(fname))) {
+ if (!ls)
+ printf("No %s\n", fname);
return;
}
- if (fsread(ino, &hdr, sizeof(hdr)) != sizeof(hdr))
+ if (xfsread(ino, &hdr, sizeof(hdr)))
return;
if (N_GETMAGIC(hdr.ex) == ZMAGIC)
fmt = 0;
@@ -201,66 +226,55 @@ load(const char *fname)
if (fmt == 0) {
addr = hdr.ex.a_entry & 0xffffff;
p = PTOV(addr);
- printf("%s=0x%x ", "text", (unsigned)hdr.ex.a_text);
fs_off = PAGE_SIZE;
- if (fsread(ino, p, hdr.ex.a_text) != hdr.ex.a_text)
+ if (xfsread(ino, p, hdr.ex.a_text))
return;
p += roundup2(hdr.ex.a_text, PAGE_SIZE);
- printf("%s=0x%x ", "data", (unsigned)hdr.ex.a_data);
- if (fsread(ino, p, hdr.ex.a_data) != hdr.ex.a_data)
+ if (xfsread(ino, p, hdr.ex.a_data))
return;
- p += hdr.ex.a_data;
- printf("%s=0x%x ", "bss", (unsigned)hdr.ex.a_bss);
- p += roundup2(hdr.ex.a_bss, PAGE_SIZE);
+ p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
bootinfo.bi_symtab = VTOP(p);
memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
p += sizeof(hdr.ex.a_syms);
- printf("symbols=[");
- printf("+0x%x", (unsigned)hdr.ex.a_syms);
if (hdr.ex.a_syms) {
- if (fsread(ino, p, hdr.ex.a_syms) != hdr.ex.a_syms)
+ if (xfsread(ino, p, hdr.ex.a_syms))
return;
p += hdr.ex.a_syms;
- if (fsread(ino, p, sizeof(int)) != sizeof(int))
+ if (xfsread(ino, p, sizeof(int)))
return;
x = *(uint32_t *)p;
p += sizeof(int);
x -= sizeof(int);
- printf("+0x%x", x);
- if (fsread(ino, p, x) != x)
+ if (xfsread(ino, p, x))
return;
p += x;
}
} else {
fs_off = hdr.eh.e_phoff;
for (j = i = 0; i < hdr.eh.e_phoff && j < 2; i++) {
- if (fsread(ino, ep + j, sizeof(ep[0])) != sizeof(ep[0]))
+ 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);
- printf("%s=0x%x ", !i ? "text" : "data", ep[i].p_filesz);
fs_off = ep[i].p_offset;
- if (fsread(ino, p, ep[i].p_filesz) != ep[i].p_filesz)
+ if (xfsread(ino, p, ep[i].p_filesz))
return;
}
- printf("%s=0x%x ", "bss", ep[1].p_memsz - ep[1].p_filesz);
p += roundup2(ep[1].p_memsz, PAGE_SIZE);
bootinfo.bi_symtab = VTOP(p);
- printf("symbols=[");
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 (fsread(ino, &es, sizeof(es)) != sizeof(es))
+ if (xfsread(ino, &es, sizeof(es)))
return;
for (i = 0; i < 2; i++) {
memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
p += sizeof(es[i].sh_size);
- printf("+0x%x", es[i].sh_size);
fs_off = es[i].sh_offset;
- if (fsread(ino, p, es[i].sh_size) != es[i].sh_size)
+ if (xfsread(ino, p, es[i].sh_size))
return;
p += es[i].sh_size;
}
@@ -268,11 +282,11 @@ load(const char *fname)
addr = hdr.eh.e_entry & 0xffffff;
}
bootinfo.bi_esymtab = VTOP(p);
- printf("]\nentry=0x%x\n", addr);
bootinfo.bi_kernelname = VTOP(fname);
- __exec((caddr_t)addr, RB_BOOTINFO | opts,
- MAKEBOOTDEV(dev_bsd[dsk.type], 0, dsk.slice, dsk.unit,
- dsk.part), 0, 0, 0, VTOP(&bootinfo));
+ bootinfo.bi_bios_dev = dsk.drive;
+ __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
+ MAKEBOOTDEV(dsk.type, 0, dsk.slice, dsk.unit, dsk.part),
+ 0, 0, 0, VTOP(&bootinfo));
}
static int
@@ -287,14 +301,25 @@ parse(char *arg)
for (p = arg; *p && *p != '\n' && *p != ' '; p++);
if (*p)
*p++ = 0;
- if (c == '-')
+ if (c == '-') {
while ((c = *arg++)) {
for (i = 0; c != optstr[i]; i++)
if (i == NOPT - 1)
return -1;
- opts |= 1 << flags[i];
+ opts ^= 1 << flags[i];
}
- else {
+ if (opts & 1 << RBX_PROBEKBD) {
+ i = *(uint8_t *)PTOV(0x496) & 0x10;
+ printf("Keyboard: %s\n", i ? "yes" : "no");
+ if (!i)
+ opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL;
+ opts &= ~(1 << RBX_PROBEKBD);
+ }
+ ioctrl = opts & 1 << RBX_DUAL ? 0x3 :
+ opts & 1 << RBX_SERIAL ? 0x2 : 0x1;
+ if (ioctrl & 0x2)
+ sio_init();
+ } else {
for (q = arg--; *q && *q != '('; q++);
if (*q) {
drv = -1;
@@ -307,7 +332,7 @@ parse(char *arg)
if (q - arg != 2)
return -1;
for (i = 0; arg[0] != dev_nm[i][0] ||
- arg[1] != dev_nm[i][1]; i++)
+ arg[1] != dev_nm[i][1]; i++)
if (i == NDEV - 1)
return -1;
dsk.type = i;
@@ -316,8 +341,9 @@ parse(char *arg)
return -1;
dsk.unit = *arg - '0';
arg += 2;
+ dsk.slice = WHOLE_DISK_SLICE;
if (arg[1] == ',') {
- if (*arg < '0' || *arg > '4')
+ if (*arg < '0' || *arg > '0' + NDOSPART)
return -1;
if ((dsk.slice = *arg - '0'))
dsk.slice++;
@@ -328,10 +354,11 @@ parse(char *arg)
dsk.part = *arg - 'a';
arg += 2;
if (drv == -1)
- dsk.drive = dev_bios[dsk.type] + dsk.unit;
- else
- dsk.drive = (dsk.type ? 0x80 : 0) + drv;
+ drv = dsk.unit;
+ dsk.drive = (dsk.type == MAJ_WD ||
+ dsk.type == MAJ_DA ? DRV_HARD : 0) + drv;
dsk.meta = 0;
+ fsread(0, NULL, 0);
}
if ((i = p - arg - !*(p - 1))) {
if (i >= sizeof(kname))
@@ -407,6 +434,16 @@ fsfind(const char *name, ino_t * ino)
return 0;
}
+static int
+xfsread(ino_t inode, void *buf, size_t nbyte)
+{
+ if (fsread(inode, buf, nbyte) != nbyte) {
+ printf("Invalid %s\n", "format");
+ return -1;
+ }
+ return 0;
+}
+
static ssize_t
fsread(ino_t inode, void *buf, size_t nbyte)
{
@@ -433,8 +470,10 @@ fsread(ino_t inode, void *buf, size_t nbyte)
return -1;
}
fsblks = fs.fs_bsize >> DEV_BSHIFT;
- dsk.meta = 1;
+ dsk.meta++;
}
+ if (!inode)
+ return 0;
if (inomap != inode) {
if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)),
fsblks))
@@ -485,7 +524,6 @@ static int
dskread(void *buf, unsigned lba, unsigned nblk)
{
static char *sec;
- static unsigned hidden;
struct dos_partition *dp;
struct disklabel *d;
unsigned sl, i;
@@ -493,42 +531,55 @@ dskread(void *buf, unsigned lba, unsigned nblk)
if (!dsk.meta) {
if (!sec)
sec = malloc(DEV_BSIZE);
- hidden = 0;
+ dsk.start = 0;
+ if (drvread(sec, DOSBBSECTOR, 1))
+ return -1;
+ dp = (void *)(sec + DOSPARTOFF);
sl = dsk.slice;
+ if (sl < BASE_SLICE) {
+ for (i = 0; i < NDOSPART; i++)
+ if (dp[i].dp_typ == DOSPTYP_386BSD &&
+ (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
+ sl = BASE_SLICE + i;
+ if (dp[i].dp_flag & 0x80 ||
+ dsk.slice == COMPATIBILITY_SLICE)
+ break;
+ }
+ if (dsk.slice == WHOLE_DISK_SLICE)
+ dsk.slice = sl;
+ }
if (sl != WHOLE_DISK_SLICE) {
- if (drvread(sec, DOSBBSECTOR, 1))
- return -1;
- dp = (void *)(sec + DOSPARTOFF);
- if (sl == COMPATIBILITY_SLICE)
- for (i = 0; i < NDOSPART; i++)
- if (dp[i].dp_typ == DOSPTYP_386BSD &&
- (dp[i].dp_flag & 0x80 ||
- sl == COMPATIBILITY_SLICE))
- sl = BASE_SLICE + i;
if (sl != COMPATIBILITY_SLICE)
dp += sl - BASE_SLICE;
if (dp->dp_typ != DOSPTYP_386BSD) {
printf("Invalid %s\n", "slice");
return -1;
}
- hidden = dp->dp_start;
+ dsk.start = dp->dp_start;
}
- if (dsk.part != RAW_PART) {
- if (drvread(sec, hidden + LABELSECTOR, 1))
+ if (drvread(sec, dsk.start + LABELSECTOR, 1))
return -1;
- d = (void *)(sec + LABELOFFSET);
- if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
+ d = (void *)(sec + LABELOFFSET);
+ if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
+ if (dsk.part != RAW_PART) {
printf("Invalid %s\n", "label");
return -1;
}
- if (dsk.part >= d->d_npartitions) {
+ } else {
+ if (!dsk.init) {
+ if (d->d_type == DTYPE_SCSI)
+ dsk.type = MAJ_DA;
+ dsk.init++;
+ }
+ if (dsk.part >= d->d_npartitions ||
+ !d->d_partitions[dsk.part].p_size) {
printf("Invalid %s\n", "partition");
return -1;
}
- hidden = d->d_partitions[dsk.part].p_offset;
+ dsk.start = d->d_partitions[dsk.part].p_offset;
}
}
- return drvread(buf, hidden + lba, nblk);
+ return drvread(buf, dsk.start + lba, nblk);
}
static int
@@ -581,9 +632,16 @@ getstr(char *str, int size)
s = str;
do {
switch (c = getchar()) {
+ case 0:
+ break;
case '\b':
- if (s > str)
+ case '\177':
+ if (s > str) {
s--;
+ putchar('\b');
+ putchar(' ');
+ } else
+ c = 0;
break;
case '\n':
*s = 0;
@@ -592,7 +650,8 @@ getstr(char *str, int size)
if (s - str < size - 1)
*s++ = c;
}
- putchar(c);
+ if (c)
+ putchar(c);
} while (c != '\n');
}
@@ -600,8 +659,8 @@ static int
putchar(int c)
{
if (c == '\n')
- putch('\r');
- return putch(c);
+ xputc('\r');
+ return xputc(c);
}
static int
@@ -609,7 +668,7 @@ getchar(void)
{
int c;
- c = getch();
+ c = xgetc(0);
if (c == '\r')
c = '\n';
return c;
@@ -649,7 +708,6 @@ malloc(size_t size)
static uint32_t
memsize(int type)
{
- v86.ctl = V86_FLAGS;
v86.addr = type;
v86.eax = 0x8800;
v86int();
@@ -661,7 +719,7 @@ drvinfo(int drive)
{
v86.addr = 0x13;
v86.eax = 0x800;
- v86.edx = 0x80 + drive;
+ v86.edx = DRV_HARD + drive;
v86int();
if (V86_CY(v86.efl))
return 0x4f010f;
@@ -672,12 +730,16 @@ drvinfo(int drive)
static int
drvread(void *buf, unsigned lba, unsigned nblk)
{
+ static unsigned c = 0x2d5c7c2f;
+
+ printf("%c\b", c = c << 8 | c >> 24);
v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
- v86.addr = 0x604;
- v86.eax = nblk;
- v86.ebx = VTOPSEG(buf) << 16 | VTOPOFF(buf);
- v86.ecx = lba;
- v86.edx = dsk.drive;
+ v86.addr = 0x704; /* call to xread in boot1 */
+ v86.es = VTOPSEG(buf);
+ v86.eax = lba;
+ v86.ebx = VTOPOFF(buf);
+ v86.ecx = lba >> 16;
+ v86.edx = nblk << 8 | dsk.drive;
v86int();
v86.ctl = V86_FLAGS;
if (V86_CY(v86.efl)) {
@@ -691,41 +753,57 @@ drvread(void *buf, unsigned lba, unsigned nblk)
static int
keyhit(unsigned ticks)
{
- uint32_t x;
+ uint32_t t0, t1;
- x = 0;
+ t0 = 0;
for (;;) {
- v86.addr = 0x16;
- v86.eax = 0x100;
- v86int();
- if (!V86_ZR(v86.efl))
+ if (xgetc(1))
return 1;
- v86.addr = 0x1a;
- v86.eax = 0;
- v86.edx = 0;
- v86int();
- if (!x)
- x = v86.edx;
- else if (v86.edx < x || v86.edx > x + ticks)
+ t1 = *(uint32_t *)PTOV(0x46c);
+ if (!t0)
+ t0 = t1;
+ if (t1 < t0 || t1 >= t0 + ticks)
return 0;
}
}
static int
-putch(int c)
+xputc(int c)
+{
+ if (ioctrl & 0x1)
+ putc(c);
+ if (ioctrl & 0x2)
+ sio_putc(c);
+ return c;
+}
+
+static int
+xgetc(int fn)
+{
+ for (;;) {
+ if (ioctrl & 0x1 && getc(1))
+ return fn ? 1 : getc(0);
+ if (ioctrl & 0x2 && sio_ischar())
+ return fn ? 1 : sio_getc();
+ if (fn)
+ return 0;
+ }
+}
+
+static void
+putc(int c)
{
v86.addr = 0x10;
v86.eax = 0xe00 | (c & 0xff);
v86.ebx = 0x7;
v86int();
- return c;
}
static int
-getch(void)
+getc(int fn)
{
v86.addr = 0x16;
- v86.eax = 0;
+ v86.eax = fn << 8;
v86int();
- return v86.eax & 0xff;
+ return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);
}
diff --git a/sys/boot/i386/boot2/lib.h b/sys/boot/i386/boot2/lib.h
new file mode 100644
index 0000000..493c4d8
--- /dev/null
+++ b/sys/boot/i386/boot2/lib.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+/*
+ * $Id:$
+ */
+
+void sio_init(void);
+void sio_flush(void);
+void sio_putc(int);
+int sio_getc(void);
+int sio_ischar(void);
diff --git a/sys/boot/i386/boot2/sio.S b/sys/boot/i386/boot2/sio.S
new file mode 100644
index 0000000..92237b8
--- /dev/null
+++ b/sys/boot/i386/boot2/sio.S
@@ -0,0 +1,80 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: sio.s,v 1.2 1998/10/20 20:20:48 rnordier Exp $
+
+ .set SIO_PRT,SIOPRT # Base port
+ .set SIO_FMT,SIOFMT # 8N1
+ .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD
+
+ .globl sio_init
+ .globl sio_flush
+ .globl sio_putc
+ .globl sio_getc
+ .globl sio_ischar
+
+# void 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
+
+# void sio_flush(void)
+
+sio_flush.0: call sio_getc.1 # Get character
+sio_flush: call sio_ischar # Check for character
+ jnz sio_flush.0 # Till none
+ 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
diff --git a/sys/boot/i386/boot2/sio.s b/sys/boot/i386/boot2/sio.s
new file mode 100644
index 0000000..92237b8
--- /dev/null
+++ b/sys/boot/i386/boot2/sio.s
@@ -0,0 +1,80 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: sio.s,v 1.2 1998/10/20 20:20:48 rnordier Exp $
+
+ .set SIO_PRT,SIOPRT # Base port
+ .set SIO_FMT,SIOFMT # 8N1
+ .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD
+
+ .globl sio_init
+ .globl sio_flush
+ .globl sio_putc
+ .globl sio_getc
+ .globl sio_ischar
+
+# void 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
+
+# void sio_flush(void)
+
+sio_flush.0: call sio_getc.1 # Get character
+sio_flush: call sio_ischar # Check for character
+ jnz sio_flush.0 # Till none
+ 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
diff --git a/sys/boot/i386/btx/Makefile b/sys/boot/i386/btx/Makefile
index 92404c6..75a170e 100644
--- a/sys/boot/i386/btx/Makefile
+++ b/sys/boot/i386/btx/Makefile
@@ -1,5 +1,5 @@
-# $Id:$
+# $Id: Makefile,v 1.4 1998/09/17 23:52:03 msmith Exp $
-SUBDIR= btx
+SUBDIR= btx btxldr lib
.include <bsd.subdir.mk>
diff --git a/sys/boot/i386/btx/btx/Makefile b/sys/boot/i386/btx/btx/Makefile
index bd0cb6f..6657f6e 100644
--- a/sys/boot/i386/btx/btx/Makefile
+++ b/sys/boot/i386/btx/btx/Makefile
@@ -1,4 +1,4 @@
-# $Id:$
+# $Id: Makefile,v 1.4 1998/09/25 17:14:15 peter Exp $
M4?= m4
@@ -12,11 +12,12 @@ btx: btx.o
dd if=btx.out of=${.TARGET} ibs=32 skip=1
.else
${LD} -N -e start -Ttext ${ORG} -o btx.out btx.o
- /usr/libexec/elf/objcopy -S -O binary btx.out ${.TARGET}
+ objcopy -S -O binary btx.out ${.TARGET}
.endif
btx.o: btx.m4 btx.s
- ${M4} btx.m4 btx.s | ${AS} ${AFLAGS} -o ${.TARGET}
+ (cd ${.CURDIR}; ${M4} btx.m4 btx.s) | ${AS} ${AFLAGS} -o ${.TARGET}
-clean:
- rm -f btx btx.out btx.o
+CLEANFILES+= btx btx.out btx.o
+
+.include <bsd.prog.mk>
diff --git a/sys/boot/i386/btx/btx/btx.S b/sys/boot/i386/btx/btx/btx.S
new file mode 100644
index 0000000..29b9795
--- /dev/null
+++ b/sys/boot/i386/btx/btx/btx.S
@@ -0,0 +1,958 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btx.s,v 1.9 1999/01/22 13:07:17 rnordier Exp $
+
+#
+# Memory layout.
+#
+ .set MEM_BTX,0x1000 # Start of BTX memory
+ .set MEM_ESP0,0x1800 # Supervisor stack
+ .set MEM_BUF,0x1800 # Scratch buffer
+ .set MEM_ESP1,0x1e00 # Link stack
+ .set MEM_IDT,0x1e00 # IDT
+ .set MEM_TSS,0x1f98 # TSS
+ .set MEM_MAP,0x2000 # I/O bit map
+ .set MEM_DIR,0x4000 # Page directory
+ .set MEM_TBL,0x5000 # Page tables
+ .set MEM_ORG,0x9000 # BTX code
+ .set MEM_USR,0xa000 # Start of user memory
+#
+# Paging control.
+#
+ .set PAG_SIZ,0x1000 # Page size
+ .set PAG_CNT,0x1000 # Pages to map
+#
+# Segment selectors.
+#
+ .set SEL_SCODE,0x8 # Supervisor code
+ .set SEL_SDATA,0x10 # Supervisor data
+ .set SEL_RCODE,0x18 # Real mode code
+ .set SEL_RDATA,0x20 # Real mode data
+ .set SEL_UCODE,0x28|3 # User code
+ .set SEL_UDATA,0x30|3 # User data
+ .set SEL_TSS,0x38 # TSS
+#
+# Task state segment fields.
+#
+ .set TSS_ESP0,0x4 # PL 0 ESP
+ .set TSS_SS0,0x8 # PL 0 SS
+ .set TSS_ESP1,0xc # PL 1 ESP
+ .set TSS_MAP,0x66 # I/O bit map base
+#
+# System calls.
+#
+ .set SYS_EXIT,0x0 # Exit
+ .set SYS_EXEC,0x1 # Exec
+#
+# V86 constants.
+#
+ .set V86_FLG,0x208eff # V86 flag mask
+ .set V86_STK,0x400 # V86 stack allowance
+#
+# Dump format control bytes.
+#
+ .set DMP_X16,0x1 # Word
+ .set DMP_X32,0x2 # Long
+ .set DMP_MEM,0x4 # Memory
+ .set DMP_EOL,0x8 # End of line
+#
+# Screen defaults and assumptions.
+#
+ .set SCR_MAT,0x7 # Mode/attribute
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+#
+# BIOS Data Area locations.
+#
+ .set BDA_MEM,0x413 # Free memory
+ .set BDA_SCR,0x449 # Video mode
+ .set BDA_POS,0x450 # Cursor position
+#
+# Derivations, for brevity.
+#
+ .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0
+ .set _ESP1H,MEM_ESP1>>0x8 # Byte 1 of ESP1
+ .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base
+ .set _TSSLM,MEM_DIR-MEM_TSS-1 # TSS limit
+ .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit
+#
+# Code segment.
+#
+ .globl start
+start: # Start of code
+#
+# BTX header.
+#
+btx_hdr: .byte 0xeb # Machine ID
+ .byte 0xe # Header size
+ .ascii "BTX" # Magic
+ .byte 0x1 # Major version
+ .byte 0x1 # Minor version
+ .byte 0x0 # Flags
+ .word PAG_CNT-MEM_ORG>>0xc # Paging control
+ .word break-start # Text size
+ .long 0x0 # Entry address
+#
+# Initialization routine.
+#
+init: cli # Disable interrupts
+ xorl %eax,%eax # Zero/segment
+ movl %ax,%ss # Set up
+ movwir(MEM_ESP0,_sp) # stack
+ movl %ax,%es # Address
+ movl %ax,%ds # data
+ pushw $0x2 # Clear
+ popfw # flags
+#
+# Initialize memory.
+#
+ movwir(MEM_IDT,_di) # Memory to initialize
+ movwir((MEM_ORG-MEM_IDT)/2,_cx) # Words to zero
+ pushl %edi # Save
+ rep # Zero-fill
+ stosl # memory
+ popl %edi # Restore
+#
+# Create IDT.
+#
+ movwir(idtctl,_si) # Control string
+init.1: lodsb # Get entry
+ cwde # count
+ xchgl %eax,%ecx # as word
+ jecxz init.4 # If done
+ lodsb # Get segment
+ xchgl %eax,%edx # P:DPL:type
+ lodsl # Get control
+ xchgl %eax,%ebx # set
+ lodsl # Get handler offset
+ movb $SEL_SCODE,%dh # Segment selector
+init.2: shrl %ebx # Handle this int?
+ jnc init.3 # No
+ movwr0(_ax,_di_) # Set handler offset
+ movbr1(_dh,0x2,_di_) # and selector
+ movbr1(_dl,0x5,_di_) # Set P:DPL:type
+ addwia(0x4) # Next handler
+init.3: leaw1r(0x8,_di_,_di) # Next entry
+ loop init.2 # Till set done
+ jmp init.1 # Continue
+#
+# Initialize TSS.
+#
+init.4: movbi1(_ESP0H,TSS_ESP0+1,_di_) # Set ESP0
+ movbi1(SEL_SDATA,TSS_SS0,_di_) # Set SS0
+ movbi1(_ESP1H,TSS_ESP1+1,_di_) # Set ESP1
+ movbi1(_TSSIO,TSS_MAP,_di_) # Set I/O bit map base
+#
+# Create page directory.
+#
+ xorw %dx,%dx # Page
+ movb $PAG_SIZ>>0x8,%dh # size
+ xorw %ax,%ax # Zero
+ movwir(MEM_DIR,_di) # Page directory
+ movb $PAG_CNT>>0xa,%cl # Entries
+ movwir(MEM_TBL|0x7,_ax) # First entry
+init.5: stosw # Write entry
+ addl %edx,%eax # To next
+ loop init.5 # Till done
+#
+# Create page tables.
+#
+ movwir(MEM_TBL,_di) # Page table
+ movb $PAG_CNT>>0x8,%ch # Entries
+ xorl %eax,%eax # Start address
+init.6: movb $0x7,%al # Set U:W:P flags
+ cmpwmr(btx_hdr+0x8,_cx) # Standard user page?
+ jb init.7 # Yes
+ cmpwir(PAG_CNT-MEM_BTX>>0xc,_cx)# BTX memory?
+ jae init.7 # No or first page
+ andb $~0x2,%al # Clear W flag
+ cmpwir(PAG_CNT-MEM_USR>>0xc,_cx)# User page zero?
+ jne init.7 # No
+ tstbim(0x80,btx_hdr+0x7) # Unmap it?
+ jz init.7 # No
+ andb $~0x1,%al # Clear P flag
+init.7: stosw # Set entry
+ addw %dx,%ax # Next address
+ loop init.6 # Till done
+#
+# Bring up the system.
+#
+ movwir(0x2820,_bx) # Set protected mode
+ callwi(setpic) # IRQ offsets
+ lidtwm(idtdesc) # Set IDT
+ xorw %ax,%ax # Set base
+ movb $MEM_DIR>>0x8,%ah # of page
+ movl %eax,%cr3 # directory
+ lgdtwm(gdtdesc) # Set GDT
+ movl %cr0,%eax # Switch to
+ o16 # protected mode
+ orl $0x80000001,%eax # and enable
+ movl %eax,%cr0 # paging
+ jmpfwi(SEL_SCODE,init.8) # To 32-bit code
+init.8: xorl %ecx,%ecx # Zero
+ movb $SEL_SDATA,%cl # To 32-bit
+ movl %cx,%ss # stack
+#
+# Launch user task.
+#
+ movb $SEL_TSS,%cl # Set task
+ ltrl %ecx # register
+ movl $MEM_USR,%edx # User base address
+ movzwl %ss:BDA_MEM,%eax # Get free memory
+ shll $0xa,%eax # To bytes
+ subl $0x1000,%eax # Less arg space
+ subl %edx,%eax # Less base
+ movb $SEL_UDATA,%cl # User data selector
+ pushl %ecx # Set SS
+ pushl %eax # Set ESP
+ pushl $0x202 # Set flags (IF set)
+ pushl $SEL_UCODE # Set CS
+ pushl btx_hdr+0xc # Set EIP
+ pushl %ecx # Set GS
+ pushl %ecx # Set FS
+ pushl %ecx # Set DS
+ pushl %ecx # Set ES
+ pushl %edx # Set EAX
+ movb $0x7,%cl # Set remaining
+init.9: pushb $0x0 # general
+ loop init.9 # registers
+ popa # and initialize
+ popl %es # Initialize
+ popl %ds # user
+ popl %fs # segment
+ popl %gs # registers
+ iret # To user mode
+#
+# Exit routine.
+#
+exit: cli # Disable interrupts
+ movl $MEM_ESP0,%esp # Clear stack
+#
+# Turn off paging.
+#
+ movl %cr0,%eax # Get CR0
+ andl $~0x80000000,%eax # Disable
+ movl %eax,%cr0 # paging
+ xorl %ecx,%ecx # Zero
+ movl %ecx,%cr3 # Flush TLB
+#
+# To 16 bits.
+#
+ o16 # Reload
+ jmpfwi(SEL_RCODE,exit.1) # CS
+exit.1: movb $SEL_RDATA,%cl # 16-bit selector
+ movl %cx,%ss # Reload SS
+ movl %cx,%ds # Load
+ movl %cx,%es # remaining
+ movl %cx,%fs # segment
+ movl %cx,%gs # registers
+#
+# To real-address mode.
+#
+ decl %eax # Switch to
+ movl %eax,%cr0 # real mode
+ jmpfwi(0x0,exit.2) # Reload CS
+exit.2: xorl %eax,%eax # Real mode segment
+ movl %ax,%ss # Reload SS
+ movl %ax,%ds # Address data
+ movwir(0x7008,_bx) # Set real mode
+ callwi(setpic) # IRQ offsets
+ lidtwm(ivtdesc) # Set IVT
+#
+# Reboot or await reset.
+#
+ sti # Enable interrupts
+ tstbim(0x1,btx_hdr+0x7) # Reboot?
+exit.3: jz exit.3 # No
+ int $0x19 # BIOS: Reboot
+#
+# Set IRQ offsets by reprogramming 8259A PICs.
+#
+setpic: inb $0x21,%al # Save master
+ pushl %eax # IMR
+ inb $0xa1,%al # Save slave
+ pushl %eax # IMR
+ movb $0x11,%al # ICW1 to
+ outb %al,$0x20 # master,
+ outb %al,$0xa0 # slave
+ movb %bl,%al # ICW2 to
+ outb %al,$0x21 # master
+ movb %bh,%al # ICW2 to
+ outb %al,$0xa1 # slave
+ movb $0x4,%al # ICW3 to
+ outb %al,$0x21 # master
+ movb $0x2,%al # ICW3 to
+ outb %al,$0xa1 # slave
+ movb $0x1,%al # ICW4 to
+ outb %al,$0x21 # master,
+ outb %al,$0xa1 # slave
+ popl %eax # Restore slave
+ outb %al,$0xa1 # IMR
+ popl %eax # Restore master
+ outb %al,$0x21 # IMR
+ ret # To caller
+#
+# Initiate return from V86 mode to user mode.
+#
+inthlt: hlt # To supervisor mode
+#
+# Exception jump table.
+#
+intx00: pushb $0x0 # Int 0x0: #DE
+ jmp ex_noc # Divide error
+ pushb $0x1 # Int 0x1: #DB
+ jmp ex_noc # Debug
+ pushb $0x3 # Int 0x3: #BP
+ jmp ex_noc # Breakpoint
+ pushb $0x4 # Int 0x4: #OF
+ jmp ex_noc # Overflow
+ pushb $0x5 # Int 0x5: #BR
+ jmp ex_noc # BOUND range exceeded
+ pushb $0x6 # Int 0x6: #UD
+ jmp ex_noc # Invalid opcode
+ pushb $0x7 # Int 0x7: #NM
+ jmp ex_noc # Device not available
+ pushb $0x8 # Int 0x8: #DF
+ jmp except # Double fault
+ pushb $0xa # Int 0xa: #TS
+ jmp except # Invalid TSS
+ pushb $0xb # Int 0xb: #NP
+ jmp except # Segment not present
+ pushb $0xc # Int 0xc: #SS
+ jmp except # Stack segment fault
+ pushb $0xd # Int 0xd: #GP
+ jmp ex_v86 # General protection
+ pushb $0xe # Int 0xe: #PF
+ jmp except # Page fault
+intx10: pushb $0x10 # Int 0x10: #MF
+ jmp ex_noc # Floating-point error
+#
+# Handle #GP exception.
+#
+ex_v86: testb $0x2,0x12(%esp,1) # V86 mode?
+ jz except # No
+ jmp v86mon # To monitor
+#
+# Save a zero error code.
+#
+ex_noc: pushl (%esp,1) # Duplicate int no
+ movb $0x0,0x4(%esp,1) # Fake error code
+#
+# Handle exception.
+#
+except: cld # String ops inc
+ pushl %ds # Save
+ pushl %es # most
+ pusha # registers
+ movb $0x6,%al # Push loop count
+ testb $0x2,0x3a(%esp,1) # V86 mode?
+ jnz except.1 # Yes
+ pushl %gs # Set GS
+ pushl %fs # Set FS
+ pushl %ds # Set DS
+ pushl %es # Set ES
+ movb $0x2,%al # Push loop count
+ cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode?
+ jne except.1 # No
+ pushl %ss # Set SS
+ leal 0x50(%esp,1),%eax # Set
+ pushl %eax # ESP
+ jmp except.2 # Join common code
+except.1: pushl 0x50(%esp,1) # Set GS, FS, DS, ES
+ decb %al # (if V86 mode), and
+ jne except.1 # SS, ESP
+except.2: pushl $SEL_SDATA # Set up
+ popl %ds # to
+ pushl %ds # address
+ popl %es # data
+ movl %esp,%ebx # Stack frame
+ movl $dmpfmt,%esi # Dump format string
+ movl $MEM_BUF,%edi # Buffer
+ pushl %edi # Dump to
+ call dump # buffer
+ popl %esi # and
+ call putstr # display
+ leal 0x18(%esp,1),%esp # Discard frame
+ popa # Restore
+ popl %es # registers
+ popl %ds # saved
+ cmpb $0x3,(%esp,1) # Breakpoint?
+ je except.3 # Yes
+ jmp exit # Exit
+except.3: leal 0x8(%esp,1),%esp # Discard err, int no
+ iret # From interrupt
+#
+# Return to user mode from V86 mode.
+#
+intrtn: cld # String ops inc
+ pushl %ds # Address
+ popl %es # data
+ leal 0x3c(%ebp),%edx # V86 Segment registers
+ movl MEM_TSS+TSS_ESP1,%esi # Link stack pointer
+ lodsl # INT_V86 args pointer
+ movl %esi,%ebx # Saved exception frame
+ testl %eax,%eax # INT_V86 args?
+ jz intrtn.2 # No
+ movl $MEM_USR,%edi # User base
+ movl 0x1c(%esi),%ebx # User ESP
+ movl %eax,(%edi,%ebx,1) # Restore to user stack
+ leal 0x8(%edi,%eax,1),%edi # Arg segment registers
+ testb $0x4,-0x6(%edi) # Return flags?
+ jz intrtn.1 # No
+ movl 0x30(%ebp),%eax # Get V86 flags
+ movw %ax,0x18(%esi) # Set user flags
+intrtn.1: leal 0x10(%esi),%ebx # Saved exception frame
+ xchgl %edx,%esi # Segment registers
+ movb $0x4,%cl # Update seg regs
+ rep # in INT_V86
+ movsl # args
+intrtn.2: movl %edx,%esi # Segment registers
+ leal 0x28(%ebp),%edi # Set up seg
+ movb $0x4,%cl # regs for
+ rep # later
+ movsl # pop
+ movl %ebx,%esi # Restore exception
+ movb $0x5,%cl # frame to
+ rep # supervisor
+ movsl # stack
+ movl %esi,MEM_TSS+TSS_ESP1 # Link stack pointer
+ popa # Restore
+ leal 0x8(%esp,1),%esp # Discard err, int no
+ popl %es # Restore
+ popl %ds # user
+ popl %fs # segment
+ popl %gs # registers
+ iret # To user mode
+#
+# V86 monitor.
+#
+v86mon: cld # String ops inc
+ pushl $SEL_SDATA # Set up for
+ popl %ds # flat addressing
+ pusha # Save registers
+ movl %esp,%ebp # Address stack frame
+ movzwl 0x2c(%ebp),%edi # Load V86 CS
+ shll $0x4,%edi # To linear
+ movl 0x28(%ebp),%esi # Load V86 IP
+ addl %edi,%esi # Code pointer
+ xorl %ecx,%ecx # Zero
+ movb $0x2,%cl # 16-bit operands
+ xorl %eax,%eax # Zero
+v86mon.1: lodsb # Get opcode
+ cmpb $0x66,%al # Operand size prefix?
+ jne v86mon.2 # No
+ movb $0x4,%cl # 32-bit operands
+ jmp v86mon.1 # Continue
+v86mon.2: cmpb $0xf4,%al # HLT?
+ jne v86mon.3 # No
+ cmpl $inthlt+0x1,%esi # Is inthlt?
+ jne v86mon.7 # No (ignore)
+ jmp intrtn # Return to user mode
+v86mon.3: cmpb $0xf,%al # Is
+ jne v86mon.4 # this
+ cmpb $0x20,(%esi) # a
+ jne v86mon.4 # MOV EAX,CR0
+ cmpb $0xc0,0x1(%esi) # instruction?
+ je v86mov # Yes
+v86mon.4: cmpb $0xfa,%al # CLI?
+ je v86cli # Yes
+ cmpb $0xfb,%al # STI?
+ je v86sti # Yes
+ movzwl 0x38(%ebp),%ebx # Load V86 SS
+ shll $0x4,%ebx # To offset
+ pushl %ebx # Save
+ addl 0x34(%ebp),%ebx # Add V86 SP
+ movl 0x30(%ebp),%edx # Load V86 flags
+ cmpb $0x9c,%al # PUSHF/PUSHFD?
+ je v86pushf # Yes
+ cmpb $0x9d,%al # POPF/POPFD?
+ je v86popf # Yes
+ cmpb $0xcd,%al # INT imm8?
+ je v86intn # Yes
+ cmpb $0xcf,%al # IRET/IRETD?
+ je v86iret # Yes
+ popl %ebx # Restore
+ popa # Restore
+ jmp except # Handle exception
+v86mon.5: movl %edx,0x30(%ebp) # Save V86 flags
+v86mon.6: popl %edx # V86 SS adjustment
+ subl %edx,%ebx # Save V86
+ movl %ebx,0x34(%ebp) # SP
+v86mon.7: subl %edi,%esi # From linear
+ movl %esi,0x28(%ebp) # Save V86 IP
+ popa # Restore
+ leal 0x8(%esp,1),%esp # Discard int no, error
+ iret # To V86 mode
+#
+# Emulate MOV EAX,CR0.
+#
+v86mov: movl %cr0,%eax # CR0 to
+ movl %eax,0x1c(%ebp) # saved EAX
+ incl %esi # Adjust
+ incl %esi # IP
+ jmp v86mon.7 # Finish up
+#
+# Emulate CLI.
+#
+v86cli: andb $~0x2,0x31(%ebp) # Clear IF
+ jmp v86mon.7 # Finish up
+#
+# Emulate STI.
+#
+v86sti: orb $0x2,0x31(%ebp) # Set IF
+ jmp v86mon.7 # Finish up
+#
+# Emulate PUSHF/PUSHFD.
+#
+v86pushf: subl %ecx,%ebx # Adjust SP
+ cmpb $0x4,%cl # 32-bit
+ je v86pushf.1 # Yes
+ o16 # 16-bit
+v86pushf.1: movl %edx,(%ebx) # Save flags
+ jmp v86mon.6 # Finish up
+#
+# Emulate IRET/IRETD.
+#
+v86iret: movzwl (%ebx),%esi # Load V86 IP
+ movzwl 0x2(%ebx),%edi # Load V86 CS
+ leal 0x4(%ebx),%ebx # Adjust SP
+ movl %edi,0x2c(%ebp) # Save V86 CS
+ xorl %edi,%edi # No ESI adjustment
+#
+# Emulate POPF/POPFD (and remainder of IRET/IRETD).
+#
+v86popf: cmpb $0x4,%cl # 32-bit?
+ je v86popf.1 # Yes
+ movl %edx,%eax # Initialize
+ o16 # 16-bit
+v86popf.1: movl (%ebx),%eax # Load flags
+ addl %ecx,%ebx # Adjust SP
+ andl $V86_FLG,%eax # Merge
+ andl $~V86_FLG,%edx # the
+ orl %eax,%edx # flags
+ jmp v86mon.5 # Finish up
+#
+# Emulate INT imm8.
+#
+v86intn: lodsb # Get int no
+ subl %edi,%esi # From
+ shrl $0x4,%edi # linear
+ movw %dx,-0x2(%ebx) # Save flags
+ movw %di,-0x4(%ebx) # Save CS
+ leal -0x6(%ebx),%ebx # Adjust SP
+ movw %si,(%ebx) # Save IP
+ shll $0x2,%eax # Scale
+ movzwl (%eax),%esi # Load IP
+ movzwl 0x2(%eax),%edi # Load CS
+ movl %edi,0x2c(%ebp) # Save CS
+ xorl %edi,%edi # No ESI adjustment
+ andb $~0x3,%dh # Clear IF and TF
+ jmp v86mon.5 # Finish up
+#
+# Hardware interrupt jump table.
+#
+intx20: pushb $0x8 # Int 0x20: IRQ0
+ jmp int_hw # V86 int 0x8
+ pushb $0x9 # Int 0x21: IRQ1
+ jmp int_hw # V86 int 0x9
+ pushb $0xa # Int 0x22: IRQ2
+ jmp int_hw # V86 int 0xa
+ pushb $0xb # Int 0x23: IRQ3
+ jmp int_hw # V86 int 0xb
+ pushb $0xc # Int 0x24: IRQ4
+ jmp int_hw # V86 int 0xc
+ pushb $0xd # Int 0x25: IRQ5
+ jmp int_hw # V86 int 0xd
+ pushb $0xe # Int 0x26: IRQ6
+ jmp int_hw # V86 int 0xe
+ pushb $0xf # Int 0x27: IRQ7
+ jmp int_hw # V86 int 0xf
+ pushb $0x70 # Int 0x28: IRQ8
+ jmp int_hw # V86 int 0x70
+ pushb $0x71 # Int 0x29: IRQ9
+ jmp int_hw # V86 int 0x71
+ pushb $0x72 # Int 0x2a: IRQ10
+ jmp int_hw # V86 int 0x72
+ pushb $0x73 # Int 0x2b: IRQ11
+ jmp int_hw # V86 int 0x73
+ pushb $0x74 # Int 0x2c: IRQ12
+ jmp int_hw # V86 int 0x74
+ pushb $0x75 # Int 0x2d: IRQ13
+ jmp int_hw # V86 int 0x75
+ pushb $0x76 # Int 0x2e: IRQ14
+ jmp int_hw # V86 int 0x76
+ pushb $0x77 # Int 0x2f: IRQ15
+ jmp int_hw # V86 int 0x77
+#
+# Reflect hardware interrupts.
+#
+int_hw: testb $0x2,0xe(%esp,1) # V86 mode?
+ jz intusr # No
+ pushl $SEL_SDATA # Address
+ popl %ds # data
+ xchgl %eax,(%esp,1) # Swap EAX, int no
+ pushl %ebp # Address
+ movl %esp,%ebp # stack frame
+ pushl %ebx # Save
+ shll $0x2,%eax # Get int
+ movl (%eax),%eax # vector
+ subl $0x6,0x14(%ebp) # Adjust V86 ESP
+ movzwl 0x18(%ebp),%ebx # V86 SS
+ shll $0x4,%ebx # * 0x10
+ addl 0x14(%ebp),%ebx # + V86 ESP
+ xchgw %ax,0x8(%ebp) # Swap V86 IP
+ rorl $0x10,%eax # Swap words
+ xchgw %ax,0xc(%ebp) # Swap V86 CS
+ roll $0x10,%eax # Swap words
+ movl %eax,(%ebx) # CS:IP for IRET
+ movl 0x10(%ebp),%eax # V86 flags
+ movw %ax,0x4(%ebx) # Flags for IRET
+ andb $~0x3,0x11(%ebp) # Clear IF, TF
+ popl %ebx # Restore
+ popl %ebp # saved
+ popl %eax # registers
+ iret # To V86 mode
+#
+# Invoke V86 interrupt from user mode, with arguments.
+#
+intx31: stc # Have btx_v86
+ pushl %eax # Missing int no
+#
+# Invoke V86 interrupt from user mode.
+#
+intusr: std # String ops dec
+ pushl %eax # Expand
+ pushl %eax # stack
+ pushl %eax # frame
+ pusha # Save
+ pushl %gs # Save
+ movl %esp,%eax # seg regs
+ pushl %fs # and
+ pushl %ds # point
+ pushl %es # to them
+ pushb $SEL_SDATA # Set up
+ popl %ds # to
+ pushl %ds # address
+ popl %es # data
+ movl $MEM_USR,%ebx # User base
+ movl %ebx,%edx # address
+ jc intusr.1 # If btx_v86
+ xorl %edx,%edx # Control flags
+ xorl %ebp,%ebp # btx_v86 pointer
+intusr.1: leal 0x50(%esp,1),%esi # Base of frame
+ pushl %esi # Save
+ addl -0x4(%esi),%ebx # User ESP
+ movl MEM_TSS+TSS_ESP1,%edi # Link stack pointer
+ leal -0x4(%edi),%edi # Adjust for push
+ xorl %ecx,%ecx # Zero
+ movb $0x5,%cl # Push exception
+ rep # frame on
+ movsl # link stack
+ xchgl %eax,%esi # Saved seg regs
+ movl 0x40(%esp,1),%eax # Get int no
+ testl %edx,%edx # Have btx_v86?
+ jz intusr.2 # No
+ movl (%ebx),%ebp # btx_v86 pointer
+ movb $0x4,%cl # Count
+ addl %ecx,%ebx # Adjust for pop
+ rep # Push saved seg regs
+ movsl # on link stack
+ addl %ebp,%edx # Flatten btx_v86 ptr
+ leal 0x14(%edx),%esi # Seg regs pointer
+ movl 0x4(%edx),%eax # Get int no/address
+ movzwl 0x2(%edx),%edx # Get control flags
+intusr.2: movl %ebp,(%edi) # Push btx_v86 and
+ movl %edi,MEM_TSS+TSS_ESP1 # save link stack ptr
+ popl %edi # Base of frame
+ xchgl %eax,%ebp # Save intno/address
+ movl 0x48(%esp,1),%eax # Get flags
+ testb $0x2,%dl # Simulate CALLF?
+ jnz intusr.3 # Yes
+ decl %ebx # Push flags
+ decl %ebx # on V86
+ movw %ax,(%ebx) # stack
+intusr.3: movb $0x4,%cl # Count
+ subl %ecx,%ebx # Push return address
+ movl $inthlt,(%ebx) # on V86 stack
+ rep # Copy seg regs to
+ movsl # exception frame
+ xchgl %eax,%ecx # Save flags
+ movl %ebx,%eax # User ESP
+ subl $V86_STK,%eax # Less bytes
+ ja intusr.4 # to
+ xorl %eax,%eax # keep
+intusr.4: shrl $0x4,%eax # Gives segment
+ stosl # Set SS
+ shll $0x4,%eax # To bytes
+ xchgl %eax,%ebx # Swap
+ subl %ebx,%eax # Gives offset
+ stosl # Set ESP
+ xchgl %eax,%ecx # Get flags
+ btsl $0x11,%eax # Set VM
+ andb $~0x3,%ah # Clear IF and TF
+ stosl # Set EFL
+ xchgl %eax,%ebp # Get int no/address
+ testb $0x1,%dl # Address?
+ jnz intusr.5 # Yes
+ shll $0x2,%eax # Scale
+ movl (%eax),%eax # Load int vector
+intusr.5: movl %eax,%ecx # Save
+ shrl $0x10,%eax # Gives segment
+ stosl # Set CS
+ movw %cx,%ax # Restore
+ stosl # Set EIP
+ leal 0x10(%esp,1),%esp # Discard seg regs
+ popa # Restore
+ iret # To V86 mode
+#
+# System Call.
+#
+intx30: cmpl $SYS_EXEC,%eax # Exec system call?
+ jne intx30.1 # No
+ pushl %ss # Set up
+ popl %es # all
+ pushl %es # segment
+ popl %ds # registers
+ pushl %ds # for the
+ popl %fs # program
+ pushl %fs # we're
+ popl %gs # invoking
+ movl $MEM_USR,%eax # User base address
+ addl 0xc(%esp,1),%eax # Change to user
+ leal 0x4(%eax),%esp # stack
+ movl %cr0,%eax # Turn
+ andl $~0x80000000,%eax # off
+ movl %eax,%cr0 # paging
+ xorl %eax,%eax # Flush
+ movl %eax,%cr3 # TLB
+ popl %eax # Call
+ call *%eax # program
+intx30.1: incb %ss:btx_hdr+0x7 # Flag reboot
+ jmp exit # Exit
+#
+# Dump structure [EBX] to [EDI], using format string [ESI].
+#
+dump.0: stosb # Save char
+dump: lodsb # Load char
+ testb %al,%al # End of string?
+ jz dump.10 # Yes
+ testb $0x80,%al # Control?
+ jz dump.0 # No
+ movb %al,%ch # Save control
+ movb $'=',%al # Append
+ stosb # '='
+ lodsb # Get offset
+ pushl %esi # Save
+ movsbl %al,%esi # To
+ addl %ebx,%esi # pointer
+ testb $DMP_X16,%ch # Dump word?
+ jz dump.1 # No
+ lodsw # Get and
+ call hex16 # dump it
+dump.1: testb $DMP_X32,%ch # Dump long?
+ jz dump.2 # No
+ lodsl # Get and
+ call hex32 # dump it
+dump.2: testb $DMP_MEM,%ch # Dump memory?
+ jz dump.8 # No
+ pushl %ds # Save
+ testb $0x2,0x52(%ebx) # V86 mode?
+ jnz dump.3 # Yes
+ verrl 0x4(%esi) # Readable selector?
+ jnz dump.3 # No
+ ldsl (%esi),%esi # Load pointer
+ jmp dump.4 # Join common code
+dump.3: lodsl # Set offset
+ xchgl %eax,%edx # Save
+ lodsl # Get segment
+ shll $0x4,%eax # * 0x10
+ addl %edx,%eax # + offset
+ xchgl %eax,%esi # Set pointer
+dump.4: movb $0x10,%cl # Bytes to dump
+dump.5: lodsb # Get byte and
+ call hex8 # dump it
+ decb %cl # Keep count
+ jz dump.7 # If done
+ movb $'-',%al # Separator
+ cmpb $0x8,%cl # Half way?
+ je dump.6 # Yes
+ movb $' ',%al # Use space
+dump.6: stosb # Save separator
+ jmp dump.5 # Continue
+dump.7: popl %ds # Restore
+dump.8: popl %esi # Restore
+ movb $0xa,%al # Line feed
+ testb $DMP_EOL,%ch # End of line?
+ jnz dump.9 # Yes
+ movb $' ',%al # Use spaces
+ stosb # Save one
+dump.9: jmp dump.0 # Continue
+dump.10: stosb # Terminate string
+ ret # To caller
+#
+# Convert EAX, AX, or AL to hex, saving the result to [EDI].
+#
+hex32: pushl %eax # Save
+ shrl $0x10,%eax # Do upper
+ call hex16 # 16
+ popl %eax # Restore
+hex16: call hex16.1 # Do upper 8
+hex16.1: xchgb %ah,%al # Save/restore
+hex8: pushl %eax # Save
+ shrb $0x4,%al # Do upper
+ call hex8.1 # 4
+ popl %eax # Restore
+hex8.1: andb $0xf,%al # Get lower 4
+ cmpb $0xa,%al # Convert
+ sbbb $0x69,%al # to hex
+ das # digit
+ orb $0x20,%al # To lower case
+ stosb # Save char
+ ret # (Recursive)
+#
+# Output zero-terminated string [ESI] to the console.
+#
+putstr.0: call putchr # Output char
+putstr: lodsb # Load char
+ testb %al,%al # End of string?
+ jnz putstr.0 # No
+ ret # To caller
+#
+# Output character AL to the console.
+#
+putchr: pusha # Save
+ xorl %ecx,%ecx # Zero for loops
+ movb $SCR_MAT,%ah # Mode/attribute
+ movl $BDA_POS,%ebx # BDA pointer
+ movw (%ebx),%dx # Cursor position
+ movl $0xb8000,%edi # Regen buffer (color)
+ cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode?
+ jne putchr.1 # No
+ xorw %di,%di # Regen buffer (mono)
+putchr.1: cmpb $0xa,%al # New line?
+ je putchr.2 # Yes
+ xchgl %eax,%ecx # Save char
+ movb $SCR_COL,%al # Columns per row
+ mulb %dh # * row position
+ addb %dl,%al # + column
+ adcb $0x0,%ah # position
+ shll %eax # * 2
+ xchgl %eax,%ecx # Swap char, offset
+ movw %ax,(%edi,%ecx,1) # Write attr:char
+ incl %edx # Bump cursor
+ cmpb $SCR_COL,%dl # Beyond row?
+ jb putchr.3 # No
+putchr.2: xorb %dl,%dl # Zero column
+ incb %dh # Bump row
+putchr.3: cmpb $SCR_ROW,%dh # Beyond screen?
+ 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
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+ movb $SCR_ROW-1,%dh # Bottom line
+putchr.4: movw %dx,(%ebx) # Update position
+ popa # Restore
+ ret # To caller
+
+ .p2align 4
+#
+# Global descriptor table.
+#
+gdt: .word 0x0,0x0,0x0,0x0 # Null entry
+ .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
+ .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
+ .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
+ .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
+ .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
+ .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
+ .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
+gdt.1:
+#
+# Pseudo-descriptors.
+#
+gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT
+idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT
+ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT
+#
+# IDT construction control string.
+#
+idtctl: .byte 0x10, 0x8e # Int 0x0-0xf
+ .word 0x7dfb,intx00 # (exceptions)
+ .byte 0x10, 0x8e # Int 0x10
+ .word 0x1, intx10 # (exception)
+ .byte 0x10, 0x8e # Int 0x20-0x2f
+ .word 0xffff,intx20 # (hardware)
+ .byte 0x1, 0xee # int 0x30
+ .word 0x1, intx30 # (system call)
+ .byte 0x2, 0xee # Int 0x31-0x32
+ .word 0x1, intx31 # (V86, null)
+ .byte 0x0 # End of string
+#
+# Dump format string.
+#
+dmpfmt: .byte '\n' # "\n"
+ .ascii "int" # "int="
+ .byte 0x80|DMP_X32, 0x40 # "00000000 "
+ .ascii "err" # "err="
+ .byte 0x80|DMP_X32, 0x44 # "00000000 "
+ .ascii "efl" # "efl="
+ .byte 0x80|DMP_X32, 0x50 # "00000000 "
+ .ascii "eip" # "eip="
+ .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
+ .ascii "eax" # "eax="
+ .byte 0x80|DMP_X32, 0x34 # "00000000 "
+ .ascii "ebx" # "ebx="
+ .byte 0x80|DMP_X32, 0x28 # "00000000 "
+ .ascii "ecx" # "ecx="
+ .byte 0x80|DMP_X32, 0x30 # "00000000 "
+ .ascii "edx" # "edx="
+ .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
+ .ascii "esi" # "esi="
+ .byte 0x80|DMP_X32, 0x1c # "00000000 "
+ .ascii "edi" # "edi="
+ .byte 0x80|DMP_X32, 0x18 # "00000000 "
+ .ascii "ebp" # "ebp="
+ .byte 0x80|DMP_X32, 0x20 # "00000000 "
+ .ascii "esp" # "esp="
+ .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n"
+ .ascii "cs" # "cs="
+ .byte 0x80|DMP_X16, 0x4c # "0000 "
+ .ascii "ds" # "ds="
+ .byte 0x80|DMP_X16, 0xc # "0000 "
+ .ascii "es" # "es="
+ .byte 0x80|DMP_X16, 0x8 # "0000 "
+ .ascii " " # " "
+ .ascii "fs" # "fs="
+ .byte 0x80|DMP_X16, 0x10 # "0000 "
+ .ascii "gs" # "gs="
+ .byte 0x80|DMP_X16, 0x14 # "0000 "
+ .ascii "ss" # "ss="
+ .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n"
+ .ascii "cs:eip" # "cs:eip="
+ .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
+ .ascii "ss:esp" # "ss:esp="
+ .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n"
+ .asciz "System halted" # End
+#
+# End of BTX memory.
+#
+ .p2align 4
+break:
diff --git a/sys/boot/i386/btx/btx/btx.s b/sys/boot/i386/btx/btx/btx.s
index 2b01359..29b9795 100644
--- a/sys/boot/i386/btx/btx/btx.s
+++ b/sys/boot/i386/btx/btx/btx.s
@@ -13,7 +13,7 @@
# purpose.
#
-# $Id:$
+# $Id: btx.s,v 1.9 1999/01/22 13:07:17 rnordier Exp $
#
# Memory layout.
@@ -52,6 +52,11 @@
.set TSS_ESP1,0xc # PL 1 ESP
.set TSS_MAP,0x66 # I/O bit map base
#
+# System calls.
+#
+ .set SYS_EXIT,0x0 # Exit
+ .set SYS_EXEC,0x1 # Exec
+#
# V86 constants.
#
.set V86_FLG,0x208eff # V86 flag mask
@@ -94,8 +99,8 @@ start: # Start of code
btx_hdr: .byte 0xeb # Machine ID
.byte 0xe # Header size
.ascii "BTX" # Magic
- .byte 0x0 # Major version
- .byte 0x50 # Minor version
+ .byte 0x1 # Major version
+ .byte 0x1 # Minor version
.byte 0x0 # Flags
.word PAG_CNT-MEM_ORG>>0xc # Paging control
.word break-start # Text size
@@ -170,21 +175,16 @@ init.5: stosw # Write entry
xorl %eax,%eax # Start address
init.6: movb $0x7,%al # Set U:W:P flags
cmpwmr(btx_hdr+0x8,_cx) # Standard user page?
- jb init.8 # Yes
+ jb init.7 # Yes
cmpwir(PAG_CNT-MEM_BTX>>0xc,_cx)# BTX memory?
- ja init.8 # No
- je init.7 # If first page
+ jae init.7 # No or first page
andb $~0x2,%al # Clear W flag
- cmpwir(PAG_CNT-MEM_ORG>>0xc,_cx)# BTX code?
- je init.8 # Yes
- cmpwir(PAG_CNT-MEM_USR>>0xc,_cx)# User memory?
- jb init.8 # User page >= 1
- ja init.7 # BTX page
- tstbim(0x80,btx_hdr+0x7) # Unmap user page 0?
+ cmpwir(PAG_CNT-MEM_USR>>0xc,_cx)# User page zero?
+ jne init.7 # No
+ tstbim(0x80,btx_hdr+0x7) # Unmap it?
jz init.7 # No
andb $~0x1,%al # Clear P flag
-init.7: andb $~0x4,%al # Clear U flag
-init.8: stosw # Set entry
+init.7: stosw # Set entry
addw %dx,%ax # Next address
loop init.6 # Till done
#
@@ -201,8 +201,8 @@ init.8: stosw # Set entry
o16 # protected mode
orl $0x80000001,%eax # and enable
movl %eax,%cr0 # paging
- jmpfwi(SEL_SCODE,init.9) # To 32-bit code
-init.9: xorl %ecx,%ecx # Zero
+ jmpfwi(SEL_SCODE,init.8) # To 32-bit code
+init.8: xorl %ecx,%ecx # Zero
movb $SEL_SDATA,%cl # To 32-bit
movl %cx,%ss # stack
#
@@ -213,21 +213,22 @@ init.9: xorl %ecx,%ecx # Zero
movl $MEM_USR,%edx # User base address
movzwl %ss:BDA_MEM,%eax # Get free memory
shll $0xa,%eax # To bytes
+ subl $0x1000,%eax # Less arg space
subl %edx,%eax # Less base
movb $SEL_UDATA,%cl # User data selector
pushl %ecx # Set SS
pushl %eax # Set ESP
pushl $0x202 # Set flags (IF set)
pushl $SEL_UCODE # Set CS
- pushl $0x0 # Set EIP
+ 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.10: pushb $0x0 # general
- loop init.10 # registers
+init.9: pushb $0x0 # general
+ loop init.9 # registers
popa # and initialize
popl %es # Initialize
popl %ds # user
@@ -237,7 +238,7 @@ init.10: pushb $0x0 # general
#
# Exit routine.
#
-exit: cld # String ops inc
+exit: cli # Disable interrupts
movl $MEM_ESP0,%esp # Clear stack
#
# Turn off paging.
@@ -271,13 +272,11 @@ exit.2: xorl %eax,%eax # Real mode segment
callwi(setpic) # IRQ offsets
lidtwm(ivtdesc) # Set IVT
#
-# Prompt for reboot.
+# Reboot or await reset.
#
sti # Enable interrupts
- movwir(prompt,_si) # Display
- callwi(puts16) # prompt
- xorb %ah,%ah # BIOS: Get
- int $0x16 # keypress
+ tstbim(0x1,btx_hdr+0x7) # Reboot?
+exit.3: jz exit.3 # No
int $0x19 # BIOS: Reboot
#
# Set IRQ offsets by reprogramming 8259A PICs.
@@ -306,16 +305,6 @@ setpic: inb $0x21,%al # Save master
outb %al,$0x21 # IMR
ret # To caller
#
-# Display zero-terminated string [ESI] using BIOS.
-#
-puts16.0: movwir(0x7,_bx) # Page:attribute
- movb $0xe,%ah # BIOS: Display
- int $0x10 # char
-puts16: lodsb # Load char
- testb %al,%al # End of string?
- jnz puts16.0 # No
- ret # To caller
-#
# Initiate return from V86 mode to user mode.
#
inthlt: hlt # To supervisor mode
@@ -351,7 +340,7 @@ intx00: pushb $0x0 # Int 0x0: #DE
intx10: pushb $0x10 # Int 0x10: #MF
jmp ex_noc # Floating-point error
#
-#
+# Handle #GP exception.
#
ex_v86: testb $0x2,0x12(%esp,1) # V86 mode?
jz except # No
@@ -470,9 +459,15 @@ v86mon.1: lodsb # Get opcode
v86mon.2: cmpb $0xf4,%al # HLT?
jne v86mon.3 # No
cmpl $inthlt+0x1,%esi # Is inthlt?
- jne v86mon.4 # No
+ jne v86mon.7 # No (ignore)
jmp intrtn # Return to user mode
-v86mon.3: cmpb $0xfa,%al # CLI?
+v86mon.3: cmpb $0xf,%al # Is
+ jne v86mon.4 # this
+ cmpb $0x20,(%esi) # a
+ jne v86mon.4 # MOV EAX,CR0
+ cmpb $0xc0,0x1(%esi) # instruction?
+ je v86mov # Yes
+v86mon.4: cmpb $0xfa,%al # CLI?
je v86cli # Yes
cmpb $0xfb,%al # STI?
je v86sti # Yes
@@ -490,7 +485,7 @@ v86mon.3: cmpb $0xfa,%al # CLI?
cmpb $0xcf,%al # IRET/IRETD?
je v86iret # Yes
popl %ebx # Restore
-v86mon.4: popa # Restore
+ popa # Restore
jmp except # Handle exception
v86mon.5: movl %edx,0x30(%ebp) # Save V86 flags
v86mon.6: popl %edx # V86 SS adjustment
@@ -502,6 +497,14 @@ v86mon.7: subl %edi,%esi # From linear
leal 0x8(%esp,1),%esp # Discard int no, error
iret # To V86 mode
#
+# Emulate MOV EAX,CR0.
+#
+v86mov: movl %cr0,%eax # CR0 to
+ movl %eax,0x1c(%ebp) # saved EAX
+ incl %esi # Adjust
+ incl %esi # IP
+ jmp v86mon.7 # Finish up
+#
# Emulate CLI.
#
v86cli: andb $~0x2,0x31(%ebp) # Clear IF
@@ -704,12 +707,12 @@ intusr.4: shrl $0x4,%eax # Gives segment
xchgl %eax,%ebp # Get int no/address
testb $0x1,%dl # Address?
jnz intusr.5 # Yes
- shll $0x2,%eax # XXX Scale
+ shll $0x2,%eax # Scale
movl (%eax),%eax # Load int vector
-intusr.5: movl %eax,%ecx # XXX Save
+intusr.5: movl %eax,%ecx # Save
shrl $0x10,%eax # Gives segment
stosl # Set CS
- movw %cx,%ax # XXX Restore
+ movw %cx,%ax # Restore
stosl # Set EIP
leal 0x10(%esp,1),%esp # Discard seg regs
popa # Restore
@@ -717,7 +720,28 @@ intusr.5: movl %eax,%ecx # XXX Save
#
# System Call.
#
-intx30: jmp exit # Just exit for now
+intx30: cmpl $SYS_EXEC,%eax # Exec system call?
+ jne intx30.1 # No
+ pushl %ss # Set up
+ popl %es # all
+ pushl %es # segment
+ popl %ds # registers
+ pushl %ds # for the
+ popl %fs # program
+ pushl %fs # we're
+ popl %gs # invoking
+ movl $MEM_USR,%eax # User base address
+ addl 0xc(%esp,1),%eax # Change to user
+ leal 0x4(%eax),%esp # stack
+ movl %cr0,%eax # Turn
+ andl $~0x80000000,%eax # off
+ movl %eax,%cr0 # paging
+ xorl %eax,%eax # Flush
+ movl %eax,%cr3 # TLB
+ popl %eax # Call
+ call *%eax # program
+intx30.1: incb %ss:btx_hdr+0x7 # Flag reboot
+ jmp exit # Exit
#
# Dump structure [EBX] to [EDI], using format string [ESI].
#
@@ -745,7 +769,7 @@ dump.1: testb $DMP_X32,%ch # Dump long?
dump.2: testb $DMP_MEM,%ch # Dump memory?
jz dump.8 # No
pushl %ds # Save
- testb $0x2,0x52(%ebx) # XXX V86 mode?
+ testb $0x2,0x52(%ebx) # V86 mode?
jnz dump.3 # Yes
verrl 0x4(%esi) # Readable selector?
jnz dump.3 # No
@@ -884,7 +908,8 @@ idtctl: .byte 0x10, 0x8e # Int 0x0-0xf
#
# Dump format string.
#
-dmpfmt: .ascii "int" # "int="
+dmpfmt: .byte '\n' # "\n"
+ .ascii "int" # "int="
.byte 0x80|DMP_X32, 0x40 # "00000000 "
.ascii "err" # "err="
.byte 0x80|DMP_X32, 0x44 # "00000000 "
@@ -925,13 +950,9 @@ dmpfmt: .ascii "int" # "int="
.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"
- .byte 0x0 # End of string
-#
-# Messages.
-#
-prompt: .asciz "Press ENTER to reboot"
+ .asciz "System halted" # End
#
-# Start of user memory.
+# End of BTX memory.
#
.p2align 4
break:
diff --git a/sys/boot/i386/btx/btxldr/Makefile b/sys/boot/i386/btx/btxldr/Makefile
new file mode 100644
index 0000000..32cb4ad
--- /dev/null
+++ b/sys/boot/i386/btx/btxldr/Makefile
@@ -0,0 +1,22 @@
+# $Id: Makefile,v 1.5 1998/10/13 18:29:18 rnordier Exp $
+
+ORG=0x100000
+AFLAGS+= --assembler-with-cpp
+
+all: btxldr
+
+btxldr: btxldr.o
+.if ${OBJFORMAT} == aout
+ ${LD} -nostdlib -N -s -T ${ORG} -o btxldr.out btxldr.o
+ dd if=btxldr.out of=${.TARGET} ibs=32 skip=1
+.else
+ ${LD} -N -e start -Ttext ${ORG} -o btxldr.out btxldr.o
+ objcopy -S -O binary btxldr.out ${.TARGET}
+.endif
+
+btxldr.o: btxldr.s
+ ${CC} ${AFLAGS} -c -o ${.TARGET} ${.CURDIR}/btxldr.s
+
+CLEANFILES+= btxldr btxldr.out btxldr.o
+
+.include <bsd.prog.mk>
diff --git a/sys/boot/i386/btx/btxldr/btxldr.S b/sys/boot/i386/btx/btxldr/btxldr.S
new file mode 100644
index 0000000..5d3b301
--- /dev/null
+++ b/sys/boot/i386/btx/btxldr/btxldr.S
@@ -0,0 +1,384 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btxldr.s,v 1.4 1998/10/30 00:11:35 msmith Exp $
+
+#
+# Prototype BTX loader program, written in a couple of hours. The
+# real thing should probably be more flexible, and in C.
+#
+
+#
+# Memory locations.
+#
+ .set MEM_STUB,0x600 # Real mode stub
+ .set MEM_ESP,0x1000 # New stack pointer
+ .set MEM_TBL,0x5000 # BTX page tables
+ .set MEM_ENTRY,0x9010 # BTX entry point
+ .set MEM_DATA,0x101000 # Data segment
+#
+# Segment selectors.
+#
+ .set SEL_SCODE,0x8 # 4GB code
+ .set SEL_SDATA,0x10 # 4GB data
+ .set SEL_RCODE,0x18 # 64K code
+ .set SEL_RDATA,0x20 # 64K data
+#
+# Paging constants.
+#
+ .set PAG_SIZ,0x1000 # Page size
+ .set PAG_ENT,0x4 # Page entry size
+#
+# Screen constants.
+#
+ .set SCR_MAT,0x7 # Mode/attribute
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+#
+# BIOS Data Area locations.
+#
+ .set BDA_MEM,0x413 # Free memory
+ .set BDA_SCR,0x449 # Video mode
+ .set BDA_POS,0x450 # Cursor position
+#
+# Required by aout gas inadequacy.
+#
+ .set SIZ_STUB,0x1a # Size of stub
+#
+# We expect to be loaded by boot2 at 0x100000.
+#
+ .globl start
+#
+# BTX program loader for ELF clients.
+#
+start: cld # String ops inc
+ movl $m_logo,%esi # Identify
+ call putstr # ourselves
+ movzwl BDA_MEM,%eax # Get base memory
+ shll $0xa,%eax # in bytes
+ movl %eax,%ebp # Base of user stack
+ movl $m_mem,%esi # Display
+ call dhexout # amount of
+ call dputstr # base memory
+ lgdt gdtdesc # Load new GDT
+#
+# Relocate caller's arguments.
+#
+ movl $m_esp,%esi # Display
+ movl %esp,%eax # caller's
+ call dhexout # stack
+ call dputstr # pointer
+ movl $m_args,%esi # Format string
+ leal 0x4(%esp,1),%ebx # First argument
+ movl $0x6,%ecx # Count
+start.1: movl (%ebx),%eax # Get argument and
+ addl $0x4,%ebx # bump pointer
+ call dhexout # Display it
+ loop start.1 # Till done
+ call dputstr # End message
+ movl $0x48,%ecx # Allocate space
+ subl %ecx,%ebp # for bootinfo
+ movl 0x18(%esp,1),%esi # Source
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # it
+ movl %ebp,0x18(%esp,1) # Update pointer
+ movl $m_rel_bi,%esi # Display
+ movl %ebp,%eax # bootinfo
+ call dhexout # relocation
+ call dputstr # message
+ movl $0x18,%ecx # Allocate space
+ subl %ecx,%ebp # for arguments
+ leal 0x4(%esp,1),%esi # Source
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # them
+ movl $m_rel_args,%esi # Display
+ movl %ebp,%eax # argument
+ call dhexout # relocation
+ call dputstr # message
+#
+# Set up BTX kernel.
+#
+ movl $MEM_ESP,%esp # Set up new stack
+ movl $MEM_DATA,%ebx # Data segment
+ movl $m_vers,%esi # Display BTX
+ call putstr # version message
+ movb 0x5(%ebx),%al # Get major version
+ addb $'0',%al # Display
+ call putchr # it
+ movb $'.',%al # And a
+ call putchr # dot
+ movb 0x6(%ebx),%al # Get minor
+ xorb %ah,%ah # version
+ movb $0xa,%dl # Divide
+ divb %dl,%al # by 10
+ addb $'0',%al # Display
+ call putchr # tens
+ movb %ah,%al # Get units
+ addb $'0',%al # Display
+ call putchr # units
+ call putstr # End message
+ movl %ebx,%esi # BTX image
+ movzwl 0x8(%ebx),%edi # Compute
+ orl $PAG_SIZ/PAG_ENT-1,%edi # the
+ incl %edi # BTX
+ shll $0x2,%edi # load
+ addl $MEM_TBL,%edi # address
+ pushl %edi # Save
+ movzwl 0xa(%ebx),%ecx # Image size
+ pushl %ecx # Save
+ rep # Relocate
+ movsb # BTX
+ movl %esi,%ebx # Keep place
+ movl $m_rel_btx,%esi # Restore
+ popl %eax # parameters
+ call dhexout # and
+ popl %ebp # display
+ movl %ebp,%eax # the
+ call dhexout # relocation
+ call dputstr # message
+ addl $PAG_SIZ,%ebp # Display
+ movl $m_base,%esi # the
+ movl %ebp,%eax # user
+ call dhexout # base
+ call dputstr # address
+#
+# Set up ELF-format client program.
+#
+ cmpl $0x464c457f,(%ebx) # ELF magic number?
+ je start.3 # Yes
+ movl $e_fmt,%esi # Display error
+ call putstr # message
+start.2: jmp start.2 # Hang
+start.3: movl $m_elf,%esi # Display ELF
+ call dputstr # message
+ movl $m_segs,%esi # Format string
+ movl $0x2,%edi # Segment count
+ movl 0x1c(%ebx),%edx # Get e_phoff
+ addl %ebx,%edx # To pointer
+ movzwl 0x2c(%ebx),%ecx # Get e_phnum
+start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD?
+ jne start.6 # No
+ movl 0x4(%edx),%eax # Display
+ call dhexout # p_offset
+ movl 0x8(%edx),%eax # Display
+ call dhexout # p_vaddr
+ movl 0x10(%edx),%eax # Display
+ call dhexout # p_filesz
+ movl 0x14(%edx),%eax # Display
+ call dhexout # p_memsz
+ call dputstr # End message
+ pushl %esi # Save
+ pushl %edi # working
+ pushl %ecx # registers
+ movl 0x4(%edx),%esi # Get p_offset
+ addl %ebx,%esi # as pointer
+ movl 0x8(%edx),%edi # Get p_vaddr
+ addl %ebp,%edi # as pointer
+ movl 0x10(%edx),%ecx # Get p_filesz
+ rep # Set up
+ movsb # segment
+ movl 0x14(%edx),%ecx # Any bytes
+ subl 0x10(%edx),%ecx # to zero?
+ jz start.5 # No
+ xorb %al,%al # Then
+ rep # zero
+ stosb # them
+start.5: popl %ecx # Restore
+ popl %edi # working
+ popl %esi # registers
+ decl %edi # Segments to do
+ je start.7 # If none
+start.6: addl $0x20,%edx # To next entry
+ loop start.4 # Till done
+start.7: movl $m_done,%esi # Display done
+ call dputstr # message
+ movl $start.8,%esi # Real mode stub
+ movl $MEM_STUB,%edi # Destination
+ movl $SIZ_STUB,%ecx # Size
+ rep # Relocate
+ movsb # it
+ ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code
+start.8: xorl %eax,%eax # Data
+ movb $SEL_RDATA,%al # selector
+ movl %eax,%ss # Reload SS
+ movl %eax,%ds # Reset
+ movl %eax,%es # other
+ movl %eax,%fs # segment
+ movl %eax,%gs # limits
+ movl %cr0,%eax # Switch to
+ decl %eax # real
+ movl %eax,%cr0 # mode
+ .byte 0xea # Jump to
+ .word MEM_ENTRY # BTX entry
+ .word 0x0 # point
+start.9:
+#
+# Output message [ESI] followed by EAX in hex.
+#
+dhexout:
+#ifndef BTXLDR_VERBOSE
+ ret
+#endif
+hexout: pushl %eax # Save
+ call putstr # Display message
+ popl %eax # Restore
+ pushl %esi # Save
+ pushl %edi # caller's
+ movl $buf,%edi # Buffer
+ pushl %edi # Save
+ call hex32 # To hex
+ xorb %al,%al # Terminate
+ stosb # string
+ popl %esi # Restore
+hexout.1: lodsb # Get a char
+ cmpb $'0',%al # Leading zero?
+ je hexout.1 # Yes
+ testb %al,%al # End of string?
+ jne hexout.2 # No
+ decl %esi # Undo
+hexout.2: decl %esi # Adjust for inc
+ call putstr # Display hex
+ popl %edi # Restore
+ popl %esi # caller's
+ ret # To caller
+#
+# Output zero-terminated string [ESI] to the console.
+#
+dputstr:
+#ifndef BTXLDR_VERBOSE
+ ret
+#else
+ jmp putstr
+#endif
+putstr.0: call putchr # Output char
+putstr: lodsb # Load char
+ testb %al,%al # End of string?
+ jne putstr.0 # No
+ ret # To caller
+#
+# Output character AL to the console.
+#
+dputchr:
+#ifndef BTXLDR_VERBOSE
+ ret
+#endif
+putchr: pusha # Save
+ xorl %ecx,%ecx # Zero for loops
+ movb $SCR_MAT,%ah # Mode/attribute
+ movl $BDA_POS,%ebx # BDA pointer
+ movw (%ebx),%dx # Cursor position
+ movl $0xb8000,%edi # Regen buffer (color)
+ cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode?
+ jne putchr.1 # No
+ xorw %di,%di # Regen buffer (mono)
+putchr.1: cmpb $0xa,%al # New line?
+ je putchr.2 # Yes
+ xchgl %eax,%ecx # Save char
+ movb $SCR_COL,%al # Columns per row
+ mulb %dh # * row position
+ addb %dl,%al # + column
+ adcb $0x0,%ah # position
+ shll %eax # * 2
+ xchgl %eax,%ecx # Swap char, offset
+ movw %ax,(%edi,%ecx,1) # Write attr:char
+ incl %edx # Bump cursor
+ cmpb $SCR_COL,%dl # Beyond row?
+ jb putchr.3 # No
+putchr.2: xorb %dl,%dl # Zero column
+ incb %dh # Bump row
+putchr.3: cmpb $SCR_ROW,%dh # Beyond screen?
+ 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
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+ movb $SCR_ROW-1,%dh # Bottom line
+putchr.4: movw %dx,(%ebx) # Update position
+ popa # Restore
+ ret # To caller
+#
+# Convert EAX, AX, or AL to hex, saving the result to [EDI].
+#
+hex32: pushl %eax # Save
+ shrl $0x10,%eax # Do upper
+ call hex16 # 16
+ popl %eax # Restore
+hex16: call hex16.1 # Do upper 8
+hex16.1: xchgb %ah,%al # Save/restore
+hex8: pushl %eax # Save
+ shrb $0x4,%al # Do upper
+ call hex8.1 # 4
+ popl %eax # Restore
+hex8.1: andb $0xf,%al # Get lower 4
+ cmpb $0xa,%al # Convert
+ sbbb $0x69,%al # to hex
+ das # digit
+ orb $0x20,%al # To lower case
+ stosb # Save char
+ ret # (Recursive)
+
+ .data
+ .p2align 4
+#
+# Global descriptor table.
+#
+gdt: .word 0x0,0x0,0x0,0x0 # Null entry
+ .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
+ .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
+ .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
+ .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
+gdt.1:
+gdtdesc: .word gdt.1-gdt-1 # Limit
+ .long gdt # Base
+#
+# Messages.
+#
+m_logo: .asciz "\nBTX loader 1.00 "
+m_vers: .asciz "BTX version is \0\n"
+e_fmt: .asciz "Error: Client format not supported\n"
+#ifdef BTXLDR_VERBOSE
+m_mem: .asciz "Starting in protected mode (base mem=\0)\n"
+m_esp: .asciz "Arguments passed (esp=\0):\n"
+m_args: .asciz"<howto="
+ .asciz" bootdev="
+ .asciz" junk="
+ .asciz" "
+ .asciz" "
+ .asciz" bootinfo=\0>\n"
+m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n"
+m_rel_args: .asciz "Relocated arguments (size=18) to \0\n"
+m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n"
+m_base: .asciz "Client base address is \0\n"
+m_elf: .asciz "Client format is ELF\n"
+m_segs: .asciz "text segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+ .asciz "data segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+m_done: .asciz "Loading complete\n"
+#endif
+#
+# Uninitialized data area.
+#
+buf: # Scratch buffer
diff --git a/sys/boot/i386/btx/btxldr/btxldr.s b/sys/boot/i386/btx/btxldr/btxldr.s
new file mode 100644
index 0000000..5d3b301
--- /dev/null
+++ b/sys/boot/i386/btx/btxldr/btxldr.s
@@ -0,0 +1,384 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btxldr.s,v 1.4 1998/10/30 00:11:35 msmith Exp $
+
+#
+# Prototype BTX loader program, written in a couple of hours. The
+# real thing should probably be more flexible, and in C.
+#
+
+#
+# Memory locations.
+#
+ .set MEM_STUB,0x600 # Real mode stub
+ .set MEM_ESP,0x1000 # New stack pointer
+ .set MEM_TBL,0x5000 # BTX page tables
+ .set MEM_ENTRY,0x9010 # BTX entry point
+ .set MEM_DATA,0x101000 # Data segment
+#
+# Segment selectors.
+#
+ .set SEL_SCODE,0x8 # 4GB code
+ .set SEL_SDATA,0x10 # 4GB data
+ .set SEL_RCODE,0x18 # 64K code
+ .set SEL_RDATA,0x20 # 64K data
+#
+# Paging constants.
+#
+ .set PAG_SIZ,0x1000 # Page size
+ .set PAG_ENT,0x4 # Page entry size
+#
+# Screen constants.
+#
+ .set SCR_MAT,0x7 # Mode/attribute
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+#
+# BIOS Data Area locations.
+#
+ .set BDA_MEM,0x413 # Free memory
+ .set BDA_SCR,0x449 # Video mode
+ .set BDA_POS,0x450 # Cursor position
+#
+# Required by aout gas inadequacy.
+#
+ .set SIZ_STUB,0x1a # Size of stub
+#
+# We expect to be loaded by boot2 at 0x100000.
+#
+ .globl start
+#
+# BTX program loader for ELF clients.
+#
+start: cld # String ops inc
+ movl $m_logo,%esi # Identify
+ call putstr # ourselves
+ movzwl BDA_MEM,%eax # Get base memory
+ shll $0xa,%eax # in bytes
+ movl %eax,%ebp # Base of user stack
+ movl $m_mem,%esi # Display
+ call dhexout # amount of
+ call dputstr # base memory
+ lgdt gdtdesc # Load new GDT
+#
+# Relocate caller's arguments.
+#
+ movl $m_esp,%esi # Display
+ movl %esp,%eax # caller's
+ call dhexout # stack
+ call dputstr # pointer
+ movl $m_args,%esi # Format string
+ leal 0x4(%esp,1),%ebx # First argument
+ movl $0x6,%ecx # Count
+start.1: movl (%ebx),%eax # Get argument and
+ addl $0x4,%ebx # bump pointer
+ call dhexout # Display it
+ loop start.1 # Till done
+ call dputstr # End message
+ movl $0x48,%ecx # Allocate space
+ subl %ecx,%ebp # for bootinfo
+ movl 0x18(%esp,1),%esi # Source
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # it
+ movl %ebp,0x18(%esp,1) # Update pointer
+ movl $m_rel_bi,%esi # Display
+ movl %ebp,%eax # bootinfo
+ call dhexout # relocation
+ call dputstr # message
+ movl $0x18,%ecx # Allocate space
+ subl %ecx,%ebp # for arguments
+ leal 0x4(%esp,1),%esi # Source
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # them
+ movl $m_rel_args,%esi # Display
+ movl %ebp,%eax # argument
+ call dhexout # relocation
+ call dputstr # message
+#
+# Set up BTX kernel.
+#
+ movl $MEM_ESP,%esp # Set up new stack
+ movl $MEM_DATA,%ebx # Data segment
+ movl $m_vers,%esi # Display BTX
+ call putstr # version message
+ movb 0x5(%ebx),%al # Get major version
+ addb $'0',%al # Display
+ call putchr # it
+ movb $'.',%al # And a
+ call putchr # dot
+ movb 0x6(%ebx),%al # Get minor
+ xorb %ah,%ah # version
+ movb $0xa,%dl # Divide
+ divb %dl,%al # by 10
+ addb $'0',%al # Display
+ call putchr # tens
+ movb %ah,%al # Get units
+ addb $'0',%al # Display
+ call putchr # units
+ call putstr # End message
+ movl %ebx,%esi # BTX image
+ movzwl 0x8(%ebx),%edi # Compute
+ orl $PAG_SIZ/PAG_ENT-1,%edi # the
+ incl %edi # BTX
+ shll $0x2,%edi # load
+ addl $MEM_TBL,%edi # address
+ pushl %edi # Save
+ movzwl 0xa(%ebx),%ecx # Image size
+ pushl %ecx # Save
+ rep # Relocate
+ movsb # BTX
+ movl %esi,%ebx # Keep place
+ movl $m_rel_btx,%esi # Restore
+ popl %eax # parameters
+ call dhexout # and
+ popl %ebp # display
+ movl %ebp,%eax # the
+ call dhexout # relocation
+ call dputstr # message
+ addl $PAG_SIZ,%ebp # Display
+ movl $m_base,%esi # the
+ movl %ebp,%eax # user
+ call dhexout # base
+ call dputstr # address
+#
+# Set up ELF-format client program.
+#
+ cmpl $0x464c457f,(%ebx) # ELF magic number?
+ je start.3 # Yes
+ movl $e_fmt,%esi # Display error
+ call putstr # message
+start.2: jmp start.2 # Hang
+start.3: movl $m_elf,%esi # Display ELF
+ call dputstr # message
+ movl $m_segs,%esi # Format string
+ movl $0x2,%edi # Segment count
+ movl 0x1c(%ebx),%edx # Get e_phoff
+ addl %ebx,%edx # To pointer
+ movzwl 0x2c(%ebx),%ecx # Get e_phnum
+start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD?
+ jne start.6 # No
+ movl 0x4(%edx),%eax # Display
+ call dhexout # p_offset
+ movl 0x8(%edx),%eax # Display
+ call dhexout # p_vaddr
+ movl 0x10(%edx),%eax # Display
+ call dhexout # p_filesz
+ movl 0x14(%edx),%eax # Display
+ call dhexout # p_memsz
+ call dputstr # End message
+ pushl %esi # Save
+ pushl %edi # working
+ pushl %ecx # registers
+ movl 0x4(%edx),%esi # Get p_offset
+ addl %ebx,%esi # as pointer
+ movl 0x8(%edx),%edi # Get p_vaddr
+ addl %ebp,%edi # as pointer
+ movl 0x10(%edx),%ecx # Get p_filesz
+ rep # Set up
+ movsb # segment
+ movl 0x14(%edx),%ecx # Any bytes
+ subl 0x10(%edx),%ecx # to zero?
+ jz start.5 # No
+ xorb %al,%al # Then
+ rep # zero
+ stosb # them
+start.5: popl %ecx # Restore
+ popl %edi # working
+ popl %esi # registers
+ decl %edi # Segments to do
+ je start.7 # If none
+start.6: addl $0x20,%edx # To next entry
+ loop start.4 # Till done
+start.7: movl $m_done,%esi # Display done
+ call dputstr # message
+ movl $start.8,%esi # Real mode stub
+ movl $MEM_STUB,%edi # Destination
+ movl $SIZ_STUB,%ecx # Size
+ rep # Relocate
+ movsb # it
+ ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code
+start.8: xorl %eax,%eax # Data
+ movb $SEL_RDATA,%al # selector
+ movl %eax,%ss # Reload SS
+ movl %eax,%ds # Reset
+ movl %eax,%es # other
+ movl %eax,%fs # segment
+ movl %eax,%gs # limits
+ movl %cr0,%eax # Switch to
+ decl %eax # real
+ movl %eax,%cr0 # mode
+ .byte 0xea # Jump to
+ .word MEM_ENTRY # BTX entry
+ .word 0x0 # point
+start.9:
+#
+# Output message [ESI] followed by EAX in hex.
+#
+dhexout:
+#ifndef BTXLDR_VERBOSE
+ ret
+#endif
+hexout: pushl %eax # Save
+ call putstr # Display message
+ popl %eax # Restore
+ pushl %esi # Save
+ pushl %edi # caller's
+ movl $buf,%edi # Buffer
+ pushl %edi # Save
+ call hex32 # To hex
+ xorb %al,%al # Terminate
+ stosb # string
+ popl %esi # Restore
+hexout.1: lodsb # Get a char
+ cmpb $'0',%al # Leading zero?
+ je hexout.1 # Yes
+ testb %al,%al # End of string?
+ jne hexout.2 # No
+ decl %esi # Undo
+hexout.2: decl %esi # Adjust for inc
+ call putstr # Display hex
+ popl %edi # Restore
+ popl %esi # caller's
+ ret # To caller
+#
+# Output zero-terminated string [ESI] to the console.
+#
+dputstr:
+#ifndef BTXLDR_VERBOSE
+ ret
+#else
+ jmp putstr
+#endif
+putstr.0: call putchr # Output char
+putstr: lodsb # Load char
+ testb %al,%al # End of string?
+ jne putstr.0 # No
+ ret # To caller
+#
+# Output character AL to the console.
+#
+dputchr:
+#ifndef BTXLDR_VERBOSE
+ ret
+#endif
+putchr: pusha # Save
+ xorl %ecx,%ecx # Zero for loops
+ movb $SCR_MAT,%ah # Mode/attribute
+ movl $BDA_POS,%ebx # BDA pointer
+ movw (%ebx),%dx # Cursor position
+ movl $0xb8000,%edi # Regen buffer (color)
+ cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode?
+ jne putchr.1 # No
+ xorw %di,%di # Regen buffer (mono)
+putchr.1: cmpb $0xa,%al # New line?
+ je putchr.2 # Yes
+ xchgl %eax,%ecx # Save char
+ movb $SCR_COL,%al # Columns per row
+ mulb %dh # * row position
+ addb %dl,%al # + column
+ adcb $0x0,%ah # position
+ shll %eax # * 2
+ xchgl %eax,%ecx # Swap char, offset
+ movw %ax,(%edi,%ecx,1) # Write attr:char
+ incl %edx # Bump cursor
+ cmpb $SCR_COL,%dl # Beyond row?
+ jb putchr.3 # No
+putchr.2: xorb %dl,%dl # Zero column
+ incb %dh # Bump row
+putchr.3: cmpb $SCR_ROW,%dh # Beyond screen?
+ 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
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+ movb $SCR_ROW-1,%dh # Bottom line
+putchr.4: movw %dx,(%ebx) # Update position
+ popa # Restore
+ ret # To caller
+#
+# Convert EAX, AX, or AL to hex, saving the result to [EDI].
+#
+hex32: pushl %eax # Save
+ shrl $0x10,%eax # Do upper
+ call hex16 # 16
+ popl %eax # Restore
+hex16: call hex16.1 # Do upper 8
+hex16.1: xchgb %ah,%al # Save/restore
+hex8: pushl %eax # Save
+ shrb $0x4,%al # Do upper
+ call hex8.1 # 4
+ popl %eax # Restore
+hex8.1: andb $0xf,%al # Get lower 4
+ cmpb $0xa,%al # Convert
+ sbbb $0x69,%al # to hex
+ das # digit
+ orb $0x20,%al # To lower case
+ stosb # Save char
+ ret # (Recursive)
+
+ .data
+ .p2align 4
+#
+# Global descriptor table.
+#
+gdt: .word 0x0,0x0,0x0,0x0 # Null entry
+ .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
+ .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
+ .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
+ .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
+gdt.1:
+gdtdesc: .word gdt.1-gdt-1 # Limit
+ .long gdt # Base
+#
+# Messages.
+#
+m_logo: .asciz "\nBTX loader 1.00 "
+m_vers: .asciz "BTX version is \0\n"
+e_fmt: .asciz "Error: Client format not supported\n"
+#ifdef BTXLDR_VERBOSE
+m_mem: .asciz "Starting in protected mode (base mem=\0)\n"
+m_esp: .asciz "Arguments passed (esp=\0):\n"
+m_args: .asciz"<howto="
+ .asciz" bootdev="
+ .asciz" junk="
+ .asciz" "
+ .asciz" "
+ .asciz" bootinfo=\0>\n"
+m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n"
+m_rel_args: .asciz "Relocated arguments (size=18) to \0\n"
+m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n"
+m_base: .asciz "Client base address is \0\n"
+m_elf: .asciz "Client format is ELF\n"
+m_segs: .asciz "text segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+ .asciz "data segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+m_done: .asciz "Loading complete\n"
+#endif
+#
+# Uninitialized data area.
+#
+buf: # Scratch buffer
diff --git a/sys/boot/i386/btx/lib/Makefile b/sys/boot/i386/btx/lib/Makefile
new file mode 100644
index 0000000..e6fb758
--- /dev/null
+++ b/sys/boot/i386/btx/lib/Makefile
@@ -0,0 +1,20 @@
+# $Id: Makefile,v 1.1 1998/09/14 10:37:00 rnordier Exp $
+
+OBJS= btxcsu.o btxsys.o btxv86.o
+AFLAGS+= -elf
+LDFLAGS+= -elf
+CLEANFILES+= crt0.o
+INTERNALLIB= true
+NOMAN= true
+NOPIC= true
+NOPROFILE= true
+
+all: crt0.o
+
+crt0.o: ${OBJS}
+ ${LD} ${LDFLAGS} -i -o ${.TARGET} ${OBJS}
+
+.include <bsd.lib.mk>
+
+.s.o:
+ ${AS} ${AFLAGS} -o ${.TARGET} ${.IMPSRC}
diff --git a/sys/boot/i386/btx/lib/btxcsu.s b/sys/boot/i386/btx/lib/btxcsu.s
new file mode 100644
index 0000000..9b3e4c2
--- /dev/null
+++ b/sys/boot/i386/btx/lib/btxcsu.s
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btxcsu.s,v 1.1 1998/09/14 10:37:00 rnordier Exp $
+
+#
+# BTX C startup code (ELF).
+#
+
+#
+# Globals.
+#
+ .global _start
+#
+# Constants.
+#
+ .set ARGADJ,0xfa0 # Argument adjustment
+#
+# Client entry point.
+#
+_start: movl %eax,__base # Set base address
+ movl %esp,%eax # Set
+ addl $ARGADJ,%eax # argument
+ movl %eax,__args # pointer
+ call main # Invoke client main()
+ call exit # Invoke client exit()
+#
+# Data.
+#
+ .comm __base,4 # Client base address
+ .comm __args,4 # Client arguments
diff --git a/sys/boot/i386/btx/lib/btxsys.s b/sys/boot/i386/btx/lib/btxsys.s
new file mode 100644
index 0000000..16e3228
--- /dev/null
+++ b/sys/boot/i386/btx/lib/btxsys.s
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id:$
+
+#
+# BTX system calls.
+#
+
+#
+# Globals.
+#
+ .global __exit
+ .global __exec
+#
+# Constants.
+#
+ .set INT_SYS,0x30 # Interrupt number
+#
+# System call: exit
+#
+__exit: xorl %eax,%eax # BTX system
+ int $INT_SYS # call 0x0
+#
+# System call: exec
+#
+__exec: movl $0x1,%eax # BTX system
+ int $INT_SYS # call 0x1
diff --git a/sys/boot/i386/btx/lib/btxv86.h b/sys/boot/i386/btx/lib/btxv86.h
new file mode 100644
index 0000000..1e7717f
--- /dev/null
+++ b/sys/boot/i386/btx/lib/btxv86.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+/*
+ * $Id: btxv86.h,v 1.3 1998/10/02 16:22:54 msmith Exp $
+ */
+
+#ifndef _BTXV86_H_
+#define _BTXV86_H_
+
+#include <sys/types.h>
+
+#define V86_ADDR 0x10000 /* Segment:offset address */
+#define V86_CALLF 0x20000 /* Emulate far call */
+#define V86_FLAGS 0x40000 /* Return flags */
+
+struct __v86 {
+ uint32_t ctl; /* Control flags */
+ uint32_t addr; /* Interrupt number or address */
+ uint32_t es; /* V86 ES register */
+ uint32_t ds; /* V86 DS register */
+ uint32_t fs; /* V86 FS register */
+ uint32_t gs; /* V86 GS register */
+ uint32_t eax; /* V86 EAX register */
+ uint32_t ecx; /* V86 ECX register */
+ uint32_t edx; /* V86 EDX register */
+ uint32_t ebx; /* V86 EBX register */
+ uint32_t efl; /* V86 eflags register */
+ uint32_t ebp; /* V86 EBP register */
+ uint32_t esi; /* V86 ESI register */
+ uint32_t edi; /* V86 EDI register */
+};
+
+extern struct __v86 __v86; /* V86 interface structure */
+void __v86int(void);
+
+#define v86 __v86
+#define v86int __v86int
+
+extern u_int32_t __base;
+extern u_int32_t __args;
+
+#define PTOV(pa) ((caddr_t)(pa) - __base)
+#define VTOP(va) ((vm_offset_t)(va) + __base)
+#define VTOPSEG(va) (u_int16_t)(VTOP((caddr_t)va) >> 4)
+#define VTOPOFF(va) (u_int16_t)(VTOP((caddr_t)va) & 0xf)
+
+void __exit(int) __attribute__((__noreturn__));
+void __exec(caddr_t, ...);
+
+#endif /* !_BTXV86_H_ */
diff --git a/sys/boot/i386/btx/lib/btxv86.s b/sys/boot/i386/btx/lib/btxv86.s
new file mode 100644
index 0000000..46709a3
--- /dev/null
+++ b/sys/boot/i386/btx/lib/btxv86.s
@@ -0,0 +1,85 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id: btxv86.s,v 1.1 1998/09/14 10:37:00 rnordier Exp $
+
+#
+# BTX V86 interface.
+#
+
+#
+# Globals.
+#
+ .global __v86int
+#
+# Fields in V86 interface structure.
+#
+ .set V86_CTL,0x0 # Control flags
+ .set V86_ADDR,0x4 # Int number/address
+ .set V86_ES,0x8 # V86 ES
+ .set V86_DS,0xc # V86 DS
+ .set V86_FS,0x10 # V86 FS
+ .set V86_GS,0x14 # V86 GS
+ .set V86_EAX,0x18 # V86 EAX
+ .set V86_ECX,0x1c # V86 ECX
+ .set V86_EDX,0x20 # V86 EDX
+ .set V86_EBX,0x24 # V86 EBX
+ .set V86_EFL,0x28 # V86 eflags
+ .set V86_EBP,0x2c # V86 EBP
+ .set V86_ESI,0x30 # V86 ESI
+ .set V86_EDI,0x34 # V86 EDI
+#
+# Other constants.
+#
+ .set INT_V86,0x31 # Interrupt number
+ .set SIZ_V86,0x38 # Size of V86 structure
+#
+# V86 interface function.
+#
+__v86int: popl __v86ret # Save return address
+ pushl $__v86 # Push pointer
+ call __v86_swap # Load V86 registers
+ int $INT_V86 # To BTX
+ call __v86_swap # Load user registers
+ addl $0x4,%esp # Discard pointer
+ pushl __v86ret # Restore return address
+ ret # To user
+#
+# Swap V86 and user registers.
+#
+__v86_swap: xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP
+ xchgl %eax,V86_EAX(%ebp) # Swap EAX
+ xchgl %ecx,V86_ECX(%ebp) # Swap ECX
+ xchgl %edx,V86_EDX(%ebp) # Swap EDX
+ xchgl %ebx,V86_EBX(%ebp) # Swap EBX
+ pushl %eax # Save
+ pushf # Put eflags
+ popl %eax # in EAX
+ xchgl %eax,V86_EFL(%ebp) # Swap
+ pushl %eax # Put EAX
+ popf # in eflags
+ movl 0x8(%esp,1),%eax # Load EBP
+ xchgl %eax,V86_EBP(%ebp) # Swap
+ movl %eax,0x8(%esp,1) # Save EBP
+ popl %eax # Restore
+ xchgl %esi,V86_ESI(%ebp) # Swap ESI
+ xchgl %edi,V86_EDI(%ebp) # Swap EDI
+ xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP
+ ret # To caller
+#
+# V86 interface structure.
+#
+ .comm __v86,SIZ_V86
+ .comm __v86ret,4
diff --git a/sys/boot/i386/gptboot/Makefile b/sys/boot/i386/gptboot/Makefile
new file mode 100644
index 0000000..d10aa12
--- /dev/null
+++ b/sys/boot/i386/gptboot/Makefile
@@ -0,0 +1,76 @@
+# $Id: Makefile,v 1.11 1999/01/10 14:48:03 rnordier Exp $
+
+PROG= boot2
+NOMAN=
+STRIP=
+BINDIR?= /boot
+BINMODE= 444
+CLEANFILES+= boot1 boot1.out boot1.o \
+ boot2.ldr boot2.bin boot2.ld boot2.out boot2.o \
+ sio.o
+
+M4?= m4
+
+BOOT_COMCONSOLE_PORT?= 0x3f8
+BOOT_COMCONSOLE_SPEED?= 9600
+B2SIOFMT?= 0x3
+
+.if exists(${.OBJDIR}/../btx)
+BTX= ${.OBJDIR}/../btx
+.else
+BTX= ${.CURDIR}/../btx
+.endif
+
+ORG1= 0x7c00
+ORG2= 0x1000
+
+CFLAGS= -elf -I${.CURDIR}/../btx/lib -I. -fno-builtin \
+ -Os -malign-functions=0 -malign-jumps=0 -malign-loops=0 -mrtd \
+ -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \
+ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
+ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings
+
+LDFLAGS=-nostdlib -static -N
+
+all: boot1 boot2
+
+boot1: boot1.out
+ objcopy -S -O binary boot1.out ${.TARGET}
+
+boot1.out: boot1.o
+ ${LD} ${LDFLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} boot1.o
+
+boot1.o: boot1.m4 boot1.s
+ (cd ${.CURDIR}; ${M4} boot1.m4 boot1.s) | \
+ ${AS} ${AFLAGS} -o ${.TARGET}
+
+boot2: boot2.ldr boot2.bin
+ btxld -v -E ${ORG2} -f bin -b ${BTX}/btx/btx -l boot2.ldr \
+ -o boot2.ld -P 1 boot2.bin
+ @ls -l boot2.ld | awk '{ x = 7680 - $$5; \
+ print x " bytes available"; if (x < 0) exit 1 }'
+ dd if=boot2.ld of=${.TARGET} obs=7680 conv=osync 2>/dev/null
+
+boot2.ldr:
+ dd if=/dev/zero of=${.TARGET} bs=512 count=1 2>/dev/null
+
+boot2.bin: boot2.out
+ objcopy -S -O binary boot2.out ${.TARGET}
+
+boot2.out: boot2.o sio.o
+ ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} \
+ ${BTX}/lib/crt0.o boot2.o sio.o
+
+sio.o: sio.s
+ (cd ${.CURDIR}; ${M4} -DSIOPRT=${BOOT_COMCONSOLE_PORT} \
+ -DSIOFMT=${B2SIOFMT} \
+ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} sio.s) | \
+ ${AS} ${AFLAGS} -o ${.TARGET}
+
+install:
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ boot1 ${DESTDIR}${BINDIR}/boot1
+ ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ boot2 ${DESTDIR}${BINDIR}/boot2
+
+.include <bsd.prog.mk>
diff --git a/sys/boot/i386/gptboot/gptboot.c b/sys/boot/i386/gptboot/gptboot.c
new file mode 100644
index 0000000..b711c28
--- /dev/null
+++ b/sys/boot/i386/gptboot/gptboot.c
@@ -0,0 +1,809 @@
+/*
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+/*
+ * $Id: boot2.c,v 1.22 1999/04/04 21:15:41 obrien Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/diskslice.h>
+#include <sys/disklabel.h>
+#include <sys/dirent.h>
+#include <machine/bootinfo.h>
+
+#include <ufs/ffs/fs.h>
+#include <ufs/ufs/dinode.h>
+
+#include <stdarg.h>
+
+#include <a.out.h>
+#include <elf.h>
+
+#include <btxv86.h>
+
+#include "lib.h"
+
+#define RBX_ASKNAME 0x0 /* -a */
+#define RBX_SINGLE 0x1 /* -s */
+#define RBX_DFLTROOT 0x5 /* -r */
+#define RBX_KDB 0x6 /* -d */
+#define RBX_CONFIG 0xa /* -c */
+#define RBX_VERBOSE 0xb /* -v */
+#define RBX_SERIAL 0xc /* -h */
+#define RBX_CDROM 0xd /* -C */
+#define RBX_GDB 0xf /* -g */
+#define RBX_DUAL 0x1d /* -D */
+#define RBX_PROBEKBD 0x1e /* -P */
+
+#define RBX_MASK 0xffff
+
+#define PATH_CONFIG "/boot.config"
+#define PATH_BOOT3 "/boot/loader"
+#define PATH_KERNEL "/kernel"
+
+#define ARGS 0x900
+#define NOPT 11
+#define BSIZEMAX 8192
+#define NDEV 5
+#define MEM_BASE 0x12
+#define MEM_EXT 0x15
+#define V86_CY(x) ((x) & 1)
+#define V86_ZR(x) ((x) & 0x40)
+
+#define DRV_HARD 0x80
+#define DRV_MASK 0x7f
+
+#define MAJ_WD 0
+#define MAJ_WFD 1
+#define MAJ_FD 2
+#define MAJ_DA 4
+
+extern uint32_t _end;
+
+static const char optstr[NOPT] = "DhaCcdgPrsv";
+static const unsigned char flags[NOPT] = {
+ RBX_DUAL,
+ RBX_SERIAL,
+ RBX_ASKNAME,
+ RBX_CDROM,
+ RBX_CONFIG,
+ RBX_KDB,
+ RBX_GDB,
+ RBX_PROBEKBD,
+ RBX_DFLTROOT,
+ RBX_SINGLE,
+ RBX_VERBOSE
+};
+
+static const char *const dev_nm[] = {"wd", " ", "fd", " ", "da"};
+
+static struct dsk {
+ unsigned drive;
+ unsigned type;
+ unsigned unit;
+ unsigned slice;
+ unsigned part;
+ unsigned start;
+ int init;
+ int meta;
+} dsk;
+static char cmd[512];
+static char kname[1024];
+static uint32_t opts;
+static struct bootinfo bootinfo;
+static int ls;
+static uint32_t fs_off;
+static uint8_t ioctrl = 0x1;
+
+void exit(int);
+static void load(const char *);
+static int parse(char *);
+static void readfile(const char *, void *, size_t);
+static ino_t lookup(const char *);
+static int fsfind(const char *, ino_t *);
+static int xfsread(ino_t, void *, size_t);
+static ssize_t fsread(ino_t, void *, size_t);
+static int dskread(void *, unsigned, unsigned);
+static int printf(const char *,...);
+static void getstr(char *, int);
+static int putchar(int);
+static int getchar(void);
+static void *memcpy(void *, const void *, size_t);
+static int strcmp(const char *, const char *);
+static void *malloc(size_t);
+static uint32_t memsize(int);
+static uint32_t drvinfo(int);
+static int drvread(void *, unsigned, unsigned);
+static int keyhit(unsigned);
+static int xputc(int);
+static int xgetc(int);
+static void putc(int);
+static int getc(int);
+
+int
+main(void)
+{
+ int autoboot, i;
+
+ v86.ctl = V86_FLAGS;
+ dsk.drive = *(uint8_t *)PTOV(ARGS);
+ dsk.type = dsk.drive & DRV_HARD ? MAJ_WD : MAJ_FD;
+ dsk.unit = dsk.drive & DRV_MASK;
+ dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
+ bootinfo.bi_version = BOOTINFO_VERSION;
+ bootinfo.bi_size = sizeof(bootinfo);
+ bootinfo.bi_basemem = memsize(MEM_BASE);
+ bootinfo.bi_extmem = memsize(MEM_EXT);
+ bootinfo.bi_memsizes_valid++;
+ for (i = 0; i < N_BIOS_GEOM; i++)
+ bootinfo.bi_bios_geom[i] = drvinfo(i);
+ autoboot = 2;
+ readfile(PATH_CONFIG, cmd, sizeof(cmd));
+ if (*cmd) {
+ printf("%s: %s", PATH_CONFIG, cmd);
+ if (parse(cmd))
+ autoboot = 0;
+ *cmd = 0;
+ }
+ if (autoboot && !*kname) {
+ if (autoboot == 2) {
+ memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
+ if (!keyhit(0x37)) {
+ load(kname);
+ autoboot = 1;
+ }
+ }
+ if (autoboot == 1)
+ memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
+ }
+ for (;;) {
+ printf(" \n>> FreeBSD/i386 BOOT\n"
+ "Default: %u:%s(%u,%c)%s\n"
+ "boot: ",
+ dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
+ 'a' + dsk.part, kname);
+ if (ioctrl & 0x2)
+ sio_flush();
+ if (!autoboot || keyhit(0x5a))
+ getstr(cmd, sizeof(cmd));
+ else
+ putchar('\n');
+ autoboot = 0;
+ if (parse(cmd))
+ putchar('\a');
+ else
+ load(kname);
+ }
+}
+
+void
+exit(int x)
+{
+}
+
+static void
+load(const char *fname)
+{
+ union {
+ struct exec ex;
+ Elf32_Ehdr eh;
+ } hdr;
+ Elf32_Phdr ep[2];
+ Elf32_Shdr es[2];
+ caddr_t p;
+ ino_t ino;
+ uint32_t addr, x;
+ int fmt, i, j;
+
+ if (!(ino = lookup(fname))) {
+ if (!ls)
+ printf("No %s\n", fname);
+ return;
+ }
+ if (xfsread(ino, &hdr, sizeof(hdr)))
+ return;
+ if (N_GETMAGIC(hdr.ex) == ZMAGIC)
+ fmt = 0;
+ else if (IS_ELF(hdr.eh))
+ fmt = 1;
+ else {
+ printf("Invalid %s\n", "format");
+ return;
+ }
+ if (fmt == 0) {
+ 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;
+ p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
+ bootinfo.bi_symtab = VTOP(p);
+ memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
+ p += sizeof(hdr.ex.a_syms);
+ if (hdr.ex.a_syms) {
+ if (xfsread(ino, p, hdr.ex.a_syms))
+ return;
+ p += hdr.ex.a_syms;
+ if (xfsread(ino, p, sizeof(int)))
+ return;
+ x = *(uint32_t *)p;
+ p += sizeof(int);
+ x -= sizeof(int);
+ if (xfsread(ino, p, x))
+ return;
+ p += x;
+ }
+ } else {
+ fs_off = hdr.eh.e_phoff;
+ for (j = i = 0; i < hdr.eh.e_phoff && j < 2; i++) {
+ 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++) {
+ memcpy(p, &es[i].sh_size, sizeof(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);
+ bootinfo.bi_kernelname = VTOP(fname);
+ bootinfo.bi_bios_dev = dsk.drive;
+ __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
+ MAKEBOOTDEV(dsk.type, 0, dsk.slice, dsk.unit, dsk.part),
+ 0, 0, 0, VTOP(&bootinfo));
+}
+
+static int
+parse(char *arg)
+{
+ char *p, *q;
+ int drv, c, i;
+
+ while ((c = *arg++)) {
+ if (c == ' ')
+ continue;
+ for (p = arg; *p && *p != '\n' && *p != ' '; p++);
+ if (*p)
+ *p++ = 0;
+ if (c == '-') {
+ while ((c = *arg++)) {
+ for (i = 0; c != optstr[i]; i++)
+ if (i == NOPT - 1)
+ return -1;
+ opts ^= 1 << flags[i];
+ }
+ if (opts & 1 << RBX_PROBEKBD) {
+ i = *(uint8_t *)PTOV(0x496) & 0x10;
+ printf("Keyboard: %s\n", i ? "yes" : "no");
+ if (!i)
+ opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL;
+ opts &= ~(1 << RBX_PROBEKBD);
+ }
+ ioctrl = opts & 1 << RBX_DUAL ? 0x3 :
+ opts & 1 << RBX_SERIAL ? 0x2 : 0x1;
+ if (ioctrl & 0x2)
+ sio_init();
+ } else {
+ for (q = arg--; *q && *q != '('; q++);
+ if (*q) {
+ drv = -1;
+ if (arg[1] == ':') {
+ if (*arg < '0' || *arg > '9')
+ return -1;
+ drv = *arg - '0';
+ 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;
+ if (arg[1] != ',' || *arg < '0' || *arg > '9')
+ return -1;
+ dsk.unit = *arg - '0';
+ arg += 2;
+ dsk.slice = WHOLE_DISK_SLICE;
+ if (arg[1] == ',') {
+ if (*arg < '0' || *arg > '0' + NDOSPART)
+ return -1;
+ if ((dsk.slice = *arg - '0'))
+ dsk.slice++;
+ arg += 2;
+ }
+ if (arg[1] != ')' || *arg < 'a' || *arg > 'p')
+ return -1;
+ dsk.part = *arg - 'a';
+ arg += 2;
+ if (drv == -1)
+ drv = dsk.unit;
+ dsk.drive = (dsk.type == MAJ_WD ||
+ dsk.type == MAJ_DA ? DRV_HARD : 0) + drv;
+ dsk.meta = 0;
+ fsread(0, NULL, 0);
+ }
+ if ((i = p - arg - !*(p - 1))) {
+ if (i >= sizeof(kname))
+ return -1;
+ memcpy(kname, arg, i + 1);
+ }
+ }
+ arg = p;
+ }
+ return 0;
+}
+
+static void
+readfile(const char *fname, void *buf, size_t size)
+{
+ ino_t ino;
+
+ if ((ino = lookup(fname)))
+ fsread(ino, buf, size);
+}
+
+static ino_t
+lookup(const char *path)
+{
+ char name[MAXNAMLEN + 1];
+ const char *s;
+ ino_t ino;
+ ssize_t n;
+ int dt;
+
+ ino = ROOTINO;
+ dt = DT_DIR;
+ for (;;) {
+ if (*path == '/')
+ path++;
+ if (!*path)
+ break;
+ for (s = path; *s && *s != '/'; s++);
+ if ((n = s - path) > MAXNAMLEN)
+ return 0;
+ ls = *path == '?' && n == 1 && !*s;
+ memcpy(name, path, n);
+ name[n] = 0;
+ if ((dt = fsfind(name, &ino)) <= 0)
+ break;
+ path = s;
+ }
+ return dt == DT_REG ? ino : 0;
+}
+
+static int
+fsfind(const char *name, ino_t * ino)
+{
+ char buf[DEV_BSIZE];
+ struct dirent *d;
+ char *s;
+ ssize_t n;
+
+ fs_off = 0;
+ while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0)
+ for (s = buf; s < buf + DEV_BSIZE;) {
+ d = (void *)s;
+ if (ls)
+ printf("%s ", d->d_name);
+ else if (!strcmp(name, d->d_name)) {
+ *ino = d->d_fileno;
+ return d->d_type;
+ }
+ s += d->d_reclen;
+ }
+ if (n != -1 && ls)
+ putchar('\n');
+ return 0;
+}
+
+static int
+xfsread(ino_t inode, void *buf, size_t nbyte)
+{
+ if (fsread(inode, buf, nbyte) != nbyte) {
+ printf("Invalid %s\n", "format");
+ return -1;
+ }
+ return 0;
+}
+
+static ssize_t
+fsread(ino_t inode, void *buf, size_t nbyte)
+{
+ static struct fs fs;
+ static struct dinode din;
+ static char *blkbuf;
+ static ufs_daddr_t *indbuf;
+ static ino_t inomap;
+ static ufs_daddr_t blkmap, indmap;
+ static unsigned fsblks;
+ char *s;
+ ufs_daddr_t lbn, addr;
+ size_t n, nb, off;
+
+ if (!dsk.meta) {
+ if (!blkbuf)
+ blkbuf = malloc(BSIZEMAX);
+ inomap = 0;
+ if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE))
+ return -1;
+ memcpy(&fs, blkbuf, sizeof(fs));
+ if (fs.fs_magic != FS_MAGIC) {
+ printf("Not ufs\n");
+ return -1;
+ }
+ fsblks = fs.fs_bsize >> DEV_BSHIFT;
+ dsk.meta++;
+ }
+ if (!inode)
+ return 0;
+ if (inomap != inode) {
+ if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)),
+ fsblks))
+ return -1;
+ din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)];
+ inomap = inode;
+ fs_off = 0;
+ blkmap = indmap = 0;
+ }
+ s = buf;
+ if (nbyte > (n = din.di_size - fs_off))
+ nbyte = n;
+ nb = nbyte;
+ while (nb) {
+ lbn = lblkno(&fs, fs_off);
+ if (lbn < NDADDR)
+ addr = din.di_db[lbn];
+ else {
+ if (indmap != din.di_ib[0]) {
+ if (!indbuf)
+ indbuf = malloc(BSIZEMAX);
+ if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]),
+ fsblks))
+ return -1;
+ indmap = din.di_ib[0];
+ }
+ addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)];
+ }
+ n = dblksize(&fs, &din, lbn);
+ if (blkmap != addr) {
+ if (dskread(blkbuf, fsbtodb(&fs, addr), n >> DEV_BSHIFT))
+ return -1;
+ blkmap = addr;
+ }
+ off = blkoff(&fs, fs_off);
+ n -= off;
+ if (n > nb)
+ n = nb;
+ memcpy(s, blkbuf + off, n);
+ s += n;
+ fs_off += n;
+ nb -= n;
+ }
+ return nbyte;
+}
+
+static int
+dskread(void *buf, unsigned lba, unsigned nblk)
+{
+ static char *sec;
+ struct dos_partition *dp;
+ struct disklabel *d;
+ unsigned sl, i;
+
+ if (!dsk.meta) {
+ if (!sec)
+ sec = malloc(DEV_BSIZE);
+ dsk.start = 0;
+ if (drvread(sec, DOSBBSECTOR, 1))
+ return -1;
+ dp = (void *)(sec + DOSPARTOFF);
+ sl = dsk.slice;
+ if (sl < BASE_SLICE) {
+ for (i = 0; i < NDOSPART; i++)
+ if (dp[i].dp_typ == DOSPTYP_386BSD &&
+ (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
+ sl = BASE_SLICE + i;
+ if (dp[i].dp_flag & 0x80 ||
+ dsk.slice == COMPATIBILITY_SLICE)
+ break;
+ }
+ if (dsk.slice == WHOLE_DISK_SLICE)
+ dsk.slice = sl;
+ }
+ if (sl != WHOLE_DISK_SLICE) {
+ if (sl != COMPATIBILITY_SLICE)
+ dp += sl - BASE_SLICE;
+ if (dp->dp_typ != DOSPTYP_386BSD) {
+ printf("Invalid %s\n", "slice");
+ return -1;
+ }
+ dsk.start = dp->dp_start;
+ }
+ if (drvread(sec, dsk.start + LABELSECTOR, 1))
+ return -1;
+ d = (void *)(sec + LABELOFFSET);
+ if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
+ if (dsk.part != RAW_PART) {
+ printf("Invalid %s\n", "label");
+ return -1;
+ }
+ } else {
+ if (!dsk.init) {
+ if (d->d_type == DTYPE_SCSI)
+ dsk.type = MAJ_DA;
+ dsk.init++;
+ }
+ if (dsk.part >= d->d_npartitions ||
+ !d->d_partitions[dsk.part].p_size) {
+ printf("Invalid %s\n", "partition");
+ return -1;
+ }
+ dsk.start = d->d_partitions[dsk.part].p_offset;
+ }
+ }
+ return drvread(buf, dsk.start + lba, nblk);
+}
+
+static int
+printf(const char *fmt,...)
+{
+ static const char digits[16] = "0123456789abcdef";
+ va_list ap;
+ char buf[10];
+ char *s;
+ unsigned r, 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':
+ case 'x':
+ r = c == 'u' ? 10U : 16U;
+ u = va_arg(ap, unsigned);
+ s = buf;
+ do
+ *s++ = digits[u % r];
+ while (u /= r);
+ while (--s >= buf)
+ putchar(*s);
+ continue;
+ }
+ }
+ putchar(c);
+ }
+ va_end(ap);
+ return 0;
+}
+
+static void
+getstr(char *str, int size)
+{
+ char *s;
+ int c;
+
+ s = str;
+ do {
+ switch (c = getchar()) {
+ case 0:
+ break;
+ case '\b':
+ case '\177':
+ if (s > str) {
+ s--;
+ putchar('\b');
+ putchar(' ');
+ } else
+ c = 0;
+ break;
+ case '\n':
+ *s = 0;
+ break;
+ default:
+ if (s - str < size - 1)
+ *s++ = c;
+ }
+ if (c)
+ putchar(c);
+ } while (c != '\n');
+}
+
+static int
+putchar(int c)
+{
+ if (c == '\n')
+ xputc('\r');
+ return xputc(c);
+}
+
+static int
+getchar(void)
+{
+ int c;
+
+ c = xgetc(0);
+ if (c == '\r')
+ c = '\n';
+ return c;
+}
+
+static void *
+memcpy(void *dst, const void *src, size_t size)
+{
+ const char *s;
+ char *d;
+
+ for (d = dst, s = src; size; size--)
+ *d++ = *s++;
+ return dst;
+}
+
+static int
+strcmp(const char *s1, const char *s2)
+{
+ for (; *s1 == *s2 && *s1; s1++, s2++);
+ return (u_char)*s1 - (u_char)*s2;
+}
+
+static void *
+malloc(size_t size)
+{
+ static uint32_t next;
+ void *p;
+
+ if (!next)
+ next = roundup2(__base + _end, 0x10000) - __base;
+ p = (void *)next;
+ next += size;
+ return p;
+}
+
+static uint32_t
+memsize(int type)
+{
+ v86.addr = type;
+ v86.eax = 0x8800;
+ v86int();
+ return v86.eax;
+}
+
+static uint32_t
+drvinfo(int drive)
+{
+ v86.addr = 0x13;
+ v86.eax = 0x800;
+ v86.edx = DRV_HARD + drive;
+ v86int();
+ if (V86_CY(v86.efl))
+ return 0x4f010f;
+ return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
+ (v86.edx & 0xff00) | (v86.ecx & 0x3f);
+}
+
+static int
+drvread(void *buf, unsigned lba, unsigned nblk)
+{
+ static unsigned c = 0x2d5c7c2f;
+
+ printf("%c\b", c = c << 8 | c >> 24);
+ v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
+ v86.addr = 0x704; /* call to xread in boot1 */
+ v86.es = VTOPSEG(buf);
+ v86.eax = lba;
+ v86.ebx = VTOPOFF(buf);
+ v86.ecx = lba >> 16;
+ v86.edx = nblk << 8 | dsk.drive;
+ v86int();
+ v86.ctl = V86_FLAGS;
+ if (V86_CY(v86.efl)) {
+ printf("Disk error 0x%x (lba=0x%x)\n", v86.eax >> 8 & 0xff,
+ lba);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+keyhit(unsigned ticks)
+{
+ uint32_t t0, t1;
+
+ t0 = 0;
+ for (;;) {
+ if (xgetc(1))
+ return 1;
+ t1 = *(uint32_t *)PTOV(0x46c);
+ if (!t0)
+ t0 = t1;
+ if (t1 < t0 || t1 >= t0 + ticks)
+ return 0;
+ }
+}
+
+static int
+xputc(int c)
+{
+ if (ioctrl & 0x1)
+ putc(c);
+ if (ioctrl & 0x2)
+ sio_putc(c);
+ return c;
+}
+
+static int
+xgetc(int fn)
+{
+ for (;;) {
+ if (ioctrl & 0x1 && getc(1))
+ return fn ? 1 : getc(0);
+ if (ioctrl & 0x2 && sio_ischar())
+ return fn ? 1 : sio_getc();
+ if (fn)
+ return 0;
+ }
+}
+
+static void
+putc(int c)
+{
+ v86.addr = 0x10;
+ v86.eax = 0xe00 | (c & 0xff);
+ v86.ebx = 0x7;
+ v86int();
+}
+
+static int
+getc(int fn)
+{
+ v86.addr = 0x16;
+ v86.eax = fn << 8;
+ v86int();
+ return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);
+}
diff --git a/sys/boot/i386/libi386/Makefile b/sys/boot/i386/libi386/Makefile
new file mode 100644
index 0000000..2cfd2e3
--- /dev/null
+++ b/sys/boot/i386/libi386/Makefile
@@ -0,0 +1,39 @@
+# $Id: Makefile,v 1.12 1998/12/22 11:51:25 abial Exp $
+#
+LIB= i386
+NOPIC=
+NOPROFILE=
+INTERNALLIB= true
+INTERNALSTATICLIB= true
+
+SRCS= aout_freebsd.c biosdisk.c biosmem.c biospnp.c biospci.c \
+ bootinfo.c comconsole.c devicename.c elf_freebsd.c gatea20.c \
+ i386_copy.c i386_module.c time.c vidconsole.c
+
+CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../btx/lib \
+ -I${.CURDIR}/../../.. -I.
+
+BOOT_COMCONSOLE_PORT?= 0x3f8
+CFLAGS+= -DCOMPORT=${BOOT_COMCONSOLE_PORT}
+
+BOOT_COMCONSOLE_SPEED?= 9600
+CFLAGS+= -DCOMSPEED=${BOOT_COMCONSOLE_SPEED}
+
+# Make the disk code more talkative
+#CFLAGS+= -DDISK_DEBUG
+
+# Include simple terminal emulation (cons25-compatible)
+CFLAGS+= -DTERM_EMU
+
+# If it's not there, don't consider it a target
+.if exists(${.CURDIR}/../../../i386/include)
+beforedepend ${OBJS}: machine
+
+machine:
+ ln -sf ${.CURDIR}/../../../i386/include machine
+
+.endif
+
+CLEANFILES+= machine
+
+.include <bsd.lib.mk>
diff --git a/sys/boot/i386/libi386/aout_freebsd.c b/sys/boot/i386/libi386/aout_freebsd.c
new file mode 100644
index 0000000..96d74d8
--- /dev/null
+++ b/sys/boot/i386/libi386/aout_freebsd.c
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: aout_freebsd.c,v 1.10 1998/10/09 07:11:19 msmith Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/imgact_aout.h>
+#include <sys/reboot.h>
+#include <sys/linker.h>
+#include <string.h>
+#include <machine/bootinfo.h>
+#include <stand.h>
+
+#include "bootstrap.h"
+#include "libi386.h"
+#include "btxv86.h"
+
+static int aout_exec(struct loaded_module *amp);
+
+struct module_format i386_aout = { aout_loadmodule, aout_exec };
+
+/*
+ * There is an a.out kernel and one or more a.out modules loaded.
+ * We wish to start executing the kernel image, so make such
+ * preparations as are required, and do so.
+ */
+static int
+aout_exec(struct loaded_module *mp)
+{
+ struct module_metadata *md;
+ struct exec *ehdr;
+ vm_offset_t entry, bootinfop;
+ int boothowto, err, bootdev;
+ struct bootinfo *bi;
+ vm_offset_t ssym, esym;
+
+ if ((md = mod_findmetadata(mp, MODINFOMD_AOUTEXEC)) == NULL)
+ return(EFTYPE); /* XXX actually EFUCKUP */
+ ehdr = (struct exec *)&(md->md_data);
+
+ if ((err = bi_load(mp->m_args, &boothowto, &bootdev, &bootinfop)) != 0)
+ return(err);
+ entry = ehdr->a_entry & 0xffffff;
+
+ ssym = esym = 0;
+ if ((md = mod_findmetadata(mp, MODINFOMD_SSYM)) != NULL)
+ ssym = *((vm_offset_t *)&(md->md_data));
+ if ((md = mod_findmetadata(mp, MODINFOMD_ESYM)) != NULL)
+ esym = *((vm_offset_t *)&(md->md_data));
+ if (ssym == 0 || esym == 0)
+ ssym = esym = 0; /* sanity */
+ bi = (struct bootinfo *)PTOV(bootinfop);
+ bi->bi_symtab = ssym; /* XXX this is only the primary kernel symtab */
+ bi->bi_esymtab = esym;
+
+ __exec((void *)entry, boothowto, bootdev, 0, 0, 0, bootinfop);
+
+ panic("exec returned");
+}
diff --git a/sys/boot/i386/libi386/biosdisk.c b/sys/boot/i386/libi386/biosdisk.c
new file mode 100644
index 0000000..7f5abd1
--- /dev/null
+++ b/sys/boot/i386/libi386/biosdisk.c
@@ -0,0 +1,832 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: biosdisk.c,v 1.22 1999/01/24 06:03:44 msmith Exp $
+ */
+
+/*
+ * BIOS disk device handling.
+ *
+ * Ideas and algorithms from:
+ *
+ * - NetBSD libi386/biosdisk.c
+ * - FreeBSD biosboot/disk.c
+ *
+ * XXX Todo: add bad144 support.
+ */
+
+#include <stand.h>
+
+#include <sys/disklabel.h>
+#include <sys/diskslice.h>
+#include <sys/reboot.h>
+
+#include <stdarg.h>
+
+#include <bootstrap.h>
+#include <btxv86.h>
+#include "libi386.h"
+
+#define BIOSDISK_SECSIZE 512
+#define BUFSIZE (1 * BIOSDISK_SECSIZE)
+#define MAXBDDEV MAXDEV
+
+#define DT_ATAPI 0x10 /* disk type for ATAPI floppies */
+#define WDMAJOR 0 /* major numbers for devices we frontend for */
+#define WFDMAJOR 1
+#define FDMAJOR 2
+#define DAMAJOR 4
+
+#ifdef DISK_DEBUG
+# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __FUNCTION__ , ## args)
+#else
+# define DEBUG(fmt, args...)
+#endif
+
+struct open_disk {
+ int od_dkunit; /* disk unit number */
+ int od_unit; /* BIOS unit number */
+ int od_cyl; /* BIOS geometry */
+ int od_hds;
+ int od_sec;
+ int od_boff; /* block offset from beginning of BIOS disk */
+ int od_flags;
+#define BD_MODEMASK 0x3
+#define BD_MODEINT13 0x0
+#define BD_MODEEDD1 0x1
+#define BD_MODEEDD3 0x2
+#define BD_FLOPPY (1<<2)
+ struct disklabel od_disklabel;
+ struct dos_partition od_parttab[NDOSPART]; /* XXX needs to grow for extended partitions */
+#define BD_LABELOK (1<<3)
+#define BD_PARTTABOK (1<<4)
+};
+
+/*
+ * List of BIOS devices, translation from disk unit number to
+ * BIOS unit number.
+ */
+static struct bdinfo
+{
+ int bd_unit; /* BIOS unit number */
+ int bd_flags;
+ int bd_type; /* BIOS 'drive type' (floppy only) */
+} bdinfo [MAXBDDEV];
+static int nbdinfo = 0;
+
+static int bd_getgeom(struct open_disk *od);
+static int bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest);
+
+static int bd_int13probe(struct bdinfo *bd);
+
+static void bd_printslice(struct open_disk *od, int offset, char *prefix);
+
+static int bd_init(void);
+static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize);
+static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize);
+static int bd_open(struct open_file *f, ...);
+static int bd_close(struct open_file *f);
+static void bd_print(int verbose);
+
+struct devsw biosdisk = {
+ "disk",
+ DEVT_DISK,
+ bd_init,
+ bd_strategy,
+ bd_open,
+ bd_close,
+ noioctl,
+ bd_print
+};
+
+static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev);
+static void bd_closedisk(struct open_disk *od);
+static int bd_bestslice(struct dos_partition *dptr);
+
+/*
+ * Translate between BIOS device numbers and our private unit numbers.
+ */
+int
+bd_bios2unit(int biosdev)
+{
+ int i;
+
+ DEBUG("looking for bios device 0x%x", biosdev);
+ for (i = 0; i < nbdinfo; i++) {
+ DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit);
+ if (bdinfo[i].bd_unit == biosdev)
+ return(i);
+ }
+ return(-1);
+}
+
+int
+bd_unit2bios(int unit)
+{
+ if ((unit >= 0) && (unit < nbdinfo))
+ return(bdinfo[unit].bd_unit);
+ return(-1);
+}
+
+/*
+ * Quiz the BIOS for disk devices, save a little info about them.
+ *
+ * XXX should we be consulting the BIOS equipment list, specifically
+ * the value at 0x475?
+ */
+static int
+bd_init(void)
+{
+ int base, unit;
+
+ /* sequence 0, 0x80 */
+ for (base = 0; base <= 0x80; base += 0x80) {
+ for (unit = base; (nbdinfo < MAXBDDEV); unit++) {
+ bdinfo[nbdinfo].bd_unit = unit;
+ bdinfo[nbdinfo].bd_flags = (unit < 0x80) ? BD_FLOPPY : 0;
+
+ /* XXX add EDD probes */
+ if (!bd_int13probe(&bdinfo[nbdinfo]))
+ break;
+
+ /* XXX we need "disk aliases" to make this simpler */
+ printf("BIOS drive %c: is disk%d\n",
+ (unit < 0x80) ? ('A' + unit) : ('C' + unit - 0x80), nbdinfo);
+ nbdinfo++;
+ }
+ }
+ return(0);
+}
+
+/*
+ * Try to detect a device supported by the legacy int13 BIOS
+ */
+
+static int
+bd_int13probe(struct bdinfo *bd)
+{
+
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x800;
+ v86.edx = bd->bd_unit;
+ v86int();
+
+ if (!(v86.efl & 0x1) && /* carry clear */
+ ((v86.edx & 0xff) > (bd->bd_unit & 0x7f))) { /* unit # OK */
+ bd->bd_flags |= BD_MODEINT13;
+ bd->bd_type = v86.ebx & 0xff;
+ return(1);
+ }
+ return(0);
+}
+
+/*
+ * Print information about disks
+ */
+static void
+bd_print(int verbose)
+{
+ int i, j;
+ char line[80];
+ struct i386_devdesc dev;
+ struct open_disk *od;
+ struct dos_partition *dptr;
+
+ for (i = 0; i < nbdinfo; i++) {
+ sprintf(line, " disk%d: BIOS drive %c:\n", i,
+ (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit) : ('C' + bdinfo[i].bd_unit - 0x80));
+ pager_output(line);
+
+ /* try to open the whole disk */
+ dev.d_kind.biosdisk.unit = i;
+ dev.d_kind.biosdisk.slice = -1;
+ dev.d_kind.biosdisk.partition = -1;
+
+ if (!bd_opendisk(&od, &dev)) {
+
+ /* Do we have a partition table? */
+ if (od->od_flags & BD_PARTTABOK) {
+ dptr = &od->od_parttab[0];
+
+ /* Check for a "truly dedicated" disk */
+ if ((dptr[3].dp_typ == DOSPTYP_386BSD) &&
+ (dptr[3].dp_start == 0) &&
+ (dptr[3].dp_size == 50000)) {
+ sprintf(line, " disk%d", i);
+ bd_printslice(od, 0, line);
+ } else {
+ for (j = 0; j < NDOSPART; j++) {
+ switch(dptr[j].dp_typ) {
+ case DOSPTYP_386BSD:
+ sprintf(line, " disk%ds%d", i, j + 1);
+ bd_printslice(od, dptr[j].dp_start, line);
+ break;
+ default:
+ }
+ }
+
+ }
+ }
+ bd_closedisk(od);
+ }
+ }
+}
+
+static void
+bd_printslice(struct open_disk *od, int offset, char *prefix)
+{
+ char line[80];
+ u_char buf[BIOSDISK_SECSIZE];
+ struct disklabel *lp;
+ int i;
+
+ /* read disklabel */
+ if (bd_read(od, offset + LABELSECTOR, 1, buf))
+ return;
+ lp =(struct disklabel *)(&buf[0]);
+ if (lp->d_magic != DISKMAGIC) {
+ sprintf(line, "bad disklabel\n");
+ pager_output(line);
+ return;
+ }
+
+ /* Print partitions */
+ for (i = 0; i < lp->d_npartitions; i++) {
+ if ((lp->d_partitions[i].p_fstype == FS_BSDFFS) || (lp->d_partitions[i].p_fstype == FS_SWAP) ||
+ ((lp->d_partitions[i].p_fstype == FS_UNUSED) &&
+ (od->od_flags & BD_FLOPPY) && (i == 0))) { /* Floppies often have bogus fstype, print 'a' */
+ sprintf(line, " %s%c: %s %.6dMB (%d - %d)\n", prefix, 'a' + i,
+ (lp->d_partitions[i].p_fstype == FS_SWAP) ? "swap" : "FFS",
+ lp->d_partitions[i].p_size / 2048, /* 512-byte sector assumption */
+ lp->d_partitions[i].p_offset, lp->d_partitions[i].p_offset + lp->d_partitions[i].p_size);
+ pager_output(line);
+ }
+ }
+}
+
+
+/*
+ * Attempt to open the disk described by (dev) for use by (f).
+ *
+ * Note that the philosophy here is "give them exactly what
+ * they ask for". This is necessary because being too "smart"
+ * about what the user might want leads to complications.
+ * (eg. given no slice or partition value, with a disk that is
+ * sliced - are they after the first BSD slice, or the DOS
+ * slice before it?)
+ */
+static int
+bd_open(struct open_file *f, ...)
+{
+ va_list ap;
+ struct i386_devdesc *dev;
+ struct open_disk *od;
+ int error;
+
+ va_start(ap, f);
+ dev = va_arg(ap, struct i386_devdesc *);
+ va_end(ap);
+ if ((error = bd_opendisk(&od, dev)))
+ return(error);
+
+ /*
+ * Save our context
+ */
+ ((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data = od;
+ DEBUG("open_disk %p, partition at 0x%x", od, od->od_boff);
+ return(0);
+}
+
+static int
+bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
+{
+ struct dos_partition *dptr;
+ struct disklabel *lp;
+ struct open_disk *od;
+ int sector, slice, i;
+ int error;
+ u_char buf[BUFSIZE];
+ daddr_t pref_slice[4];
+
+ if (dev->d_kind.biosdisk.unit >= nbdinfo) {
+ DEBUG("attempt to open nonexistent disk");
+ return(ENXIO);
+ }
+
+ od = (struct open_disk *)malloc(sizeof(struct open_disk));
+ if (!od) {
+ DEBUG("no memory");
+ return (ENOMEM);
+ }
+
+ /* Look up BIOS unit number, intialise open_disk structure */
+ od->od_dkunit = dev->d_kind.biosdisk.unit;
+ od->od_unit = bdinfo[od->od_dkunit].bd_unit;
+ od->od_flags = bdinfo[od->od_dkunit].bd_flags;
+ od->od_boff = 0;
+ error = 0;
+ DEBUG("open '%s', unit 0x%x slice %d partition %c",
+ i386_fmtdev(dev), dev->d_kind.biosdisk.unit,
+ dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition + 'a');
+
+ /* Get geometry for this open (removable device may have changed) */
+ if (bd_getgeom(od)) {
+ DEBUG("can't get geometry");
+ error = ENXIO;
+ goto out;
+ }
+
+ /*
+ * Following calculations attempt to determine the correct value
+ * for d->od_boff by looking for the slice and partition specified,
+ * or searching for reasonable defaults.
+ */
+
+ /*
+ * Find the slice in the DOS slice table.
+ */
+ if (bd_read(od, 0, 1, buf)) {
+ DEBUG("error reading MBR");
+ error = EIO;
+ goto out;
+ }
+
+ /*
+ * Check the slice table magic.
+ */
+ if ((buf[0x1fe] != 0x55) || (buf[0x1ff] != 0xaa)) {
+ /* If a slice number was explicitly supplied, this is an error */
+ if (dev->d_kind.biosdisk.slice > 0) {
+ DEBUG("no slice table/MBR (no magic)");
+ error = ENOENT;
+ goto out;
+ }
+ sector = 0;
+ goto unsliced; /* may be a floppy */
+ }
+ bcopy(buf + DOSPARTOFF, &od->od_parttab, sizeof(struct dos_partition) * NDOSPART);
+ dptr = &od->od_parttab[0];
+ od->od_flags |= BD_PARTTABOK;
+
+ /* Is this a request for the whole disk? */
+ if (dev->d_kind.biosdisk.slice == -1) {
+ sector = 0;
+ goto unsliced;
+ }
+
+ /* Try to auto-detect the best slice; this should always give a slice number */
+ if (dev->d_kind.biosdisk.slice == 0)
+ dev->d_kind.biosdisk.slice = bd_bestslice(dptr);
+
+ switch (dev->d_kind.biosdisk.slice) {
+ case -1:
+ error = ENOENT;
+ goto out;
+ case 0:
+ sector = 0;
+ goto unsliced;
+ default:
+ break;
+ }
+
+ /*
+ * Accept the supplied slice number unequivocally (we may be looking
+ * at a DOS partition).
+ */
+ dptr += (dev->d_kind.biosdisk.slice - 1); /* we number 1-4, offsets are 0-3 */
+ sector = dptr->dp_start;
+ DEBUG("slice entry %d at %d, %d sectors", dev->d_kind.biosdisk.slice - 1, sector, dptr->dp_size);
+
+ /*
+ * If we are looking at a BSD slice, and the partition is < 0, assume the 'a' partition
+ */
+ if ((dptr->dp_typ == DOSPTYP_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");
+ error = EIO;
+ goto out;
+ }
+ DEBUG("copy %d bytes of label from %p to %p", sizeof(struct disklabel), buf + LABELOFFSET, &od->od_disklabel);
+ bcopy(buf + LABELOFFSET, &od->od_disklabel, sizeof(struct disklabel));
+ lp = &od->od_disklabel;
+ od->od_flags |= BD_LABELOK;
+
+ if (lp->d_magic != DISKMAGIC) {
+ DEBUG("no disklabel");
+ error = ENOENT;
+ goto out;
+ }
+ if (dev->d_kind.biosdisk.partition >= lp->d_npartitions) {
+ DEBUG("partition '%c' exceeds partitions in table (a-'%c')",
+ 'a' + dev->d_kind.biosdisk.partition, 'a' + lp->d_npartitions);
+ error = EPART;
+ goto out;
+
+ }
+
+ /* Complain if the partition type is wrong */
+ if ((lp->d_partitions[dev->d_kind.biosdisk.partition].p_fstype == FS_UNUSED) &&
+ !(od->od_flags & BD_FLOPPY)) /* Floppies often have bogus fstype */
+ DEBUG("warning, partition marked as unused");
+
+ od->od_boff = lp->d_partitions[dev->d_kind.biosdisk.partition].p_offset;
+ }
+
+ out:
+ if (error) {
+ free(od);
+ } else {
+ *odp = od; /* return the open disk */
+ }
+ return(error);
+}
+
+
+/*
+ * Search for a slice with the following preferences:
+ *
+ * 1: Active FreeBSD slice
+ * 2: Non-active FreeBSD slice
+ * 3: Active FAT/FAT32 slice
+ * 4: non-active FAT/FAT32 slice
+ */
+#define PREF_FBSD_ACT 0
+#define PREF_FBSD 1
+#define PREF_DOS_ACT 2
+#define PREF_DOS 3
+#define PREF_NONE 4
+
+static int
+bd_bestslice(struct dos_partition *dptr)
+{
+ int i;
+ int preflevel, pref;
+
+
+ /*
+ * Check for the historically bogus MBR found on true dedicated disks
+ */
+ if ((dptr[3].dp_typ == DOSPTYP_386BSD) &&
+ (dptr[3].dp_start == 0) &&
+ (dptr[3].dp_size == 50000))
+ return(0);
+
+ preflevel = PREF_NONE;
+ pref = -1;
+
+ /*
+ * XXX No support here for 'extended' slices
+ */
+ for (i = 0; i < NDOSPART; i++) {
+ switch(dptr[i].dp_typ) {
+ case DOSPTYP_386BSD: /* FreeBSD */
+ if ((dptr[i].dp_flag & 0x80) && (preflevel > PREF_FBSD_ACT)) {
+ pref = i;
+ preflevel = PREF_FBSD_ACT;
+ } else if (preflevel > PREF_FBSD) {
+ pref = i;
+ preflevel = PREF_FBSD;
+ }
+ break;
+
+ case 0x04: /* DOS/Windows */
+ case 0x06:
+ case 0x0b:
+ case 0x0c:
+ case 0x0e:
+ case 0x63:
+ if ((dptr[i].dp_flag & 0x80) && (preflevel > PREF_DOS_ACT)) {
+ pref = i;
+ preflevel = PREF_DOS_ACT;
+ } else if (preflevel > PREF_DOS) {
+ pref = i;
+ preflevel = PREF_DOS;
+ }
+ break;
+ }
+ }
+ return(pref + 1); /* slices numbered 1-4 */
+}
+
+
+static int
+bd_close(struct open_file *f)
+{
+ struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data);
+
+ bd_closedisk(od);
+ return(0);
+}
+
+static void
+bd_closedisk(struct open_disk *od)
+{
+ DEBUG("open_disk %p", od);
+#if 0
+ /* XXX is this required? (especially if disk already open...) */
+ if (od->od_flags & BD_FLOPPY)
+ delay(3000000);
+#endif
+ free(od);
+}
+
+static int
+bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
+{
+ struct bcache_devdata bcd;
+
+ bcd.dv_strategy = bd_realstrategy;
+ bcd.dv_devdata = devdata;
+ return(bcache_strategy(&bcd, rw, dblk, size, buf, rsize));
+}
+
+static int
+bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
+{
+ struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data);
+ int blks;
+#ifdef BD_SUPPORT_FRAGS
+ char fragbuf[BIOSDISK_SECSIZE];
+ size_t fragsize;
+
+ fragsize = size % BIOSDISK_SECSIZE;
+#else
+ if (size % BIOSDISK_SECSIZE)
+ panic("bd_strategy: %d bytes I/O not multiple of block size", size);
+#endif
+
+ DEBUG("open_disk %p", od);
+
+ if (rw != F_READ)
+ return(EROFS);
+
+
+ blks = size / BIOSDISK_SECSIZE;
+ DEBUG("read %d from %d+%d to %p", blks, od->od_boff, dblk, buf);
+
+ if (rsize)
+ *rsize = 0;
+ if (blks && bd_read(od, dblk + od->od_boff, blks, buf)) {
+ DEBUG("read error");
+ return (EIO);
+ }
+#ifdef BD_SUPPORT_FRAGS
+ DEBUG("bd_strategy: frag read %d from %d+%d+d to %p",
+ fragsize, od->od_boff, dblk, blks, buf + (blks * BIOSDISK_SECSIZE));
+ if (fragsize && bd_read(od, dblk + od->od_boff + blks, 1, fragsize)) {
+ DEBUG("frag read error");
+ return(EIO);
+ }
+ bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize);
+#endif
+ if (rsize)
+ *rsize = size;
+ return (0);
+}
+
+/* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */
+#define FLOPPY_BOUNCEBUF 18
+
+static int
+bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
+{
+ int x, bpc, cyl, hd, sec, result, resid, cnt, retry, maxfer;
+ caddr_t p, xp, bbuf, breg;
+
+ bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */
+ resid = blks;
+ p = dest;
+
+ /* Decide whether we have to bounce */
+ if ((od->od_unit < 0x80) &&
+ ((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16))) {
+
+ /*
+ * There is a 64k physical boundary somewhere in the destination buffer, so we have
+ * to arrange a suitable bounce buffer. Allocate a buffer twice as large as we
+ * need to. Use the bottom half unless there is a break there, in which case we
+ * use the top half.
+ */
+ x = min(FLOPPY_BOUNCEBUF, blks);
+ bbuf = malloc(x * 2 * BIOSDISK_SECSIZE);
+ if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(dest + x * BIOSDISK_SECSIZE) & 0xffff0000)) {
+ breg = bbuf;
+ } else {
+ breg = bbuf + x * BIOSDISK_SECSIZE;
+ }
+ maxfer = x; /* limit transfers to bounce region size */
+ } else {
+ bbuf = NULL;
+ maxfer = 0;
+ }
+
+ while (resid > 0) {
+ x = dblk;
+ cyl = x / bpc; /* block # / blocks per cylinder */
+ x %= bpc; /* block offset into cylinder */
+ hd = x / od->od_sec; /* offset / blocks per track */
+ sec = x % od->od_sec; /* offset into track */
+
+ /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */
+ x = min(od->od_sec - sec, resid);
+ if (maxfer > 0)
+ x = min(x, maxfer); /* fit bounce buffer */
+
+ /* where do we transfer to? */
+ xp = bbuf == NULL ? p : breg;
+
+ /* correct sector number for 1-based BIOS numbering */
+ sec++;
+
+ /* 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 = 0x13;
+ v86.eax = 0;
+ v86.edx = od->od_unit;
+ v86int();
+ }
+
+ /* build request XXX support EDD requests too */
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x200 | x;
+ v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec;
+ v86.edx = (hd << 8) | od->od_unit;
+ v86.es = VTOPSEG(xp);
+ v86.ebx = VTOPOFF(xp);
+ v86int();
+ result = (v86.efl & 0x1);
+ if (result == 0)
+ break;
+ }
+
+ DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, sec - 1, p, VTOP(p), result ? "failed" : "ok");
+ /* BUG here, cannot use v86 in printf because putchar uses it too */
+ DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x",
+ 0x200 | x, ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec, (hd << 8) | od->od_unit, (v86.eax >> 8) & 0xff);
+ if (result) {
+ if (bbuf != NULL)
+ free(bbuf);
+ return(-1);
+ }
+ if (bbuf != NULL)
+ bcopy(breg, p, x * BIOSDISK_SECSIZE);
+ p += (x * BIOSDISK_SECSIZE);
+ dblk += x;
+ resid -= x;
+ }
+
+/* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */
+ if (bbuf != NULL)
+ free(bbuf);
+ return(0);
+}
+
+static int
+bd_getgeom(struct open_disk *od)
+{
+
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x800;
+ v86.edx = od->od_unit;
+ v86int();
+
+ if ((v86.efl & 0x1) || /* carry set */
+ ((v86.edx & 0xff) <= (od->od_unit & 0x7f))) /* unit # bad */
+ return(1);
+
+ /* convert max cyl # -> # of cylinders */
+ od->od_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
+ /* convert max head # -> # of heads */
+ od->od_hds = ((v86.edx & 0xff00) >> 8) + 1;
+ od->od_sec = v86.ecx & 0x3f;
+
+ DEBUG("unit 0x%x geometry %d/%d/%d", od->od_unit, od->od_cyl, od->od_hds, od->od_sec);
+ return(0);
+}
+
+/*
+ * Return a suitable dev_t value for (dev).
+ *
+ * In the case where it looks like (dev) is a SCSI disk, we allow the number of
+ * IDE disks to be specified in $num_ide_disks. There should be a Better Way.
+ */
+int
+bd_getdev(struct i386_devdesc *dev)
+{
+ struct open_disk *od;
+ int biosdev;
+ int major;
+ int rootdev;
+ char *nip, *cp;
+ int unitofs = 0, i, unit;
+
+ biosdev = bd_unit2bios(dev->d_kind.biosdisk.unit);
+ DEBUG("unit %d BIOS device %d", dev->d_kind.biosdisk.unit, biosdev);
+ if (biosdev == -1) /* not a BIOS device */
+ return(-1);
+ if (bd_opendisk(&od, dev) != 0) /* oops, not a viable device */
+ return(-1);
+
+ if (biosdev < 0x80) {
+ /* floppy (or emulated floppy) or ATAPI device */
+ if (bdinfo[dev->d_kind.biosdisk.unit].bd_type == DT_ATAPI) {
+ /* is an ATAPI disk */
+ major = WFDMAJOR;
+ } else {
+ /* is a floppy disk */
+ major = FDMAJOR;
+ }
+ } else {
+ /* harddisk */
+ if ((od->od_flags & BD_LABELOK) && (od->od_disklabel.d_type == DTYPE_SCSI)) {
+ /* label OK, disk labelled as SCSI */
+ major = DAMAJOR;
+ /* check for unit number correction hint, now deprecated */
+ if ((nip = getenv("num_ide_disks")) != NULL) {
+ i = strtol(nip, &cp, 0);
+ /* check for parse error */
+ if ((cp != nip) && (*cp == 0))
+ unitofs = i;
+ }
+ } else {
+ /* assume an IDE disk */
+ major = WDMAJOR;
+ }
+ }
+ /* XXX a better kludge to set the root disk unit number */
+ if ((nip = getenv("root_disk_unit")) != NULL) {
+ i = strtol(nip, &cp, 0);
+ /* check for parse error */
+ if ((cp != nip) && (*cp == 0))
+ unit = i;
+ } else {
+ unit = (biosdev & 0x7f) - unitofs; /* allow for #wd compenstation in da case */
+ }
+
+ rootdev = MAKEBOOTDEV(major,
+ (dev->d_kind.biosdisk.slice + 1) >> 4, /* XXX slices may be wrong here */
+ (dev->d_kind.biosdisk.slice + 1) & 0xf,
+ unit,
+ dev->d_kind.biosdisk.partition);
+ DEBUG("dev is 0x%x\n", rootdev);
+ return(rootdev);
+}
+
+/*
+ * Fix (dev) so that it refers to the 'real' disk/slice/partition that it implies.
+ */
+int
+bd_fixupdev(struct i386_devdesc *dev)
+{
+ struct open_disk *od;
+
+ /*
+ * Open the disk. This will fix up the slice and partition fields.
+ */
+ if (bd_opendisk(&od, dev) != 0)
+ return(ENOENT);
+
+ bd_closedisk(od);
+}
diff --git a/sys/boot/i386/libi386/biosmem.c b/sys/boot/i386/libi386/biosmem.c
new file mode 100644
index 0000000..1e4e540
--- /dev/null
+++ b/sys/boot/i386/libi386/biosmem.c
@@ -0,0 +1,52 @@
+/*
+ * mjs copyright
+ */
+
+/*
+ * Obtain memory configuration information from the BIOS
+ *
+ * Note that we don't try too hard here; knowing the size of
+ * base memory and extended memory out to 16 or 64M is enough for
+ * the requirements of the bootstrap.
+ *
+ * We also maintain a pointer to the top of physical memory
+ * once called to allow rangechecking of load/copy requests.
+ */
+#include <stand.h>
+#include "btxv86.h"
+
+vm_offset_t memtop;
+
+/*
+ * Return base memory size in kB.
+ */
+int
+getbasemem(void)
+{
+ v86.ctl = 0;
+ v86.addr = 0x12; /* int 0x12 */
+ v86int();
+
+ return(v86.eax & 0xffff);
+}
+
+/*
+ * Return extended memory size in kB
+ */
+int
+getextmem(void)
+{
+ int extkb;
+
+ v86.ctl = 0;
+ v86.addr = 0x15; /* int 0x15 function 0x88*/
+ v86.eax = 0x8800;
+ v86int();
+ extkb = v86.eax & 0xffff;
+
+ /* Set memtop to actual top or 16M, whicheve is less */
+ memtop = min((0x100000 + (extkb * 1024)), (16 * 1024 * 1024));
+
+ return(extkb);
+}
+
diff --git a/sys/boot/i386/libi386/biospci.c b/sys/boot/i386/libi386/biospci.c
new file mode 100644
index 0000000..92f4fd2
--- /dev/null
+++ b/sys/boot/i386/libi386/biospci.c
@@ -0,0 +1,294 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/*
+ * PnP enumerator using the PCI BIOS.
+ */
+
+#include <stand.h>
+#include <string.h>
+#include <machine/stdarg.h>
+#include <bootstrap.h>
+#include <isapnp.h>
+#include <btxv86.h>
+
+/*
+ * Stupid PCI BIOS interface doesn't let you simply enumerate everything
+ * that's there, instead you have to ask it if it has something.
+ *
+ * So we have to scan by class code, subclass code and sometimes programming
+ * interface.
+ */
+
+struct pci_progif
+{
+ int pi_code;
+ char *pi_name;
+};
+
+static struct pci_progif progif_null[] = {
+ {0x0, NULL},
+ {-1, NULL}
+};
+
+static struct pci_progif progif_display[] = {
+ {0x0, "VGA"},
+ {0x1, "8514"},
+ {-1, NULL}
+};
+
+static struct pci_progif progif_ide[] = {
+ {0x00, NULL},
+ {0x01, NULL},
+ {0x02, NULL},
+ {0x03, NULL},
+ {0x04, NULL},
+ {0x05, NULL},
+ {0x06, NULL},
+ {0x07, NULL},
+ {0x08, NULL},
+ {0x09, NULL},
+ {0x0a, NULL},
+ {0x0b, NULL},
+ {0x0c, NULL},
+ {0x0d, NULL},
+ {0x0e, NULL},
+ {0x0f, NULL},
+ {0x80, NULL},
+ {0x81, NULL},
+ {0x82, NULL},
+ {0x83, NULL},
+ {0x84, NULL},
+ {0x85, NULL},
+ {0x86, NULL},
+ {0x87, NULL},
+ {0x88, NULL},
+ {0x89, NULL},
+ {0x8a, NULL},
+ {0x8b, NULL},
+ {0x8c, NULL},
+ {0x8d, NULL},
+ {0x8e, NULL},
+ {0x8f, NULL},
+ {-1, NULL}
+};
+
+static struct pci_progif progif_serial[] = {
+ {0x0, "8250"},
+ {0x1, "16450"},
+ {0x2, "16550"},
+ {-1, NULL}
+};
+
+static struct pci_progif progif_parallel[] = {
+ {0x0, "Standard"},
+ {0x1, "Bidirectional"},
+ {0x2, "ECP"},
+ {-1, NULL}
+};
+
+
+struct pci_subclass
+{
+ int ps_subclass;
+ char *ps_name;
+ struct pci_progif *ps_progif; /* if set, use for programming interface value(s) */
+};
+
+static struct pci_subclass subclass_old[] = {
+ {0x0, "Old non-VGA", progif_null},
+ {0x1, "Old VGA", progif_null},
+ {-1, NULL, NULL}
+};
+
+static struct pci_subclass subclass_mass[] = {
+ {0x0, "SCSI", progif_null},
+ {0x1, "IDE", progif_ide},
+ {0x2, "Floppy disk", progif_null},
+ {0x3, "IPI", progif_null},
+ {0x4, "RAID", progif_null},
+ {0x80, "mass storage", progif_null},
+ {-1, NULL, NULL}
+};
+
+static struct pci_subclass subclass_net[] = {
+ {0x0, "Ethernet", progif_null},
+ {0x1, "Token ring", progif_null},
+ {0x2, "FDDI", progif_null},
+ {0x3, "ATM", progif_null},
+ {0x80, "network", progif_null},
+ {-1, NULL, NULL}
+};
+
+static struct pci_subclass subclass_display[] = {
+ {0x0, NULL, progif_display},
+ {0x1, "XGA", progif_null},
+ {0x80, "other", progif_null},
+ {-1, NULL, NULL}
+};
+
+static struct pci_subclass subclass_comms[] = {
+ {0x0, "serial", progif_serial},
+ {0x1, "parallel", progif_parallel},
+ {0x80, "communications", progif_null},
+ {-1, NULL, NULL}
+};
+
+static struct pci_subclass subclass_serial[] = {
+ {0x0, "Firewire", progif_null},
+ {0x1, "ACCESS.bus", progif_null},
+ {0x2, "SSA", progif_null},
+ {0x3, "USB", progif_null},
+ {0x4, "Fibrechannel", progif_null},
+ {-1, NULL, NULL}
+};
+
+static struct pci_class
+{
+ int pc_class;
+ char *pc_name;
+ struct pci_subclass *pc_subclass;
+} pci_classes[] = {
+ {0x0, "device", subclass_old},
+ {0x1, "controller", subclass_mass},
+ {0x2, "controller", subclass_net},
+ {0x3, "display", subclass_display},
+ {0x7, "controller", subclass_comms},
+ {0xc, "controller", subclass_serial},
+ {-1, NULL, NULL}
+};
+
+
+static void biospci_enumerate(void);
+static void biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, struct pci_progif *ppi);
+
+static int biospci_version;
+static int biospci_hwcap;
+
+struct pnphandler biospcihandler =
+{
+ "PCI BIOS",
+ biospci_enumerate
+};
+
+static void
+biospci_enumerate(void)
+{
+ int index, locator, devid;
+ struct pci_class *pc;
+ struct pci_subclass *psc;
+ struct pci_progif *ppi;
+
+ /* Find the PCI BIOS */
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x1a;
+ v86.eax = 0xb101;
+ v86.edi = 0x0;
+ v86int();
+
+ /* Check for OK response */
+ if ((v86.efl & 1) || ((v86.eax & 0xff00) != 0) || (v86.edx != 0x20494350))
+ return;
+
+ biospci_version = v86.ebx & 0xffff;
+ biospci_hwcap = v86.eax & 0xff;
+#if 0
+ printf("PCI BIOS %d.%d%s%s\n",
+ bcd2bin((biospci_version >> 8) & 0xf), bcd2bin(biospci_version & 0xf),
+ (biospci_hwcap & 1) ? " config1" : "", (biospci_hwcap & 2) ? " config2" : "");
+#endif
+ /* Iterate over known classes */
+ for (pc = pci_classes; pc->pc_class >= 0; pc++) {
+ /* Iterate over subclasses */
+ for (psc = pc->pc_subclass; psc->ps_subclass >= 0; psc++) {
+ /* Iterate over programming interfaces */
+ for (ppi = psc->ps_progif; ppi->pi_code >= 0; ppi++) {
+
+ /* Scan for matches */
+ for (index = 0; ; index++) {
+
+ /* Look for a match */
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x1a;
+ v86.eax = 0xb103;
+ v86.ecx = (pc->pc_class << 16) + (psc->ps_subclass << 8) + ppi->pi_code;
+ v86.esi = index;
+ v86int();
+ /* error/end of matches */
+ if ((v86.efl & 1) || (v86.eax & 0xff00))
+ break;
+
+ /* Got something */
+ locator = v86.ebx;
+
+ /* Read the device identifier from the nominated device */
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x1a;
+ v86.eax = 0xb10a;
+ v86.ebx = locator;
+ v86.edi = 0x0;
+ v86int();
+ /* error */
+ if ((v86.efl & 1) || (v86.eax & 0xff00))
+ break;
+
+ /* We have the device ID, create a PnP object and save everything */
+ devid = v86.ecx;
+ biospci_addinfo(devid, pc, psc, ppi);
+ }
+ }
+ }
+ }
+}
+
+static void
+biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, struct pci_progif *ppi)
+{
+ struct pnpinfo *pi;
+ char desc[80];
+
+
+ /* build the description */
+ desc[0] = 0;
+ if (ppi->pi_name != NULL) {
+ strcat(desc, ppi->pi_name);
+ strcat(desc, " ");
+ }
+ if (psc->ps_name != NULL) {
+ strcat(desc, psc->ps_name);
+ strcat(desc, " ");
+ }
+ if (pc->pc_name != NULL)
+ strcat(desc, pc->pc_name);
+
+ pi = pnp_allocinfo();
+ pi->pi_desc = strdup(desc);
+ sprintf(desc,"0x%08x", devid);
+ pnp_addident(pi, desc);
+ pnp_addinfo(pi);
+}
diff --git a/sys/boot/i386/libi386/biospnp.c b/sys/boot/i386/libi386/biospnp.c
new file mode 100644
index 0000000..a6064ba
--- /dev/null
+++ b/sys/boot/i386/libi386/biospnp.c
@@ -0,0 +1,289 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: biospnp.c,v 1.2 1998/10/23 22:29:08 msmith Exp $
+ */
+
+/*
+ * PnP BIOS enumerator.
+ */
+
+#include <stand.h>
+#include <string.h>
+#include <machine/stdarg.h>
+#include <bootstrap.h>
+#include <isapnp.h>
+#include <btxv86.h>
+
+
+static int biospnp_init(void);
+static void biospnp_enumerate(void);
+
+struct pnphandler biospnphandler =
+{
+ "PnP BIOS",
+ biospnp_enumerate
+};
+
+struct pnp_ICstructure
+{
+ u_int8_t pnp_signature[4] __attribute__ ((packed));
+ u_int8_t pnp_version __attribute__ ((packed));
+ u_int8_t pnp_length __attribute__ ((packed));
+ u_int16_t pnp_BIOScontrol __attribute__ ((packed));
+ u_int8_t pnp_checksum __attribute__ ((packed));
+ u_int32_t pnp_eventflag __attribute__ ((packed));
+ u_int16_t pnp_rmip __attribute__ ((packed));
+ u_int16_t pnp_rmcs __attribute__ ((packed));
+ u_int16_t pnp_pmip __attribute__ ((packed));
+ u_int32_t pnp_pmcs __attribute__ ((packed));
+ u_int8_t pnp_OEMdev[4] __attribute__ ((packed));
+ u_int16_t pnp_rmds __attribute__ ((packed));
+ u_int32_t pnp_pmds __attribute__ ((packed));
+};
+
+struct pnp_devNode
+{
+ u_int16_t dn_size __attribute__ ((packed));
+ u_int8_t dn_handle __attribute__ ((packed));
+ u_int8_t dn_id[4] __attribute__ ((packed));
+ u_int8_t dn_type[3] __attribute__ ((packed));
+ u_int16_t dn_attrib __attribute__ ((packed));
+ u_int8_t dn_data[0] __attribute__ ((packed));
+};
+
+struct pnp_isaConfiguration
+{
+ u_int8_t ic_revision __attribute__ ((packed));
+ u_int8_t ic_nCSN __attribute__ ((packed));
+ u_int16_t ic_rdport __attribute__ ((packed));
+ u_int16_t ic_reserved __attribute__ ((packed));
+};
+
+static struct pnp_ICstructure *pnp_Icheck = NULL;
+static u_int16_t pnp_NumNodes;
+static u_int16_t pnp_NodeSize;
+
+static void biospnp_scanresdata(struct pnpinfo *pi, struct pnp_devNode *dn);
+static int biospnp_call(int func, char *fmt, ...);
+
+#define vsegofs(vptr) (((u_int32_t)VTOPSEG(vptr) << 16) + VTOPOFF(vptr))
+void (* v86bios)(u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) = (void *)v86int;
+
+#define biospnp_f00(NumNodes, NodeSize) biospnp_call(0x00, "ll", NumNodes, NodeSize)
+#define biospnp_f01(Node, devNodeBuffer, Control) biospnp_call(0x01, "llw", Node, devNodeBuffer, Control)
+#define biospnp_f40(Configuration) biospnp_call(0x40, "l", Configuration)
+
+/* PnP BIOS return codes */
+#define PNP_SUCCESS 0x00
+#define PNP_FUNCTION_NOT_SUPPORTED 0x80
+
+/*
+ * Initialisation: locate the PnP BIOS, test that we can call it.
+ * Returns nonzero if the PnP BIOS is not usable on this system.
+ */
+static int
+biospnp_init(void)
+{
+ struct pnp_isaConfiguration icfg;
+ char *sigptr;
+ int result;
+
+ /* Search for the $PnP signature */
+ pnp_Icheck = NULL;
+ for (sigptr = PTOV(0xf0000); sigptr < PTOV(0xfffff); sigptr += 16)
+ if (!bcmp(sigptr, "$PnP", 4)) {
+ pnp_Icheck = (struct pnp_ICstructure *)sigptr;
+ break;
+ }
+
+ /* No signature, no BIOS */
+ if (pnp_Icheck == NULL)
+ return(1);
+
+ /*
+ * Fetch the system table parameters as a test of the BIOS
+ */
+ result = biospnp_f00(vsegofs(&pnp_NumNodes), vsegofs(&pnp_NodeSize));
+ if (result != PNP_SUCCESS) {
+ return(1);
+ }
+
+ /*
+ * Look for the PnP ISA configuration table
+ */
+ result = biospnp_f40(vsegofs(&icfg));
+ switch (result) {
+ case PNP_SUCCESS:
+ /* If the BIOS found some PnP devices, take its hint for the read port */
+ if ((icfg.ic_revision == 1) && (icfg.ic_nCSN > 0))
+ isapnp_readport = icfg.ic_rdport;
+ break;
+ case PNP_FUNCTION_NOT_SUPPORTED:
+ /* The BIOS says there is no ISA bus (should we trust that this works?) */
+ printf("PnP BIOS claims no ISA bus\n");
+ isapnp_readport = -1;
+ break;
+ }
+ return(0);
+}
+
+static void
+biospnp_enumerate(void)
+{
+ u_int8_t Node;
+ struct pnp_devNode *devNodeBuffer;
+ int result;
+ struct pnpinfo *pi;
+ int count;
+
+ /* Init/check state */
+ if (biospnp_init())
+ return;
+
+ devNodeBuffer = (struct pnp_devNode *)malloc(pnp_NodeSize);
+ Node = 0;
+ count = 1000;
+ while((Node != 0xff) && (count-- > 0)) {
+ result = biospnp_f01(vsegofs(&Node), vsegofs(devNodeBuffer), 0x1);
+ if (result != PNP_SUCCESS) {
+ printf("PnP BIOS node %d: error 0x%x\n", Node, result);
+ } else {
+ pi = pnp_allocinfo();
+ pnp_addident(pi, pnp_eisaformat(devNodeBuffer->dn_id));
+ biospnp_scanresdata(pi, devNodeBuffer);
+ pnp_addinfo(pi);
+ }
+ }
+}
+
+/*
+ * Scan the resource data in the node's data area for compatible device IDs
+ * and descriptions.
+ */
+static void
+biospnp_scanresdata(struct pnpinfo *pi, struct pnp_devNode *dn)
+{
+ int tag, i, rlen, dlen;
+ u_int8_t *p;
+ char *str;
+
+ p = dn->dn_data; /* point to resource data */
+ dlen = dn->dn_size - (p - (u_int8_t *)dn); /* length of resource data */
+
+ for (i = 0; i < dlen; i+= rlen) {
+ tag = p[i];
+ i++;
+ if (PNP_RES_TYPE(tag) == 0) {
+ rlen = PNP_SRES_LEN(tag);
+ /* small resource */
+ switch (PNP_SRES_NUM(tag)) {
+
+ case COMP_DEVICE_ID:
+ /* got a compatible device ID */
+ pnp_addident(pi, pnp_eisaformat(p + i));
+ break;
+
+ case END_TAG:
+ return;
+ }
+ } else {
+ /* large resource */
+ rlen = *(u_int16_t *)(p + i);
+ i += sizeof(u_int16_t);
+
+ switch(PNP_LRES_NUM(tag)) {
+
+ case ID_STRING_ANSI:
+ str = malloc(rlen + 1);
+ bcopy(p + i, str, rlen);
+ str[rlen] = 0;
+ if (pi->pi_desc == NULL) {
+ pi->pi_desc = str;
+ } else {
+ free(str);
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+/*
+ * Make a 16-bit realmode PnP BIOS call.
+ *
+ * The first argument passed is the function number, the last is the
+ * BIOS data segment selector. Intermediate arguments may be 16 or
+ * 32 bytes in length, and are described by the format string.
+ *
+ * Arguments to the BIOS functions must be packed on the stack, hence
+ * this evil.
+ */
+static int
+biospnp_call(int func, char *fmt, ...)
+{
+ va_list ap;
+ char *p;
+ u_int8_t *argp;
+ u_int32_t args[4];
+ u_int32_t i;
+
+ /* function number first */
+ argp = (u_int8_t *)args;
+ *(u_int16_t *)argp = func;
+ argp += sizeof(u_int16_t);
+
+ /* take args according to format */
+ va_start(ap, fmt);
+ for (p = fmt; *p != 0; p++) {
+ switch(*p) {
+
+ case 'w':
+ i = va_arg(ap, u_int16_t);
+ *(u_int16_t *)argp = i;
+ argp += sizeof(u_int16_t);
+ break;
+
+ case 'l':
+ i = va_arg(ap, u_int32_t);
+ *(u_int32_t *)argp = i;
+ argp += sizeof(u_int32_t);
+ break;
+ }
+ }
+
+ /* BIOS segment last */
+ *(u_int16_t *)argp = pnp_Icheck->pnp_rmds;
+ argp += sizeof(u_int16_t);
+
+ /* prepare for call */
+ v86.ctl = V86_ADDR | V86_CALLF;
+ v86.addr = ((u_int32_t)pnp_Icheck->pnp_rmcs << 16) + pnp_Icheck->pnp_rmip;
+
+ /* call with packed stack and return */
+ v86bios(args[0], args[1], args[2], args[3]);
+ return(v86.eax & 0xffff);
+}
diff --git a/sys/boot/i386/libi386/bootinfo.c b/sys/boot/i386/libi386/bootinfo.c
new file mode 100644
index 0000000..87405f0
--- /dev/null
+++ b/sys/boot/i386/libi386/bootinfo.c
@@ -0,0 +1,325 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: bootinfo.c,v 1.17 1999/03/08 11:05:52 dcs Exp $
+ */
+
+#include <stand.h>
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/linker.h>
+#include <machine/bootinfo.h>
+#include "bootstrap.h"
+#include "libi386.h"
+#include "btxv86.h"
+
+static struct bootinfo bi;
+
+/*
+ * Return a 'boothowto' value corresponding to the kernel arguments in
+ * (kargs) and any relevant environment variables.
+ */
+static struct
+{
+ char *ev;
+ int mask;
+} howto_names[] = {
+ {"boot_askname", RB_ASKNAME},
+ {"boot_userconfig", RB_CONFIG},
+ {"boot_ddb", RB_KDB},
+ {"boot_gdb", RB_GDB},
+ {"boot_single", RB_SINGLE},
+ {"boot_verbose", RB_VERBOSE},
+ {NULL, 0}
+};
+
+int
+bi_getboothowto(char *kargs)
+{
+ char *cp;
+ int howto;
+ int active;
+ int i;
+
+ /* Parse kargs */
+ howto = 0;
+ if (kargs != NULL) {
+ cp = kargs;
+ active = 0;
+ while (*cp != 0) {
+ if (!active && (*cp == '-')) {
+ active = 1;
+ } else if (active)
+ switch (*cp) {
+ case 'a':
+ howto |= RB_ASKNAME;
+ break;
+ case 'c':
+ howto |= RB_CONFIG;
+ break;
+ case 'd':
+ howto |= RB_KDB;
+ break;
+ case 'g':
+ howto |= RB_GDB;
+ break;
+ case 'h':
+ howto |= RB_SERIAL;
+ break;
+ case 'r':
+ howto |= RB_DFLTROOT;
+ break;
+ case 's':
+ howto |= RB_SINGLE;
+ break;
+ case 'v':
+ howto |= RB_VERBOSE;
+ break;
+ default:
+ active = 0;
+ break;
+ }
+ cp++;
+ }
+ }
+ /* get equivalents from the environment */
+ for (i = 0; howto_names[i].ev != NULL; i++)
+ if (getenv(howto_names[i].ev) != NULL)
+ howto |= howto_names[i].mask;
+ if (!strcmp(getenv("console"), "comconsole"))
+ howto |= RB_SERIAL;
+ return(howto);
+}
+
+/*
+ * Copy the environment into the load area starting at (addr).
+ * Each variable is formatted as <name>=<value>, with a single nul
+ * separating each variable, and a double nul terminating the environment.
+ */
+vm_offset_t
+bi_copyenv(vm_offset_t addr)
+{
+ struct env_var *ep;
+
+ /* traverse the environment */
+ for (ep = environ; ep != NULL; ep = ep->ev_next) {
+ i386_copyin(ep->ev_name, addr, strlen(ep->ev_name));
+ addr += strlen(ep->ev_name);
+ i386_copyin("=", addr, 1);
+ addr++;
+ if (ep->ev_value != NULL) {
+ i386_copyin(ep->ev_value, addr, strlen(ep->ev_value));
+ addr += strlen(ep->ev_value);
+ }
+ i386_copyin("", addr, 1);
+ addr++;
+ }
+ i386_copyin("", addr, 1);
+ addr++;
+ return(addr);
+}
+
+/*
+ * Copy module-related data into the load area, where it can be
+ * used as a directory for loaded modules.
+ *
+ * Module data is presented in a self-describing format. Each datum
+ * is preceeded by a 32-bit identifier and a 32-bit size field.
+ *
+ * Currently, the following data are saved:
+ *
+ * MOD_NAME (variable) module name (string)
+ * MOD_TYPE (variable) module type (string)
+ * MOD_ARGS (variable) module parameters (string)
+ * MOD_ADDR sizeof(vm_offset_t) module load address
+ * MOD_SIZE sizeof(size_t) module size
+ * MOD_METADATA (variable) type-specific metadata
+ */
+#define COPY32(v, a) { \
+ u_int32_t x = (v); \
+ i386_copyin(&x, a, sizeof(x)); \
+ a += sizeof(x); \
+}
+
+#define MOD_STR(t, a, s) { \
+ COPY32(t, a); \
+ COPY32(strlen(s) + 1, a); \
+ i386_copyin(s, a, strlen(s) + 1); \
+ a += roundup(strlen(s) + 1, sizeof(u_long));\
+}
+
+#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s)
+#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s)
+#define MOD_ARGS(a, s) MOD_STR(MODINFO_ARGS, a, s)
+
+#define MOD_VAR(t, a, s) { \
+ COPY32(t, a); \
+ COPY32(sizeof(s), a); \
+ i386_copyin(&s, a, sizeof(s)); \
+ a += roundup(sizeof(s), sizeof(u_long)); \
+}
+
+#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s)
+#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s)
+
+#define MOD_METADATA(a, mm) { \
+ COPY32(MODINFO_METADATA | mm->md_type, a); \
+ COPY32(mm->md_size, a); \
+ i386_copyin(mm->md_data, a, mm->md_size); \
+ a += roundup(mm->md_size, sizeof(u_long));\
+}
+
+#define MOD_END(a) { \
+ COPY32(MODINFO_END, a); \
+ COPY32(0, a); \
+}
+
+vm_offset_t
+bi_copymodules(vm_offset_t addr)
+{
+ struct loaded_module *mp;
+ struct module_metadata *md;
+
+ /* start with the first module on the list, should be the kernel */
+ for (mp = mod_findmodule(NULL, NULL); mp != NULL; mp = mp->m_next) {
+
+ MOD_NAME(addr, mp->m_name); /* this field must come first */
+ MOD_TYPE(addr, mp->m_type);
+ if (mp->m_args)
+ MOD_ARGS(addr, mp->m_args);
+ MOD_ADDR(addr, mp->m_addr);
+ MOD_SIZE(addr, mp->m_size);
+ for (md = mp->m_metadata; md != NULL; md = md->md_next)
+ if (!(md->md_type & MODINFOMD_NOCOPY))
+ MOD_METADATA(addr, md);
+ }
+ MOD_END(addr);
+ return(addr);
+}
+
+/*
+ * Load the information expected by an i386 kernel.
+ *
+ * - The 'boothowto' argument is constructed
+ * - The 'botdev' argument is constructed
+ * - The 'bootinfo' struct is constructed, and copied into the kernel space.
+ * - The kernel environment is copied into kernel space.
+ * - Module metadata are formatted and placed in kernel space.
+ */
+int
+bi_load(char *args, int *howtop, int *bootdevp, vm_offset_t *bip)
+{
+ struct loaded_module *xp;
+ struct i386_devdesc *rootdev;
+ vm_offset_t addr, bootinfo_addr;
+ char *rootdevname;
+ int bootdevnr;
+ u_int pad;
+ char *kernelname;
+ const char *kernelpath;
+
+ *howtop = bi_getboothowto(args);
+
+ /*
+ * Allow the environment variable 'rootdev' to override the supplied device
+ * This should perhaps go to MI code and/or have $rootdev tested/set by
+ * MI code before launching the kernel.
+ */
+ rootdevname = getenv("rootdev");
+ i386_getdev((void **)(&rootdev), rootdevname, NULL);
+ if (rootdev == NULL) { /* bad $rootdev/$currdev */
+ printf("can't determine root device\n");
+ return(EINVAL);
+ }
+
+ switch(rootdev->d_type) {
+ case DEVT_DISK:
+ /* pass in the BIOS device number of the current disk */
+ bi.bi_bios_dev = bd_unit2bios(rootdev->d_kind.biosdisk.unit);
+ bootdevnr = bd_getdev(rootdev);
+ if (bootdevnr != -1)
+ break;
+ printf("root device %s invalid\n", i386_fmtdev(rootdev));
+ return(EINVAL);
+
+ default:
+ printf("aout_exec: WARNING - don't know how to boot from device type %d\n", rootdev->d_type);
+ }
+ free(rootdev);
+ *bootdevp = bootdevnr;
+
+ /* legacy bootinfo structure */
+ bi.bi_version = BOOTINFO_VERSION;
+ bi.bi_kernelname = 0; /* XXX char * -> kernel name */
+ bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */
+ bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */
+ /* bi.bi_bios_geom[] */
+ bi.bi_size = sizeof(bi);
+ bi.bi_memsizes_valid = 1;
+ bi.bi_basemem = getbasemem();
+ bi.bi_extmem = getextmem();
+
+ /* find the last module in the chain */
+ addr = 0;
+ for (xp = mod_findmodule(NULL, NULL); xp != NULL; xp = xp->m_next) {
+ if (addr < (xp->m_addr + xp->m_size))
+ addr = xp->m_addr + xp->m_size;
+ }
+ /* pad to a page boundary */
+ pad = (u_int)addr & PAGE_MASK;
+ if (pad != 0) {
+ pad = PAGE_SIZE - pad;
+ addr += pad;
+ }
+
+ /* copy our environment */
+ bi.bi_envp = addr;
+ addr = bi_copyenv(addr);
+
+ /* pad to a page boundary */
+ pad = (u_int)addr & PAGE_MASK;
+ if (pad != 0) {
+ pad = PAGE_SIZE - pad;
+ addr += pad;
+ }
+ /* copy module list and metadata */
+ bi.bi_modulep = addr;
+ addr = bi_copymodules(addr);
+
+ /* all done copying stuff in, save end of loaded object space */
+ bi.bi_kernend = addr;
+
+ *howtop |= RB_BOOTINFO; /* it's there now */
+
+ /*
+ * Get the kernel name, strip off any device prefix.
+ */
+ kernelname = getenv("kernelname");
+ i386_getdev(NULL, kernelname, &kernelpath);
+ bi.bi_kernelname = VTOP(kernelpath);
+ *bip = VTOP(&bi);
+
+ return(0);
+}
diff --git a/sys/boot/i386/libi386/bootinfo32.c b/sys/boot/i386/libi386/bootinfo32.c
new file mode 100644
index 0000000..87405f0
--- /dev/null
+++ b/sys/boot/i386/libi386/bootinfo32.c
@@ -0,0 +1,325 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: bootinfo.c,v 1.17 1999/03/08 11:05:52 dcs Exp $
+ */
+
+#include <stand.h>
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/linker.h>
+#include <machine/bootinfo.h>
+#include "bootstrap.h"
+#include "libi386.h"
+#include "btxv86.h"
+
+static struct bootinfo bi;
+
+/*
+ * Return a 'boothowto' value corresponding to the kernel arguments in
+ * (kargs) and any relevant environment variables.
+ */
+static struct
+{
+ char *ev;
+ int mask;
+} howto_names[] = {
+ {"boot_askname", RB_ASKNAME},
+ {"boot_userconfig", RB_CONFIG},
+ {"boot_ddb", RB_KDB},
+ {"boot_gdb", RB_GDB},
+ {"boot_single", RB_SINGLE},
+ {"boot_verbose", RB_VERBOSE},
+ {NULL, 0}
+};
+
+int
+bi_getboothowto(char *kargs)
+{
+ char *cp;
+ int howto;
+ int active;
+ int i;
+
+ /* Parse kargs */
+ howto = 0;
+ if (kargs != NULL) {
+ cp = kargs;
+ active = 0;
+ while (*cp != 0) {
+ if (!active && (*cp == '-')) {
+ active = 1;
+ } else if (active)
+ switch (*cp) {
+ case 'a':
+ howto |= RB_ASKNAME;
+ break;
+ case 'c':
+ howto |= RB_CONFIG;
+ break;
+ case 'd':
+ howto |= RB_KDB;
+ break;
+ case 'g':
+ howto |= RB_GDB;
+ break;
+ case 'h':
+ howto |= RB_SERIAL;
+ break;
+ case 'r':
+ howto |= RB_DFLTROOT;
+ break;
+ case 's':
+ howto |= RB_SINGLE;
+ break;
+ case 'v':
+ howto |= RB_VERBOSE;
+ break;
+ default:
+ active = 0;
+ break;
+ }
+ cp++;
+ }
+ }
+ /* get equivalents from the environment */
+ for (i = 0; howto_names[i].ev != NULL; i++)
+ if (getenv(howto_names[i].ev) != NULL)
+ howto |= howto_names[i].mask;
+ if (!strcmp(getenv("console"), "comconsole"))
+ howto |= RB_SERIAL;
+ return(howto);
+}
+
+/*
+ * Copy the environment into the load area starting at (addr).
+ * Each variable is formatted as <name>=<value>, with a single nul
+ * separating each variable, and a double nul terminating the environment.
+ */
+vm_offset_t
+bi_copyenv(vm_offset_t addr)
+{
+ struct env_var *ep;
+
+ /* traverse the environment */
+ for (ep = environ; ep != NULL; ep = ep->ev_next) {
+ i386_copyin(ep->ev_name, addr, strlen(ep->ev_name));
+ addr += strlen(ep->ev_name);
+ i386_copyin("=", addr, 1);
+ addr++;
+ if (ep->ev_value != NULL) {
+ i386_copyin(ep->ev_value, addr, strlen(ep->ev_value));
+ addr += strlen(ep->ev_value);
+ }
+ i386_copyin("", addr, 1);
+ addr++;
+ }
+ i386_copyin("", addr, 1);
+ addr++;
+ return(addr);
+}
+
+/*
+ * Copy module-related data into the load area, where it can be
+ * used as a directory for loaded modules.
+ *
+ * Module data is presented in a self-describing format. Each datum
+ * is preceeded by a 32-bit identifier and a 32-bit size field.
+ *
+ * Currently, the following data are saved:
+ *
+ * MOD_NAME (variable) module name (string)
+ * MOD_TYPE (variable) module type (string)
+ * MOD_ARGS (variable) module parameters (string)
+ * MOD_ADDR sizeof(vm_offset_t) module load address
+ * MOD_SIZE sizeof(size_t) module size
+ * MOD_METADATA (variable) type-specific metadata
+ */
+#define COPY32(v, a) { \
+ u_int32_t x = (v); \
+ i386_copyin(&x, a, sizeof(x)); \
+ a += sizeof(x); \
+}
+
+#define MOD_STR(t, a, s) { \
+ COPY32(t, a); \
+ COPY32(strlen(s) + 1, a); \
+ i386_copyin(s, a, strlen(s) + 1); \
+ a += roundup(strlen(s) + 1, sizeof(u_long));\
+}
+
+#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s)
+#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s)
+#define MOD_ARGS(a, s) MOD_STR(MODINFO_ARGS, a, s)
+
+#define MOD_VAR(t, a, s) { \
+ COPY32(t, a); \
+ COPY32(sizeof(s), a); \
+ i386_copyin(&s, a, sizeof(s)); \
+ a += roundup(sizeof(s), sizeof(u_long)); \
+}
+
+#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s)
+#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s)
+
+#define MOD_METADATA(a, mm) { \
+ COPY32(MODINFO_METADATA | mm->md_type, a); \
+ COPY32(mm->md_size, a); \
+ i386_copyin(mm->md_data, a, mm->md_size); \
+ a += roundup(mm->md_size, sizeof(u_long));\
+}
+
+#define MOD_END(a) { \
+ COPY32(MODINFO_END, a); \
+ COPY32(0, a); \
+}
+
+vm_offset_t
+bi_copymodules(vm_offset_t addr)
+{
+ struct loaded_module *mp;
+ struct module_metadata *md;
+
+ /* start with the first module on the list, should be the kernel */
+ for (mp = mod_findmodule(NULL, NULL); mp != NULL; mp = mp->m_next) {
+
+ MOD_NAME(addr, mp->m_name); /* this field must come first */
+ MOD_TYPE(addr, mp->m_type);
+ if (mp->m_args)
+ MOD_ARGS(addr, mp->m_args);
+ MOD_ADDR(addr, mp->m_addr);
+ MOD_SIZE(addr, mp->m_size);
+ for (md = mp->m_metadata; md != NULL; md = md->md_next)
+ if (!(md->md_type & MODINFOMD_NOCOPY))
+ MOD_METADATA(addr, md);
+ }
+ MOD_END(addr);
+ return(addr);
+}
+
+/*
+ * Load the information expected by an i386 kernel.
+ *
+ * - The 'boothowto' argument is constructed
+ * - The 'botdev' argument is constructed
+ * - The 'bootinfo' struct is constructed, and copied into the kernel space.
+ * - The kernel environment is copied into kernel space.
+ * - Module metadata are formatted and placed in kernel space.
+ */
+int
+bi_load(char *args, int *howtop, int *bootdevp, vm_offset_t *bip)
+{
+ struct loaded_module *xp;
+ struct i386_devdesc *rootdev;
+ vm_offset_t addr, bootinfo_addr;
+ char *rootdevname;
+ int bootdevnr;
+ u_int pad;
+ char *kernelname;
+ const char *kernelpath;
+
+ *howtop = bi_getboothowto(args);
+
+ /*
+ * Allow the environment variable 'rootdev' to override the supplied device
+ * This should perhaps go to MI code and/or have $rootdev tested/set by
+ * MI code before launching the kernel.
+ */
+ rootdevname = getenv("rootdev");
+ i386_getdev((void **)(&rootdev), rootdevname, NULL);
+ if (rootdev == NULL) { /* bad $rootdev/$currdev */
+ printf("can't determine root device\n");
+ return(EINVAL);
+ }
+
+ switch(rootdev->d_type) {
+ case DEVT_DISK:
+ /* pass in the BIOS device number of the current disk */
+ bi.bi_bios_dev = bd_unit2bios(rootdev->d_kind.biosdisk.unit);
+ bootdevnr = bd_getdev(rootdev);
+ if (bootdevnr != -1)
+ break;
+ printf("root device %s invalid\n", i386_fmtdev(rootdev));
+ return(EINVAL);
+
+ default:
+ printf("aout_exec: WARNING - don't know how to boot from device type %d\n", rootdev->d_type);
+ }
+ free(rootdev);
+ *bootdevp = bootdevnr;
+
+ /* legacy bootinfo structure */
+ bi.bi_version = BOOTINFO_VERSION;
+ bi.bi_kernelname = 0; /* XXX char * -> kernel name */
+ bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */
+ bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */
+ /* bi.bi_bios_geom[] */
+ bi.bi_size = sizeof(bi);
+ bi.bi_memsizes_valid = 1;
+ bi.bi_basemem = getbasemem();
+ bi.bi_extmem = getextmem();
+
+ /* find the last module in the chain */
+ addr = 0;
+ for (xp = mod_findmodule(NULL, NULL); xp != NULL; xp = xp->m_next) {
+ if (addr < (xp->m_addr + xp->m_size))
+ addr = xp->m_addr + xp->m_size;
+ }
+ /* pad to a page boundary */
+ pad = (u_int)addr & PAGE_MASK;
+ if (pad != 0) {
+ pad = PAGE_SIZE - pad;
+ addr += pad;
+ }
+
+ /* copy our environment */
+ bi.bi_envp = addr;
+ addr = bi_copyenv(addr);
+
+ /* pad to a page boundary */
+ pad = (u_int)addr & PAGE_MASK;
+ if (pad != 0) {
+ pad = PAGE_SIZE - pad;
+ addr += pad;
+ }
+ /* copy module list and metadata */
+ bi.bi_modulep = addr;
+ addr = bi_copymodules(addr);
+
+ /* all done copying stuff in, save end of loaded object space */
+ bi.bi_kernend = addr;
+
+ *howtop |= RB_BOOTINFO; /* it's there now */
+
+ /*
+ * Get the kernel name, strip off any device prefix.
+ */
+ kernelname = getenv("kernelname");
+ i386_getdev(NULL, kernelname, &kernelpath);
+ bi.bi_kernelname = VTOP(kernelpath);
+ *bip = VTOP(&bi);
+
+ return(0);
+}
diff --git a/sys/boot/i386/libi386/bootinfo64.c b/sys/boot/i386/libi386/bootinfo64.c
new file mode 100644
index 0000000..87405f0
--- /dev/null
+++ b/sys/boot/i386/libi386/bootinfo64.c
@@ -0,0 +1,325 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: bootinfo.c,v 1.17 1999/03/08 11:05:52 dcs Exp $
+ */
+
+#include <stand.h>
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/linker.h>
+#include <machine/bootinfo.h>
+#include "bootstrap.h"
+#include "libi386.h"
+#include "btxv86.h"
+
+static struct bootinfo bi;
+
+/*
+ * Return a 'boothowto' value corresponding to the kernel arguments in
+ * (kargs) and any relevant environment variables.
+ */
+static struct
+{
+ char *ev;
+ int mask;
+} howto_names[] = {
+ {"boot_askname", RB_ASKNAME},
+ {"boot_userconfig", RB_CONFIG},
+ {"boot_ddb", RB_KDB},
+ {"boot_gdb", RB_GDB},
+ {"boot_single", RB_SINGLE},
+ {"boot_verbose", RB_VERBOSE},
+ {NULL, 0}
+};
+
+int
+bi_getboothowto(char *kargs)
+{
+ char *cp;
+ int howto;
+ int active;
+ int i;
+
+ /* Parse kargs */
+ howto = 0;
+ if (kargs != NULL) {
+ cp = kargs;
+ active = 0;
+ while (*cp != 0) {
+ if (!active && (*cp == '-')) {
+ active = 1;
+ } else if (active)
+ switch (*cp) {
+ case 'a':
+ howto |= RB_ASKNAME;
+ break;
+ case 'c':
+ howto |= RB_CONFIG;
+ break;
+ case 'd':
+ howto |= RB_KDB;
+ break;
+ case 'g':
+ howto |= RB_GDB;
+ break;
+ case 'h':
+ howto |= RB_SERIAL;
+ break;
+ case 'r':
+ howto |= RB_DFLTROOT;
+ break;
+ case 's':
+ howto |= RB_SINGLE;
+ break;
+ case 'v':
+ howto |= RB_VERBOSE;
+ break;
+ default:
+ active = 0;
+ break;
+ }
+ cp++;
+ }
+ }
+ /* get equivalents from the environment */
+ for (i = 0; howto_names[i].ev != NULL; i++)
+ if (getenv(howto_names[i].ev) != NULL)
+ howto |= howto_names[i].mask;
+ if (!strcmp(getenv("console"), "comconsole"))
+ howto |= RB_SERIAL;
+ return(howto);
+}
+
+/*
+ * Copy the environment into the load area starting at (addr).
+ * Each variable is formatted as <name>=<value>, with a single nul
+ * separating each variable, and a double nul terminating the environment.
+ */
+vm_offset_t
+bi_copyenv(vm_offset_t addr)
+{
+ struct env_var *ep;
+
+ /* traverse the environment */
+ for (ep = environ; ep != NULL; ep = ep->ev_next) {
+ i386_copyin(ep->ev_name, addr, strlen(ep->ev_name));
+ addr += strlen(ep->ev_name);
+ i386_copyin("=", addr, 1);
+ addr++;
+ if (ep->ev_value != NULL) {
+ i386_copyin(ep->ev_value, addr, strlen(ep->ev_value));
+ addr += strlen(ep->ev_value);
+ }
+ i386_copyin("", addr, 1);
+ addr++;
+ }
+ i386_copyin("", addr, 1);
+ addr++;
+ return(addr);
+}
+
+/*
+ * Copy module-related data into the load area, where it can be
+ * used as a directory for loaded modules.
+ *
+ * Module data is presented in a self-describing format. Each datum
+ * is preceeded by a 32-bit identifier and a 32-bit size field.
+ *
+ * Currently, the following data are saved:
+ *
+ * MOD_NAME (variable) module name (string)
+ * MOD_TYPE (variable) module type (string)
+ * MOD_ARGS (variable) module parameters (string)
+ * MOD_ADDR sizeof(vm_offset_t) module load address
+ * MOD_SIZE sizeof(size_t) module size
+ * MOD_METADATA (variable) type-specific metadata
+ */
+#define COPY32(v, a) { \
+ u_int32_t x = (v); \
+ i386_copyin(&x, a, sizeof(x)); \
+ a += sizeof(x); \
+}
+
+#define MOD_STR(t, a, s) { \
+ COPY32(t, a); \
+ COPY32(strlen(s) + 1, a); \
+ i386_copyin(s, a, strlen(s) + 1); \
+ a += roundup(strlen(s) + 1, sizeof(u_long));\
+}
+
+#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s)
+#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s)
+#define MOD_ARGS(a, s) MOD_STR(MODINFO_ARGS, a, s)
+
+#define MOD_VAR(t, a, s) { \
+ COPY32(t, a); \
+ COPY32(sizeof(s), a); \
+ i386_copyin(&s, a, sizeof(s)); \
+ a += roundup(sizeof(s), sizeof(u_long)); \
+}
+
+#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s)
+#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s)
+
+#define MOD_METADATA(a, mm) { \
+ COPY32(MODINFO_METADATA | mm->md_type, a); \
+ COPY32(mm->md_size, a); \
+ i386_copyin(mm->md_data, a, mm->md_size); \
+ a += roundup(mm->md_size, sizeof(u_long));\
+}
+
+#define MOD_END(a) { \
+ COPY32(MODINFO_END, a); \
+ COPY32(0, a); \
+}
+
+vm_offset_t
+bi_copymodules(vm_offset_t addr)
+{
+ struct loaded_module *mp;
+ struct module_metadata *md;
+
+ /* start with the first module on the list, should be the kernel */
+ for (mp = mod_findmodule(NULL, NULL); mp != NULL; mp = mp->m_next) {
+
+ MOD_NAME(addr, mp->m_name); /* this field must come first */
+ MOD_TYPE(addr, mp->m_type);
+ if (mp->m_args)
+ MOD_ARGS(addr, mp->m_args);
+ MOD_ADDR(addr, mp->m_addr);
+ MOD_SIZE(addr, mp->m_size);
+ for (md = mp->m_metadata; md != NULL; md = md->md_next)
+ if (!(md->md_type & MODINFOMD_NOCOPY))
+ MOD_METADATA(addr, md);
+ }
+ MOD_END(addr);
+ return(addr);
+}
+
+/*
+ * Load the information expected by an i386 kernel.
+ *
+ * - The 'boothowto' argument is constructed
+ * - The 'botdev' argument is constructed
+ * - The 'bootinfo' struct is constructed, and copied into the kernel space.
+ * - The kernel environment is copied into kernel space.
+ * - Module metadata are formatted and placed in kernel space.
+ */
+int
+bi_load(char *args, int *howtop, int *bootdevp, vm_offset_t *bip)
+{
+ struct loaded_module *xp;
+ struct i386_devdesc *rootdev;
+ vm_offset_t addr, bootinfo_addr;
+ char *rootdevname;
+ int bootdevnr;
+ u_int pad;
+ char *kernelname;
+ const char *kernelpath;
+
+ *howtop = bi_getboothowto(args);
+
+ /*
+ * Allow the environment variable 'rootdev' to override the supplied device
+ * This should perhaps go to MI code and/or have $rootdev tested/set by
+ * MI code before launching the kernel.
+ */
+ rootdevname = getenv("rootdev");
+ i386_getdev((void **)(&rootdev), rootdevname, NULL);
+ if (rootdev == NULL) { /* bad $rootdev/$currdev */
+ printf("can't determine root device\n");
+ return(EINVAL);
+ }
+
+ switch(rootdev->d_type) {
+ case DEVT_DISK:
+ /* pass in the BIOS device number of the current disk */
+ bi.bi_bios_dev = bd_unit2bios(rootdev->d_kind.biosdisk.unit);
+ bootdevnr = bd_getdev(rootdev);
+ if (bootdevnr != -1)
+ break;
+ printf("root device %s invalid\n", i386_fmtdev(rootdev));
+ return(EINVAL);
+
+ default:
+ printf("aout_exec: WARNING - don't know how to boot from device type %d\n", rootdev->d_type);
+ }
+ free(rootdev);
+ *bootdevp = bootdevnr;
+
+ /* legacy bootinfo structure */
+ bi.bi_version = BOOTINFO_VERSION;
+ bi.bi_kernelname = 0; /* XXX char * -> kernel name */
+ bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */
+ bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */
+ /* bi.bi_bios_geom[] */
+ bi.bi_size = sizeof(bi);
+ bi.bi_memsizes_valid = 1;
+ bi.bi_basemem = getbasemem();
+ bi.bi_extmem = getextmem();
+
+ /* find the last module in the chain */
+ addr = 0;
+ for (xp = mod_findmodule(NULL, NULL); xp != NULL; xp = xp->m_next) {
+ if (addr < (xp->m_addr + xp->m_size))
+ addr = xp->m_addr + xp->m_size;
+ }
+ /* pad to a page boundary */
+ pad = (u_int)addr & PAGE_MASK;
+ if (pad != 0) {
+ pad = PAGE_SIZE - pad;
+ addr += pad;
+ }
+
+ /* copy our environment */
+ bi.bi_envp = addr;
+ addr = bi_copyenv(addr);
+
+ /* pad to a page boundary */
+ pad = (u_int)addr & PAGE_MASK;
+ if (pad != 0) {
+ pad = PAGE_SIZE - pad;
+ addr += pad;
+ }
+ /* copy module list and metadata */
+ bi.bi_modulep = addr;
+ addr = bi_copymodules(addr);
+
+ /* all done copying stuff in, save end of loaded object space */
+ bi.bi_kernend = addr;
+
+ *howtop |= RB_BOOTINFO; /* it's there now */
+
+ /*
+ * Get the kernel name, strip off any device prefix.
+ */
+ kernelname = getenv("kernelname");
+ i386_getdev(NULL, kernelname, &kernelpath);
+ bi.bi_kernelname = VTOP(kernelpath);
+ *bip = VTOP(&bi);
+
+ return(0);
+}
diff --git a/sys/boot/i386/libi386/comconsole.c b/sys/boot/i386/libi386/comconsole.c
new file mode 100644
index 0000000..7b35d1d
--- /dev/null
+++ b/sys/boot/i386/libi386/comconsole.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: comconsole.c,v 1.5 1998/11/22 07:59:16 rnordier Exp $
+ */
+
+#include <stand.h>
+#include <bootstrap.h>
+#include <machine/cpufunc.h>
+#include "libi386.h"
+
+/* selected defines from ns16550.h */
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
+
+/* selected defines from sioreg.h */
+#define CFCR_DLAB 0x80
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+#define LSR_TXRDY 0x20
+#define LSR_RXRDY 0x01
+
+#define COMC_FMT 0x3 /* 8N1 */
+#define COMC_TXWAIT 0x40000 /* transmit timeout */
+#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */
+
+#ifndef COMPORT
+#define COMPORT 0x3f8
+#endif
+#ifndef COMSPEED
+#define COMSPEED 9600
+#endif
+
+static void comc_probe(struct console *cp);
+static int comc_init(int arg);
+static void comc_putchar(int c);
+static int comc_getchar(void);
+static int comc_ischar(void);
+
+static int comc_started;
+
+struct console comconsole = {
+ "comconsole",
+ "serial port",
+ 0,
+ comc_probe,
+ comc_init,
+ comc_putchar,
+ comc_getchar,
+ comc_ischar
+};
+
+static void
+comc_probe(struct console *cp)
+{
+ /* XXX check the BIOS equipment list? */
+ cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
+}
+
+static int
+comc_init(int arg)
+{
+ if (comc_started && arg == 0)
+ return 0;
+ comc_started = 1;
+
+ outb(COMPORT + com_cfcr, CFCR_DLAB | COMC_FMT);
+ outb(COMPORT + com_dlbl, COMC_BPS(COMSPEED) & 0xff);
+ outb(COMPORT + com_dlbh, COMC_BPS(COMSPEED) >> 8);
+ outb(COMPORT + com_cfcr, COMC_FMT);
+ outb(COMPORT + com_mcr, MCR_RTS | MCR_DTR);
+
+ do
+ inb(COMPORT + com_data);
+ while (inb(COMPORT + com_lsr) & LSR_RXRDY);
+
+ return(0);
+}
+
+static void
+comc_putchar(int c)
+{
+ int wait;
+
+ for (wait = COMC_TXWAIT; wait > 0; wait--)
+ if (inb(COMPORT + com_lsr) & LSR_TXRDY) {
+ outb(COMPORT + com_data, c);
+ break;
+ }
+}
+
+static int
+comc_getchar(void)
+{
+ return(comc_ischar() ? inb(COMPORT + com_data) : -1);
+}
+
+static int
+comc_ischar(void)
+{
+ return(inb(COMPORT + com_lsr) & LSR_RXRDY);
+}
diff --git a/sys/boot/i386/libi386/devicename.c b/sys/boot/i386/libi386/devicename.c
new file mode 100644
index 0000000..418163e
--- /dev/null
+++ b/sys/boot/i386/libi386/devicename.c
@@ -0,0 +1,235 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: devicename.c,v 1.2 1998/09/26 01:30:20 msmith Exp $
+ */
+
+#include <stand.h>
+#include <string.h>
+#include <sys/disklabel.h>
+#include "bootstrap.h"
+#include "libi386.h"
+
+static int i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path);
+
+/*
+ * Point (dev) at an allocated device specifier for the device matching the
+ * path in (devspec). If it contains an explicit device specification,
+ * use that. If not, use the default device.
+ */
+int
+i386_getdev(void **vdev, const char *devspec, const char **path)
+{
+ struct i386_devdesc **dev = (struct i386_devdesc **)vdev;
+ int rv;
+
+ /*
+ * If it looks like this is just a path and no
+ * device, go with the current device.
+ */
+ if ((devspec == NULL) ||
+ (devspec[0] == '/') ||
+ (strchr(devspec, ':') == NULL)) {
+
+ if (((rv = i386_parsedev(dev, getenv("currdev"), NULL)) == 0) &&
+ (path != NULL))
+ *path = devspec;
+ return(rv);
+ }
+
+ /*
+ * Try to parse the device name off the beginning of the devspec
+ */
+ return(i386_parsedev(dev, devspec, path));
+}
+
+/*
+ * Point (dev) at an allocated device specifier matching the string version
+ * at the beginning of (devspec). Return a pointer to the remaining
+ * text in (path).
+ *
+ * In all cases, the beginning of (devspec) is compared to the names
+ * of known devices in the device switch, and then any following text
+ * is parsed according to the rules applied to the device type.
+ *
+ * For disk-type devices, the syntax is:
+ *
+ * disk<unit>[s<slice>][<partition>]:
+ *
+ */
+static int
+i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path)
+{
+ struct i386_devdesc *idev;
+ struct devsw *dv;
+ int i, unit, slice, partition, err;
+ char *cp;
+ const char *np;
+
+ /* minimum length check */
+ if (strlen(devspec) < 2)
+ return(EINVAL);
+
+ /* look for a device that matches */
+ for (i = 0, dv = NULL; devsw[i] != NULL; i++) {
+ if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) {
+ dv = devsw[i];
+ break;
+ }
+ }
+ if (dv == NULL)
+ return(ENOENT);
+ idev = malloc(sizeof(struct i386_devdesc));
+ err = 0;
+ np = (devspec + strlen(dv->dv_name));
+
+ switch(dv->dv_type) {
+ case DEVT_NONE: /* XXX what to do here? Do we care? */
+ break;
+
+ case DEVT_DISK:
+ unit = -1;
+ slice = -1;
+ partition = -1;
+ if (*np && (*np != ':')) {
+ unit = strtol(np, &cp, 10); /* next comes the unit number */
+ if (cp == np) {
+ err = EUNIT;
+ goto fail;
+ }
+ if (*cp == 's') { /* got a slice number */
+ np = cp + 1;
+ slice = strtol(np, &cp, 10);
+ if (cp == np) {
+ err = ESLICE;
+ goto fail;
+ }
+ }
+ if (*cp && (*cp != ':')) {
+ partition = *cp - 'a'; /* get a partition number */
+ if ((partition < 0) || (partition >= MAXPARTITIONS)) {
+ err = EPART;
+ goto fail;
+ }
+ cp++;
+ }
+ }
+ if (*cp && (*cp != ':')) {
+ err = EINVAL;
+ goto fail;
+ }
+
+ idev->d_kind.biosdisk.unit = unit;
+ idev->d_kind.biosdisk.slice = slice;
+ idev->d_kind.biosdisk.partition = partition;
+ if (path != NULL)
+ *path = (*cp == 0) ? cp : cp + 1;
+ break;
+
+ case DEVT_NET:
+ unit = 0;
+
+ if (*np && (*np != ':')) {
+ unit = strtol(np, &cp, 0); /* get unit number if present */
+ if (cp == np) {
+ err = EUNIT;
+ goto fail;
+ }
+ }
+ if (*cp && (*cp != ':')) {
+ err = EINVAL;
+ goto fail;
+ }
+
+ idev->d_kind.netif.unit = unit;
+ if (path != NULL)
+ *path = (*cp == 0) ? cp : cp + 1;
+ break;
+
+ default:
+ err = EINVAL;
+ goto fail;
+ }
+ idev->d_dev = dv;
+ idev->d_type = dv->dv_type;
+ if (dev == NULL) {
+ free(idev);
+ } else {
+ *dev = idev;
+ }
+ return(0);
+
+ fail:
+ free(idev);
+ return(err);
+}
+
+
+char *
+i386_fmtdev(void *vdev)
+{
+ struct i386_devdesc *dev = (struct i386_devdesc *)vdev;
+ static char buf[128]; /* XXX device length constant? */
+ char *cp;
+
+ switch(dev->d_type) {
+ case DEVT_NONE:
+ strcpy(buf, "(no device)");
+ break;
+
+ case DEVT_DISK:
+ cp = buf;
+ cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_kind.biosdisk.unit);
+ if (dev->d_kind.biosdisk.slice > 0)
+ cp += sprintf(cp, "s%d", dev->d_kind.biosdisk.slice);
+ if (dev->d_kind.biosdisk.partition >= 0)
+ cp += sprintf(cp, "%c", dev->d_kind.biosdisk.partition + 'a');
+ strcat(cp, ":");
+ break;
+
+ case DEVT_NET:
+ sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_kind.netif.unit);
+ break;
+ }
+ return(buf);
+}
+
+
+/*
+ * Set currdev to suit the value being supplied in (value)
+ */
+int
+i386_setcurrdev(struct env_var *ev, int flags, void *value)
+{
+ struct i386_devdesc *ncurr;
+ int rv;
+
+ if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0)
+ return(rv);
+ free(ncurr);
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ return(0);
+}
+
diff --git a/sys/boot/i386/libi386/elf32_freebsd.c b/sys/boot/i386/libi386/elf32_freebsd.c
new file mode 100644
index 0000000..130b0ca
--- /dev/null
+++ b/sys/boot/i386/libi386/elf32_freebsd.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: elf_freebsd.c,v 1.5 1998/10/04 20:58:46 msmith Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/reboot.h>
+#include <sys/linker.h>
+#include <string.h>
+#include <machine/bootinfo.h>
+#include <machine/elf.h>
+#include <stand.h>
+
+#include "bootstrap.h"
+#include "libi386.h"
+#include "btxv86.h"
+
+static int elf_exec(struct loaded_module *amp);
+
+struct module_format i386_elf = { elf_loadmodule, elf_exec };
+
+static struct bootinfo bi;
+
+/*
+ * There is an a.out kernel and one or more a.out modules loaded.
+ * We wish to start executing the kernel image, so make such
+ * preparations as are required, and do so.
+ */
+static int
+elf_exec(struct loaded_module *mp)
+{
+ struct module_metadata *md;
+ Elf_Ehdr *ehdr;
+ vm_offset_t entry, bootinfop;
+ int boothowto, err, bootdev;
+ struct bootinfo *bi;
+ vm_offset_t ssym, esym;
+
+ if ((md = mod_findmetadata(mp, MODINFOMD_ELFHDR)) == NULL)
+ return(EFTYPE); /* XXX actually EFUCKUP */
+ ehdr = (Elf_Ehdr *)&(md->md_data);
+
+ if ((err = bi_load(mp->m_args, &boothowto, &bootdev, &bootinfop)) != 0)
+ return(err);
+ entry = ehdr->e_entry & 0xffffff;
+
+ ssym = esym = 0;
+ if ((md = mod_findmetadata(mp, MODINFOMD_SSYM)) != NULL)
+ ssym = *((vm_offset_t *)&(md->md_data));
+ if ((md = mod_findmetadata(mp, MODINFOMD_ESYM)) != NULL)
+ esym = *((vm_offset_t *)&(md->md_data));
+ if (ssym == 0 || esym == 0)
+ ssym = esym = 0; /* sanity */
+ bi = (struct bootinfo *)PTOV(bootinfop);
+ bi->bi_symtab = ssym; /* XXX this is only the primary kernel symtab */
+ bi->bi_esymtab = esym;
+
+
+#ifdef DEBUG
+ printf("Start @ 0x%lx ...\n", entry);
+#endif
+
+ __exec((void *)entry, boothowto, bootdev, 0, 0, 0, bootinfop);
+
+ panic("exec returned");
+}
diff --git a/sys/boot/i386/libi386/elf64_freebsd.c b/sys/boot/i386/libi386/elf64_freebsd.c
new file mode 100644
index 0000000..130b0ca
--- /dev/null
+++ b/sys/boot/i386/libi386/elf64_freebsd.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: elf_freebsd.c,v 1.5 1998/10/04 20:58:46 msmith Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/reboot.h>
+#include <sys/linker.h>
+#include <string.h>
+#include <machine/bootinfo.h>
+#include <machine/elf.h>
+#include <stand.h>
+
+#include "bootstrap.h"
+#include "libi386.h"
+#include "btxv86.h"
+
+static int elf_exec(struct loaded_module *amp);
+
+struct module_format i386_elf = { elf_loadmodule, elf_exec };
+
+static struct bootinfo bi;
+
+/*
+ * There is an a.out kernel and one or more a.out modules loaded.
+ * We wish to start executing the kernel image, so make such
+ * preparations as are required, and do so.
+ */
+static int
+elf_exec(struct loaded_module *mp)
+{
+ struct module_metadata *md;
+ Elf_Ehdr *ehdr;
+ vm_offset_t entry, bootinfop;
+ int boothowto, err, bootdev;
+ struct bootinfo *bi;
+ vm_offset_t ssym, esym;
+
+ if ((md = mod_findmetadata(mp, MODINFOMD_ELFHDR)) == NULL)
+ return(EFTYPE); /* XXX actually EFUCKUP */
+ ehdr = (Elf_Ehdr *)&(md->md_data);
+
+ if ((err = bi_load(mp->m_args, &boothowto, &bootdev, &bootinfop)) != 0)
+ return(err);
+ entry = ehdr->e_entry & 0xffffff;
+
+ ssym = esym = 0;
+ if ((md = mod_findmetadata(mp, MODINFOMD_SSYM)) != NULL)
+ ssym = *((vm_offset_t *)&(md->md_data));
+ if ((md = mod_findmetadata(mp, MODINFOMD_ESYM)) != NULL)
+ esym = *((vm_offset_t *)&(md->md_data));
+ if (ssym == 0 || esym == 0)
+ ssym = esym = 0; /* sanity */
+ bi = (struct bootinfo *)PTOV(bootinfop);
+ bi->bi_symtab = ssym; /* XXX this is only the primary kernel symtab */
+ bi->bi_esymtab = esym;
+
+
+#ifdef DEBUG
+ printf("Start @ 0x%lx ...\n", entry);
+#endif
+
+ __exec((void *)entry, boothowto, bootdev, 0, 0, 0, bootinfop);
+
+ panic("exec returned");
+}
diff --git a/sys/boot/i386/libi386/elf_freebsd.c b/sys/boot/i386/libi386/elf_freebsd.c
new file mode 100644
index 0000000..130b0ca
--- /dev/null
+++ b/sys/boot/i386/libi386/elf_freebsd.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: elf_freebsd.c,v 1.5 1998/10/04 20:58:46 msmith Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/reboot.h>
+#include <sys/linker.h>
+#include <string.h>
+#include <machine/bootinfo.h>
+#include <machine/elf.h>
+#include <stand.h>
+
+#include "bootstrap.h"
+#include "libi386.h"
+#include "btxv86.h"
+
+static int elf_exec(struct loaded_module *amp);
+
+struct module_format i386_elf = { elf_loadmodule, elf_exec };
+
+static struct bootinfo bi;
+
+/*
+ * There is an a.out kernel and one or more a.out modules loaded.
+ * We wish to start executing the kernel image, so make such
+ * preparations as are required, and do so.
+ */
+static int
+elf_exec(struct loaded_module *mp)
+{
+ struct module_metadata *md;
+ Elf_Ehdr *ehdr;
+ vm_offset_t entry, bootinfop;
+ int boothowto, err, bootdev;
+ struct bootinfo *bi;
+ vm_offset_t ssym, esym;
+
+ if ((md = mod_findmetadata(mp, MODINFOMD_ELFHDR)) == NULL)
+ return(EFTYPE); /* XXX actually EFUCKUP */
+ ehdr = (Elf_Ehdr *)&(md->md_data);
+
+ if ((err = bi_load(mp->m_args, &boothowto, &bootdev, &bootinfop)) != 0)
+ return(err);
+ entry = ehdr->e_entry & 0xffffff;
+
+ ssym = esym = 0;
+ if ((md = mod_findmetadata(mp, MODINFOMD_SSYM)) != NULL)
+ ssym = *((vm_offset_t *)&(md->md_data));
+ if ((md = mod_findmetadata(mp, MODINFOMD_ESYM)) != NULL)
+ esym = *((vm_offset_t *)&(md->md_data));
+ if (ssym == 0 || esym == 0)
+ ssym = esym = 0; /* sanity */
+ bi = (struct bootinfo *)PTOV(bootinfop);
+ bi->bi_symtab = ssym; /* XXX this is only the primary kernel symtab */
+ bi->bi_esymtab = esym;
+
+
+#ifdef DEBUG
+ printf("Start @ 0x%lx ...\n", entry);
+#endif
+
+ __exec((void *)entry, boothowto, bootdev, 0, 0, 0, bootinfop);
+
+ panic("exec returned");
+}
diff --git a/sys/boot/i386/libi386/gatea20.c b/sys/boot/i386/libi386/gatea20.c
new file mode 100644
index 0000000..bb109db
--- /dev/null
+++ b/sys/boot/i386/libi386/gatea20.c
@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ * From: $NetBSD: gatea20.c,v 1.2 1997/10/29 00:32:49 fvdl Exp $
+ */
+
+/* extracted from freebsd:sys/i386/boot/biosboot/io.c */
+
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+
+#include <stand.h>
+
+#include "libi386.h"
+
+#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
+#define K_STATUS 0x64 /* keyboard status */
+#define K_CMD 0x64 /* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL 0x01 /* output buffer full */
+#define K_IBUF_FUL 0x02 /* input buffer full */
+
+#define KC_CMD_WIN 0xd0 /* read output port */
+#define KC_CMD_WOUT 0xd1 /* write output port */
+#define KB_A20 0x9f /* enable A20,
+ reset (!),
+ enable output buffer full interrupt
+ enable data line
+ disable clock line */
+
+/*
+ * Gate A20 for high memory
+ */
+static unsigned char x_20 = KB_A20;
+void gateA20()
+{
+ __asm("pushfl ; cli");
+#ifdef IBM_L40
+ outb(0x92, 0x2);
+#else IBM_L40
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ while (inb(K_STATUS) & K_OBUF_FUL)
+ (void)inb(K_RDWR);
+
+ outb(K_CMD, KC_CMD_WOUT);
+ delay(100);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ outb(K_RDWR, x_20);
+ delay(100);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+#endif IBM_L40
+ __asm("popfl");
+}
diff --git a/sys/boot/i386/libi386/i386_copy.c b/sys/boot/i386/libi386/i386_copy.c
new file mode 100644
index 0000000..d0903f1
--- /dev/null
+++ b/sys/boot/i386/libi386/i386_copy.c
@@ -0,0 +1,63 @@
+/*
+ * mjs copyright
+ */
+/*
+ * MD primitives supporting placement of module data
+ *
+ * XXX should check load address/size against memory top.
+ */
+#include <stand.h>
+
+#include "libi386.h"
+#include "btxv86.h"
+
+#define READIN_BUF (16 * 1024)
+
+int
+i386_copyin(void *src, vm_offset_t dest, size_t len)
+{
+ if (dest + len >= memtop)
+ return(0);
+
+ bcopy(src, PTOV(dest), len);
+ return(len);
+}
+
+int
+i386_copyout(vm_offset_t src, void *dest, size_t len)
+{
+ if (src + len >= memtop)
+ return(0);
+
+ bcopy(PTOV(src), dest, len);
+ return(len);
+}
+
+
+int
+i386_readin(int fd, vm_offset_t dest, size_t len)
+{
+ void *buf;
+ size_t resid, chunk, get;
+ ssize_t got;
+
+ if (dest + len >= memtop)
+ return(0);
+
+ chunk = min(READIN_BUF, len);
+ buf = malloc(chunk);
+ if (buf == NULL)
+ return(0);
+
+ for (resid = len; resid > 0; resid -= got, dest += got) {
+ get = min(chunk, resid);
+ got = read(fd, buf, get);
+ if (got <= 0)
+ break;
+ bcopy(buf, PTOV(dest), got);
+ }
+ free(buf);
+ return(len - resid);
+}
+
+
diff --git a/sys/boot/i386/libi386/i386_module.c b/sys/boot/i386/libi386/i386_module.c
new file mode 100644
index 0000000..3d75c76
--- /dev/null
+++ b/sys/boot/i386/libi386/i386_module.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: i386_module.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $
+ */
+
+/*
+ * i386-specific module functionality.
+ *
+ */
+
+#include <stand.h>
+#include <string.h>
+
+#include "bootstrap.h"
+#include "libi386.h"
+
+/*
+ * Use voodoo to load modules required by current hardware.
+ */
+int
+i386_autoload(void)
+{
+ /* XXX use PnP to locate stuff here */
+ return(0);
+}
diff --git a/sys/boot/i386/libi386/libi386.h b/sys/boot/i386/libi386/libi386.h
new file mode 100644
index 0000000..3933323
--- /dev/null
+++ b/sys/boot/i386/libi386/libi386.h
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: libi386.h,v 1.7 1998/10/02 16:32:45 msmith Exp $
+ */
+
+
+/*
+ * i386 fully-qualified device descriptor.
+ * Note, this must match the 'struct devdesc' declaration
+ * in bootstrap.h.
+ */
+struct i386_devdesc
+{
+ struct devsw *d_dev;
+ int d_type;
+ union
+ {
+ struct
+ {
+ int unit;
+ int slice;
+ int partition;
+ void *data;
+ } biosdisk;
+ struct
+ {
+ int unit; /* XXX net layer lives over these? */
+ } netif;
+ } d_kind;
+};
+
+extern int i386_getdev(void **vdev, const char *devspec, const char **path);
+extern char *i386_fmtdev(void *vdev);
+extern int i386_setcurrdev(struct env_var *ev, int flags, void *value);
+
+extern struct devdesc currdev; /* our current device */
+
+#define MAXDEV 31 /* maximum number of distinct devices */
+
+/* exported devices XXX rename? */
+extern struct devsw biosdisk;
+
+extern int bd_bios2unit(int biosdev); /* xlate BIOS device -> biosdisk unit */
+extern int bd_unit2bios(int unit); /* xlate biosdisk unit -> BIOS device */
+extern int bd_getdev(struct i386_devdesc *dev); /* return dev_t for (dev) */
+
+extern int i386_copyin(void *src, vm_offset_t dest, size_t len);
+extern int i386_copyout(vm_offset_t src, void *dest, size_t len);
+extern int i386_readin(int fd, vm_offset_t dest, size_t len);
+
+extern int getbasemem(void);
+extern int getextmem(void);
+extern vm_offset_t memtop;
+
+extern void gateA20(void);
+
+extern int i386_autoload(void);
+
+extern int bi_getboothowto(char *kargs);
+extern vm_offset_t bi_copyenv(vm_offset_t addr);
+extern int bi_load(char *args, int *howtop, int *bootdevp, vm_offset_t *bip);
+
+
diff --git a/sys/boot/i386/libi386/pread.c b/sys/boot/i386/libi386/pread.c
new file mode 100644
index 0000000..36ffb01
--- /dev/null
+++ b/sys/boot/i386/libi386/pread.c
@@ -0,0 +1,79 @@
+/*
+ * $Id$
+ * From: $NetBSD: pread.c,v 1.2 1997/03/22 01:48:38 thorpej Exp $
+ */
+
+/*
+ * Copyright (c) 1996
+ * Matthias Drochner. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project
+ * by Matthias Drochner.
+ * 4. 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.
+ *
+ */
+
+/* read into destination in flat addr space */
+
+#include <stand.h>
+
+#include "libi386.h"
+
+#ifdef SAVE_MEMORY
+#define BUFSIZE (1*1024)
+#else
+#define BUFSIZE (4*1024)
+#endif
+
+static char buf[BUFSIZE];
+
+int
+pread(fd, dest, size)
+ int fd;
+ vm_offset_t dest;
+ int size;
+{
+ int rsize;
+
+ rsize = size;
+ while (rsize > 0) {
+ int count, got;
+
+ count = (rsize < BUFSIZE ? rsize : BUFSIZE);
+
+ got = read(fd, buf, count);
+ if (got < 0)
+ return (-1);
+
+ /* put to physical space */
+ vpbcopy(buf, dest, got);
+
+ dest += got;
+ rsize -= got;
+ if (got < count)
+ break; /* EOF */
+ }
+ return (size - rsize);
+}
diff --git a/sys/boot/i386/libi386/time.c b/sys/boot/i386/libi386/time.c
new file mode 100644
index 0000000..a3f0f72
--- /dev/null
+++ b/sys/boot/i386/libi386/time.c
@@ -0,0 +1,56 @@
+/*
+ * mjs copyright
+ */
+
+#include <stand.h>
+#include <btxv86.h>
+
+/*
+ * Return the time in seconds since the beginning of the day.
+ *
+ * If we pass midnight, don't wrap back to 0.
+ *
+ * XXX uses undocumented BCD support from libstand.
+ */
+
+time_t
+time(time_t *t)
+{
+ static time_t lasttime, now;
+ int hr, min, sec;
+
+ v86.ctl = 0;
+ v86.addr = 0x1a; /* int 0x1a, function 2 */
+ v86.eax = 0x0200;
+ v86int();
+
+ hr = bcd2bin((v86.ecx & 0xff00) >> 8); /* hour in %ch */
+ min = bcd2bin(v86.ecx & 0xff); /* minute in %cl */
+ sec = bcd2bin((v86.edx & 0xff00) >> 8); /* second in %dh */
+
+ now = hr * 3600 + min * 60 + sec;
+ if (now < lasttime)
+ now += 24 * 3600;
+ lasttime = now;
+
+ if (t != NULL)
+ *t = now;
+ return(now);
+}
+
+/*
+ * Use the BIOS Wait function to pause for (period) microseconds.
+ *
+ * Resolution of this function is variable, but typically around
+ * 1ms.
+ */
+void
+delay(int period)
+{
+ v86.ctl = 0;
+ v86.addr = 0x15; /* int 0x15, function 0x86 */
+ v86.eax = 0x8600;
+ v86.ecx = period >> 16;
+ v86.edx = period & 0xffff;
+ v86int();
+}
diff --git a/sys/boot/i386/libi386/vidconsole.c b/sys/boot/i386/libi386/vidconsole.c
new file mode 100644
index 0000000..05e7711
--- /dev/null
+++ b/sys/boot/i386/libi386/vidconsole.c
@@ -0,0 +1,627 @@
+/*
+ * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
+ * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
+ *
+ * $Id: vidconsole.c,v 1.10 1998/12/31 13:44:04 abial Exp $
+ */
+
+#include <stand.h>
+#include <bootstrap.h>
+#include <btxv86.h>
+#include <machine/psl.h>
+#include "libi386.h"
+
+#if KEYBOARD_PROBE
+#include <machine/cpufunc.h>
+
+static int probe_keyboard(void);
+#endif
+static void vidc_probe(struct console *cp);
+static int vidc_init(int arg);
+static void vidc_putchar(int c);
+static int vidc_getchar(void);
+static int vidc_ischar(void);
+
+static int vidc_started;
+
+#ifdef TERM_EMU
+void end_term();
+void bail_out(int c);
+void vidc_term_emu(int c);
+void get_pos(void);
+void curs_move(int x, int y);
+void write_char(int c, int fg, int bg);
+void scroll_up(int rows, int fg, int bg);
+void AB(void);
+void AF(void);
+void CD(void);
+void CM(void);
+void HO(void);
+void ME(void);
+
+static int args[2],argc,br;
+static int fg,bg,dig;
+static int fg_c,bg_c,curx,cury;
+static int esc;
+#endif
+
+
+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;
+
+ if (vidc_started && arg == 0)
+ return;
+ vidc_started = 1;
+#ifdef TERM_EMU
+ /* Init terminal emulator */
+ end_term();
+ get_pos();
+ curs_move(curx,cury);
+ fg_c=7;
+ bg_c=0;
+#endif
+ for(i = 0; i < 10 && vidc_ischar(); i++)
+ (void)vidc_getchar();
+ return(0); /* XXX reinit? */
+}
+
+static void
+vidc_biosputchar(int c)
+{
+ v86.ctl = 0;
+ v86.addr = 0x10;
+ v86.eax = 0xe00 | (c & 0xff);
+ v86.ebx = 0x7;
+ v86int();
+}
+
+static void
+vidc_rawputchar(int c)
+{
+ int i;
+
+ if(c == '\t')
+ /* lame tab expansion */
+ for (i = 0; i < 8; i++)
+ vidc_rawputchar(' ');
+ else {
+#ifndef TERM_EMU
+ vidc_biosputchar(c);
+#else
+ /* Emulate AH=0eh (teletype output) */
+ switch(c) {
+ case '\a':
+ vidc_biosputchar(c);
+ return;
+ case '\r':
+ curx=0;
+ curs_move(curx,cury);
+ return;
+ case '\n':
+ cury++;
+ if(cury>24) {
+ scroll_up(1,fg_c,bg_c);
+ cury--;
+ } else {
+ curs_move(curx,cury);
+ }
+ return;
+ case '\b':
+ if(curx>0) {
+ curx--;
+ curs_move(curx,cury);
+ /* write_char(' ',fg_c,bg_c); XXX destructive(!) */
+ return;
+ }
+ return;
+ default:
+ write_char(c,fg_c,bg_c);
+ curx++;
+ if(curx>79) {
+ curx=0;
+ cury++;
+ }
+ if(cury>24) {
+ curx=0;
+ scroll_up(1,fg_c,bg_c);
+ cury--;
+ }
+ }
+ curs_move(curx,cury);
+#endif
+ }
+}
+
+#ifdef TERM_EMU
+
+/* Get cursor position on the screen. Result is in edx. Sets
+ * curx and cury appropriately.
+ */
+void
+get_pos(void)
+{
+ v86.ctl = 0;
+ v86.addr = 0x10;
+ v86.eax = 0x0300;
+ v86.ebx = 0x0;
+ v86int();
+ curx=v86.edx & 0x00ff;
+ cury=(v86.edx & 0xff00)>>8;
+}
+
+/* Move cursor to x rows and y cols (0-based). */
+void
+curs_move(int x, int y)
+{
+ v86.ctl = 0;
+ v86.addr = 0x10;
+ v86.eax = 0x0200;
+ v86.ebx = 0x0;
+ v86.edx = ((0x00ff & y)<<8)+(0x00ff & x);
+ v86int();
+ curx=x;
+ cury=y;
+ /* If there is ctrl char at this position, cursor would be invisible.
+ * Make it a space instead.
+ */
+ v86.ctl=0;
+ v86.addr = 0x10;
+ v86.eax = 0x0800;
+ v86.ebx= 0x0;
+ v86int();
+#define isvisible(c) (((c)>32) && ((c)<255))
+ if(!isvisible(v86.eax & 0x00ff)) {
+ write_char(' ',fg_c,bg_c);
+ }
+}
+
+/* Scroll up the whole window by a number of rows. If rows==0,
+ * clear the window. fg and bg are attributes for the new lines
+ * inserted in the window.
+ */
+void
+scroll_up(int rows, int fg, int bg)
+{
+ if(rows==0) rows=25;
+ v86.ctl = 0;
+ v86.addr = 0x10;
+ v86.eax = 0x0600+(0x00ff & rows);
+ v86.ebx = (bg<<12)+(fg<<8);
+ v86.ecx = 0x0;
+ v86.edx = 0x184f;
+ v86int();
+}
+
+/* Write character and attribute at cursor position. */
+void
+write_char(int c, int fg, int bg)
+{
+ v86.ctl=0;
+ v86.addr = 0x10;
+ v86.eax = 0x0900+(0x00ff & c);
+ v86.ebx = (bg<<4)+fg;
+ v86.ecx = 0x1;
+ v86int();
+}
+
+/* Calculate power of 10 */
+int
+pow10(int i)
+{
+ int res=1;
+
+ while(i-->0) {
+ res*=10;
+ }
+ return res;
+}
+
+/**************************************************************/
+/*
+ * Screen manipulation functions. They use accumulated data in
+ * args[] and argc variables.
+ *
+ */
+
+/* Set background color */
+void
+AB(void){
+ bg_c=args[0];
+ end_term();
+}
+
+/* Set foreground color */
+void
+AF(void)
+{
+ fg_c=args[0];
+ end_term();
+}
+
+/* Clear display from current position to end of screen */
+void
+CD(void)
+{
+ get_pos();
+ v86.ctl = 0;
+ v86.addr = 0x10;
+ v86.eax = 0x0600;
+ v86.ebx = (bg_c<<4)+fg_c;
+ v86.ecx = v86.edx;
+ v86.edx = 0x184f;
+ v86int();
+ curx=0;
+ curs_move(curx,cury);
+ end_term();
+}
+
+/* Absolute cursor move to args[0] rows and args[1] columns
+ * (the coordinates are 1-based).
+ */
+void
+CM(void)
+{
+ if(args[0]>0) args[0]--;
+ if(args[1]>0) args[1]--;
+ curs_move(args[1],args[0]);
+ end_term();
+}
+
+/* Home cursor (left top corner) */
+void
+HO(void)
+{
+ argc=1;
+ args[0]=args[1]=1;
+ CM();
+}
+
+/* Exit attribute mode (reset fore/back-ground colors to defaults) */
+void
+ME(void)
+{
+ fg_c=7;
+ bg_c=0;
+ end_term();
+}
+
+/* Clear internal state of the terminal emulation code */
+void
+end_term(void)
+{
+ esc=0;
+ argc=-1;
+ fg=bg=br=0;
+ args[0]=args[1]=0;
+ dig=0;
+}
+
+/* Gracefully exit ESC-sequence processing in case of misunderstanding */
+void
+bail_out(int c)
+{
+ char buf[6],*ch;
+
+ if(esc) vidc_rawputchar('\033');
+ if(br) vidc_rawputchar('[');
+ if(argc>-1) {
+ sprintf(buf,"%d",args[0]);
+ ch=buf;
+ while(*ch) vidc_rawputchar(*ch++);
+
+ if(argc>0) {
+ vidc_rawputchar(';');
+ sprintf(buf,"%d",args[1]);
+ ch=buf;
+ while(*ch) vidc_rawputchar(*ch++);
+ }
+ }
+ vidc_rawputchar(c);
+ end_term();
+}
+
+/* Emulate basic capabilities of cons25 terminal */
+void
+vidc_term_emu(int c)
+{
+
+ if(!esc) {
+ if(c=='\033') {
+ esc=1;
+ } else {
+ vidc_rawputchar(c);
+ }
+ return;
+ }
+
+ /* Do ESC sequences processing */
+ switch(c) {
+ case '\033':
+ /* ESC in ESC sequence - error */
+ bail_out(c);
+ break;
+ case '[':
+ /* Check if it's first char after ESC */
+ if(argc<0) {
+ br=1;
+ } else {
+ bail_out(c);
+ }
+ break;
+ case 'H':
+ /* Emulate \E[H (cursor home) and
+ * \E%d;%dH (cursor absolute move) */
+ if(br) {
+ switch(argc) {
+ case -1:
+ HO();
+ break;
+ case 1:
+ if(fg) args[0]+=pow10(dig)*3;
+ if(bg) args[0]+=pow10(dig)*4;
+ CM();
+ break;
+ default:
+ bail_out(c);
+ }
+ } else bail_out(c);
+ break;
+ case 'J':
+ /* Emulate \EJ (clear to end of screen) */
+ if(br && argc<0) {
+ CD();
+ } else bail_out(c);
+ break;
+ case ';':
+ /* perhaps args separator */
+ if(br && (argc>-1)) {
+ argc++;
+ } else bail_out(c);
+ break;
+ case 'm':
+ /* Change char attributes */
+ if(br) {
+ switch(argc) {
+ case -1:
+ ME();
+ break;
+ case 0:
+ if(fg) AF();
+ else AB();
+ break;
+ default:
+ bail_out(c);
+ }
+ } else bail_out(c);
+ break;
+ default:
+ if(isdigit(c)) {
+ /* Carefully collect numeric arguments */
+ /* XXX this is ugly. */
+ if(br) {
+ if(argc==-1) {
+ argc=0;
+ args[argc]=0;
+ dig=0;
+ /* in case we're in error... */
+ if(c=='3') {
+ fg=1;
+ return;
+ }
+ if(c=='4') {
+ bg=1;
+ return;
+ }
+ args[argc]=(int)(c-'0');
+ dig=1;
+ args[argc+1]=0;
+ } else {
+ args[argc]=args[argc]*10+(int)(c-'0');
+ if(argc==0) dig++;
+ }
+ } else bail_out(c);
+ } else bail_out(c);
+ break;
+ }
+}
+#endif
+
+static void
+vidc_putchar(int c)
+{
+#ifdef TERM_EMU
+ vidc_term_emu(c);
+#else
+ vidc_rawputchar(c);
+#endif
+}
+
+static int
+vidc_getchar(void)
+{
+ if (vidc_ischar()) {
+ v86.ctl = 0;
+ v86.addr = 0x16;
+ v86.eax = 0x0;
+ v86int();
+ return(v86.eax & 0xff);
+ } else {
+ return(-1);
+ }
+}
+
+static int
+vidc_ischar(void)
+{
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x16;
+ v86.eax = 0x100;
+ v86int();
+ return(!(v86.efl & PSL_Z));
+}
+
+#if KEYBOARD_PROBE
+
+#define PROBE_MAXRETRY 5
+#define PROBE_MAXWAIT 400
+#define IO_DUMMY 0x84
+#define IO_KBD 0x060 /* 8042 Keyboard */
+
+/* selected defines from kbdio.h */
+#define KBD_STATUS_PORT 4 /* status port, read */
+#define KBD_DATA_PORT 0 /* data port, read/write
+ * also used as keyboard command
+ * and mouse command port
+ */
+#define KBDC_ECHO 0x00ee
+#define KBDS_ANY_BUFFER_FULL 0x0001
+#define KBDS_INPUT_BUFFER_FULL 0x0002
+#define KBD_ECHO 0x00ee
+
+/* 7 microsec delay necessary for some keyboard controllers */
+static void
+delay7(void)
+{
+ /*
+ * I know this is broken, but no timer is available yet at this stage...
+ * See also comments in `delay1ms()'.
+ */
+ inb(IO_DUMMY); inb(IO_DUMMY);
+ inb(IO_DUMMY); inb(IO_DUMMY);
+ inb(IO_DUMMY); inb(IO_DUMMY);
+}
+
+/*
+ * This routine uses an inb to an unused port, the time to execute that
+ * inb is approximately 1.25uS. This value is pretty constant across
+ * all CPU's and all buses, with the exception of some PCI implentations
+ * that do not forward this I/O adress to the ISA bus as they know it
+ * is not a valid ISA bus address, those machines execute this inb in
+ * 60 nS :-(.
+ *
+ */
+static void
+delay1ms(void)
+{
+ int i = 800;
+ while (--i >= 0)
+ (void)inb(0x84);
+}
+
+/*
+ * We use the presence/absence of a keyboard to determine whether the internal
+ * console can be used for input.
+ *
+ * Perform a simple test on the keyboard; issue the ECHO command and see
+ * if the right answer is returned. We don't do anything as drastic as
+ * full keyboard reset; it will be too troublesome and take too much time.
+ */
+static int
+probe_keyboard(void)
+{
+ int retry = PROBE_MAXRETRY;
+ int wait;
+ int i;
+
+ while (--retry >= 0) {
+ /* flush any noise */
+ while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
+ delay7();
+ inb(IO_KBD + KBD_DATA_PORT);
+ delay1ms();
+ }
+
+ /* wait until the controller can accept a command */
+ for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
+ if (((i = inb(IO_KBD + KBD_STATUS_PORT))
+ & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0)
+ break;
+ if (i & KBDS_ANY_BUFFER_FULL) {
+ delay7();
+ inb(IO_KBD + KBD_DATA_PORT);
+ }
+ delay1ms();
+ }
+ if (wait <= 0)
+ continue;
+
+ /* send the ECHO command */
+ outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
+
+ /* wait for a response */
+ for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
+ if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)
+ break;
+ delay1ms();
+ }
+ if (wait <= 0)
+ continue;
+
+ delay7();
+ i = inb(IO_KBD + KBD_DATA_PORT);
+#ifdef PROBE_KBD_BEBUG
+ printf("probe_keyboard: got 0x%x.\n", i);
+#endif
+ if (i == KBD_ECHO) {
+ /* got the right answer */
+ return (0);
+ }
+ }
+
+ return (1);
+}
+#endif /* KEYBOARD_PROBE */
diff --git a/sys/boot/i386/loader/Makefile b/sys/boot/i386/loader/Makefile
new file mode 100644
index 0000000..07cb6b2
--- /dev/null
+++ b/sys/boot/i386/loader/Makefile
@@ -0,0 +1,126 @@
+# $Id: Makefile,v 1.33 1999/04/24 17:25:35 dcs Exp $
+
+BASE= loader
+PROG= ${BASE}
+MAN5= ../../forth/loader.conf.5
+MAN8= loader.8 ../../forth/loader.4th.8
+#NOMAN=
+STRIP=
+NEWVERSWHAT= "bootstrap loader"
+BINDIR?= /boot
+
+# architecture-specific loader code
+SRCS= main.c conf.c
+
+# Enable PnP and ISA-PnP code.
+HAVE_PNP= yes
+HAVE_ISABUS= yes
+
+# Enable BootForth
+BOOT_FORTH= yes
+CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl
+.if exists(${.OBJDIR}/../../ficl/libficl.a)
+LIBFICL= ${.OBJDIR}/../../ficl/libficl.a
+.else
+LIBFICL= ${.CURDIR}/../../ficl/libficl.a
+.endif
+
+# Always add MI sources
+.PATH: ${.CURDIR}/../../common
+.include <${.CURDIR}/../../common/Makefile.inc>
+CFLAGS+= -I${.CURDIR}/../../common
+CFLAGS+= -I${.CURDIR}/../../.. -I.
+
+CLEANFILES+= vers.c vers.o ${BASE}.list ${BASE}.bin ${BASE}.sym ${BASE}.help
+
+CFLAGS+= -Wall
+LDFLAGS= -nostdlib -static -Ttext 0x0
+
+# i386 standalone support library
+LIBI386= ${.OBJDIR}/../libi386/libi386.a
+CFLAGS+= -I${.CURDIR}/..
+
+# where to get libstand from
+LIBSTAND= -lstand
+#LIBSTAND= ${.CURDIR}/../../../lib/libstand/libstand.a
+#CFLAGS+= -I${.CURDIR}/../../../lib/libstand/
+
+# BTX components
+.if exists(${.OBJDIR}/../btx)
+BTXDIR= ${.OBJDIR}/../btx
+.else
+BTXDIR= ${.CURDIR}/../btx
+.endif
+BTXLDR= ${BTXDIR}/btxldr/btxldr
+BTXKERN= ${BTXDIR}/btx/btx
+BTXCRT= ${BTXDIR}/lib/crt0.o
+CFLAGS+= -I${.CURDIR}/../btx/lib
+
+# BTX is expecting ELF components
+CFLAGS+= -elf
+
+# New linker set code
+CFLAGS+= -DNEW_LINKER_SET
+
+# Debug me!
+#CFLAGS+= -g
+#LDFLAGS+= -g
+
+vers.o:
+ sh ${.CURDIR}/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
+ ${CC} -c vers.c
+
+${BASE}: ${BASE}.bin ${BTXLDR} ${BTXKERN} ${BTXCRT} ${BASE}.help
+ btxld -v -f aout -e 0x100000 -o ${.TARGET} -l ${BTXLDR} -b ${BTXKERN} \
+ ${BASE}.bin
+# /usr/bin/kzip ${.TARGET}
+# mv ${.TARGET}.kz ${.TARGET}
+
+${BASE}.bin: ${BASE}.sym
+ cp ${.ALLSRC} ${.TARGET}
+ strip ${.TARGET}
+
+${BASE}.help: help.common help.i386
+ cat ${.ALLSRC} | awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET}
+
+beforeinstall:
+.if exists(${DESTDIR}/boot/loader)
+ mv ${DESTDIR}/boot/loader ${DESTDIR}/boot/loader.old
+.endif
+.if exists(${.OBJDIR}/loader.help)
+ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${.OBJDIR}/${BASE}.help ${DESTDIR}/boot
+.else
+ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${.CURDIR}/${BASE}.help ${DESTDIR}/boot
+.endif
+.if !exists(${DESTDIR}/boot/loader.rc)
+ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${.CURDIR}/../../forth/loader.rc ${DESTDIR}/boot
+.endif
+ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${.CURDIR}/../../forth/loader.4th ${DESTDIR}/boot
+ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${.CURDIR}/../../forth/support.4th ${DESTDIR}/boot
+ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${.CURDIR}/../../forth/loader.conf ${DESTDIR}/boot/defaults
+
+# Cannot use ${OBJS} above this line
+.include <bsd.prog.mk>
+
+${BASE}.sym: ${OBJS} ${LIBI386} ${LIBSTAND} ${LIBFICL} vers.o
+ ${CC} ${LDFLAGS} -o ${.TARGET} ${BTXCRT} ${OBJS} vers.o \
+ ${LIBFICL} ${LIBSTAND} ${LIBI386} ${LIBSTAND}
+
+# If it's not there, don't consider it a target
+.if exists(${.CURDIR}/../../../i386/include)
+beforedepend ${OBJS}: machine
+
+machine:
+ ln -sf ${.CURDIR}/../../../i386/include machine
+
+.endif
+
+CLEANFILES+= machine
+
+
diff --git a/sys/boot/i386/loader/conf.c b/sys/boot/i386/loader/conf.c
new file mode 100644
index 0000000..9b4d554
--- /dev/null
+++ b/sys/boot/i386/loader/conf.c
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: conf.c,v 1.9 1998/10/22 20:23:58 msmith Exp $
+ */
+
+#include <stand.h>
+#include <bootstrap.h>
+#include "libi386/libi386.h"
+
+/*
+ * We could use linker sets for some or all of these, but
+ * then we would have to control what ended up linked into
+ * the bootstrap. So it's easier to conditionalise things
+ * here.
+ *
+ * XXX rename these arrays to be consistent and less namespace-hostile
+ *
+ * XXX as libi386 and biosboot merge, some of these can become linker sets.
+ */
+
+/* Exported for libstand */
+struct devsw *devsw[] = {
+ &biosdisk,
+ /* XXX network devices? */
+ NULL
+};
+
+struct fs_ops *file_system[] = {
+ &ufs_fsops,
+ &dosfs_fsops,
+ &zipfs_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 module_format i386_aout;
+extern struct module_format i386_elf;
+
+struct module_format *module_formats[] = {
+ &i386_elf,
+ &i386_aout,
+ 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;
+
+struct console *consoles[] = {
+ &vidconsole,
+ &comconsole,
+ NULL
+};
+
+extern struct pnphandler isapnphandler;
+extern struct pnphandler biospnphandler;
+extern struct pnphandler biospcihandler;
+
+struct pnphandler *pnphandlers[] = {
+ &biospnphandler, /* should go first, as it may set isapnp_readport */
+ &isapnphandler,
+ &biospcihandler,
+ NULL
+};
diff --git a/sys/boot/i386/loader/help.i386 b/sys/boot/i386/loader/help.i386
new file mode 100644
index 0000000..4e4ec8b
--- /dev/null
+++ b/sys/boot/i386/loader/help.i386
@@ -0,0 +1,46 @@
+################################################################################
+# Treboot DReboot the system
+
+ reboot
+
+ Causes the system to immediately reboot.
+
+################################################################################
+# Theap DDisplay memory management statistics
+
+ heap
+
+ Requests debugging output from the heap manager. For debugging use
+ only.
+
+################################################################################
+# Tset Snum_ide_disks DSet the number of IDE disks
+
+ NOTE: this variable is deprecated, use root_disk_unit instead.
+
+ set num_ide_disks=<value>
+
+ When booting from a SCSI disk on a system with one or more IDE disks,
+ and where the IDE disks are the default boot device, it is necessary
+ to tell the kernel how many IDE disks there are in order to have it
+ correctly locate the SCSI disk you are booting from.
+
+################################################################################
+# Tset Sboot_userconfig DStart Userconfig
+
+ set boot_userconfig
+
+ Requests that the kernel's interactive device configuration program
+ be run when the kernel is booted.
+
+################################################################################
+# Tset Sroot_disk_unit DForce the root disk unit number.
+
+ set root_disk_unit=<value>
+
+ If the code which detects the disk unit number for the root disk is
+ confused, eg. by a mix of SCSI and IDE disks, or IDE disks with
+ gaps in the sequence (eg. no primary slave), the unit number can be
+ forced by setting this variable.
+
+################################################################################
diff --git a/sys/boot/i386/loader/loader.8 b/sys/boot/i386/loader/loader.8
new file mode 100644
index 0000000..89a3ead
--- /dev/null
+++ b/sys/boot/i386/loader/loader.8
@@ -0,0 +1,753 @@
+.\" Copyright (c) 1999 Daniel C. Sobral
+.\" 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: loader.8,v 1.5 1999/05/11 11:20:13 jb Exp $
+.\"
+.\" Note: The date here should be updated whenever a non-trivial
+.\" change is made to the manual page.
+.Dd March 14, 1999
+.Dt LOADER 8
+.Os
+.Sh NAME
+.Nm loader
+.Nd system bootstrap stage three
+.Sh DESCRIPTION
+The program called
+.Nm
+is the third stage of FreeBSD's three stage bootstrap.
+It is a
+.Pa BTX
+client linked statically to
+.Xr libstand 3
+and usually located in the directory
+.Pa /boot .
+.Pp
+It provides a scripting language that can be used to
+automate tasks, do pre-configuration or assist in recovery
+procedures. This scripting language is roughly divided in
+two main components. The smaller one is a set of commands
+designed for direct use by the casual user, called "builtin
+commands" for historical reasons. The main drive behind
+these commands is user-friendlyness. The bigger component
+is an
+.Tn ANS
+Forth compatible Forth interpreter based on
+ficl, by
+.An John Sadler .
+.Pp
+During initialization,
+.Nm
+will probe for a console and set the
+.Va console
+variable, or set it to serial console
+.Pq Dq comconsole
+if the previous boot stage used that. Then, devices are probed,
+.Va currdev
+and
+.Va loaddev
+are set, and
+.Va LINES
+is set to 24 . Next,
+.Tn FICL
+is initialized, the builtin words are added to it's vocabulary, and
+.Pa /boot/boot.4th
+will be processed if it exists. No disk switching is possible while
+that file is being read. The inner interpreter
+.Nm
+will use with
+.Tn FICL
+is then set to
+.Ic interpret ,
+which is
+.Tn FICL Ns 's
+default. After that,
+.Pa /boot/loader.rc
+is processed if available, and, failing that,
+.Pa /boot/boot.conf
+will be read for historical reasons. These files are processed
+through the
+.Ic include
+command, which read all of them into memory before processing them,
+making disk changes possible.
+.Pp
+At this point, if an
+.Ic autoboot
+has not been tried, and if
+.Va autoboot_delay
+is not set to
+.Dq NO
+(not case sensitive), then an
+.Ic autoboot
+will be tried. If the system gets past this point,
+.Va prompt
+will be set and
+.Nm
+will engage interactive mode.
+.Sh BUILTIN COMMANDS
+.Nm Loader Ns No 's
+builtin commands take it's parameters from the command line. Presently,
+the only way to call them from a script is by using
+.Pa evaluate
+on a string. If an error condition occurs, an exception will be
+generated, which can be intercepted using
+.Tn ANS
+Forth exception handling
+words. If not intercepted, an error message will be displayed and
+the interpreter's state will be reset, emptying the stack and restoring
+interpreting mode.
+.Pp
+The builtin commands available are:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ic autoboot Op Ar seconds
+Proceeds to bootstrap the system after a number of seconds, if not
+interrupted by the user. Displays a countdown prompt warning the
+user the system is about to be booted, unless interrupted by a key
+press. The kernel will be loaded first if necessary. Defaults to
+10 seconds.
+.Pp
+.It Ic bcachestat
+Displays statistics about disk cache usage. For depuration only.
+.Pp
+.It Ic boot
+.It Ic boot Ar kernelname Op Cm ...
+.It Ic boot Fl flag Cm ...
+Immediately proceeds to bootstrap the system, loading the kernel
+if necessary. Any flags or arguments are passed to the kernel, but they
+must precede the kernel name, if a kernel name is provided.
+.Pp
+.It Ic echo Xo
+.Op Fl n
+.Op Aq message
+.Xc
+Displays a text on the screen. A new line will be printed unless
+.Fl n
+is specified.
+.Pp
+.It Ic heap
+Displays memory usage statistics. For debugging purposes only.
+.Pp
+.It Ic help Op topic Op subtopic
+Shows help messages read from
+.Pa /boot/loader.help .
+The special topic
+.Em index
+will list the topics available.
+.Pp
+.It Ic include Ar file Op Ar
+Process script files. Each file is, at a turn, completely read into
+memory, and then have each of it's lines passed to the command line
+interpreter. If any error is returned by the interpreter, the include
+commands aborts immediately, without reading any other files, and
+returns an error itself (see
+.Sx ERRORS ) .
+.Pp
+.It Ic load Xo
+.Op Fl t Ar type
+.Ar file Cm ...
+.Xc
+Loads a kernel, kernel loadable module (kld), or a file of opaque
+contents tagged as being of the type
+.Ar type .
+Kernel and modules can be either in a.out or elf format. Any arguments
+passed after the name of the file to be loaded will be passed as
+arguments to that file. Notice, though, that, at the present, this does
+not work for the kernel.
+.Pp
+.It Ic ls Xo
+.Op Fl l
+.Op Ar path
+.Xc
+Displays a listing of files in the directory
+.Ar path ,
+or the root directory if
+.Ar path
+is not specified. If
+.Fl l
+is specified, file sizes will be shown too.
+.Pp
+.It Ic lsdev Op Fl v
+Lists all of the devices from which it may be possible to load modules. If
+.Fl v
+is specified, more details are printed.
+.Pp
+.It Ic lsmod Op Fl v
+Displays loaded modules. If
+.Fl v
+is specified, more details are shown.
+.Pp
+.It Ic more Ar file Op Ar
+Display the files specified, with a pause at each
+.Va LINES
+displayed.
+.Pp
+.It Ic pnpscan Op Fl v
+Scans for Plug-and-Play devices. This is not functional at the present.
+.Pp
+.It Ic read Xo
+.Op Fl t Ar seconds
+.Op Fl p Ar prompt
+.Op Va variable
+.Xc
+Reads a line of input from the terminal, storing it in
+.Va variable
+if specified. A timeout can be specified with
+.Fl t ,
+though it will be canceled at the first key pressed. A prompt may
+also be displayed through the
+.Fl p
+flag.
+.Pp
+.It Ic reboot
+Immediately reboots the system.
+.Pp
+.It Ic set Ar variable
+.It Ic set Ar variable Ns = Ns Ar value
+Set loader's environment variables.
+.Pp
+.It Ic show Op Va variable
+Displays the specified variable's value, or all variables and their
+values if
+.Va variable
+is not specified.
+.Pp
+.It Ic unload
+Remove all modules from memory.
+.Pp
+.It Ic unset Va variable
+Removes
+.Va variable
+from the environment.
+.Pp
+.It Ic \&?
+Same as
+.Dq help index .
+.Pp
+.El
+.Ss BUILTIN ENVIRONMENT VARIABLES
+The
+.Nm
+has actually two different kinds of
+.Sq environment
+variables. There are ANS Forth's
+.Em environmental queries ,
+and a separate space of environment variables used by builtins, which
+are not directly available to Forth words. It is the later ones that
+this session covers.
+.Pp
+Environment variables can be set and unset through the use of the
+.Ic set
+and
+.Ic unset
+builtins, and have their value interactively examined through the
+use of the
+.Ic show
+builtin. Their values can also be accessed as described in
+.Sx BUILTIN PARSER .
+.Pp
+Notice that this environment variables are not inherited by any shell
+after the system has been booted.
+.Pp
+A few variables are set automatically by
+.Nm .
+Others can affect either
+.Nm
+or kernel's behavior at boot. While some of these may require a value,
+others define behavior just by being set. These are described below.
+.Bl -tag -width bootfile -offset indent
+.It Va autoboot_delay
+Number of seconds
+.Ic autoboot
+will wait before booting. If this variable is not defined,
+.Ic autoboot
+will default to 10 seconds.
+.Pp
+If set to
+.Dq NO ,
+no
+.Ic autoboot
+will be automatically attempted after processing
+.Pa /boot/loader.rc ,
+though explict
+.Ic autoboot Ns 's
+will be processed normally, defaulting to 10 seconds delay.
+.It Va boot_askname
+Instructs the kernel to prompt the user for the name of the root device
+when the kernel is booted.
+.It Va boot_ddb
+Instructs the kernel to start in the DDB debugger, rather than
+proceeding to initialise when booted.
+.It Va boot_gdb
+Selects gdb-remote mode for the kernel debugger by default.
+.It Va boot_single
+Prevents the kernel from initiating a multi-user startup, single-user
+mode will be entered when the kernel has finished device probes.
+.It Va boot_userconfig
+Requests that the kernel's interactive device configuration program
+be run when the kernel is booted.
+.It Va boot_verbose
+Setting this variable causes extra debugging information to be printed
+by the kernel during the boot phase.
+.It Va bootfile
+List of semicolon-separated search path for bootable kernels. The default
+is
+.Li Dq kernel;kernel.old .
+.It Va console
+Defines the current console.
+.It Va currdev
+Selects the default device. Syntax for devices is odd.
+.It Va init_path
+Sets the list of binaries which the kernel will try to run as initial
+process. The default is
+.Li Dq /sbin/init:/sbin/oinit:/sbin/init.bak:/stand/sysinstall .
+.It Va interpret
+Has the value
+.Li Dq ok
+if the Forth's current state is interpreting.
+.It Va LINES
+Define the number of lines on the screen, to be used by the pager.
+.It Va module_path
+Sets the list of directories which will be searched in for modules
+named in a load command or implicitly required by a dependancy. The
+default value for this variable is
+.Li Dq /;/boot;/modules .
+.It Va num_ide_disks
+Sets the number of IDE disks as a work around for some problems in
+finding the root disk at boot. This has been deprecated in favour of
+.Va root_disk_unit .
+.It Va prompt
+Value of
+.Nm Ns No 's
+prompt. Defaults to
+.Li Dq "${currdev}>" .
+.It Va 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.
+.It Va rootdev
+By default the value of
+.Va currdev
+is used to set the root filesystem
+when the kernel is booted. This can be overridden by setting
+.Va rootdev
+explicitly.
+.El
+.Pp
+Other variables are used to override kernel tunnable parameters.
+The following tunables are available:
+.Bl -tag -width Va -offset indent
+.It Va kern.ipc.nmbclusters
+Set the number of mbuf clusters to be allocated. The value
+cannot be set below the default determined when the kernel
+was compiled. Modifies
+.Va NMBCLUSTERS .
+.It Va kern.vm.kmem.size
+Sets the size of kernel memory (bytes). This overrides
+completely the value determined when the kernel was
+compiled. Modifies
+.Va VM_KMEM_SIZE .
+.It Va machdep.pccard.pcic_irq
+Overrides the IRQ normally assigned to a PCCARD controller.
+Typically the first available interrupt will be allocated,
+which may conflict with other hardware. If this value is
+set to 0, an interrupt will not be assigned and the
+controller will operate in polled mode only.
+.It Va net.inet.tcp.tcbhashsize
+Overrides the compile-time set value of
+.Va TCBHASHSIZE
+or the preset default of 512. Must be a power of 2.
+.El
+.Ss BUILTIN PARSER
+When a builtin command is executed, the rest of the line is taken
+by it as arguments, and it's processed by a special parser which
+is not used for regular Forth commands.
+.Pp
+This special parser applies the following rules to the parsed text:
+.Pp
+.Bl -enum
+.It
+All backslash characters are preprocessed.
+.Bl -bullet
+.It
+\eb , \ef , \er , \en and \et are processed as by C's
+.Fn printf .
+.It
+\es is converted to a space.
+.It
+\ev is converted to
+.Tn ASCII
+11.
+.It
+\ez is just skipped. Useful for things like
+.Dq \e0xf\ez\e0xf .
+.It
+\e0xN and \e0xNN are replaced by the hex N or NN.
+.It
+\eNNN is replaced by the octal NNN
+.Tn ASCII
+character.
+.It
+\e" , \e' and \e$ will escape these characters, preventing them from
+receiving special semantics on the step 2 described below.
+.It
+\e\e will be replaced with a single \e .
+.It
+In any other occurance, backslash will just be removed.
+.El
+.It
+Every string between non-escaped quotes or double-quotes will be treated
+as a single word for the purposes of the remaining steps.
+.It
+Replace any
+.Li $VARIABLE
+or
+.Li ${VARIABLE}
+with the value of the environemnt variable
+.Va VARIABLE .
+.It
+Passes multiple space-delimited arguments to the builtin command called.
+Spaces can also be escaped through the use of \e\e .
+.El
+.Pp
+An exception to this parsing rule exists, and is described in
+.Sx BUILTINS AND FORTH .
+.Ss BUILTINS AND FORTH
+All builtin words are state-smart, immediate words. If interpreted, they
+behave exactly as described previously. If they are compiled, though,
+they extract their arguments from the stack instead of the command line.
+.Pp
+If compiled, the builtin words expect to find, at execution time, the
+following parameters on the stack:
+.D1 Ar addrN lenN ... addr2 len2 addr1 len1 N
+where
+.Ar addrX lenX
+are strings which will compose the command line that will be parsed
+into the builtin's arguments. Internally, these strings are
+concatenated in from 1 to N, with a space put between each one.
+.Pp
+If no arguments are passed, a 0
+.Em must
+be passed, even if the builtin accepts no arguments.
+.Pp
+While this behavior has benefits, it has it's trade-offs. If the
+execution token of a builtin is acquired (through
+.Ic No '
+or
+.Ic No ['] ) ,
+and then passed to
+.Ic catch
+or
+.Ic execute ,
+the builtin behavior will depend on the system state
+.Bf Em
+at the time
+.Ic catch
+or
+.Ic execute
+is processed
+.Ef
+\&! This is particular annoying for programs that want or need to
+treat exceptions. In this case, it is recommended the use of a proxy.
+For example:
+.Dl : (boot) boot ;
+.Sh FICL
+.Tn FICL
+is a Forth interpreter written in C, in the form of a forth
+virtual machine library that can be called by C functions and vice
+versa.
+.Pp
+In
+.Nm No ,
+each line read interactively is then fed to
+.Tn FICL ,
+which may call
+.Nm
+back to execute the builtin words. The builtin
+.Ic include
+will also feed
+.Tn FICL ,
+one line at a time.
+.Pp
+The words available to
+.Tn FICL
+can be classified in four groups. The
+.Tn ANS
+Forth standard words, extra
+.Tn FICL
+words, extra
+.Os
+words, and the builtin commands. The later were already described. The
+.Tn ANS
+Forth standard words are listed in the
+.Sx STANDARDS
+section. The words falling in the two other groups are described in the
+following subsections.
+.Ss FICL EXTRA WORDS
+.Bl -tag -width wid-set-super -offset indent
+.It Ic .env
+.It Ic .ver
+.It Ic -roll
+.It Ic 2constant
+.It Ic >name
+.It Ic body>
+.It Ic compare
+This the STRING word set's
+.Ic compare .
+.It Ic compile-only
+.It Ic endif
+.It Ic forget-wid
+.It Ic parse-word
+.It Ic sliteral
+This is the STRING word set's
+.Ic sliteral .
+.It Ic wid-set-super
+.It Ic w@
+.It Ic w!
+.It Ic x.
+.It Ic empty
+.It Ic cell-
+.It Ic -rot
+.El
+.Ss FREEBSD EXTRA WORDS
+.Bl -tag -width XXXXXXX -offset indent
+.It Ic tib> Pq -- Ar addr len
+Returns the remainder of the input buffer as a string on the stack.
+.It Ic \&% Pq --
+Evaluates the remainder of the input buffer under a
+.Ic catch
+exception guard.
+.It Ic \&$ Pq --
+Evaluates the remainder of the input buffer, after having printed it first.
+.It Ic fopen Pq Ar addr len -- fd
+Open a file. Returns a file descriptor, or -1 in case of failure.
+.It Ic fclose Pq Ar fd --
+Closes a file.
+.It Xo
+.Ic fread
+.Pq Ar fd addr len -- len'
+.Xc
+Tries to read
+.Em len
+bytes from file
+.Em fd
+into buffer
+.Em addr .
+Returns the actual number of bytes read, or -1 in case of error or end of
+file.
+.It Ic fload Pq Ar fd --
+Process file
+.Em fd .
+.It Ic fkey Pq Ar fd -- char
+Reads a single character from a file.
+.It Ic key Pq -- Ar char
+Reads a single character from the console.
+.It Ic key? Pq -- Ar flag
+Returns
+.Ic true
+if there is a character available to be read from the console.
+.It Ic ms Pq Ar u --
+Waits
+.Em u
+microseconds.
+.It Ic seconds Pq -- Ar u
+Returns the number of seconds since midnight.
+.It Ic trace! Pq Ar flag --
+Activates or deactivates tracing. Does not work with
+.Ic catch .
+.It Ic outb Pq Ar port char --
+Writes a byte to a port.
+.It Ic inb Pq Ar port -- char
+Reads a byte from a port.
+.El
+.Ss FREEBSD DEFINED ENVIRONMENTAL QUERIES
+.Bl -tag -width Ds -offset indent
+.It arch-i386
+.Ic TRUE
+if the architecture is IA32.
+.It arch-alpha
+.Ic TRUE
+if the architecture is AXP.
+.It FreeBSD_version
+.Fx
+version at compile time.
+.It loader_version
+.Nm
+version.
+.El
+.Ss SYSTEM DOCUMENTATION
+.Sh FILES
+.Bl -tag -width /dev/loader.helpX -compact
+.It Pa /boot/loader
+.Nm
+itself.
+.It Pa /boot/boot.4th
+Additional
+.Tn FICL
+initialization.
+.It Pa /boot/boot.conf
+.Nm
+bootstrapping script. Deprecated.
+.It Pa /boot/loader.rc
+.Nm
+bootstrapping script.
+.It Pa /boot/loader.help
+Loaded by
+.Ic help .
+Contains the help messages.
+.El
+.Sh EXAMPLES
+Boot in single user mode:
+.Pp
+.Dl boot -s
+.Pp
+Loads kernel's user configuration file. Notice that a kernel must be
+loaded before any other
+.Ic load
+command is attempted.
+.Pp
+.Bd -literal -offset indent -compact
+load kernel
+load -t userconfig_script /boot/kernel.conf
+.Ed
+.Pp
+Loads the kernel, a splash screen, and then autoboots in five seconds.
+.Pp
+.Bd -literal -offset indent -compact
+load kernel
+load splash_bmp
+load -t splash_image_data /boot/chuckrulez.bmp
+autoboot 5
+.Ed
+.Pp
+Sets the disk unit of the root device to 2, and then boots. This would
+be needed in the case of a two IDE disks system, with the second IDE
+hardwired to wd2 instead of wd1.
+.Pp
+.Bd -literal -offset indent -compact
+set root_disk_unit=2
+boot /kernel
+.Ed
+.Pp
+See also:
+.Bl -tag -width /usr/share/examples/bootforth/X
+.It Pa /boot/loader.4th
+Extra builtin-like words.
+.It Pa /boot/support.4th
+.Pa loader.conf
+processing words.
+.It Pa /usr/share/examples/bootforth/
+Assorted examples.
+.El
+.Sh ERRORS
+The following values are thrown by
+.Nm :
+.Bl -tag -width XXXXX -offset indent
+.It 100
+Any type of error in the processing of a builtin.
+.It -1
+.Ic Abort
+executed.
+.It -2
+.Ic Abort"
+executed.
+.It -56
+.Ic Quit
+executed.
+.It -256
+Out of interpreting text.
+.It -257
+Need more text to succeed -- will finish on next run.
+.It -258
+.Ic Bye
+executed.
+.It -259
+Unspecified error.
+.El
+.Sh SEE ALSO
+.Xr libstand 3 ,
+.Xr loader.conf 5 ,
+.Xr boot 8 ,
+.Xr btxld 8
+.Sh STANDARDS
+For the purposes of ANS Forth compliance, loader is an
+.Bf Em
+ANS Forth System with Environmental Restrictions, Providing
+.Ef
+.Bf Li
+.No .( ,
+.No :noname ,
+.No ?do ,
+parse, pick, roll, refill, to, value, \e, false, true,
+.No <> ,
+.No 0<> ,
+compile\&, , erase, nip, tuck
+.Ef
+.Em and
+.Li marker
+.Bf Em
+from the Core Extensions word set, Providing the Exception Extensions
+word set, Providing the Locals Extensions word set, Providing the
+Memory-Allocation Extensions word set, Providing
+.Ef
+.Bf Li
+\&.s ,
+bye, forget, see, words,
+\&[if] ,
+\&[else]
+.Ef
+.Em and
+.Li No [then]
+.Bf Em
+from the Programming-Tools extension word set, Providing the
+Search-Order extensions word set.
+.Ef
+.Sh HISTORY
+.Nm
+first appeared in
+.Fx 3.1 .
+.Sh AUTHORS
+.Bl -item
+.It
+.Nm
+was written by
+.An Michael Smith Aq msmith@freebsd.org .
+.It
+.Tn FICL
+was written by
+.An John Sadler Aq john_sadler@alum.mit.edu .
+.El
+.Sh BUGS
+.Tn FICL
+is case sensitive. Though this is not a standard violation, all Forth
+words are lower cased, which would result in a standard violation. Do
+not rely on this bug.
+.Pp
+The
+.Ic expect
+and
+.Ic accept
+words will read from the input buffer instead of the console. The later
+will be fixed, but the former will not.
+
diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c
new file mode 100644
index 0000000..dfd1bff
--- /dev/null
+++ b/sys/boot/i386/loader/main.c
@@ -0,0 +1,233 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: main.c,v 1.13 1998/10/22 20:23:58 msmith Exp $
+ */
+
+/*
+ * MD bootstrap main() and assorted miscellaneous
+ * commands.
+ */
+
+#include <stand.h>
+#include <string.h>
+#include <machine/bootinfo.h>
+#include <sys/reboot.h>
+
+#include "bootstrap.h"
+#include "libi386/libi386.h"
+#include "btxv86.h"
+
+/* Arguments passed in from the boot1/boot2 loader */
+static struct
+{
+ u_int32_t howto;
+ u_int32_t bootdev;
+ u_int32_t res0;
+ u_int32_t res1;
+ u_int32_t res2;
+ u_int32_t bootinfo;
+} *kargs;
+
+static u_int32_t initial_howto;
+static u_int32_t initial_bootdev;
+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);
+
+/* from vers.c */
+extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
+
+/* XXX debugging */
+extern char end[];
+
+void
+main(void)
+{
+ int i;
+
+ /* Pick up arguments */
+ kargs = (void *)__args;
+ initial_howto = kargs->howto;
+ initial_bootdev = kargs->bootdev;
+ initial_bootinfo = (struct bootinfo *)PTOV(kargs->bootinfo);
+
+ /*
+ * Initialise the heap as early as possible. Once this is done, malloc() is usable.
+ *
+ * XXX better to locate end of memory and use that
+ */
+ setheap((void *)end, (void *)(end + (384 * 1024)));
+
+ /*
+ * XXX Chicken-and-egg problem; we want to have console output early, but some
+ * console attributes may depend on reading from eg. the boot device, which we
+ * can't do yet.
+ *
+ * We can use printf() etc. once this is done.
+ * If the previous boot stage has requested a serial console, prefer that.
+ */
+ if (initial_howto & RB_SERIAL)
+ setenv("console", "comconsole", 1);
+ cons_probe();
+
+ /*
+ * Initialise the block cache
+ */
+ bcache_init(32, 512); /* 16k cache XXX tune this */
+
+ /*
+ * March through the device switch probing for things.
+ */
+ for (i = 0; devsw[i] != NULL; i++)
+ if (devsw[i]->dv_init != NULL)
+ (devsw[i]->dv_init)();
+
+ printf("\n");
+ printf("%s, Revision %s %d/%dkB\n", bootprog_name, bootprog_rev, getbasemem(), getextmem());
+ printf("(%s, %s)\n", bootprog_maker, bootprog_date);
+
+ extract_currdev(); /* set $currdev and $loaddev */
+ setenv("LINES", "24", 1); /* optional */
+
+ archsw.arch_autoload = i386_autoload;
+ archsw.arch_getdev = i386_getdev;
+ archsw.arch_copyin = i386_copyin;
+ archsw.arch_copyout = i386_copyout;
+ archsw.arch_readin = i386_readin;
+ archsw.arch_isainb = isa_inb;
+ archsw.arch_isaoutb = isa_outb;
+
+ interact(); /* doesn't return */
+}
+
+/*
+ * Set the 'current device' by (if possible) recovering the boot device as
+ * supplied by the initial bootstrap.
+ *
+ * XXX should be extended for netbooting.
+ */
+static void
+extract_currdev(void)
+{
+ struct i386_devdesc currdev;
+ int major, biosdev;
+
+ /* We're booting from a BIOS disk, try to spiff this */
+ currdev.d_dev = devsw[0]; /* XXX presumes that biosdisk is first in devsw */
+ currdev.d_type = currdev.d_dev->dv_type;
+
+ if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) {
+ /* The passed-in boot device is bad */
+ currdev.d_kind.biosdisk.slice = -1;
+ currdev.d_kind.biosdisk.partition = 0;
+ biosdev = -1;
+ } else {
+ currdev.d_kind.biosdisk.slice = (B_ADAPTOR(initial_bootdev) << 4) + B_CONTROLLER(initial_bootdev) - 1;
+ currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev);
+ biosdev = initial_bootinfo->bi_bios_dev;
+ major = B_TYPE(initial_bootdev);
+
+ /*
+ * If we are booted by an old bootstrap, we have to guess at the BIOS
+ * unit number. We will loose if there is more than one disk type
+ * and we are not booting from the lowest-numbered disk type
+ * (ie. SCSI when IDE also exists).
+ */
+ if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */
+ biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */
+ }
+
+ if ((currdev.d_kind.biosdisk.unit = bd_bios2unit(biosdev)) == -1) {
+ printf("Can't work out which disk we are booting from.\n"
+ "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev);
+ currdev.d_kind.biosdisk.unit = 0;
+ }
+ env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&currdev), i386_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&currdev), env_noset, env_nounset);
+}
+
+COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
+
+static int
+command_reboot(int argc, char *argv[])
+{
+
+ printf("Rebooting...\n");
+ delay(1000000);
+ __exit(0);
+}
+
+/* provide this for panic, as it's not in the startup code */
+void
+exit(int code)
+{
+ __exit(code);
+}
+
+COMMAND_SET(heap, "heap", "show heap usage", command_heap);
+
+static int
+command_heap(int argc, char *argv[])
+{
+ mallocstats();
+ printf("heap base at %p, top at %p\n", end, sbrk(0));
+ return(CMD_OK);
+}
+
+/* ISA bus access functions for PnP, derived from <machine/cpufunc.h> */
+static int
+isa_inb(int port)
+{
+ u_char data;
+
+ if (__builtin_constant_p(port) &&
+ (((port) & 0xffff) < 0x100) &&
+ ((port) < 0x10000)) {
+ __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
+ } else {
+ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
+ }
+ return(data);
+}
+
+static void
+isa_outb(int port, int value)
+{
+ u_char al = value;
+
+ if (__builtin_constant_p(port) &&
+ (((port) & 0xffff) < 0x100) &&
+ ((port) < 0x10000)) {
+ __asm __volatile("outb %0,%1" : : "a" (al), "id" ((u_short)(port)));
+ } else {
+ __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
+ }
+}
+
diff --git a/sys/boot/i386/loader/newvers.sh b/sys/boot/i386/loader/newvers.sh
new file mode 100755
index 0000000..476913b
--- /dev/null
+++ b/sys/boot/i386/loader/newvers.sh
@@ -0,0 +1,46 @@
+#!/bin/sh -
+#
+# $NetBSD: newvers.sh,v 1.1 1997/07/26 01:50:38 thorpej Exp $
+#
+# Copyright (c) 1984, 1986, 1990, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)newvers.sh 8.1 (Berkeley) 4/20/94
+
+LC_TIME=C; export LC_TIME
+u=${USER-root} h=`hostname` t=`date`
+#r=`head -n 6 $1 | tail -n 1 | awk -F: ' { print $1 } '`
+r=`awk -F: ' /^[0-9]\.[0-9]+:/ { print $1; exit }' $1`
+
+echo "char bootprog_name[] = \"FreeBSD/i386 ${2}\";" > vers.c
+echo "char bootprog_rev[] = \"${r}\";" >> vers.c
+echo "char bootprog_date[] = \"${t}\";" >> vers.c
+echo "char bootprog_maker[] = \"${u}@${h}\";" >> vers.c
diff --git a/sys/boot/i386/loader/version b/sys/boot/i386/loader/version
new file mode 100644
index 0000000..ad31045
--- /dev/null
+++ b/sys/boot/i386/loader/version
@@ -0,0 +1,11 @@
+$Id: version,v 1.3 1999/02/08 04:14:31 dcs Exp $
+
+NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this
+file is important. Make sure the current version number is on line 6.
+
+0.7: Supports large KVM
+0.6: Increased dictionary size -- supports loader.4th
+0.5: First release version
+0.2: Initial integration with BTX
+0.1: Initial i386 version, inspiration and some structure from the
+ NetBSD version.
OpenPOWER on IntegriCloud