diff options
Diffstat (limited to 'sys/boot/i386')
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. |