Mega i386 loader commit.

- Don't hard code 0x10000 as the entry point for the loader.  Instead add
  src/sys/boot/i386/Makefile.inc which defines a make variable with the
  entry point for the loader.  Move the loader's entry point up to
  0x20000, which makes PXE happy.
- Don't try to use cpp to parse btxldr for the optional BTXLDR_VERBOSE,
  instead use m4 to achieve this.  Also, add a BTXLDR_VERBOSE knob in the
  btxldr Makefile to turn this option on.
- Redo parts of cdldr's Makefile so that it now builds and installs cdboot
  instead of having i386/loader/Makefile do that.  Also, add in some more
  variables to make the pxeldr Makefile almost identical and thus to ease
  maintainability.
- Teach cdldr about the a.out format.  Cdldr now parsers the a.out header
  of the loader binary and relocates it based on that.  The entry point of
  the loader no longer has to be hardcoded into cdldr.  Also, the boot
  info table from mkisofs is no longer required to get a useful cdboot.
- Update the lsdev function for BIOS disks to parse other file systems
  (such as DOS FAT) that we currently support.  This is still buggy as
  it assumes that a floppy with a DOS boot sector actually has a MBR and
  parses it as such.  I'll be fixing this in the future.
- The biggie:  Add in support for booting off of PXE-enabled network
  adapters.  Currently, we use the TFTP API provided by the PXE BIOS.
  Eventually we will switch to using the low-level NIC driver thus
  allowing both TFTP and NFS to be used, but for now it's just TFTP.

Submitted by:	ps, alfred
Testing by:	Benno Rice <benno@netizen.com.au>
This commit is contained in:
John Baldwin 2000-03-28 01:19:53 +00:00
parent 7ef719fb93
commit 48a0c4ea04
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=58713
18 changed files with 1612 additions and 273 deletions

View file

@ -1,5 +1,9 @@
# $FreeBSD$
SUBDIR= mbr boot0 kgzldr btx boot2 cdldr libi386 loader
SUBDIR= mbr boot0 kgzldr btx boot2 libi386 loader
# special boot programs, 'self-extracting boot2+loader'
SUBDIR+= cdldr
SUBDIR+= pxeldr
.include <bsd.subdir.mk>

View file

@ -0,0 +1,5 @@
# Common defines for all of /sys/boot/i386/
#
# $FreeBSD$
LOADER_ADDRESS?= 0x200000

View file

@ -1,22 +1,28 @@
# $FreeBSD$
ORG=0x100000
AFLAGS+= --assembler-with-cpp
M4?= m4
M4FLAGS+= -DLOADER_ADDRESS=${LOADER_ADDRESS}
.if defined(BTXLDR_VERBOSE)
M4FLAGS+= -DBTXLDR_VERBOSE
.endif
all: btxldr
btxldr: btxldr.o
.if ${OBJFORMAT} == aout
${LD} -nostdlib -N -s -T ${ORG} -o btxldr.out btxldr.o
${LD} -nostdlib -N -s -T ${LOADER_ADDRESS} -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
${LD} -N -e start -Ttext ${LOADER_ADDRESS} -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
(cd ${.CURDIR}; ${M4} ${M4FLAGS} btxldr.s ) | \
${AS} ${AFLAGS} -o ${.TARGET}
CLEANFILES+= btxldr btxldr.out btxldr.o
.include <${.CURDIR}/../../Makefile.inc>
.include <bsd.prog.mk>

View file

