mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 21:05:08 +00:00
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:
parent
7ef719fb93
commit
48a0c4ea04
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=58713
|
@ -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>
|
||||
|
|
5
sys/boot/i386/Makefile.inc
Normal file
5
sys/boot/i386/Makefile.inc
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Common defines for all of /sys/boot/i386/
|
||||
#
|
||||
# $FreeBSD$
|
||||
|
||||
LOADER_ADDRESS?= 0x200000
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
#
|
||||
|
|
|
@ -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.
|
||||
#
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
640
sys/boot/i386/libi386/pxe.c
Normal 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;
|
||||
}
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
40
sys/boot/i386/pxeldr/Makefile
Normal file
40
sys/boot/i386/pxeldr/Makefile
Normal 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>
|
267
sys/boot/i386/pxeldr/pxeldr.S
Normal file
267
sys/boot/i386/pxeldr/pxeldr.S
Normal 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:
|
267
sys/boot/i386/pxeldr/pxeldr.s
Normal file
267
sys/boot/i386/pxeldr/pxeldr.s
Normal 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:
|
Loading…
Reference in a new issue