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