@ -27,7 +27,7 @@
.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
.set MEM_DATA,start+0x1000 # Data segment
#
# Segment selectors.
#
@ -57,7 +57,7 @@
#
.set SIZ_STUB,0x1a # Size of stub
#
# We expect to be loaded by boot2 at 0x100000.
# We expect to be loaded by boot2 at the origin defined in ./Makefile.
#
.globl start
#
@ -69,25 +69,29 @@ start: cld # String ops inc
movzwl BDA_MEM,%eax # Get base memory
shll $0xa,%eax # in bytes
movl %eax,%ebp # Base of user stack
ifdef(`BTXLDR_VERBOSE',`
movl $m_mem,%esi # Display
call dhexout # amount of
call dputstr # base memory
call hexout # amount of
call putstr # base memory
')
lgdt gdtdesc # Load new GDT
#
# Relocate caller's arguments.
#
ifdef('BTXLDR_VERBOSE',`
movl $m_esp,%esi # Display
movl %esp,%eax # caller's
call dhexout # stack
call dputstr # pointer
movl %esp,%eax # caller
call hexout # stack
call putstr # 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
call hexout # Display it
loop start.1 # Till done
call dputstr # End message
call putstr # End message
')
movl $0x48,%ecx # Allocate space
subl %ecx,%ebp # for bootinfo
movl 0x18(%esp,1),%esi # Source: bootinfo
@ -97,20 +101,24 @@ start.1: movl (%ebx),%eax # Get argument and
rep # Copy
movsb # it
movl %ebp,0x18(%esp,1) # Update pointer
ifdef(`BTXLDR_VERBOSE',`
movl $m_rel_bi,%esi # Display
movl %ebp,%eax # bootinfo
call dhexout # relocation
call dputstr # message
call hexout # relocation
call putstr # message
')
start_null_bi: movl $0x18,%ecx # Allocate space
subl %ecx,%ebp # for arguments
leal 0x4(%esp,1),%esi # Source
movl %ebp,%edi # Destination
rep # Copy
movsb # them
ifdef(`BTXLDR_VERBOSE',`
movl $m_rel_args,%esi # Display
movl %ebp,%eax # argument
call dhexout # relocation
call dputstr # message
call hexout # relocation
call putstr # message
')
#
# Set up BTX kernel.
#
@ -139,24 +147,32 @@ start_null_bi: movl $0x18,%ecx # Allocate space
incl %edi # BTX
shll $0x2,%edi # load
addl $MEM_TBL,%edi # address
pushl %edi # Save
pushl %edi # Save load address
movzwl 0xa(%ebx),%ecx # Image size
pushl %ecx # Save
ifdef(`BTXLDR_VERBOSE',`
pushl %ecx # Save image size
')
rep # Relocate
movsb # BTX
movl %esi,%ebx # Keep place
ifdef(`BTXLDR_VERBOSE',`
movl $m_rel_btx,%esi # Restore
popl %eax # parameters
call dhexout # and
call hexout # and
')
popl %ebp # display
ifdef(`BTXLDR_VERBOSE',`
movl %ebp,%eax # the
call dhexout # relocation
call dputstr # message
call hexout # relocation
call putstr # message
')
addl $PAG_SIZ,%ebp # Display
ifdef(`BTXLDR_VERBOSE',`
movl $m_base,%esi # the
movl %ebp,%eax # user
call dhexout # base
call dputstr # address
call hexout # base
call putstr # address
')
#
# Set up ELF-format client program.
#
@ -165,24 +181,29 @@ start_null_bi: movl $0x18,%ecx # Allocate space
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
start.3:
ifdef(`BTXLDR_VERBOSE',`
movl $m_elf,%esi # Display ELF
call putstr # 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
ifdef(`BTXLDR_VERBOSE',`
movl 0x4(%edx),%eax # Display
call dhexout # p_offset
call hexout # p_offset
movl 0x8(%edx),%eax # Display
call dhexout # p_vaddr
call hexout # p_vaddr
movl 0x10(%edx),%eax # Display
call dhexout # p_filesz
call hexout # p_filesz
movl 0x14(%edx),%eax # Display
call dhexout # p_memsz
call dputstr # End message
call hexout # p_memsz
call putstr # End message
')
pushl %esi # Save
pushl %edi # working
pushl %ecx # registers
@ -206,8 +227,11 @@ start.5: popl %ecx # Restore
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
start.7:
ifdef(`BTXLDR_VERBOSE',`
movl $m_done,%esi # Display done
call putstr # message
')
movl $start.8,%esi # Real mode stub
movl $MEM_STUB,%edi # Destination
movl $SIZ_STUB,%ecx # Size
@ -231,10 +255,6 @@ 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
@ -260,12 +280,6 @@ hexout.2: decl %esi # Adjust for inc
#
# 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?
@ -274,10 +288,6 @@ putstr: lodsb # Load char
#
# 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
@ -356,7 +366,7 @@ gdtdesc: .word gdt.1-gdt-1 # Limit
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
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="
@ -379,7 +389,7 @@ m_segs: .asciz "text segment: offset="
.asciz " filesz="
.asciz " memsz=\0\n"
m_done: .asciz "Loading complete\n"
#endif
')
#
# Uninitialized data area.
#

View file

@ -27,7 +27,7 @@
.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
.set MEM_DATA,start+0x1000 # Data segment
#
# Segment selectors.
#
@ -57,7 +57,7 @@
#
.set SIZ_STUB,0x1a # Size of stub
#
# We expect to be loaded by boot2 at 0x100000.
# We expect to be loaded by boot2 at the origin defined in ./Makefile.
#
.globl start
#
@ -69,25 +69,29 @@ start: cld # String ops inc
movzwl BDA_MEM,%eax # Get base memory
shll $0xa,%eax # in bytes
movl %eax,%ebp # Base of user stack
ifdef(`BTXLDR_VERBOSE',`
movl $m_mem,%esi # Display
call dhexout # amount of
call dputstr # base memory
call hexout # amount of
call putstr # base memory
')
lgdt gdtdesc # Load new GDT
#
# Relocate caller's arguments.
#
ifdef('BTXLDR_VERBOSE',`
movl $m_esp,%esi # Display
movl %esp,%eax # caller's
call dhexout # stack
call dputstr # pointer
movl %esp,%eax # caller
call hexout # stack
call putstr # 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
call hexout # Display it
loop start.1 # Till done
call dputstr # End message
call putstr # End message
')
movl $0x48,%ecx # Allocate space
subl %ecx,%ebp # for bootinfo
movl 0x18(%esp,1),%esi # Source: bootinfo
@ -97,20 +101,24 @@ start.1: movl (%ebx),%eax # Get argument and
rep # Copy
movsb # it
movl %ebp,0x18(%esp,1) # Update pointer
ifdef(`BTXLDR_VERBOSE',`
movl $m_rel_bi,%esi # Display
movl %ebp,%eax # bootinfo
call dhexout # relocation
call dputstr # message
call hexout # relocation
call putstr # message
')
start_null_bi: movl $0x18,%ecx # Allocate space
subl %ecx,%ebp # for arguments
leal 0x4(%esp,1),%esi # Source
movl %ebp,%edi # Destination
rep # Copy
movsb # them
ifdef(`BTXLDR_VERBOSE',`
movl $m_rel_args,%esi # Display
movl %ebp,%eax # argument
call dhexout # relocation
call dputstr # message
call hexout # relocation
call putstr # message
')
#
# Set up BTX kernel.
#
@ -139,24 +147,32 @@ start_null_bi: movl $0x18,%ecx # Allocate space
incl %edi # BTX
shll $0x2,%edi # load
addl $MEM_TBL,%edi # address
pushl %edi # Save
pushl %edi # Save load address
movzwl 0xa(%ebx),%ecx # Image size
pushl %ecx # Save
ifdef(`BTXLDR_VERBOSE',`
pushl %ecx # Save image size
')
rep # Relocate
movsb # BTX
movl %esi,%ebx # Keep place
ifdef(`BTXLDR_VERBOSE',`
movl $m_rel_btx,%esi # Restore
popl %eax # parameters
call dhexout # and
call hexout # and
')
popl %ebp # display
ifdef(`BTXLDR_VERBOSE',`
movl %ebp,%eax # the
call dhexout # relocation
call dputstr # message
call hexout # relocation
call putstr # message
')
addl $PAG_SIZ,%ebp # Display
ifdef(`BTXLDR_VERBOSE',`
movl $m_base,%esi # the
movl %ebp,%eax # user
call dhexout # base
call dputstr # address
call hexout # base
call putstr # address
')
#
# Set up ELF-format client program.
#
@ -165,24 +181,29 @@ start_null_bi: movl $0x18,%ecx # Allocate space
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
start.3:
ifdef(`BTXLDR_VERBOSE',`
movl $m_elf,%esi # Display ELF
call putstr # 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
ifdef(`BTXLDR_VERBOSE',`
movl 0x4(%edx),%eax # Display
call dhexout # p_offset
call hexout # p_offset
movl 0x8(%edx),%eax # Display
call dhexout # p_vaddr
call hexout # p_vaddr
movl 0x10(%edx),%eax # Display
call dhexout # p_filesz
call hexout # p_filesz
movl 0x14(%edx),%eax # Display
call dhexout # p_memsz
call dputstr # End message
call hexout # p_memsz
call putstr # End message
')
pushl %esi # Save
pushl %edi # working
pushl %ecx # registers
@ -206,8 +227,11 @@ start.5: popl %ecx # Restore
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
start.7:
ifdef(`BTXLDR_VERBOSE',`
movl $m_done,%esi # Display done
call putstr # message
')
movl $start.8,%esi # Real mode stub
movl $MEM_STUB,%edi # Destination
movl $SIZ_STUB,%ecx # Size
@ -231,10 +255,6 @@ 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
@ -260,12 +280,6 @@ hexout.2: decl %esi # Adjust for inc
#
# 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?
@ -274,10 +288,6 @@ putstr: lodsb # Load char
#
# 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
@ -356,7 +366,7 @@ gdtdesc: .word gdt.1-gdt-1 # Limit
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
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="
@ -379,7 +389,7 @@ m_segs: .asciz "text segment: offset="
.asciz " filesz="
.asciz " memsz=\0\n"
m_done: .asciz "Loading complete\n"
#endif
')
#
# Uninitialized data area.
#

View file

@ -2,22 +2,39 @@
MAINTAINER=jhb@FreeBSD.org
ORG=0x00
ORG= 0x7c00
all: cdldr
LDR= cdldr
BOOT= cdboot
PROG= ${BOOT}
NOMAN=
STRIP=
BINDIR?= /boot
cdldr: cdldr.o
.if ${OBJFORMAT} == aout
${LD} -nostdlib -N -s -T ${ORG} -o cdldr.out cdldr.o
dd if=cdldr.out of=${.TARGET} ibs=32 skip=1
.if exists(${.OBJDIR}/../loader)
LOADER= ${.OBJDIR}/../loader/loader
.else
${LD} -N -e start -Ttext ${ORG} -o cdldr.out cdldr.o
objcopy -S -O binary cdldr.out ${.TARGET}
LOADER= ${.CURDIR}/../loader/loader
.endif
cdldr.o: cdldr.s
${AS} ${AFLAGS} -o ${.TARGET} ${.CURDIR}/cdldr.s
${BOOT}: ${LDR} ${LOADER}
cat ${LDR} ${LOADER} > ${.TARGET}.tmp
dd if=${.TARGET}.tmp of=${.TARGET} obs=2k conv=osync
rm ${.TARGET}.tmp
CLEANFILES+= cdldr cdldr.out cdldr.o
${LDR}: ${LDR}.o
.if ${OBJFORMAT} == aout
${LD} -nostdlib -N -s -T ${ORG} -o ${LDR}.out ${LDR}.o
dd if=${LDR}.out of=${.TARGET} ibs=32 skip=1
.else
${LD} -N -e start -Ttext ${ORG} -o ${LDR}.out ${LDR}.o
objcopy -S -O binary ${LDR}.out ${.TARGET}
.endif
${LDR}.o: ${.CURDIR}/${LDR}.s
${AS} ${AFLAGS} -o ${.TARGET} ${.CURDIR}/${LDR}.s
CLEANFILES+= ${LDR} ${LDR}.out ${LDR}.o ${BOOT}.tmp
.include <bsd.prog.mk>

View file

@ -28,20 +28,25 @@
#
# Memory locations.
#
.set MEM_LOADER_ADDRESS,0x100000 # where the loader lives
.set MEM_LDR_ENTRY,0x7c00 # our entry point
.set MEM_PAGE_SIZE,0x1000 # memory page size, 4k
.set MEM_ARG,0x900 # Arguments at start
.set MEM_ARG_BTX,0xa100 # Where we move them to so the
# BTX client can see them
.set MEM_ARG_SIZE,0x18 # Size of the arguments
.set MEM_BTX_ADDRESS,0x9000 # where BTX lives
.set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute
.set MEM_AOUT_HEADER,0x1000 # size of the a.out header
.set MEM_BTX_OFFSET,0x1000 # offset of BTX in the loader
.set MEM_BTX_IMAGE,MEM_LOADER_ADDRESS+MEM_BTX_OFFSET # where
# BTX is in the loader
.set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader
.set MEM_BTX_CLIENT,0xa000 # where BTX clients live
#
# a.out header fields
#
.set AOUT_TEXT,0x04 # text segment size
.set AOUT_DATA,0x08 # data segment size
.set AOUT_BSS,0x0c # zero'd BSS size
.set AOUT_SYMBOLS,0x10 # symbol table
.set AOUT_ENTRY,0x14 # entry point
.set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header
#
# Flags for kargs->bootflags
#
.set KARGS_FLAGS_CD,0x1 # flag to indicate booting from
@ -58,7 +63,8 @@
#
.set INT_SYS,0x30 # BTX syscall interrupt
#
# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry point)
# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry
# point)
#
.code16
.globl start
@ -66,40 +72,22 @@
#
# BTX program loader for CD booting
#
start: jmp begin # skip the boot info table
.org 0x8, 0x90 # fill with nops up to the table
#
# Boot information table that is filled in by mkisofs(8), see the man page for
# details
#
boot_info_table:
bi_pvd_LBA: .long 0x0
bi_file_LBA: .long 0x0
bi_file_length: .long 0x0
bi_checksum: .long 0x0
bi_reserved: .byte 0x0
.org 0x40, 0x0
#
# Actual start of execution
#
begin: cld # string ops inc
start: cld # string ops inc
xorw %ax, %ax # zero %ax
movw %ax, %ss # setup the
movw $MEM_LDR_ENTRY, %sp # stack
movw $start, %sp # stack
pushw %dx # save the BIOS boot device in
# %dl for later
movw $(MEM_LDR_ENTRY/0x10), %ax # setup the
movw %ax, %ds # data segment
movl $welcome_msg, %si # %ds:(%si) -> welcome message
movw %ax, %ds # setup the
movw %ax, %es # data segments
movw $welcome_msg, %si # %ds:(%si) -> welcome message
call putstr # display the welcome message
#
# Setup the arguments that the loader is expecting from boot[12]
#
movl $bootinfo_msg, %si # %ds:(%si) -> boot args message
movw $bootinfo_msg, %si # %ds:(%si) -> boot args message
call putstr # display the message
pushw %ss # Copy %ss
popw %es # to %es
movl $MEM_ARG, %ebx # %es:(%ebx) -> boot args
movl $MEM_ARG, %ebx # %ds:(%ebx) -> boot args
movw %bx, %di # %es:(%di) -> boot args
xorl %eax, %eax # zero %eax
movw $(MEM_ARG_SIZE/4), %cx # Size of arguments in 32-bit
@ -107,8 +95,9 @@ begin: cld # string ops inc
rep # Clear the arguments
stosl # to zero
popw %dx # restore BIOS boot device
movb %dl, %es:0x4(%ebx) # set kargs->bootdev
orb $KARGS_FLAGS_CD, %es:0x8(%ebx) # kargs->bootflags |= KARGS_FLAGS_CD
movb %dl, 0x4(%ebx) # set kargs->bootdev
orb $KARGS_FLAGS_CD, 0x8(%ebx) # kargs->bootflags |=
# KARGS_FLAGS_CD
#
# Turn on the A20 address line
#
@ -118,49 +107,61 @@ begin: cld # string ops inc
#
movw $relocate_msg, %si # Display the
call putstr # relocation message
movl $MEM_LOADER_ADDRESS, %edi # %edi is the destination
movl $(MEM_LDR_ENTRY+end-start+MEM_AOUT_HEADER), %esi # %esi is
# the start of the raw loader
movl bi_file_length, %ecx # Set %ecx to the length
subl $(end-start+MEM_AOUT_HEADER), %ecx # of the raw loader
movl end+AOUT_ENTRY, %edi # %edi is the destination
movl $(end+AOUT_HEADER), %esi # %esi is
# the start of the text
# segment
movl end+AOUT_TEXT, %ecx # %ecx = length of the text
# segment
lgdt gdtdesc # setup our own gdt
cli # turn off interrupts
movl %cr0, %eax # Turn on
orl $0x1, %eax # protected
orb $0x1, %al # protected
movl %eax, %cr0 # mode
.byte 0xea # long jump to
.word MEM_LDR_ENTRY+pm_start # clear the instruction
.word SEL_SCODE # pre-fetch
.word pm_start # clear the instruction
.word SEL_SCODE # pre-fetch queue
.code32
pm_start: movw $SEL_SDATA, %ax # Initialize
movw %ax, %ds # %ds and
movw %ax, %es # %es to a flat selector
rep # Relocate
movsb # the loader
movl $MEM_BTX_IMAGE, %esi # %esi -> BTX in the loader
rep # Relocate the
movsb # text segment
addl $(MEM_PAGE_SIZE - 1), %edi # pad %edi out to a new page
andl $~(MEM_PAGE_SIZE - 1), %edi # for the data segment
movl end+AOUT_DATA, %ecx # size of the data segment
rep # Relocate the
movsb # data segment
movl end+AOUT_BSS, %ecx # size of the bss
xorl %eax, %eax # zero %eax
addb $3, %cl # round %ecx up to
shrl $2, %ecx # a multiple of 4
rep # zero the
stosl # bss
movl end+AOUT_ENTRY, %esi # %esi -> relocated loader
addl $MEM_BTX_OFFSET, %esi # %esi -> BTX in the loader
movl $MEM_BTX_ADDRESS, %edi # %edi -> where BTX needs to go
movzwl 0xa(%esi), %ecx # %ecx -> length of BTX
rep # Relocate
movsb # BTX
ljmp $SEL_SCODE16,$(MEM_LDR_ENTRY+pm_16) # Jump to 16-bit PM
ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM
.code16
pm_16: movw $SEL_RDATA, %ax # Initialize
movw %ax, %ds # %ds and
movw %ax, %es # %es to a real mode selector
movl %cr0, %eax # Turn off
andl $~0x1, %eax # protected
andb $~0x1, %al # protected
movl %eax, %cr0 # mode
.byte 0xea # Long jump to
.word pm_end # clear the instruction
.word MEM_LDR_ENTRY/0x10 # pre-fetch
.word 0x0 # pre-fetch
pm_end: sti # Turn interrupts back on now
#
# Copy the BTX client to MEM_BTX_CLIENT
#
movw $(MEM_LDR_ENTRY/0x10), %ax # Initialize
movw %ax, %ds # %ds to local data segment
xorw %ax, %ax # zero %ax and initialize
movw %ax, %es # %es to segment 0
xorw %ax, %ax # zero %ax and set
movw %ax, %ds # %ds and %es
movw %ax, %es # to segment 0
movw $MEM_BTX_CLIENT, %di # Prepare to relocate
movw $btx_client, %si # the simple btx client
movw $(btx_client_end-btx_client), %cx # length of btx client
@ -170,17 +171,20 @@ pm_end: sti # Turn interrupts back on now
# Copy the boot[12] args to where the BTX client can see them
#
movw $MEM_ARG, %si # where the args are at now
movw %ax, %ds # need segment 0 in %ds
movw $MEM_ARG_BTX, %di # where the args are moving to
movw $(MEM_ARG_SIZE/4), %cx # size of the arguments in longs
rep # Relocate
movsl # the words
#
# Save the entry point so the client can get to it later on
#
movl end+AOUT_ENTRY, %eax # load the entry point
stosl # add it to the end of the
# arguments
#
# Now we just start up BTX and let it do the rest
#
movw $(MEM_LDR_ENTRY/0x10), %ax # Initialize
movw %ax, %ds # %ds to the local data segment
movl $jump_message, %si # Display the
movw $jump_message, %si # Display the
call putstr # jump message
.byte 0xea # Jump to
.word MEM_BTX_ENTRY # BTX entry
@ -216,7 +220,7 @@ seta20.2: inb $0x64,%al # Get status
ret # To caller
#
# BTX client to start btxld
# BTX client to start btxldr
#
.code32
btx_client: movl $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi
@ -228,7 +232,8 @@ push_arg: lodsl # Read argument
pushl %eax # Push it onto the stack
loop push_arg # Push all of the arguments
cld # In case anyone depends on this
pushl $(MEM_LOADER_ADDRESS) # Address to jump to
pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of
# the loader
pushl %eax # Emulate a near call
movl $0x1, %eax # 'exec' system call
int $INT_SYS # BTX system call
@ -249,7 +254,7 @@ gdt.1:
# Pseudo-descriptors.
#
gdtdesc: .word gdt.1-gdt-1 # Limit
.long gdt+MEM_LDR_ENTRY # Base
.long gdt # Base
welcome_msg: .asciz "CD Loader 1.00\r\n\n"
bootinfo_msg: .asciz "Building the boot loader arguments\r\n"

View file

@ -2,22 +2,39 @@
MAINTAINER=jhb@FreeBSD.org
ORG=0x00
ORG= 0x7c00
all: cdldr
LDR= cdldr
BOOT= cdboot
PROG= ${BOOT}
NOMAN=
STRIP=
BINDIR?= /boot
cdldr: cdldr.o
.if ${OBJFORMAT} == aout
${LD} -nostdlib -N -s -T ${ORG} -o cdldr.out cdldr.o
dd if=cdldr.out of=${.TARGET} ibs=32 skip=1
.if exists(${.OBJDIR}/../loader)
LOADER= ${.OBJDIR}/../loader/loader
.else
${LD} -N -e start -Ttext ${ORG} -o cdldr.out cdldr.o
objcopy -S -O binary cdldr.out ${.TARGET}
LOADER= ${.CURDIR}/../loader/loader
.endif
cdldr.o: cdldr.s
${AS} ${AFLAGS} -o ${.TARGET} ${.CURDIR}/cdldr.s
${BOOT}: ${LDR} ${LOADER}
cat ${LDR} ${LOADER} > ${.TARGET}.tmp
dd if=${.TARGET}.tmp of=${.TARGET} obs=2k conv=osync
rm ${.TARGET}.tmp
CLEANFILES+= cdldr cdldr.out cdldr.o
${LDR}: ${LDR}.o
.if ${OBJFORMAT} == aout
${LD} -nostdlib -N -s -T ${ORG} -o ${LDR}.out ${LDR}.o
dd if=${LDR}.out of=${.TARGET} ibs=32 skip=1
.else
${LD} -N -e start -Ttext ${ORG} -o ${LDR}.out ${LDR}.o
objcopy -S -O binary ${LDR}.out ${.TARGET}
.endif
${LDR}.o: ${.CURDIR}/${LDR}.s
${AS} ${AFLAGS} -o ${.TARGET} ${.CURDIR}/${LDR}.s
CLEANFILES+= ${LDR} ${LDR}.out ${LDR}.o ${BOOT}.tmp
.include <bsd.prog.mk>

View file

@ -28,20 +28,25 @@
#
# Memory locations.
#
.set MEM_LOADER_ADDRESS,0x100000 # where the loader lives
.set MEM_LDR_ENTRY,0x7c00 # our entry point
.set MEM_PAGE_SIZE,0x1000 # memory page size, 4k
.set MEM_ARG,0x900 # Arguments at start
.set MEM_ARG_BTX,0xa100 # Where we move them to so the
# BTX client can see them
.set MEM_ARG_SIZE,0x18 # Size of the arguments
.set MEM_BTX_ADDRESS,0x9000 # where BTX lives
.set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute
.set MEM_AOUT_HEADER,0x1000 # size of the a.out header
.set MEM_BTX_OFFSET,0x1000 # offset of BTX in the loader
.set MEM_BTX_IMAGE,MEM_LOADER_ADDRESS+MEM_BTX_OFFSET # where
# BTX is in the loader
.set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader
.set MEM_BTX_CLIENT,0xa000 # where BTX clients live
#
# a.out header fields
#
.set AOUT_TEXT,0x04 # text segment size
.set AOUT_DATA,0x08 # data segment size
.set AOUT_BSS,0x0c # zero'd BSS size
.set AOUT_SYMBOLS,0x10 # symbol table
.set AOUT_ENTRY,0x14 # entry point
.set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header
#
# Flags for kargs->bootflags
#
.set KARGS_FLAGS_CD,0x1 # flag to indicate booting from
@ -58,7 +63,8 @@
#
.set INT_SYS,0x30 # BTX syscall interrupt
#
# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry point)
# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry
# point)
#
.code16
.globl start
@ -66,40 +72,22 @@
#
# BTX program loader for CD booting
#
start: jmp begin # skip the boot info table
.org 0x8, 0x90 # fill with nops up to the table
#
# Boot information table that is filled in by mkisofs(8), see the man page for
# details
#
boot_info_table:
bi_pvd_LBA: .long 0x0
bi_file_LBA: .long 0x0
bi_file_length: .long 0x0
bi_checksum: .long 0x0
bi_reserved: .byte 0x0
.org 0x40, 0x0
#
# Actual start of execution
#
begin: cld # string ops inc
start: cld # string ops inc
xorw %ax, %ax # zero %ax
movw %ax, %ss # setup the
movw $MEM_LDR_ENTRY, %sp # stack
movw $start, %sp # stack
pushw %dx # save the BIOS boot device in
# %dl for later
movw $(MEM_LDR_ENTRY/0x10), %ax # setup the
movw %ax, %ds # data segment
movl $welcome_msg, %si # %ds:(%si) -> welcome message
movw %ax, %ds # setup the
movw %ax, %es # data segments
movw $welcome_msg, %si # %ds:(%si) -> welcome message
call putstr # display the welcome message
#
# Setup the arguments that the loader is expecting from boot[12]
#
movl $bootinfo_msg, %si # %ds:(%si) -> boot args message
movw $bootinfo_msg, %si # %ds:(%si) -> boot args message
call putstr # display the message
pushw %ss # Copy %ss
popw %es # to %es
movl $MEM_ARG, %ebx # %es:(%ebx) -> boot args
movl $MEM_ARG, %ebx # %ds:(%ebx) -> boot args
movw %bx, %di # %es:(%di) -> boot args
xorl %eax, %eax # zero %eax
movw $(MEM_ARG_SIZE/4), %cx # Size of arguments in 32-bit
@ -107,8 +95,9 @@ begin: cld # string ops inc
rep # Clear the arguments
stosl # to zero
popw %dx # restore BIOS boot device
movb %dl, %es:0x4(%ebx) # set kargs->bootdev
orb $KARGS_FLAGS_CD, %es:0x8(%ebx) # kargs->bootflags |= KARGS_FLAGS_CD
movb %dl, 0x4(%ebx) # set kargs->bootdev
orb $KARGS_FLAGS_CD, 0x8(%ebx) # kargs->bootflags |=
# KARGS_FLAGS_CD
#
# Turn on the A20 address line
#
@ -118,49 +107,61 @@ begin: cld # string ops inc
#
movw $relocate_msg, %si # Display the
call putstr # relocation message
movl $MEM_LOADER_ADDRESS, %edi # %edi is the destination
movl $(MEM_LDR_ENTRY+end-start+MEM_AOUT_HEADER), %esi # %esi is
# the start of the raw loader
movl bi_file_length, %ecx # Set %ecx to the length
subl $(end-start+MEM_AOUT_HEADER), %ecx # of the raw loader
movl end+AOUT_ENTRY, %edi # %edi is the destination
movl $(end+AOUT_HEADER), %esi # %esi is
# the start of the text
# segment
movl end+AOUT_TEXT, %ecx # %ecx = length of the text
# segment
lgdt gdtdesc # setup our own gdt
cli # turn off interrupts
movl %cr0, %eax # Turn on
orl $0x1, %eax # protected
orb $0x1, %al # protected
movl %eax, %cr0 # mode
.byte 0xea # long jump to
.word MEM_LDR_ENTRY+pm_start # clear the instruction
.word SEL_SCODE # pre-fetch
.word pm_start # clear the instruction
.word SEL_SCODE # pre-fetch queue
.code32
pm_start: movw $SEL_SDATA, %ax # Initialize
movw %ax, %ds # %ds and
movw %ax, %es # %es to a flat selector
rep # Relocate
movsb # the loader
movl $MEM_BTX_IMAGE, %esi # %esi -> BTX in the loader
rep # Relocate the
movsb # text segment
addl $(MEM_PAGE_SIZE - 1), %edi # pad %edi out to a new page
andl $~(MEM_PAGE_SIZE - 1), %edi # for the data segment
movl end+AOUT_DATA, %ecx # size of the data segment
rep # Relocate the
movsb # data segment
movl end+AOUT_BSS, %ecx # size of the bss
xorl %eax, %eax # zero %eax
addb $3, %cl # round %ecx up to
shrl $2, %ecx # a multiple of 4
rep # zero the
stosl # bss
movl end+AOUT_ENTRY, %esi # %esi -> relocated loader
addl $MEM_BTX_OFFSET, %esi # %esi -> BTX in the loader
movl $MEM_BTX_ADDRESS, %edi # %edi -> where BTX needs to go
movzwl 0xa(%esi), %ecx # %ecx -> length of BTX
rep # Relocate
movsb # BTX
ljmp $SEL_SCODE16,$(MEM_LDR_ENTRY+pm_16) # Jump to 16-bit PM
ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM
.code16
pm_16: movw $SEL_RDATA, %ax # Initialize
movw %ax, %ds # %ds and
movw %ax, %es # %es to a real mode selector
movl %cr0, %eax # Turn off
andl $~0x1, %eax # protected
andb $~0x1, %al # protected
movl %eax, %cr0 # mode
.byte 0xea # Long jump to
.word pm_end # clear the instruction
.word MEM_LDR_ENTRY/0x10 # pre-fetch
.word 0x0 # pre-fetch
pm_end: sti # Turn interrupts back on now
#
# Copy the BTX client to MEM_BTX_CLIENT
#
movw $(MEM_LDR_ENTRY/0x10), %ax # Initialize
movw %ax, %ds # %ds to local data segment
xorw %ax, %ax # zero %ax and initialize
movw %ax, %es # %es to segment 0
xorw %ax, %ax # zero %ax and set
movw %ax, %ds # %ds and %es
movw %ax, %es # to segment 0
movw $MEM_BTX_CLIENT, %di # Prepare to relocate
movw $btx_client, %si # the simple btx client
movw $(btx_client_end-btx_client), %cx # length of btx client
@ -170,17 +171,20 @@ pm_end: sti # Turn interrupts back on now
# Copy the boot[12] args to where the BTX client can see them
#
movw $MEM_ARG, %si # where the args are at now
movw %ax, %ds # need segment 0 in %ds
movw $MEM_ARG_BTX, %di # where the args are moving to
movw $(MEM_ARG_SIZE/4), %cx # size of the arguments in longs
rep # Relocate
movsl # the words
#
# Save the entry point so the client can get to it later on
#
movl end+AOUT_ENTRY, %eax # load the entry point
stosl # add it to the end of the
# arguments
#
# Now we just start up BTX and let it do the rest
#
movw $(MEM_LDR_ENTRY/0x10), %ax # Initialize
movw %ax, %ds # %ds to the local data segment
movl $jump_message, %si # Display the
movw $jump_message, %si # Display the
call putstr # jump message
.byte 0xea # Jump to
.word MEM_BTX_ENTRY # BTX entry
@ -216,7 +220,7 @@ seta20.2: inb $0x64,%al # Get status
ret # To caller
#
# BTX client to start btxld
# BTX client to start btxldr
#
.code32
btx_client: movl $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi
@ -228,7 +232,8 @@ push_arg: lodsl # Read argument
pushl %eax # Push it onto the stack
loop push_arg # Push all of the arguments
cld # In case anyone depends on this
pushl $(MEM_LOADER_ADDRESS) # Address to jump to
pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of
# the loader
pushl %eax # Emulate a near call
movl $0x1, %eax # 'exec' system call
int $INT_SYS # BTX system call
@ -249,7 +254,7 @@ gdt.1:
# Pseudo-descriptors.
#
gdtdesc: .word gdt.1-gdt-1 # Limit
.long gdt+MEM_LDR_ENTRY # Base
.long gdt # Base
welcome_msg: .asciz "CD Loader 1.00\r\n\n"
bootinfo_msg: .asciz "Building the boot loader arguments\r\n"

View file

@ -243,7 +243,31 @@ bd_print(int verbose)
sprintf(line, " disk%ds%d", i, j + 1);
bd_printslice(od, dptr[j].dp_start, line);
break;
case 0x00: /* unused partition */
break;
case 0x01:
sprintf(line, " disk%ds%d: FAT-12\n", i,
j + 1);
pager_output(line);
break;
case 0x04:
case 0x06:
case 0x0e:
sprintf(line, " disk%ds%d: FAT-16\n", i,
j + 1);
pager_output(line);
break;
case 0x0b:
case 0x0c:
sprintf(line, " disk%ds%d: FAT-32\n", i,
j + 1);
pager_output(line);
break;
default:
sprintf(line, " disk%ds%d: Unknown fs: 0x%x\n",
i, j + 1, dptr[j].dp_typ);
pager_output(line);
break;
}
}
@ -525,12 +549,12 @@ bd_bestslice(struct dos_partition *dptr)
}
break;
case 0x04: /* DOS/Windows */
case 0x06:
case 0x0b:
case 0x0c:
case 0x0e:
case 0x63:
case 0x01: /* DOS/Windows */
case 0x04:
case 0x06:
case 0x0b:
case 0x0c:
case 0x0e:
if ((dptr[i].dp_flag & 0x80) && (preflevel > PREF_DOS_ACT)) {
pref = i;
preflevel = PREF_DOS_ACT;

View file

@ -62,6 +62,8 @@ extern struct devdesc currdev; /* our current device */
/* exported devices XXX rename? */
extern struct devsw biosdisk;
extern struct devsw pxedisk;
extern struct fs_ops pxe_fsops;
u_int32_t bd_getbigeom(int bunit); /* return geometry in bootinfo format */
extern int bd_bios2unit(int biosdev); /* xlate BIOS device -> biosdisk unit */
@ -85,4 +87,4 @@ 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);
extern void pxe_enable(void *pxeinfo);

640
sys/boot/i386/libi386/pxe.c Normal file
View file

@ -0,0 +1,640 @@
/*
* Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org>
* All rights reserved.
* Copyright (c) 2000 Paul Saab <ps@freebsd.org>
* All rights reserved.
* Copyright (c) 2000 John Baldwin <jhb@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* The typedefs and structures declared in this file
* clearly violate style(9), the reason for this is to conform to the
* typedefs/structure-names used in the Intel literature to avoid confusion.
*
* It's for your own good. :)
*/
#include <stand.h>
#include <sys/reboot.h>
#include <string.h>
#include <sys/reboot.h>
#include <arpa/tftp.h>
#include <stdarg.h>
#include <bootstrap.h>
#include "btxv86.h"
#define PXENV_GET_CACHED_INFO 0x0071
#define PXENV_TFTP_OPEN 0x0020
#define PXENV_TFTP_CLOSE 0x0021
#define PXENV_TFTP_READ 0x0022
/*
* Allocate the PXE buffers statically instead of sticking grimy fingers into
* BTX's private data area. The scratch buffer is used to send information to
* the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS.
*/
#define PXE_BUFFER_SIZE 0x2000
#define PXE_TFTP_BUFFER_SIZE 512
char scratch_buffer[PXE_BUFFER_SIZE];
char data_buffer[PXE_BUFFER_SIZE];
#define S_SIZE(s) s, sizeof(s) - 1
#define IP_STR "%d.%d.%d.%d"
#define IP_ARGS(ip) \
(int)(ip >> 24) & 0xff, (int)(ip >> 16) & 0xff, \
(int)(ip >> 8) & 0xff, (int)ip & 0xff
#define MAC_STR "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC_ARGS(mac) \
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
typedef struct {
uint16_t offset;
uint16_t segment;
} SEGOFF16_t;
typedef uint16_t PXENV_STATUS;
struct pxenv {
char Signature[6]; /* 'PXENV+' */
uint16_t Version; /* MSB = major, LSB = minor */
uint8_t Length; /* structure length */
uint8_t Checksum; /* checksum pad */
SEGOFF16_t RMEntry; /* SEG:OFF to PXE entry point */
/* don't use PMOffset and PMSelector (from the 2.1 PXE manual) */
uint32_t PMOffset; /* Protected mode entry */
uint16_t PMSelector; /* Protected mode selector */
uint16_t StackSeg; /* Stack segment address */
uint16_t StackSize; /* Stack segment size (bytes) */
uint16_t BC_CodeSeg; /* BC Code segment address */
uint16_t BC_CodeSize; /* BC Code segment size (bytes) */
uint16_t BC_DataSeg; /* BC Data segment address */
uint16_t BC_DataSize; /* BC Data segment size (bytes) */
uint16_t UNDIDataSeg; /* UNDI Data segment address */
uint16_t UNDIDataSize; /* UNDI Data segment size (bytes) */
uint16_t UNDICodeSeg; /* UNDI Code segment address */
uint16_t UNDICodeSize; /* UNDI Code segment size (bytes) */
SEGOFF16_t PXEPtr; /* SEG:OFF to !PXE struct,
only present when Version > 2.1 */
} *pxenv_p = NULL;
static uint32_t myip; /* my IP address */
static uint32_t serverip; /* where I got my initial bootstrap from */
static uint32_t secondip; /* where I should go to get the rest of my boot files */
static char *servername = NULL; /* name of server I DHCP'd from */
static char *bootfile = NULL; /* name of file that I booted with */
static uint16_t pxe_return_status;
static uint16_t pxe_open_status;
#define PACKED __attribute__ ((packed))
#define MAC_ADDR_LEN 16
typedef uint8_t MAC_ADDR[MAC_ADDR_LEN];
/* PXENV_GET_CACHED_INFO request */
typedef struct {
PXENV_STATUS Status;
uint16_t PacketType; /* type (defined right here) */
# define PXENV_PACKET_TYPE_DHCP_DISCOVER 1
# define PXENV_PACKET_TYPE_DHCP_ACK 2
# define PXENV_PACKET_TYPE_BINL_REPLY 3
uint16_t BufferSize; /* max to copy, leave at 0 for pointer */
SEGOFF16_t Buffer; /* copy to, leave at 0 for pointer */
uint16_t BufferLimit; /* max size of buffer in BC dataseg ? */
} PACKED t_PXENV_GET_CACHED_INFO;
/*
* structure filled in by PXENV_GET_CACHED_INFO
* (how we determine which IP we downloaded the initial bootstrap from)
*/
typedef struct {
uint8_t opcode;
# define BOOTP_REQ 1
# define BOOTP_REP 2
uint8_t Hardware; /* hardware type */
uint8_t Hardlen; /* hardware addr len */
uint8_t Gatehops; /* zero it */
uint32_t ident; /* random number chosen by client */
uint16_t seconds; /* seconds since did initial bootstrap */
uint16_t flags; /* seconds since did initial bootstrap */
# define BOOTP_BCAST 0x8000 /* ? */
uint32_t cip; /* Client IP */
uint32_t yip; /* Your IP */
uint32_t sip; /* IP to use for next boot stage */
uint32_t gip; /* Relay IP ? */
MAC_ADDR CAddr; /* Client hardware address */
char Sname[64]; /* Server's hostname (Optional) */
char bootfile[128]; /* boot filename */
union {
# if 1
# define BOOTP_DHCPVEND 1024 /* DHCP extended vendor field size */
# else
# define BOOTP_DHCPVEND 312 /* DHCP standard vendor field size */
# endif
uint8_t d[BOOTP_DHCPVEND]; /* raw array of vendor/dhcp options */
struct {
uint8_t magic[4]; /* DHCP magic cookie */
# define VM_RFC1048 0x63825363L /* ? */
uint32_t flags; /* bootp flags/opcodes */
uint8_t pad[56]; /* I don't think Intel knows what a
union does... */
} v;
} vendor;
} PACKED BOOTPLAYER;
/* tftp open */
typedef struct {
uint16_t status;
uint32_t src_ip;
uint32_t gw_ip;
uint8_t filename[128];
uint16_t tftpport;
uint16_t packetsize;
} PACKED t_PXENV_TFTP_OPEN;
/* tftp close */
typedef struct {
uint16_t status;
} PACKED t_PXENV_TFTP_CLOSE;
/* tftp read */
typedef struct {
uint16_t status;
uint16_t packetnumber;
uint16_t buffer_size;
SEGOFF16_t buffer;
} PACKED t_PXENV_TFTP_READ;
void pxe_enable(void *pxeinfo);
static int pxe_init(void);
static int pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
void *buf, size_t *rsize);
static int pxe_open(struct open_file *f, ...);
static int pxe_close(struct open_file *f);
static void pxe_print(int verbose);
static void pxe_perror(int error);
void pxe_call(int func);
static int pxe_fs_open(const char *path, struct open_file *f);
static int pxe_fs_close(struct open_file *f);
static int pxe_fs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
static int pxe_fs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
static off_t pxe_fs_seek(struct open_file *f, off_t offset, int where);
static int pxe_fs_stat(struct open_file *f, struct stat *sb);
struct devsw pxedisk = {
"pxe",
DEVT_NET,
pxe_init,
pxe_strategy,
pxe_open,
pxe_close,
noioctl,
pxe_print
};
struct fs_ops pxe_fsops = {
"pxe",
pxe_fs_open,
pxe_fs_close,
pxe_fs_read,
pxe_fs_write,
pxe_fs_seek,
pxe_fs_stat
};
/*
* This function is called by the loader to enable PXE support if we
* are booted by PXE. The passed in pointer is a pointer to the
* PXENV+ structure.
*/
void
pxe_enable(void *pxeinfo)
{
pxenv_p = (struct pxenv *)pxeinfo;
}
/*
* return true if pxe structures are found/initialized,
* also figures out our IP information via the pxe cached info struct
*/
static int
pxe_init(void)
{
t_PXENV_GET_CACHED_INFO *gci_p;
BOOTPLAYER *bootplayer;
int counter;
uint8_t checksum;
uint8_t *checkptr;
if(pxenv_p == NULL)
return (0);
/* look for "PXENV+" */
if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+")))
return (0);
/* make sure the size is something we can handle */
if (pxenv_p->Length > sizeof(*pxenv_p)) {
printf("PXENV+ structure too large, ignoring\n");
pxenv_p = NULL;
return (0);
}
/*
* do byte checksum:
* add up each byte in the structure, the total should be 0
*/
checksum = 0;
checkptr = (uint8_t *) pxenv_p;
for (counter = 0; counter < pxenv_p->Length; counter++)
checksum += *checkptr++;
if (checksum != 0) {
printf("PXENV+ structure failed checksum, ignoring\n");
pxenv_p = NULL;
return (0);
}
printf("\nPXENV+ version %d.%d, real mode entry point @%04x:%04x\n",
(uint8_t) (pxenv_p->Version >> 8),
(uint8_t) (pxenv_p->Version & 0xFF),
pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset);
gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer;
bzero(gci_p, sizeof(*gci_p));
gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY;
pxe_call(PXENV_GET_CACHED_INFO);
if (gci_p->Status != 0) {
pxe_perror(gci_p->Status);
pxenv_p = NULL;
return (0);
}
bootplayer = (BOOTPLAYER *)
PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset);
serverip = bootplayer->sip;
servername = strdup(bootplayer->Sname);
bootfile = strdup(bootplayer->bootfile);
myip = bootplayer->yip;
secondip = bootplayer->sip;
return (1);
}
int
pxe_tftpopen(uint32_t srcip, uint32_t gateip, char *filename, uint16_t port,
uint16_t pktsize)
{
t_PXENV_TFTP_OPEN *tftpo_p;
tftpo_p = (t_PXENV_TFTP_OPEN *)scratch_buffer;
bzero(tftpo_p, sizeof(*tftpo_p));
tftpo_p->src_ip = srcip;
tftpo_p->gw_ip = gateip;
bcopy(filename, tftpo_p->filename, strlen(filename));
tftpo_p->tftpport = port;
tftpo_p->packetsize = pktsize;
pxe_call(PXENV_TFTP_OPEN);
pxe_return_status = tftpo_p->status;
if (tftpo_p->status != 0)
return (-1);
return (tftpo_p->packetsize);
}
int
pxe_tftpclose(void)
{
t_PXENV_TFTP_CLOSE *tftpc_p;
tftpc_p = (t_PXENV_TFTP_CLOSE *)scratch_buffer;
bzero(tftpc_p, sizeof(*tftpc_p));
pxe_call(PXENV_TFTP_CLOSE);
pxe_return_status = tftpc_p->status;
if (tftpc_p->status != 0)
return (-1);
return (1);
}
int
pxe_tftpread(void *buf)
{
t_PXENV_TFTP_READ *tftpr_p;
tftpr_p = (t_PXENV_TFTP_READ *)scratch_buffer;
bzero(tftpr_p, sizeof(*tftpr_p));
tftpr_p->buffer.segment = VTOPSEG(data_buffer);
tftpr_p->buffer.offset = VTOPOFF(data_buffer);
pxe_call(PXENV_TFTP_READ);
/* XXX - I don't know why we need this. */
delay(1000);
pxe_return_status = tftpr_p->status;
if (tftpr_p->status != 0)
return (-1);
bcopy(data_buffer, buf, tftpr_p->buffer_size);
return (tftpr_p->buffer_size);
}
void
pxe_perror(int err)
{
return;
}
void
pxe_call(int func)
{
bzero(&v86, sizeof(v86));
bzero(data_buffer, sizeof(data_buffer));
v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
/* high 16 == segment, low 16 == offset, shift and or */
v86.addr =
((uint32_t)pxenv_p->RMEntry.segment << 16) | pxenv_p->RMEntry.offset;
v86.es = VTOPSEG(scratch_buffer);
v86.edi = VTOPOFF(scratch_buffer);
v86.ebx = func;
v86int();
v86.ctl = V86_FLAGS;
}
static int
pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
void *buf, size_t *rsize)
{
return (EIO);
}
static int
pxe_open(struct open_file *f, ...)
{
return (0);
}
static int
pxe_close(struct open_file *f)
{
return (0);
}
static void
pxe_print(int verbose)
{
if (pxenv_p != NULL) {
if (*servername == '\0') {
printf(" "IP_STR":/%s\n", IP_ARGS(htonl(serverip)),
bootfile);
} else {
printf(" %s:/%s\n", servername, bootfile);
}
}
return;
}
/*
* Most of this code was ripped from libstand/tftp.c and
* modified to work with pxe. :)
*/
#define RSPACE 520 /* max data packet, rounded up */
struct tftp_handle {
int currblock; /* contents of lastdata */
int islastblock; /* flag */
int validsize;
int off;
int opened;
char *path; /* saved for re-requests */
u_char space[RSPACE];
};
static int
tftp_makereq(h)
struct tftp_handle *h;
{
ssize_t res;
char *p;
p = h->path;
if (*p == '/')
++p;
if (h->opened)
pxe_tftpclose();
if (pxe_tftpopen(serverip, 0, p, htons(69), PXE_TFTP_BUFFER_SIZE) < 0)
return(ENOENT);
pxe_open_status = pxe_return_status;
res = pxe_tftpread(h->space);
if (res == -1)
return (errno);
h->currblock = 1;
h->validsize = res;
h->islastblock = 0;
if (res < SEGSIZE)
h->islastblock = 1; /* very short file */
return (0);
}
/* ack block, expect next */
static int
tftp_getnextblock(h)
struct tftp_handle *h;
{
int res;
res = pxe_tftpread(h->space);
if (res == -1) /* 0 is OK! */
return (errno);
h->currblock++;
h->validsize = res;
if (res < SEGSIZE)
h->islastblock = 1; /* EOF */
return (0);
}
static int
pxe_fs_open(const char *path, struct open_file *f)
{
struct tftp_handle *tftpfile;
int res;
/* make sure the device is a PXE device */
if(f->f_dev != &pxedisk)
return (EINVAL);
tftpfile = (struct tftp_handle *) malloc(sizeof(*tftpfile));
if (!tftpfile)
return (ENOMEM);
tftpfile->off = 0;
tftpfile->path = strdup(path);
if (tftpfile->path == NULL) {
free(tftpfile);
return(ENOMEM);
}
res = tftp_makereq(tftpfile);
if (res) {
free(tftpfile->path);
free(tftpfile);
return (res);
}
tftpfile->opened = 1;
f->f_fsdata = (void *) tftpfile;
return(0);
}
static int
pxe_fs_close(struct open_file *f)
{
struct tftp_handle *tftpfile;
tftpfile = (struct tftp_handle *) f->f_fsdata;
if (tftpfile) {
if (tftpfile->opened)
pxe_tftpclose();
free(tftpfile->path);
free(tftpfile);
}
return (0);
}
static int
pxe_fs_read(struct open_file *f, void *addr, size_t size, size_t *resid)
{
struct tftp_handle *tftpfile;
static int tc = 0;
char *dest = (char *)addr;
tftpfile = (struct tftp_handle *) f->f_fsdata;
while (size > 0) {
int needblock, count;
if (!(tc++ % 16))
twiddle();
needblock = tftpfile->off / SEGSIZE + 1;
if (tftpfile->currblock > needblock) /* seek backwards */
tftp_makereq(tftpfile); /* no error check, it worked
* for open */
while (tftpfile->currblock < needblock) {
int res;
res = tftp_getnextblock(tftpfile);
if (res) { /* no answer */
return (res);
}
if (tftpfile->islastblock)
break;
}
if (tftpfile->currblock == needblock) {
int offinblock, inbuffer;
offinblock = tftpfile->off % SEGSIZE;
inbuffer = tftpfile->validsize - offinblock;
if (inbuffer < 0) {
return (EINVAL);
}
count = (size < inbuffer ? size : inbuffer);
bcopy(tftpfile->space + offinblock,
dest, count);
dest += count;
tftpfile->off += count;
size -= count;
if ((tftpfile->islastblock) && (count == inbuffer))
break; /* EOF */
} else {
printf("tftp: block %d not found\n", needblock);
return (EINVAL);
}
}
if (resid)
*resid = size;
return(0);
}
static int
pxe_fs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
{
return 0;
}
static off_t
pxe_fs_seek(struct open_file *f, off_t offset, int where)
{
struct tftp_handle *tftpfile;
tftpfile = (struct tftp_handle *) f->f_fsdata;
switch (where) {
case SEEK_SET:
tftpfile->off = offset;
break;
case SEEK_CUR:
tftpfile->off += offset;
break;
default:
errno = EOFFSET;
return (-1);
}
return (tftpfile->off);
}
static int
pxe_fs_stat(struct open_file *f, struct stat *sb)
{
if (pxe_open_status != 0)
return -1;
sb->st_mode = 0444 | S_IFREG;
sb->st_nlink = 1;
sb->st_uid = 0;
sb->st_gid = 0;
sb->st_size = -1;
return 0;
}

View file

@ -1,7 +1,7 @@
# $FreeBSD$
BASE= loader
PROG= ${BASE} cdboot
PROG= ${BASE}
MAN5= ../../forth/loader.conf.5
MAN8= loader.8 ../../forth/loader.4th.8
#NOMAN=
@ -10,7 +10,8 @@ NEWVERSWHAT= "bootstrap loader" i386
BINDIR?= /boot
# architecture-specific loader code
SRCS= main.c conf.c
SRCS= main.c conf.c pxe.c
.PATH: ${.CURDIR}/../libi386
# Enable PnP and ISA-PnP code.
HAVE_PNP= yes
@ -47,13 +48,6 @@ LIBSTAND= -lstand
#LIBSTAND= ${.CURDIR}/../../../lib/libstand/libstand.a
#CFLAGS+= -I${.CURDIR}/../../../lib/libstand/
# where to get cdldr from
.if exists(${.OBJDIR}/../cdldr)
CDLDR= ${.OBJDIR}/../cdldr/cdldr
.else
CDLDR= ${.CURDIR}/../cdldr/cdldr
.endif
# BTX components
.if exists(${.OBJDIR}/../btx)
BTXDIR= ${.OBJDIR}/../btx
@ -79,14 +73,9 @@ vers.o: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version
sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
${CC} -c vers.c
cdboot: ${BASE} ${CDLDR}
cat ${CDLDR} ${BASE} > ${.TARGET}.tmp
dd if=${.TARGET}.tmp of=${.TARGET} obs=2k conv=osync
rm ${.TARGET}.tmp
${BASE}: ${BASE}.bin ${BTXLDR} ${BTXKERN} ${BTXCRT} ${BASE}.help
btxld -v -f aout -e 0x100000 -o ${.TARGET} -l ${BTXLDR} -b ${BTXKERN} \
${BASE}.bin
btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \
-b ${BTXKERN} ${BASE}.bin
# /usr/bin/kzip ${.TARGET}
# mv ${.TARGET}.kz ${.TARGET}
@ -119,6 +108,8 @@ beforeinstall:
${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 \
${.CURDIR}/../../forth/loader.conf ${DESTDIR}/boot/defaults
.include <${.CURDIR}/../Makefile.inc>
# Cannot use ${OBJS} above this line
.include <bsd.prog.mk>
@ -136,5 +127,3 @@ machine:
.endif
CLEANFILES+= machine

View file

@ -44,6 +44,7 @@
/* Exported for libstand */
struct devsw *devsw[] = {
&biosdisk,
&pxedisk,
/* XXX network devices? */
NULL
};
@ -52,6 +53,7 @@ struct fs_ops *file_system[] = {
&ufs_fsops,
&dosfs_fsops,
&zipfs_fsops,
&pxe_fsops,
NULL
};

View file

@ -41,6 +41,7 @@
#include "btxv86.h"
#define KARGS_FLAGS_CD 0x1
#define KARGS_FLAGS_PXE 0x2
/* Arguments passed in from the boot1/boot2 loader */
static struct
@ -48,7 +49,7 @@ static struct
u_int32_t howto;
u_int32_t bootdev;
u_int32_t bootflags;
u_int32_t res1;
u_int32_t pxeinfo;
u_int32_t res2;
u_int32_t bootinfo;
} *kargs;
@ -78,14 +79,14 @@ main(void)
kargs = (void *)__args;
initial_howto = kargs->howto;
initial_bootdev = kargs->bootdev;
initial_bootinfo = (struct bootinfo *)PTOV(kargs->bootinfo);
initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL;
/*
* Initialise the heap as early as possible. Once this is done, malloc() is usable.
*/
bios_getmem();
setheap((void *)end, (void *)bios_basemem);
/*
* 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
@ -103,6 +104,15 @@ main(void)
*/
bcache_init(32, 512); /* 16k cache XXX tune this */
/*
* We only want the PXE disk to try to init itself in the below walk through
* devsw if we actually booted off of PXE.
*/
if((kargs->bootinfo == NULL) &&
((kargs->bootflags & KARGS_FLAGS_PXE) != 0)) {
pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL);
}
/*
* March through the device switch probing for things.
*/
@ -141,22 +151,36 @@ 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 */
/* Assume we are booting from a BIOS disk by default */
currdev.d_dev = &biosdisk;
currdev.d_type = currdev.d_dev->dv_type;
if ((kargs->bootinfo == NULL) && ((kargs->bootflags & KARGS_FLAGS_CD) != 0)) {
/* we are booting from a CD with cdldr */
currdev.d_kind.biosdisk.slice = -1;
currdev.d_kind.biosdisk.partition = 0;
biosdev = initial_bootdev;
/* new-style boot loaders such as pxeldr and cdldr */
if (kargs->bootinfo == NULL) {
if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) {
/* we are booting from a CD with cdldr */
currdev.d_kind.biosdisk.slice = -1;
currdev.d_kind.biosdisk.partition = 0;
biosdev = initial_bootdev;
} else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) {
/* we are booting from pxeldr */
currdev.d_dev = &pxedisk;
currdev.d_type = currdev.d_dev->dv_type;
currdev.d_kind.netif.unit = 0;
} else {
/* we don't know what our boot device is */
currdev.d_kind.biosdisk.slice = -1;
currdev.d_kind.biosdisk.partition = 0;
biosdev = -1;
}
} else 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.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);
@ -171,7 +195,12 @@ extract_currdev(void)
biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */
}
if ((currdev.d_kind.biosdisk.unit = bd_bios2unit(biosdev)) == -1) {
/*
* If we are booting off of a BIOS disk and we didn't succeed in determining
* which one we booted off of, just use disk0: as a reasonable default.
*/
if ((currdev.d_type == devsw[0]->dv_type) &&
((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;

View file

@ -0,0 +1,40 @@
# $FreeBSD$
MAINTAINER=jhb@FreeBSD.org
ORG= 0x7c00
LDR= pxeldr
BOOT= pxeboot
PROG= ${BOOT}
NOMAN=
STRIP=
BINDIR?= /boot
.if exists(${.OBJDIR}/../loader)
LOADER= ${.OBJDIR}/../loader/loader
.else
LOADER= ${.CURDIR}/../loader/loader
.endif
${BOOT}: ${LDR} ${LOADER}
cat ${LDR} ${LOADER} > ${.TARGET}.tmp
dd if=${.TARGET}.tmp of=${.TARGET} obs=2k conv=osync
rm ${.TARGET}.tmp
${LDR}: ${LDR}.o
.if ${OBJFORMAT} == aout
${LD} -nostdlib -N -s -T ${ORG} -o ${LDR}.out ${LDR}.o
dd if=${LDR}.out of=${.TARGET} ibs=32 skip=1
.else
${LD} -N -e start -Ttext ${ORG} -o ${LDR}.out ${LDR}.o
objcopy -S -O binary ${LDR}.out ${.TARGET}
.endif
${LDR}.o: ${.CURDIR}/${LDR}.s
${AS} ${AFLAGS} -o ${.TARGET} ${.CURDIR}/${LDR}.s
CLEANFILES+= ${LDR} ${LDR}.out ${LDR}.o ${BOOT}.tmp
.include <bsd.prog.mk>

View file

@ -0,0 +1,267 @@
#
# Copyright (c) 2000 John Baldwin
# All rights reserved.
#
# Redistribution and use in source and binary forms are freely
# permitted provided that the above copyright notice and this
# paragraph and the following disclaimer are duplicated in all
# such forms.
#
# This software is provided "AS IS" and without any express or
# implied warranties, including, without limitation, the implied
# warranties of merchantability and fitness for a particular
# purpose.
#
# $FreeBSD$
#
# This simple program is a preloader for the normal boot3 loader. It is simply
# prepended to the beginning of a fully built and btxld'd loader. It then
# copies the loader to the address boot2 normally loads it, emulates the
# boot[12] environment (protected mode, a bootinfo struct, etc.), and then jumps
# to the start of btxldr to start the boot process. This method allows a stock
# /boot/loader to be booted over the network via PXE w/o having to write a
# seperate PXE-aware client just to load the loader.
#
#
# Memory locations.
#
.set MEM_PAGE_SIZE,0x1000 # memory page size, 4k
.set MEM_ARG,0x900 # Arguments at start
.set MEM_ARG_BTX,0xa100 # Where we move them to so the
# BTX client can see them
.set MEM_ARG_SIZE,0x18 # Size of the arguments
.set MEM_BTX_ADDRESS,0x9000 # where BTX lives
.set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute
.set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader
.set MEM_BTX_CLIENT,0xa000 # where BTX clients live
#
# a.out header fields
#
.set AOUT_TEXT,0x04 # text segment size
.set AOUT_DATA,0x08 # data segment size
.set AOUT_BSS,0x0c # zero'd BSS size
.set AOUT_SYMBOLS,0x10 # symbol table
.set AOUT_ENTRY,0x14 # entry point
.set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header
#
# Flags for kargs->bootflags
#
.set KARGS_FLAGS_PXE,0x2 # flag to indicate booting from
# PXE loader
#
# Segment selectors.
#
.set SEL_SDATA,0x8 # Supervisor data
.set SEL_RDATA,0x10 # Real mode data
.set SEL_SCODE,0x18 # PM-32 code
.set SEL_SCODE16,0x20 # PM-16 code
#
# BTX constants
#
.set INT_SYS,0x30 # BTX syscall interrupt
#
# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry
# point)
#
.code16
.globl start
.org 0x0, 0x0
#
# BTX program loader for PXE network booting
#
start: cld # string ops inc
xorw %ax, %ax # zero %ax
movw %ax, %ss # setup the
movw $start, %sp # stack
movw %es, %cx # save PXENV+ segment
movw %ax, %ds # setup the
movw %ax, %es # data segments
andl $0xffff, %ecx # clear upper words
andl $0xffff, %ebx # of %ebx and %ecx
shll $4, %ecx # calculate the offset of
addl %ebx, %ecx # the PXENV+ struct and
pushl %ecx # save it on the stack
movw $welcome_msg, %si # %ds:(%si) -> welcome message
call putstr # display the welcome message
#
# Setup the arguments that the loader is expecting from boot[12]
#
movw $bootinfo_msg, %si # %ds:(%si) -> boot args message
call putstr # display the message
movl $MEM_ARG, %ebx # %ds:(%ebx) -> boot args
movw %bx, %di # %es:(%di) -> boot args
xorl %eax, %eax # zero %eax
movw $(MEM_ARG_SIZE/4), %cx # Size of arguments in 32-bit
# dwords
rep # Clear the arguments
stosl # to zero
orb $KARGS_FLAGS_PXE, 0x8(%ebx) # kargs->bootflags |=
# KARGS_FLAGS_PXE
popl 0xc(%ebx) # kargs->pxeinfo = *PXENV+
#
# Turn on the A20 address line
#
call seta20 # Turn A20 on
#
# Relocate the loader and BTX using a very lazy protected mode
#
movw $relocate_msg, %si # Display the
call putstr # relocation message
movl end+AOUT_ENTRY, %edi # %edi is the destination
movl $(end+AOUT_HEADER), %esi # %esi is
# the start of the text
# segment
movl end+AOUT_TEXT, %ecx # %ecx = length of the text
# segment
lgdt gdtdesc # setup our own gdt
cli # turn off interrupts
movl %cr0, %eax # Turn on
orb $0x1, %al # protected
movl %eax, %cr0 # mode
.byte 0xea # long jump to
.word pm_start # clear the instruction
.word SEL_SCODE # pre-fetch queue
.code32
pm_start: movw $SEL_SDATA, %ax # Initialize
movw %ax, %ds # %ds and
movw %ax, %es # %es to a flat selector
rep # Relocate the
movsb # text segment
addl $(MEM_PAGE_SIZE - 1), %edi # pad %edi out to a new page
andl $~(MEM_PAGE_SIZE - 1), %edi # for the data segment
movl end+AOUT_DATA, %ecx # size of the data segment
rep # Relocate the
movsb # data segment
movl end+AOUT_BSS, %ecx # size of the bss
xorl %eax, %eax # zero %eax
addb $3, %cl # round %ecx up to
shrl $2, %ecx # a multiple of 4
rep # zero the
stosl # bss
movl end+AOUT_ENTRY, %esi # %esi -> relocated loader
addl $MEM_BTX_OFFSET, %esi # %esi -> BTX in the loader
movl $MEM_BTX_ADDRESS, %edi # %edi -> where BTX needs to go
movzwl 0xa(%esi), %ecx # %ecx -> length of BTX
rep # Relocate
movsb # BTX
ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM
.code16
pm_16: movw $SEL_RDATA, %ax # Initialize
movw %ax, %ds # %ds and
movw %ax, %es # %es to a real mode selector
movl %cr0, %eax # Turn off
andb $~0x1, %al # protected
movl %eax, %cr0 # mode
.byte 0xea # Long jump to
.word pm_end # clear the instruction
.word 0x0 # pre-fetch
pm_end: sti # Turn interrupts back on now
#
# Copy the BTX client to MEM_BTX_CLIENT
#
xorw %ax, %ax # zero %ax and set
movw %ax, %ds # %ds and %es
movw %ax, %es # to segment 0
movw $MEM_BTX_CLIENT, %di # Prepare to relocate
movw $btx_client, %si # the simple btx client
movw $(btx_client_end-btx_client), %cx # length of btx client
rep # Relocate the
movsb # simple BTX client
#
# Copy the boot[12] args to where the BTX client can see them
#
movw $MEM_ARG, %si # where the args are at now
movw $MEM_ARG_BTX, %di # where the args are moving to
movw $(MEM_ARG_SIZE/4), %cx # size of the arguments in longs
rep # Relocate
movsl # the words
#
# Save the entry point so the client can get to it later on
#
movl end+AOUT_ENTRY, %eax # load the entry point
stosl # add it to the end of the
# arguments
#
# Now we just start up BTX and let it do the rest
#
movw $jump_message, %si # Display the
call putstr # jump message
.byte 0xea # Jump to
.word MEM_BTX_ENTRY # BTX entry
.word 0x0 # point
#
# Display a null-terminated string
#
putstr: lodsb # load %al from %ds:(%si)
testb %al,%al # stop at null
jnz putc # if the char != null, output it
ret # return when null is hit
putc: movw $0x7,%bx # attribute for output
movb $0xe,%ah # BIOS: put_char
int $0x10 # call BIOS, print char in %al
jmp putstr # keep looping
#
# 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
#
# BTX client to start btxldr
#
.code32
btx_client: movl $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi
# %ds:(%esi) -> end
# of boot[12] args
movl $(MEM_ARG_SIZE/4), %ecx # Number of words to push
std # Go backwards
push_arg: lodsl # Read argument
pushl %eax # Push it onto the stack
loop push_arg # Push all of the arguments
cld # In case anyone depends on this
pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of
# the loader
pushl %eax # Emulate a near call
movl $0x1, %eax # 'exec' system call
int $INT_SYS # BTX system call
btx_client_end:
.code16
.p2align 4
#
# Global descriptor table.
#
gdt: .word 0x0,0x0,0x0,0x0 # Null entry
.word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
.word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
.word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE (32-bit)
.word 0xffff,0x0,0x9a00,0x8f # SEL_SCODE16 (16-bit)
gdt.1:
#
# Pseudo-descriptors.
#
gdtdesc: .word gdt.1-gdt-1 # Limit
.long gdt # Base
welcome_msg: .asciz "PXE Loader 1.00\r\n\n"
bootinfo_msg: .asciz "Building the boot loader arguments\r\n"
relocate_msg: .asciz "Relocating the loader and the BTX\r\n"
jump_message: .asciz "Starting the BTX loader\r\n"
end:

View file

@ -0,0 +1,267 @@
#
# Copyright (c) 2000 John Baldwin
# All rights reserved.
#
# Redistribution and use in source and binary forms are freely
# permitted provided that the above copyright notice and this
# paragraph and the following disclaimer are duplicated in all
# such forms.
#
# This software is provided "AS IS" and without any express or
# implied warranties, including, without limitation, the implied
# warranties of merchantability and fitness for a particular
# purpose.
#
# $FreeBSD$
#
# This simple program is a preloader for the normal boot3 loader. It is simply
# prepended to the beginning of a fully built and btxld'd loader. It then
# copies the loader to the address boot2 normally loads it, emulates the
# boot[12] environment (protected mode, a bootinfo struct, etc.), and then jumps
# to the start of btxldr to start the boot process. This method allows a stock
# /boot/loader to be booted over the network via PXE w/o having to write a
# seperate PXE-aware client just to load the loader.
#
#
# Memory locations.
#
.set MEM_PAGE_SIZE,0x1000 # memory page size, 4k
.set MEM_ARG,0x900 # Arguments at start
.set MEM_ARG_BTX,0xa100 # Where we move them to so the
# BTX client can see them
.set MEM_ARG_SIZE,0x18 # Size of the arguments
.set MEM_BTX_ADDRESS,0x9000 # where BTX lives
.set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute
.set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader
.set MEM_BTX_CLIENT,0xa000 # where BTX clients live
#
# a.out header fields
#
.set AOUT_TEXT,0x04 # text segment size
.set AOUT_DATA,0x08 # data segment size
.set AOUT_BSS,0x0c # zero'd BSS size
.set AOUT_SYMBOLS,0x10 # symbol table
.set AOUT_ENTRY,0x14 # entry point
.set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header
#
# Flags for kargs->bootflags
#
.set KARGS_FLAGS_PXE,0x2 # flag to indicate booting from
# PXE loader
#
# Segment selectors.
#
.set SEL_SDATA,0x8 # Supervisor data
.set SEL_RDATA,0x10 # Real mode data
.set SEL_SCODE,0x18 # PM-32 code
.set SEL_SCODE16,0x20 # PM-16 code
#
# BTX constants
#
.set INT_SYS,0x30 # BTX syscall interrupt
#
# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry
# point)
#
.code16
.globl start
.org 0x0, 0x0
#
# BTX program loader for PXE network booting
#
start: cld # string ops inc
xorw %ax, %ax # zero %ax
movw %ax, %ss # setup the
movw $start, %sp # stack
movw %es, %cx # save PXENV+ segment
movw %ax, %ds # setup the
movw %ax, %es # data segments
andl $0xffff, %ecx # clear upper words
andl $0xffff, %ebx # of %ebx and %ecx
shll $4, %ecx # calculate the offset of
addl %ebx, %ecx # the PXENV+ struct and
pushl %ecx # save it on the stack
movw $welcome_msg, %si # %ds:(%si) -> welcome message
call putstr # display the welcome message
#
# Setup the arguments that the loader is expecting from boot[12]
#
movw $bootinfo_msg, %si # %ds:(%si) -> boot args message
call putstr # display the message
movl $MEM_ARG, %ebx # %ds:(%ebx) -> boot args
movw %bx, %di # %es:(%di) -> boot args
xorl %eax, %eax # zero %eax
movw $(MEM_ARG_SIZE/4), %cx # Size of arguments in 32-bit
# dwords
rep # Clear the arguments
stosl # to zero
orb $KARGS_FLAGS_PXE, 0x8(%ebx) # kargs->bootflags |=
# KARGS_FLAGS_PXE
popl 0xc(%ebx) # kargs->pxeinfo = *PXENV+
#
# Turn on the A20 address line
#
call seta20 # Turn A20 on
#
# Relocate the loader and BTX using a very lazy protected mode
#
movw $relocate_msg, %si # Display the
call putstr # relocation message
movl end+AOUT_ENTRY, %edi # %edi is the destination
movl $(end+AOUT_HEADER), %esi # %esi is
# the start of the text
# segment
movl end+AOUT_TEXT, %ecx # %ecx = length of the text
# segment
lgdt gdtdesc # setup our own gdt
cli # turn off interrupts
movl %cr0, %eax # Turn on
orb $0x1, %al # protected
movl %eax, %cr0 # mode
.byte 0xea # long jump to
.word pm_start # clear the instruction
.word SEL_SCODE # pre-fetch queue
.code32
pm_start: movw $SEL_SDATA, %ax # Initialize
movw %ax, %ds # %ds and
movw %ax, %es # %es to a flat selector
rep # Relocate the
movsb # text segment
addl $(MEM_PAGE_SIZE - 1), %edi # pad %edi out to a new page
andl $~(MEM_PAGE_SIZE - 1), %edi # for the data segment
movl end+AOUT_DATA, %ecx # size of the data segment
rep # Relocate the
movsb # data segment
movl end+AOUT_BSS, %ecx # size of the bss
xorl %eax, %eax # zero %eax
addb $3, %cl # round %ecx up to
shrl $2, %ecx # a multiple of 4
rep # zero the
stosl # bss
movl end+AOUT_ENTRY, %esi # %esi -> relocated loader
addl $MEM_BTX_OFFSET, %esi # %esi -> BTX in the loader
movl $MEM_BTX_ADDRESS, %edi # %edi -> where BTX needs to go
movzwl 0xa(%esi), %ecx # %ecx -> length of BTX
rep # Relocate
movsb # BTX
ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM
.code16
pm_16: movw $SEL_RDATA, %ax # Initialize
movw %ax, %ds # %ds and
movw %ax, %es # %es to a real mode selector
movl %cr0, %eax # Turn off
andb $~0x1, %al # protected
movl %eax, %cr0 # mode
.byte 0xea # Long jump to
.word pm_end # clear the instruction
.word 0x0 # pre-fetch
pm_end: sti # Turn interrupts back on now
#
# Copy the BTX client to MEM_BTX_CLIENT
#
xorw %ax, %ax # zero %ax and set
movw %ax, %ds # %ds and %es
movw %ax, %es # to segment 0
movw $MEM_BTX_CLIENT, %di # Prepare to relocate
movw $btx_client, %si # the simple btx client
movw $(btx_client_end-btx_client), %cx # length of btx client
rep # Relocate the
movsb # simple BTX client
#
# Copy the boot[12] args to where the BTX client can see them
#
movw $MEM_ARG, %si # where the args are at now
movw $MEM_ARG_BTX, %di # where the args are moving to
movw $(MEM_ARG_SIZE/4), %cx # size of the arguments in longs
rep # Relocate
movsl # the words
#
# Save the entry point so the client can get to it later on
#
movl end+AOUT_ENTRY, %eax # load the entry point
stosl # add it to the end of the
# arguments
#
# Now we just start up BTX and let it do the rest
#
movw $jump_message, %si # Display the
call putstr # jump message
.byte 0xea # Jump to
.word MEM_BTX_ENTRY # BTX entry
.word 0x0 # point
#
# Display a null-terminated string
#
putstr: lodsb # load %al from %ds:(%si)
testb %al,%al # stop at null
jnz putc # if the char != null, output it
ret # return when null is hit
putc: movw $0x7,%bx # attribute for output
movb $0xe,%ah # BIOS: put_char
int $0x10 # call BIOS, print char in %al
jmp putstr # keep looping
#
# 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
#
# BTX client to start btxldr
#
.code32
btx_client: movl $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi
# %ds:(%esi) -> end
# of boot[12] args
movl $(MEM_ARG_SIZE/4), %ecx # Number of words to push
std # Go backwards
push_arg: lodsl # Read argument
pushl %eax # Push it onto the stack
loop push_arg # Push all of the arguments
cld # In case anyone depends on this
pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of
# the loader
pushl %eax # Emulate a near call
movl $0x1, %eax # 'exec' system call
int $INT_SYS # BTX system call
btx_client_end:
.code16
.p2align 4
#
# Global descriptor table.
#
gdt: .word 0x0,0x0,0x0,0x0 # Null entry
.word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
.word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
.word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE (32-bit)
.word 0xffff,0x0,0x9a00,0x8f # SEL_SCODE16 (16-bit)
gdt.1:
#
# Pseudo-descriptors.
#
gdtdesc: .word gdt.1-gdt-1 # Limit
.long gdt # Base
welcome_msg: .asciz "PXE Loader 1.00\r\n\n"
bootinfo_msg: .asciz "Building the boot loader arguments\r\n"
relocate_msg: .asciz "Relocating the loader and the BTX\r\n"
jump_message: .asciz "Starting the BTX loader\r\n"
end: