xref: /titanic_54/usr/src/boot/sys/boot/i386/cdboot/cdboot.S (revision 4d40e39c66a331aefef24083480939f0e78a9045)
14a5d661aSToomas Soome#
24a5d661aSToomas Soome# Copyright (c) 2001 John Baldwin <jhb@FreeBSD.org>
34a5d661aSToomas Soome# All rights reserved.
44a5d661aSToomas Soome#
54a5d661aSToomas Soome# Redistribution and use in source and binary forms, with or without
64a5d661aSToomas Soome# modification, are permitted provided that the following conditions
74a5d661aSToomas Soome# are met:
84a5d661aSToomas Soome# 1. Redistributions of source code must retain the above copyright
94a5d661aSToomas Soome#    notice, this list of conditions and the following disclaimer.
104a5d661aSToomas Soome# 2. Redistributions in binary form must reproduce the above copyright
114a5d661aSToomas Soome#    notice, this list of conditions and the following disclaimer in the
124a5d661aSToomas Soome#    documentation and/or other materials provided with the distribution.
134a5d661aSToomas Soome#
144a5d661aSToomas Soome# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
154a5d661aSToomas Soome# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
164a5d661aSToomas Soome# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
174a5d661aSToomas Soome# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
184a5d661aSToomas Soome# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
194a5d661aSToomas Soome# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
204a5d661aSToomas Soome# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
214a5d661aSToomas Soome# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
224a5d661aSToomas Soome# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
234a5d661aSToomas Soome# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
244a5d661aSToomas Soome# SUCH DAMAGE.
254a5d661aSToomas Soome#
264a5d661aSToomas Soome
274a5d661aSToomas Soome# $FreeBSD$
284a5d661aSToomas Soome
294a5d661aSToomas Soome#
304a5d661aSToomas Soome# This program is a freestanding boot program to load an a.out binary
314a5d661aSToomas Soome# from a CD-ROM booted with no emulation mode as described by the El
324a5d661aSToomas Soome# Torito standard.  Due to broken BIOSen that do not load the desired
334a5d661aSToomas Soome# number of sectors, we try to fit this in as small a space as possible.
344a5d661aSToomas Soome#
354a5d661aSToomas Soome# Basically, we first create a set of boot arguments to pass to the loaded
364a5d661aSToomas Soome# binary.  Then we attempt to load /boot/loader from the CD we were booted
37*4d40e39cSAndy Fiddaman# from.
384a5d661aSToomas Soome#
394a5d661aSToomas Soome
404a5d661aSToomas Soome#include <bootargs.h>
414a5d661aSToomas Soome
424a5d661aSToomas Soome#
434a5d661aSToomas Soome# Memory locations.
444a5d661aSToomas Soome#
454a5d661aSToomas Soome		.set MEM_PAGE_SIZE,0x1000	# memory page size, 4k
464a5d661aSToomas Soome		.set MEM_ARG,0x900		# Arguments at start
474a5d661aSToomas Soome		.set MEM_ARG_BTX,0xa100		# Where we move them to so the
484a5d661aSToomas Soome						#  BTX client can see them
494a5d661aSToomas Soome		.set MEM_ARG_SIZE,0x18		# Size of the arguments
504a5d661aSToomas Soome		.set MEM_BTX_ADDRESS,0x9000	# where BTX lives
514a5d661aSToomas Soome		.set MEM_BTX_ENTRY,0x9010	# where BTX starts to execute
524a5d661aSToomas Soome		.set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader
534a5d661aSToomas Soome		.set MEM_BTX_CLIENT,0xa000	# where BTX clients live
544a5d661aSToomas Soome#
554a5d661aSToomas Soome# a.out header fields
564a5d661aSToomas Soome#
574a5d661aSToomas Soome		.set AOUT_TEXT,0x04		# text segment size
584a5d661aSToomas Soome		.set AOUT_DATA,0x08		# data segment size
594a5d661aSToomas Soome		.set AOUT_BSS,0x0c		# zero'd BSS size
604a5d661aSToomas Soome		.set AOUT_SYMBOLS,0x10		# symbol table
614a5d661aSToomas Soome		.set AOUT_ENTRY,0x14		# entry point
624a5d661aSToomas Soome		.set AOUT_HEADER,MEM_PAGE_SIZE	# size of the a.out header
634a5d661aSToomas Soome#
644a5d661aSToomas Soome# Segment selectors.
654a5d661aSToomas Soome#
664a5d661aSToomas Soome		.set SEL_SDATA,0x8		# Supervisor data
674a5d661aSToomas Soome		.set SEL_RDATA,0x10		# Real mode data
684a5d661aSToomas Soome		.set SEL_SCODE,0x18		# PM-32 code
694a5d661aSToomas Soome		.set SEL_SCODE16,0x20		# PM-16 code
704a5d661aSToomas Soome#
714a5d661aSToomas Soome# BTX constants
724a5d661aSToomas Soome#
734a5d661aSToomas Soome		.set INT_SYS,0x30		# BTX syscall interrupt
744a5d661aSToomas Soome#
754a5d661aSToomas Soome# Constants for reading from the CD.
764a5d661aSToomas Soome#
774a5d661aSToomas Soome		.set ERROR_TIMEOUT,0x80		# BIOS timeout on read
784a5d661aSToomas Soome		.set NUM_RETRIES,3		# Num times to retry
794a5d661aSToomas Soome		.set SECTOR_SIZE,0x800		# size of a sector
804a5d661aSToomas Soome		.set SECTOR_SHIFT,11		# number of place to shift
814a5d661aSToomas Soome		.set BUFFER_LEN,0x100		# number of sectors in buffer
824a5d661aSToomas Soome		.set MAX_READ,0x10000		# max we can read at a time
834a5d661aSToomas Soome		.set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT
844a5d661aSToomas Soome		.set MEM_READ_BUFFER,0x9000	# buffer to read from CD
854a5d661aSToomas Soome		.set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor
864a5d661aSToomas Soome		.set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer
874a5d661aSToomas Soome		.set VOLDESC_LBA,0x10		# LBA of vol descriptor
884a5d661aSToomas Soome		.set VD_PRIMARY,1		# Primary VD
894a5d661aSToomas Soome		.set VD_END,255			# VD Terminator
904a5d661aSToomas Soome		.set VD_ROOTDIR,156		# Offset of Root Dir Record
914a5d661aSToomas Soome		.set DIR_LEN,0			# Offset of Dir Record length
924a5d661aSToomas Soome		.set DIR_EA_LEN,1		# Offset of EA length
934a5d661aSToomas Soome		.set DIR_EXTENT,2		# Offset of 64-bit LBA
944a5d661aSToomas Soome		.set DIR_SIZE,10		# Offset of 64-bit length
954a5d661aSToomas Soome		.set DIR_NAMELEN,32		# Offset of 8-bit name len
964a5d661aSToomas Soome		.set DIR_NAME,33		# Offset of dir name
974a5d661aSToomas Soome#
984a5d661aSToomas Soome# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry
994a5d661aSToomas Soome# point)
1004a5d661aSToomas Soome#
1014a5d661aSToomas Soome		.code16
1024a5d661aSToomas Soome		.globl start
1034a5d661aSToomas Soome		.org 0x0, 0x0
1044a5d661aSToomas Soome#
1054a5d661aSToomas Soome# Program start.
1064a5d661aSToomas Soome#
1074a5d661aSToomas Soomestart:		jmp real_start
1084a5d661aSToomas Soome		.org 0x8, 0x8
1094a5d661aSToomas Soome
1104a5d661aSToomas Soomebi_pvd:		.long VOLDESC_LBA		# LBA of primary volume desc
1114a5d661aSToomas Soomebi_file:	.long 0				# LBA of boot file.
1124a5d661aSToomas Soomebi_length:	.long 0				# Length of boot file.
1134a5d661aSToomas Soomebi_csum:	.long 0				# Checksum of boot file
1144a5d661aSToomas Soomebi_reserved:	.space (10*4)			# Reserved
1154a5d661aSToomas Soome
1164a5d661aSToomas Soomereal_start:	cld				# string ops inc
1174a5d661aSToomas Soome		xor %ax,%ax			# zero %ax
1184a5d661aSToomas Soome		mov %ax,%ss			# setup the
1194a5d661aSToomas Soome		mov $start,%sp			#  stack
1204a5d661aSToomas Soome		mov %ax,%ds			# setup the
1214a5d661aSToomas Soome		mov %ax,%es			#  data segments
1224a5d661aSToomas Soome		mov %dl,drive			# Save BIOS boot device
1234a5d661aSToomas Soome		mov $msg_welcome,%si		# %ds:(%si) -> welcome message
1244a5d661aSToomas Soome		call putstr			# display the welcome message
1254a5d661aSToomas Soome#
1264a5d661aSToomas Soome# Setup the arguments that the loader is expecting from boot[12]
1274a5d661aSToomas Soome#
1284a5d661aSToomas Soome		mov $msg_bootinfo,%si		# %ds:(%si) -> boot args message
1294a5d661aSToomas Soome		call putstr			# display the message
1304a5d661aSToomas Soome		mov $MEM_ARG,%bx		# %ds:(%bx) -> boot args
1314a5d661aSToomas Soome		mov %bx,%di			# %es:(%di) -> boot args
1324a5d661aSToomas Soome		xor %eax,%eax			# zero %eax
1334a5d661aSToomas Soome		mov $(MEM_ARG_SIZE/4),%cx	# Size of arguments in 32-bit
1344a5d661aSToomas Soome						#  dwords
1354a5d661aSToomas Soome		rep				# Clear the arguments
1364a5d661aSToomas Soome		stosl				#  to zero
1374a5d661aSToomas Soome		mov drive,%dl			# Store BIOS boot device
1384a5d661aSToomas Soome		mov %dl,0x4(%bx)		#  in kargs->bootdev
139*4d40e39cSAndy Fiddaman		orb $KARGS_FLAGS_CD,0x8(%bx)	# kargs->bootflags |=
1404a5d661aSToomas Soome						#  KARGS_FLAGS_CD
1414a5d661aSToomas Soome#
1424a5d661aSToomas Soome# Load Volume Descriptor
1434a5d661aSToomas Soome#
1444a5d661aSToomas Soome		mov $VOLDESC_LBA,%eax		# Set LBA of first VD
1454a5d661aSToomas Soomeload_vd:	push %eax			# Save %eax
1464a5d661aSToomas Soome		mov $1,%dh			# One sector
1474a5d661aSToomas Soome		mov $MEM_VOLDESC,%ebx		# Destination
1484a5d661aSToomas Soome		call read			# Read it in
1494a5d661aSToomas Soome		cmpb $VD_PRIMARY,(%bx)		# Primary VD?
1504a5d661aSToomas Soome		je have_vd			# Yes
1514a5d661aSToomas Soome		pop %eax			# Prepare to
1524a5d661aSToomas Soome		inc %eax			#  try next
1534a5d661aSToomas Soome		cmpb $VD_END,(%bx)		# Last VD?
1544a5d661aSToomas Soome		jne load_vd			# No, read next
1554a5d661aSToomas Soome		mov $msg_novd,%si		# No VD
1564a5d661aSToomas Soome		jmp error			# Halt
1574a5d661aSToomas Soomehave_vd:					# Have Primary VD
1584a5d661aSToomas Soome#
1594a5d661aSToomas Soome# Try to look up the loader binary using the paths in the loader_paths
1604a5d661aSToomas Soome# array.
1614a5d661aSToomas Soome#
1624a5d661aSToomas Soome		mov $loader_paths,%si		# Point to start of array
1634a5d661aSToomas Soomelookup_path:	push %si			# Save file name pointer
1644a5d661aSToomas Soome		call lookup			# Try to find file
1654a5d661aSToomas Soome		pop %di				# Restore file name pointer
1664a5d661aSToomas Soome		jnc lookup_found		# Found this file
1674a5d661aSToomas Soome		xor %al,%al			# Look for next
1684a5d661aSToomas Soome		mov $0xffff,%cx			#  path name by
1694a5d661aSToomas Soome		repnz				#  scanning for
1704a5d661aSToomas Soome		scasb				#  nul char
1714a5d661aSToomas Soome		mov %di,%si			# Point %si at next path
1724a5d661aSToomas Soome		mov (%si),%al			# Get first char of next path
1734a5d661aSToomas Soome		or %al,%al			# Is it double nul?
1744a5d661aSToomas Soome		jnz lookup_path			# No, try it.
1754a5d661aSToomas Soome		mov $msg_failed,%si		# Failed message
1764a5d661aSToomas Soome		jmp error			# Halt
1774a5d661aSToomas Soomelookup_found:					# Found a loader file
1784a5d661aSToomas Soome#
1794a5d661aSToomas Soome# Load the binary into the buffer.  Due to real mode addressing limitations
1804a5d661aSToomas Soome# we have to read it in 64k chunks.
1814a5d661aSToomas Soome#
1824a5d661aSToomas Soome		mov DIR_SIZE(%bx),%eax		# Read file length
1834a5d661aSToomas Soome		add $SECTOR_SIZE-1,%eax		# Convert length to sectors
1844a5d661aSToomas Soome		shr $SECTOR_SHIFT,%eax
1854a5d661aSToomas Soome		cmp $BUFFER_LEN,%eax
1864a5d661aSToomas Soome		jbe load_sizeok
1874a5d661aSToomas Soome		mov $msg_load2big,%si		# Error message
1884a5d661aSToomas Soome		call error
1894a5d661aSToomas Soomeload_sizeok:	movzbw %al,%cx			# Num sectors to read
1904a5d661aSToomas Soome		mov DIR_EXTENT(%bx),%eax	# Load extent
1914a5d661aSToomas Soome		xor %edx,%edx
1924a5d661aSToomas Soome		mov DIR_EA_LEN(%bx),%dl
1934a5d661aSToomas Soome		add %edx,%eax			# Skip extended
1944a5d661aSToomas Soome		mov $MEM_READ_BUFFER,%ebx	# Read into the buffer
1954a5d661aSToomas Soomeload_loop:	mov %cl,%dh
1964a5d661aSToomas Soome		cmp $MAX_READ_SEC,%cl		# Truncate to max read size
1974a5d661aSToomas Soome		jbe load_notrunc
1984a5d661aSToomas Soome		mov $MAX_READ_SEC,%dh
1994a5d661aSToomas Soomeload_notrunc:	sub %dh,%cl			# Update count
2004a5d661aSToomas Soome		push %eax			# Save
2014a5d661aSToomas Soome		call read			# Read it in
2024a5d661aSToomas Soome		pop %eax			# Restore
2034a5d661aSToomas Soome		add $MAX_READ_SEC,%eax		# Update LBA
2044a5d661aSToomas Soome		add $MAX_READ,%ebx		# Update dest addr
2054a5d661aSToomas Soome		jcxz load_done			# Done?
2064a5d661aSToomas Soome		jmp load_loop			# Keep going
2074a5d661aSToomas Soomeload_done:
2084a5d661aSToomas Soome#
2094a5d661aSToomas Soome# Turn on the A20 address line
2104a5d661aSToomas Soome#
2114a5d661aSToomas Soome		call seta20			# Turn A20 on
2124a5d661aSToomas Soome#
2134a5d661aSToomas Soome# Relocate the loader and BTX using a very lazy protected mode
2144a5d661aSToomas Soome#
2154a5d661aSToomas Soome		mov $msg_relocate,%si		# Display the
2164a5d661aSToomas Soome		call putstr			#  relocation message
2174a5d661aSToomas Soome		mov MEM_READ_BUFFER+AOUT_ENTRY,%edi # %edi is the destination
2184a5d661aSToomas Soome		mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi	# %esi is
2194a5d661aSToomas Soome						#  the start of the text
2204a5d661aSToomas Soome						#  segment
2214a5d661aSToomas Soome		mov MEM_READ_BUFFER+AOUT_TEXT,%ecx # %ecx = length of the text
2224a5d661aSToomas Soome						#  segment
2234a5d661aSToomas Soome		push %edi			# Save entry point for later
2244a5d661aSToomas Soome		lgdt gdtdesc			# setup our own gdt
2254a5d661aSToomas Soome		cli				# turn off interrupts
2264a5d661aSToomas Soome		mov %cr0,%eax			# Turn on
2274a5d661aSToomas Soome		or $0x1,%al			#  protected
2284a5d661aSToomas Soome		mov %eax,%cr0			#  mode
2294a5d661aSToomas Soome		ljmp $SEL_SCODE,$pm_start	# long jump to clear the
2304a5d661aSToomas Soome						#  instruction pre-fetch queue
2314a5d661aSToomas Soome		.code32
2324a5d661aSToomas Soomepm_start:	mov $SEL_SDATA,%ax		# Initialize
2334a5d661aSToomas Soome		mov %ax,%ds			#  %ds and
2344a5d661aSToomas Soome		mov %ax,%es			#  %es to a flat selector
2354a5d661aSToomas Soome		rep				# Relocate the
2364a5d661aSToomas Soome		movsb				#  text segment
2374a5d661aSToomas Soome		add $(MEM_PAGE_SIZE - 1),%edi	# pad %edi out to a new page
2384a5d661aSToomas Soome		and $~(MEM_PAGE_SIZE - 1),%edi #  for the data segment
2394a5d661aSToomas Soome		mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment
2404a5d661aSToomas Soome		rep				# Relocate the
2414a5d661aSToomas Soome		movsb				#  data segment
2424a5d661aSToomas Soome		mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss
2434a5d661aSToomas Soome		xor %eax,%eax			# zero %eax
2444a5d661aSToomas Soome		add $3,%cl			# round %ecx up to
2454a5d661aSToomas Soome		shr $2,%ecx			#  a multiple of 4
2464a5d661aSToomas Soome		rep				# zero the
2474a5d661aSToomas Soome		stosl				#  bss
2484a5d661aSToomas Soome		mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader
2494a5d661aSToomas Soome		add $MEM_BTX_OFFSET,%esi	# %esi -> BTX in the loader
2504a5d661aSToomas Soome		mov $MEM_BTX_ADDRESS,%edi	# %edi -> where BTX needs to go
2514a5d661aSToomas Soome		movzwl 0xa(%esi),%ecx		# %ecx -> length of BTX
2524a5d661aSToomas Soome		rep				# Relocate
2534a5d661aSToomas Soome		movsb				#  BTX
2544a5d661aSToomas Soome		ljmp $SEL_SCODE16,$pm_16	# Jump to 16-bit PM
2554a5d661aSToomas Soome		.code16
2564a5d661aSToomas Soomepm_16:		mov $SEL_RDATA,%ax		# Initialize
2574a5d661aSToomas Soome		mov %ax,%ds			#  %ds and
2584a5d661aSToomas Soome		mov %ax,%es			#  %es to a real mode selector
2594a5d661aSToomas Soome		mov %cr0,%eax			# Turn off
2604a5d661aSToomas Soome		and $~0x1,%al			#  protected
2614a5d661aSToomas Soome		mov %eax,%cr0			#  mode
2624a5d661aSToomas Soome		ljmp $0,$pm_end			# Long jump to clear the
2634a5d661aSToomas Soome						#  instruction pre-fetch queue
2644a5d661aSToomas Soomepm_end:		sti				# Turn interrupts back on now
2654a5d661aSToomas Soome#
2664a5d661aSToomas Soome# Copy the BTX client to MEM_BTX_CLIENT
2674a5d661aSToomas Soome#
2684a5d661aSToomas Soome		xor %ax,%ax			# zero %ax and set
2694a5d661aSToomas Soome		mov %ax,%ds			#  %ds and %es
2704a5d661aSToomas Soome		mov %ax,%es			#  to segment 0
2714a5d661aSToomas Soome		mov $MEM_BTX_CLIENT,%di		# Prepare to relocate
2724a5d661aSToomas Soome		mov $btx_client,%si		#  the simple btx client
2734a5d661aSToomas Soome		mov $(btx_client_end-btx_client),%cx # length of btx client
2744a5d661aSToomas Soome		rep				# Relocate the
2754a5d661aSToomas Soome		movsb				#  simple BTX client
2764a5d661aSToomas Soome#
2774a5d661aSToomas Soome# Copy the boot[12] args to where the BTX client can see them
2784a5d661aSToomas Soome#
2794a5d661aSToomas Soome		mov $MEM_ARG,%si		# where the args are at now
2804a5d661aSToomas Soome		mov $MEM_ARG_BTX,%di		# where the args are moving to
2814a5d661aSToomas Soome		mov $(MEM_ARG_SIZE/4),%cx	# size of the arguments in longs
2824a5d661aSToomas Soome		rep				# Relocate
2834a5d661aSToomas Soome		movsl				#  the words
2844a5d661aSToomas Soome#
2854a5d661aSToomas Soome# Save the entry point so the client can get to it later on
2864a5d661aSToomas Soome#
2874a5d661aSToomas Soome		pop %eax			# Restore saved entry point
2884a5d661aSToomas Soome		stosl				#  and add it to the end of
2894a5d661aSToomas Soome						#  the arguments
2904a5d661aSToomas Soome#
2914a5d661aSToomas Soome# Now we just start up BTX and let it do the rest
2924a5d661aSToomas Soome#
2934a5d661aSToomas Soome		mov $msg_jump,%si		# Display the
2944a5d661aSToomas Soome		call putstr			#  jump message
2954a5d661aSToomas Soome		ljmp $0,$MEM_BTX_ENTRY		# Jump to the BTX entry point
2964a5d661aSToomas Soome
2974a5d661aSToomas Soome#
2984a5d661aSToomas Soome# Lookup the file in the path at [SI] from the root directory.
2994a5d661aSToomas Soome#
3004a5d661aSToomas Soome# Trashes: All but BX
3014a5d661aSToomas Soome# Returns: CF = 0 (success), BX = pointer to record
3024a5d661aSToomas Soome#          CF = 1 (not found)
3034a5d661aSToomas Soome#
3044a5d661aSToomas Soomelookup:		mov $VD_ROOTDIR+MEM_VOLDESC,%bx	# Root directory record
3054a5d661aSToomas Soome		push %si
3064a5d661aSToomas Soome		mov $msg_lookup,%si		# Display lookup message
3074a5d661aSToomas Soome		call putstr
3084a5d661aSToomas Soome		pop %si
3094a5d661aSToomas Soome		push %si
3104a5d661aSToomas Soome		call putstr
3114a5d661aSToomas Soome		mov $msg_lookup2,%si
3124a5d661aSToomas Soome		call putstr
3134a5d661aSToomas Soome		pop %si
3144a5d661aSToomas Soomelookup_dir:	lodsb				# Get first char of path
3154a5d661aSToomas Soome		cmp $0,%al			# Are we done?
3164a5d661aSToomas Soome		je lookup_done			# Yes
3174a5d661aSToomas Soome		cmp $'/',%al			# Skip path separator.
3184a5d661aSToomas Soome		je lookup_dir
3194a5d661aSToomas Soome		dec %si				# Undo lodsb side effect
3204a5d661aSToomas Soome		call find_file			# Lookup first path item
3214a5d661aSToomas Soome		jnc lookup_dir			# Try next component
3224a5d661aSToomas Soome		mov $msg_lookupfail,%si		# Not found message
3234a5d661aSToomas Soome		call putstr
3244a5d661aSToomas Soome		stc				# Set carry
3254a5d661aSToomas Soome		ret
3264a5d661aSToomas Soome		jmp error
3274a5d661aSToomas Soomelookup_done:	mov $msg_lookupok,%si		# Success message
3284a5d661aSToomas Soome		call putstr
3294a5d661aSToomas Soome		clc				# Clear carry
3304a5d661aSToomas Soome		ret
3314a5d661aSToomas Soome
3324a5d661aSToomas Soome#
3334a5d661aSToomas Soome# Lookup file at [SI] in directory whose record is at [BX].
3344a5d661aSToomas Soome#
3354a5d661aSToomas Soome# Trashes: All but returns
3364a5d661aSToomas Soome# Returns: CF = 0 (success), BX = pointer to record, SI = next path item
3374a5d661aSToomas Soome#          CF = 1 (not found), SI = preserved
3384a5d661aSToomas Soome#
3394a5d661aSToomas Soomefind_file:	mov DIR_EXTENT(%bx),%eax	# Load extent
3404a5d661aSToomas Soome		xor %edx,%edx
3414a5d661aSToomas Soome		mov DIR_EA_LEN(%bx),%dl
3424a5d661aSToomas Soome		add %edx,%eax			# Skip extended attributes
3434a5d661aSToomas Soome		mov %eax,rec_lba		# Save LBA
3444a5d661aSToomas Soome		mov DIR_SIZE(%bx),%eax		# Save size
3454a5d661aSToomas Soome		mov %eax,rec_size
3464a5d661aSToomas Soome		xor %cl,%cl			# Zero length
3474a5d661aSToomas Soome		push %si			# Save
3484a5d661aSToomas Soomeff.namelen:	inc %cl				# Update length
3494a5d661aSToomas Soome		lodsb				# Read char
3504a5d661aSToomas Soome		cmp $0,%al			# Nul?
3514a5d661aSToomas Soome		je ff.namedone			# Yes
3524a5d661aSToomas Soome		cmp $'/',%al			# Path separator?
3534a5d661aSToomas Soome		jnz ff.namelen			# No, keep going
3544a5d661aSToomas Soomeff.namedone:	dec %cl				# Adjust length and save
3554a5d661aSToomas Soome		mov %cl,name_len
3564a5d661aSToomas Soome		pop %si				# Restore
3574a5d661aSToomas Soomeff.load:	mov rec_lba,%eax		# Load LBA
3584a5d661aSToomas Soome		mov $MEM_DIR,%ebx		# Address buffer
3594a5d661aSToomas Soome		mov $1,%dh			# One sector
3604a5d661aSToomas Soome		call read			# Read directory block
3614a5d661aSToomas Soome		incl rec_lba			# Update LBA to next block
3624a5d661aSToomas Soomeff.scan:	mov %ebx,%edx			# Check for EOF
3634a5d661aSToomas Soome		sub $MEM_DIR,%edx
3644a5d661aSToomas Soome		cmp %edx,rec_size
3654a5d661aSToomas Soome		ja ff.scan.1
3664a5d661aSToomas Soome		stc				# EOF reached
3674a5d661aSToomas Soome		ret
3684a5d661aSToomas Soomeff.scan.1:	cmpb $0,DIR_LEN(%bx)		# Last record in block?
3694a5d661aSToomas Soome		je ff.nextblock
3704a5d661aSToomas Soome		push %si			# Save
3714a5d661aSToomas Soome		movzbw DIR_NAMELEN(%bx),%si	# Find end of string
3724a5d661aSToomas Soomeff.checkver:	cmpb $'0',DIR_NAME-1(%bx,%si)	# Less than '0'?
3734a5d661aSToomas Soome		jb ff.checkver.1
3744a5d661aSToomas Soome		cmpb $'9',DIR_NAME-1(%bx,%si)	# Greater than '9'?
3754a5d661aSToomas Soome		ja ff.checkver.1
3764a5d661aSToomas Soome		dec %si				# Next char
3774a5d661aSToomas Soome		jnz ff.checkver
3784a5d661aSToomas Soome		jmp ff.checklen			# All numbers in name, so
3794a5d661aSToomas Soome						#  no version
3804a5d661aSToomas Soomeff.checkver.1:	movzbw DIR_NAMELEN(%bx),%cx
3814a5d661aSToomas Soome		cmp %cx,%si			# Did we find any digits?
3824a5d661aSToomas Soome		je ff.checkdot			# No
3834a5d661aSToomas Soome		cmpb $';',DIR_NAME-1(%bx,%si)	# Check for semicolon
3844a5d661aSToomas Soome		jne ff.checkver.2
3854a5d661aSToomas Soome		dec %si				# Skip semicolon
3864a5d661aSToomas Soome		mov %si,%cx
3874a5d661aSToomas Soome		mov %cl,DIR_NAMELEN(%bx)	# Adjust length
3884a5d661aSToomas Soome		jmp ff.checkdot
3894a5d661aSToomas Soomeff.checkver.2:	mov %cx,%si			# Restore %si to end of string
3904a5d661aSToomas Soomeff.checkdot:	cmpb $'.',DIR_NAME-1(%bx,%si)	# Trailing dot?
3914a5d661aSToomas Soome		jne ff.checklen			# No
3924a5d661aSToomas Soome		decb DIR_NAMELEN(%bx)		# Adjust length
3934a5d661aSToomas Soomeff.checklen:	pop %si				# Restore
3944a5d661aSToomas Soome		movzbw name_len,%cx		# Load length of name
3954a5d661aSToomas Soome		cmp %cl,DIR_NAMELEN(%bx)	# Does length match?
3964a5d661aSToomas Soome		je ff.checkname			# Yes, check name
3974a5d661aSToomas Soomeff.nextrec:	add DIR_LEN(%bx),%bl		# Next record
3984a5d661aSToomas Soome		adc $0,%bh
3994a5d661aSToomas Soome		jmp ff.scan
4004a5d661aSToomas Soomeff.nextblock:	subl $SECTOR_SIZE,rec_size	# Adjust size
4014a5d661aSToomas Soome		jnc ff.load			# If subtract ok, keep going
4024a5d661aSToomas Soome		ret				# End of file, so not found
4034a5d661aSToomas Soomeff.checkname:	lea DIR_NAME(%bx),%di		# Address name in record
4044a5d661aSToomas Soome		push %si			# Save
4054a5d661aSToomas Soome		repe cmpsb			# Compare name
4064a5d661aSToomas Soome		je ff.match			# We have a winner!
4074a5d661aSToomas Soome		pop %si				# Restore
4084a5d661aSToomas Soome		jmp ff.nextrec			# Keep looking.
4094a5d661aSToomas Soomeff.match:	add $2,%sp			# Discard saved %si
4104a5d661aSToomas Soome		clc				# Clear carry
4114a5d661aSToomas Soome		ret
4124a5d661aSToomas Soome
4134a5d661aSToomas Soome#
4144a5d661aSToomas Soome# Load DH sectors starting at LBA EAX into [EBX].
4154a5d661aSToomas Soome#
4164a5d661aSToomas Soome# Trashes: EAX
4174a5d661aSToomas Soome#
4184a5d661aSToomas Soomeread:		push %si			# Save
4194a5d661aSToomas Soome		push %cx			# Save since some BIOSs trash
4204a5d661aSToomas Soome		mov %eax,edd_lba		# LBA to read from
4214a5d661aSToomas Soome		mov %ebx,%eax			# Convert address
4224a5d661aSToomas Soome		shr $4,%eax			#  to segment
4234a5d661aSToomas Soome		mov %ax,edd_addr+0x2		#  and store
4244a5d661aSToomas Soomeread.retry:	call twiddle			# Entertain the user
4254a5d661aSToomas Soome		push %dx			# Save
4264a5d661aSToomas Soome		mov $edd_packet,%si		# Address Packet
4274a5d661aSToomas Soome		mov %dh,edd_len			# Set length
4284a5d661aSToomas Soome		mov drive,%dl			# BIOS Device
4294a5d661aSToomas Soome		mov $0x42,%ah			# BIOS: Extended Read
4304a5d661aSToomas Soome		int $0x13			# Call BIOS
4314a5d661aSToomas Soome		pop %dx				# Restore
4324a5d661aSToomas Soome		jc read.fail			# Worked?
4334a5d661aSToomas Soome		pop %cx				# Restore
4344a5d661aSToomas Soome		pop %si
4354a5d661aSToomas Soome		ret				# Return
4364a5d661aSToomas Soomeread.fail:	cmp $ERROR_TIMEOUT,%ah		# Timeout?
4374a5d661aSToomas Soome		je read.retry			# Yes, Retry.
4384a5d661aSToomas Soomeread.error:	mov %ah,%al			# Save error
4394a5d661aSToomas Soome		mov $hex_error,%di		# Format it
4404a5d661aSToomas Soome		call hex8			#  as hex
4414a5d661aSToomas Soome		mov $msg_badread,%si		# Display Read error message
4424a5d661aSToomas Soome
4434a5d661aSToomas Soome#
4444a5d661aSToomas Soome# Display error message at [SI] and halt.
4454a5d661aSToomas Soome#
4464a5d661aSToomas Soomeerror:		call putstr			# Display message
4474a5d661aSToomas Soomehalt:		hlt
4484a5d661aSToomas Soome		jmp halt			# Spin
4494a5d661aSToomas Soome
4504a5d661aSToomas Soome#
4514a5d661aSToomas Soome# Display a null-terminated string.
4524a5d661aSToomas Soome#
4534a5d661aSToomas Soome# Trashes: AX, SI
4544a5d661aSToomas Soome#
4554a5d661aSToomas Soomeputstr:		push %bx			# Save
4564a5d661aSToomas Soomeputstr.load:	lodsb				# load %al from %ds:(%si)
4574a5d661aSToomas Soome		test %al,%al			# stop at null
4584a5d661aSToomas Soome		jnz putstr.putc			# if the char != null, output it
4594a5d661aSToomas Soome		pop %bx				# Restore
4604a5d661aSToomas Soome		ret				# return when null is hit
4614a5d661aSToomas Soomeputstr.putc:	call putc			# output char
4624a5d661aSToomas Soome		jmp putstr.load			# next char
4634a5d661aSToomas Soome
4644a5d661aSToomas Soome#
4654a5d661aSToomas Soome# Display a single char.
4664a5d661aSToomas Soome#
4674a5d661aSToomas Soomeputc:		mov $0x7,%bx			# attribute for output
4684a5d661aSToomas Soome		mov $0xe,%ah			# BIOS: put_char
4694a5d661aSToomas Soome		int $0x10			# call BIOS, print char in %al
4704a5d661aSToomas Soome		ret				# Return to caller
4714a5d661aSToomas Soome
4724a5d661aSToomas Soome#
4734a5d661aSToomas Soome# Output the "twiddle"
4744a5d661aSToomas Soome#
4754a5d661aSToomas Soometwiddle:	push %ax			# Save
4764a5d661aSToomas Soome		push %bx			# Save
4774a5d661aSToomas Soome		mov twiddle_index,%al		# Load index
4784a5d661aSToomas Soome		mov $twiddle_chars,%bx		# Address table
4794a5d661aSToomas Soome		inc %al				# Next
4804a5d661aSToomas Soome		and $3,%al			#  char
4814a5d661aSToomas Soome		mov %al,twiddle_index		# Save index for next call
4824a5d661aSToomas Soome		xlat				# Get char
4834a5d661aSToomas Soome		call putc			# Output it
4844a5d661aSToomas Soome		mov $8,%al			# Backspace
4854a5d661aSToomas Soome		call putc			# Output it
4864a5d661aSToomas Soome		pop %bx				# Restore
4874a5d661aSToomas Soome		pop %ax				# Restore
4884a5d661aSToomas Soome		ret
4894a5d661aSToomas Soome
4904a5d661aSToomas Soome#
4914a5d661aSToomas Soome# Enable A20. Put an upper limit on the amount of time we wait for the
4924a5d661aSToomas Soome# keyboard controller to get ready (65K x ISA access time). If
4934a5d661aSToomas Soome# we wait more than that amount, the hardware is probably
4944a5d661aSToomas Soome# legacy-free and simply doesn't have a keyboard controller.
4954a5d661aSToomas Soome# Thus, the A20 line is already enabled.
4964a5d661aSToomas Soome#
4974a5d661aSToomas Soomeseta20:		cli				# Disable interrupts
4984a5d661aSToomas Soome		xor %cx,%cx			# Clear
4994a5d661aSToomas Soomeseta20.1:	inc %cx				# Increment, overflow?
5004a5d661aSToomas Soome		jz seta20.3			# Yes
5014a5d661aSToomas Soome		in $0x64,%al			# Get status
5024a5d661aSToomas Soome		test $0x2,%al			# Busy?
5034a5d661aSToomas Soome		jnz seta20.1			# Yes
5044a5d661aSToomas Soome		mov $0xd1,%al			# Command: Write
5054a5d661aSToomas Soome		out %al,$0x64			#  output port
5064a5d661aSToomas Soomeseta20.2:	in $0x64,%al			# Get status
5074a5d661aSToomas Soome		test $0x2,%al			# Busy?
5084a5d661aSToomas Soome		jnz seta20.2			# Yes
5094a5d661aSToomas Soome		mov $0xdf,%al			# Enable
5104a5d661aSToomas Soome		out %al,$0x60			#  A20
5114a5d661aSToomas Soomeseta20.3:	sti				# Enable interrupts
5124a5d661aSToomas Soome		ret				# To caller
5134a5d661aSToomas Soome
5144a5d661aSToomas Soome#
5154a5d661aSToomas Soome# Convert AL to hex, saving the result to [EDI].
5164a5d661aSToomas Soome#
5174a5d661aSToomas Soomehex8:		pushl %eax			# Save
5184a5d661aSToomas Soome		shrb $0x4,%al			# Do upper
5194a5d661aSToomas Soome		call hex8.1			#  4
5204a5d661aSToomas Soome		popl %eax			# Restore
5214a5d661aSToomas Soomehex8.1:		andb $0xf,%al			# Get lower 4
5224a5d661aSToomas Soome		cmpb $0xa,%al			# Convert
5234a5d661aSToomas Soome		sbbb $0x69,%al			#  to hex
5244a5d661aSToomas Soome		das				#  digit
5254a5d661aSToomas Soome		orb $0x20,%al			# To lower case
5264a5d661aSToomas Soome		stosb				# Save char
5274a5d661aSToomas Soome		ret				# (Recursive)
5284a5d661aSToomas Soome
5294a5d661aSToomas Soome#
5304a5d661aSToomas Soome# BTX client to start btxldr
5314a5d661aSToomas Soome#
5324a5d661aSToomas Soome		.code32
5334a5d661aSToomas Soomebtx_client:	mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi
5344a5d661aSToomas Soome						# %ds:(%esi) -> end
5354a5d661aSToomas Soome						#  of boot[12] args
5364a5d661aSToomas Soome		mov $(MEM_ARG_SIZE/4),%ecx	# Number of words to push
5374a5d661aSToomas Soome		std				# Go backwards
5384a5d661aSToomas Soomepush_arg:	lodsl				# Read argument
5394a5d661aSToomas Soome		push %eax			# Push it onto the stack
5404a5d661aSToomas Soome		loop push_arg			# Push all of the arguments
5414a5d661aSToomas Soome		cld				# In case anyone depends on this
5424a5d661aSToomas Soome		pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of
5434a5d661aSToomas Soome						#  the loader
5444a5d661aSToomas Soome		push %eax			# Emulate a near call
5454a5d661aSToomas Soome		mov $0x1,%eax			# 'exec' system call
5464a5d661aSToomas Soome		int $INT_SYS			# BTX system call
5474a5d661aSToomas Soomebtx_client_end:
5484a5d661aSToomas Soome		.code16
5494a5d661aSToomas Soome
5504a5d661aSToomas Soome		.p2align 4
5514a5d661aSToomas Soome#
5524a5d661aSToomas Soome# Global descriptor table.
5534a5d661aSToomas Soome#
5544a5d661aSToomas Soomegdt:		.word 0x0,0x0,0x0,0x0		# Null entry
5554a5d661aSToomas Soome		.word 0xffff,0x0,0x9200,0xcf	# SEL_SDATA
5564a5d661aSToomas Soome		.word 0xffff,0x0,0x9200,0x0	# SEL_RDATA
5574a5d661aSToomas Soome		.word 0xffff,0x0,0x9a00,0xcf	# SEL_SCODE (32-bit)
5584a5d661aSToomas Soome		.word 0xffff,0x0,0x9a00,0x8f	# SEL_SCODE16 (16-bit)
5594a5d661aSToomas Soomegdt.1:
5604a5d661aSToomas Soome#
5614a5d661aSToomas Soome# Pseudo-descriptors.
5624a5d661aSToomas Soome#
5634a5d661aSToomas Soomegdtdesc:	.word gdt.1-gdt-1		# Limit
5644a5d661aSToomas Soome		.long gdt			# Base
5654a5d661aSToomas Soome#
5664a5d661aSToomas Soome# EDD Packet
5674a5d661aSToomas Soome#
5684a5d661aSToomas Soomeedd_packet:	.byte 0x10			# Length
5694a5d661aSToomas Soome		.byte 0				# Reserved
5704a5d661aSToomas Soomeedd_len:	.byte 0x0			# Num to read
5714a5d661aSToomas Soome		.byte 0				# Reserved
5724a5d661aSToomas Soomeedd_addr:	.word 0x0,0x0			# Seg:Off
5734a5d661aSToomas Soomeedd_lba:	.quad 0x0			# LBA
5744a5d661aSToomas Soome
5754a5d661aSToomas Soomedrive:		.byte 0
5764a5d661aSToomas Soome
5774a5d661aSToomas Soome#
5784a5d661aSToomas Soome# State for searching dir
5794a5d661aSToomas Soome#
5804a5d661aSToomas Soomerec_lba:	.long 0x0			# LBA (adjusted for EA)
5814a5d661aSToomas Soomerec_size:	.long 0x0			# File size
5824a5d661aSToomas Soomename_len:	.byte 0x0			# Length of current name
5834a5d661aSToomas Soome
5844a5d661aSToomas Soometwiddle_index:	.byte 0x0
5854a5d661aSToomas Soome
5864a5d661aSToomas Soomemsg_welcome:	.asciz	"CD Loader 1.2\r\n\n"
5874a5d661aSToomas Soomemsg_bootinfo:	.asciz	"Building the boot loader arguments\r\n"
5884a5d661aSToomas Soomemsg_relocate:	.asciz	"Relocating the loader and the BTX\r\n"
5894a5d661aSToomas Soomemsg_jump:	.asciz	"Starting the BTX loader\r\n"
5904a5d661aSToomas Soomemsg_badread:	.ascii  "Read Error: 0x"
5914a5d661aSToomas Soomehex_error:	.asciz	"00\r\n"
5924a5d661aSToomas Soomemsg_novd:	.asciz  "Could not find Primary Volume Descriptor\r\n"
5934a5d661aSToomas Soomemsg_lookup:	.asciz  "Looking up "
5944a5d661aSToomas Soomemsg_lookup2:	.asciz  "... "
5954a5d661aSToomas Soomemsg_lookupok:	.asciz  "Found\r\n"
5964a5d661aSToomas Soomemsg_lookupfail:	.asciz  "File not found\r\n"
5974a5d661aSToomas Soomemsg_load2big:	.asciz  "File too big\r\n"
5984a5d661aSToomas Soomemsg_failed:	.asciz	"Boot failed\r\n"
5994a5d661aSToomas Soometwiddle_chars:	.ascii	"|/-\\"
6004a5d661aSToomas Soomeloader_paths:	.asciz  "/BOOT/ZFSLOADER"
6014a5d661aSToomas Soome		.asciz	"/boot/zfsloader"
6024a5d661aSToomas Soome		.byte 0
603