cdboot.S revision 123476
156693Sjhb# 285998Sjhb# Copyright (c) 2001 John Baldwin 356693Sjhb# All rights reserved. 456693Sjhb# 556693Sjhb# Redistribution and use in source and binary forms are freely 656693Sjhb# permitted provided that the above copyright notice and this 756693Sjhb# paragraph and the following disclaimer are duplicated in all 856693Sjhb# such forms. 956693Sjhb# 1056693Sjhb# This software is provided "AS IS" and without any express or 1156693Sjhb# implied warranties, including, without limitation, the implied 1256693Sjhb# warranties of merchantability and fitness for a particular 1356693Sjhb# purpose. 1456693Sjhb# 1556693Sjhb 1656693Sjhb# $FreeBSD: head/sys/boot/i386/cdboot/cdboot.s 123476 2003-12-11 22:42:50Z jhb $ 1756693Sjhb 1856693Sjhb# 1985998Sjhb# This program is a freestanding boot program to load an a.out binary 2085998Sjhb# from a CD-ROM booted with no emulation mode as described by the El 2185998Sjhb# Torito standard. Due to broken BIOSen that do not load the desired 2285998Sjhb# number of sectors, we try to fit this in as small a space as possible. 2356693Sjhb# 2485998Sjhb# Basically, we first create a set of boot arguments to pass to the loaded 2585998Sjhb# binary. Then we attempt to load /boot/loader from the CD we were booted 2685998Sjhb# off of. 2785998Sjhb# 2856693Sjhb 2956693Sjhb# 3056693Sjhb# Memory locations. 3156693Sjhb# 3258713Sjhb .set MEM_PAGE_SIZE,0x1000 # memory page size, 4k 3356693Sjhb .set MEM_ARG,0x900 # Arguments at start 3456693Sjhb .set MEM_ARG_BTX,0xa100 # Where we move them to so the 3556693Sjhb # BTX client can see them 3656693Sjhb .set MEM_ARG_SIZE,0x18 # Size of the arguments 3756693Sjhb .set MEM_BTX_ADDRESS,0x9000 # where BTX lives 3856693Sjhb .set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute 3958713Sjhb .set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader 4056693Sjhb .set MEM_BTX_CLIENT,0xa000 # where BTX clients live 4156693Sjhb# 4258713Sjhb# a.out header fields 4358713Sjhb# 4458713Sjhb .set AOUT_TEXT,0x04 # text segment size 4558713Sjhb .set AOUT_DATA,0x08 # data segment size 4658713Sjhb .set AOUT_BSS,0x0c # zero'd BSS size 4758713Sjhb .set AOUT_SYMBOLS,0x10 # symbol table 4858713Sjhb .set AOUT_ENTRY,0x14 # entry point 4958713Sjhb .set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header 5058713Sjhb# 5156693Sjhb# Flags for kargs->bootflags 5256693Sjhb# 5356693Sjhb .set KARGS_FLAGS_CD,0x1 # flag to indicate booting from 5456693Sjhb # CD loader 5556693Sjhb# 5656693Sjhb# Segment selectors. 5756693Sjhb# 5856693Sjhb .set SEL_SDATA,0x8 # Supervisor data 5956693Sjhb .set SEL_RDATA,0x10 # Real mode data 6056693Sjhb .set SEL_SCODE,0x18 # PM-32 code 6156693Sjhb .set SEL_SCODE16,0x20 # PM-16 code 6256693Sjhb# 6356693Sjhb# BTX constants 6456693Sjhb# 6556693Sjhb .set INT_SYS,0x30 # BTX syscall interrupt 6656693Sjhb# 6785998Sjhb# Constants for reading from the CD. 6885998Sjhb# 6985998Sjhb .set ERROR_TIMEOUT,0x80 # BIOS timeout on read 7085998Sjhb .set NUM_RETRIES,3 # Num times to retry 7185998Sjhb .set SECTOR_SIZE,0x800 # size of a sector 7285998Sjhb .set SECTOR_SHIFT,11 # number of place to shift 7385998Sjhb .set BUFFER_LEN,0x100 # number of sectors in buffer 7485998Sjhb .set MAX_READ,0x10000 # max we can read at a time 7585998Sjhb .set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT 7685998Sjhb .set MEM_READ_BUFFER,0x9000 # buffer to read from CD 7785998Sjhb .set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor 7885998Sjhb .set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer 7985998Sjhb .set VOLDESC_LBA,0x10 # LBA of vol descriptor 8085998Sjhb .set VD_PRIMARY,1 # Primary VD 8185998Sjhb .set VD_END,255 # VD Terminator 8285998Sjhb .set VD_ROOTDIR,156 # Offset of Root Dir Record 8385998Sjhb .set DIR_LEN,0 # Offset of Dir Record length 8485998Sjhb .set DIR_EA_LEN,1 # Offset of EA length 8585998Sjhb .set DIR_EXTENT,2 # Offset of 64-bit LBA 8685998Sjhb .set DIR_SIZE,10 # Offset of 64-bit length 8785998Sjhb .set DIR_NAMELEN,32 # Offset of 8-bit name len 8885998Sjhb .set DIR_NAME,33 # Offset of dir name 8985998Sjhb# 9058713Sjhb# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry 9158713Sjhb# point) 9256693Sjhb# 9356693Sjhb .code16 9456693Sjhb .globl start 9556693Sjhb .org 0x0, 0x0 9656693Sjhb# 9785998Sjhb# Program start. 9856693Sjhb# 9958713Sjhbstart: cld # string ops inc 10085998Sjhb xor %ax,%ax # zero %ax 10185998Sjhb mov %ax,%ss # setup the 10285998Sjhb mov $start,%sp # stack 10385998Sjhb mov %ax,%ds # setup the 10485998Sjhb mov %ax,%es # data segments 10585998Sjhb mov %dl,drive # Save BIOS boot device 10685998Sjhb mov $msg_welcome,%si # %ds:(%si) -> welcome message 10785998Sjhb call putstr # display the welcome message 10856693Sjhb# 10956693Sjhb# Setup the arguments that the loader is expecting from boot[12] 11056693Sjhb# 11185998Sjhb mov $msg_bootinfo,%si # %ds:(%si) -> boot args message 11285998Sjhb call putstr # display the message 11385998Sjhb mov $MEM_ARG,%bx # %ds:(%bx) -> boot args 11485998Sjhb mov %bx,%di # %es:(%di) -> boot args 11585998Sjhb xor %eax,%eax # zero %eax 11685998Sjhb mov $(MEM_ARG_SIZE/4),%cx # Size of arguments in 32-bit 11756693Sjhb # dwords 11856693Sjhb rep # Clear the arguments 11956693Sjhb stosl # to zero 12085998Sjhb mov drive,%dl # Store BIOS boot device 12185998Sjhb mov %dl,0x4(%bx) # in kargs->bootdev 12285998Sjhb or $KARGS_FLAGS_CD,0x8(%bx) # kargs->bootflags |= 12358713Sjhb # KARGS_FLAGS_CD 12456693Sjhb# 12585998Sjhb# Load Volume Descriptor 12685998Sjhb# 12785998Sjhb mov $VOLDESC_LBA,%eax # Set LBA of first VD 12885998Sjhbload_vd: push %eax # Save %eax 12985998Sjhb mov $1,%dh # One sector 13085998Sjhb mov $MEM_VOLDESC,%ebx # Destination 13185998Sjhb call read # Read it in 13285998Sjhb cmpb $VD_PRIMARY,(%bx) # Primary VD? 13385998Sjhb je have_vd # Yes 13485998Sjhb pop %eax # Prepare to 13585998Sjhb inc %eax # try next 13685998Sjhb cmpb $VD_END,(%bx) # Last VD? 13785998Sjhb jne load_vd # No, read next 13885998Sjhb mov $msg_novd,%si # No VD 13985998Sjhb jmp error # Halt 14086164Sjhbhave_vd: # Have Primary VD 14185998Sjhb# 142123476Sjhb# Try to look up the loader binary using the paths in the loader_paths 143123476Sjhb# array. 14485998Sjhb# 145123476Sjhb mov $loader_paths,%si # Point to start of array 146123476Sjhblookup_path: push %si # Save file name pointer 147123476Sjhb call lookup # Try to find file 148123476Sjhb pop %di # Restore file name pointer 149123476Sjhb jnc lookup_found # Found this file 150123476Sjhb xor %al,%al # Look for next 151123476Sjhb mov $0xffff,%cx # path name by 152123476Sjhb repnz # scanning for 153123476Sjhb scasb # nul char 154123476Sjhb inc %di # Skip nul 155123476Sjhb mov %di,%si # Point %si at next path 156123476Sjhb mov (%si),%al # Get first char of next path 157123476Sjhb or %al,%al # Is it double nul? 158123476Sjhb jnz lookup_path # No, try it. 159123476Sjhb mov $msg_failed,%si # Failed message 160123476Sjhb jmp error # Halt 161123476Sjhblookup_found: # Found a loader file 16285998Sjhb# 16385998Sjhb# Load the binary into the buffer. Due to real mode addressing limitations 16485998Sjhb# we have to read it in in 64k chunks. 16585998Sjhb# 16685998Sjhb mov DIR_SIZE(%bx),%eax # Read file length 16785998Sjhb add $SECTOR_SIZE-1,%eax # Convert length to sectors 16885998Sjhb shr $11,%eax 16985998Sjhb cmp $BUFFER_LEN,%eax 17085998Sjhb jbe load_sizeok 17185998Sjhb mov $msg_load2big,%si # Error message 17285998Sjhb call error 17385998Sjhbload_sizeok: movzbw %al,%cx # Num sectors to read 17485998Sjhb mov DIR_EXTENT(%bx),%eax # Load extent 17585998Sjhb xor %edx,%edx 17685998Sjhb mov DIR_EA_LEN(%bx),%dl 17785998Sjhb add %edx,%eax # Skip extended 17885998Sjhb mov $MEM_READ_BUFFER,%ebx # Read into the buffer 17985998Sjhbload_loop: mov %cl,%dh 18085998Sjhb cmp $MAX_READ_SEC,%cl # Truncate to max read size 18185998Sjhb jbe load_notrunc 18285998Sjhb mov $MAX_READ_SEC,%dh 18385998Sjhbload_notrunc: sub %dh,%cl # Update count 18485998Sjhb push %eax # Save 18585998Sjhb call read # Read it in 18685998Sjhb pop %eax # Restore 18785998Sjhb add $MAX_READ_SEC,%eax # Update LBA 18885998Sjhb add $MAX_READ,%ebx # Update dest addr 18985998Sjhb jcxz load_done # Done? 19085998Sjhb jmp load_loop # Keep going 19185998Sjhbload_done: 19285998Sjhb# 19356693Sjhb# Turn on the A20 address line 19456693Sjhb# 19585998Sjhb call seta20 # Turn A20 on 19656693Sjhb# 19756693Sjhb# Relocate the loader and BTX using a very lazy protected mode 19856693Sjhb# 19985998Sjhb mov $msg_relocate,%si # Display the 20085998Sjhb call putstr # relocation message 20185998Sjhb mov MEM_READ_BUFFER+AOUT_ENTRY,%edi # %edi is the destination 20285998Sjhb mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi # %esi is 20358713Sjhb # the start of the text 20458713Sjhb # segment 20585998Sjhb mov MEM_READ_BUFFER+AOUT_TEXT,%ecx # %ecx = length of the text 20658713Sjhb # segment 20785998Sjhb push %edi # Save entry point for later 20856693Sjhb lgdt gdtdesc # setup our own gdt 20956693Sjhb cli # turn off interrupts 21085998Sjhb mov %cr0,%eax # Turn on 21185998Sjhb or $0x1,%al # protected 21285998Sjhb mov %eax,%cr0 # mode 21360821Sjhb ljmp $SEL_SCODE,$pm_start # long jump to clear the 21460821Sjhb # instruction pre-fetch queue 21556693Sjhb .code32 21685998Sjhbpm_start: mov $SEL_SDATA,%ax # Initialize 21785998Sjhb mov %ax,%ds # %ds and 21885998Sjhb mov %ax,%es # %es to a flat selector 21958713Sjhb rep # Relocate the 22058713Sjhb movsb # text segment 22185998Sjhb add $(MEM_PAGE_SIZE - 1),%edi # pad %edi out to a new page 22285998Sjhb and $~(MEM_PAGE_SIZE - 1),%edi # for the data segment 22385998Sjhb mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment 22458713Sjhb rep # Relocate the 22558713Sjhb movsb # data segment 22685998Sjhb mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss 22785998Sjhb xor %eax,%eax # zero %eax 22885998Sjhb add $3,%cl # round %ecx up to 22985998Sjhb shr $2,%ecx # a multiple of 4 23058713Sjhb rep # zero the 23158713Sjhb stosl # bss 23285998Sjhb mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader 23385998Sjhb add $MEM_BTX_OFFSET,%esi # %esi -> BTX in the loader 23485998Sjhb mov $MEM_BTX_ADDRESS,%edi # %edi -> where BTX needs to go 23585998Sjhb movzwl 0xa(%esi),%ecx # %ecx -> length of BTX 23656693Sjhb rep # Relocate 23756693Sjhb movsb # BTX 23858713Sjhb ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM 23956693Sjhb .code16 24085998Sjhbpm_16: mov $SEL_RDATA,%ax # Initialize 24185998Sjhb mov %ax,%ds # %ds and 24285998Sjhb mov %ax,%es # %es to a real mode selector 24385998Sjhb mov %cr0,%eax # Turn off 24485998Sjhb and $~0x1,%al # protected 24585998Sjhb mov %eax,%cr0 # mode 24660821Sjhb ljmp $0,$pm_end # Long jump to clear the 24760821Sjhb # instruction pre-fetch queue 24856693Sjhbpm_end: sti # Turn interrupts back on now 24956693Sjhb# 25056693Sjhb# Copy the BTX client to MEM_BTX_CLIENT 25156693Sjhb# 25285998Sjhb xor %ax,%ax # zero %ax and set 25385998Sjhb mov %ax,%ds # %ds and %es 25485998Sjhb mov %ax,%es # to segment 0 25585998Sjhb mov $MEM_BTX_CLIENT,%di # Prepare to relocate 25685998Sjhb mov $btx_client,%si # the simple btx client 25785998Sjhb mov $(btx_client_end-btx_client),%cx # length of btx client 25856693Sjhb rep # Relocate the 25956693Sjhb movsb # simple BTX client 26056693Sjhb# 26156693Sjhb# Copy the boot[12] args to where the BTX client can see them 26256693Sjhb# 26385998Sjhb mov $MEM_ARG,%si # where the args are at now 26485998Sjhb mov $MEM_ARG_BTX,%di # where the args are moving to 26585998Sjhb mov $(MEM_ARG_SIZE/4),%cx # size of the arguments in longs 26656693Sjhb rep # Relocate 26756693Sjhb movsl # the words 26856693Sjhb# 26958713Sjhb# Save the entry point so the client can get to it later on 27058713Sjhb# 27185998Sjhb pop %eax # Restore saved entry point 27285998Sjhb stosl # and add it to the end of 27385998Sjhb # the arguments 27458713Sjhb# 27556693Sjhb# Now we just start up BTX and let it do the rest 27656693Sjhb# 27785998Sjhb mov $msg_jump,%si # Display the 27885998Sjhb call putstr # jump message 27960821Sjhb ljmp $0,$MEM_BTX_ENTRY # Jump to the BTX entry point 28056693Sjhb 28156693Sjhb# 28285998Sjhb# Lookup the file in the path at [SI] from the root directory. 28356693Sjhb# 28485998Sjhb# Trashes: All but BX 285123476Sjhb# Returns: CF = 0 (success), BX = pointer to record 286123476Sjhb# CF = 1 (not found) 28785998Sjhb# 28885998Sjhblookup: mov $VD_ROOTDIR+MEM_VOLDESC,%bx # Root directory record 28985998Sjhb push %si 29085998Sjhb mov $msg_lookup,%si # Display lookup message 29185998Sjhb call putstr 29285998Sjhb pop %si 29385998Sjhb push %si 29485998Sjhb call putstr 29585998Sjhb mov $msg_lookup2,%si 29685998Sjhb call putstr 29785998Sjhb pop %si 29885998Sjhblookup_dir: lodsb # Get first char of path 29985998Sjhb cmp $0,%al # Are we done? 30085998Sjhb je lookup_done # Yes 30185998Sjhb cmp $'/',%al # Skip path separator. 30285998Sjhb je lookup_dir 30385998Sjhb dec %si # Undo lodsb side effect 30485998Sjhb call find_file # Lookup first path item 30585998Sjhb jnc lookup_dir # Try next component 306123476Sjhb mov $msg_lookupfail,%si # Not found message 307123476Sjhb call putstr 308123476Sjhb stc # Set carry 309123476Sjhb ret 31085998Sjhb jmp error 31185998Sjhblookup_done: mov $msg_lookupok,%si # Success message 31285998Sjhb call putstr 313123476Sjhb clc # Clear carry 31485998Sjhb ret 31585998Sjhb 31685998Sjhb# 31785998Sjhb# Lookup file at [SI] in directory whose record is at [BX]. 31885998Sjhb# 31985998Sjhb# Trashes: All but returns 320123476Sjhb# Returns: CF = 0 (success), BX = pointer to record, SI = next path item 32185998Sjhb# CF = 1 (not found), SI = preserved 32285998Sjhb# 32386001Sjhbfind_file: mov DIR_EXTENT(%bx),%eax # Load extent 32485998Sjhb xor %edx,%edx 32585998Sjhb mov DIR_EA_LEN(%bx),%dl 32685998Sjhb add %edx,%eax # Skip extended attributes 32785998Sjhb mov %eax,rec_lba # Save LBA 32885998Sjhb mov DIR_SIZE(%bx),%eax # Save size 32985998Sjhb mov %eax,rec_size 33085998Sjhb xor %cl,%cl # Zero length 33185998Sjhb push %si # Save 33285998Sjhbff.namelen: inc %cl # Update length 33385998Sjhb lodsb # Read char 33485998Sjhb cmp $0,%al # Nul? 33585998Sjhb je ff.namedone # Yes 33685998Sjhb cmp $'/',%al # Path separator? 33785998Sjhb jnz ff.namelen # No, keep going 33885998Sjhbff.namedone: dec %cl # Adjust length and save 33985998Sjhb mov %cl,name_len 34085998Sjhb pop %si # Restore 34185998Sjhbff.load: mov rec_lba,%eax # Load LBA 34285998Sjhb mov $MEM_DIR,%ebx # Address buffer 34385998Sjhb mov $1,%dh # One sector 34485998Sjhb call read # Read directory block 34585998Sjhb incl rec_lba # Update LBA to next block 34685998Sjhbff.scan: mov %ebx,%edx # Check for EOF 34785998Sjhb sub $MEM_DIR,%edx 34885998Sjhb cmp %edx,rec_size 34985998Sjhb ja ff.scan.1 35085998Sjhb stc # EOF reached 35185998Sjhb ret 35285998Sjhbff.scan.1: cmpb $0,DIR_LEN(%bx) # Last record in block? 35385998Sjhb je ff.nextblock 35485998Sjhb push %si # Save 35585998Sjhb movzbw DIR_NAMELEN(%bx),%si # Find end of string 35686001Sjhbff.checkver: cmpb $'0',DIR_NAME-1(%bx,%si) # Less than '0'? 35785998Sjhb jb ff.checkver.1 35885998Sjhb cmpb $'9',DIR_NAME-1(%bx,%si) # Greater than '9'? 35985998Sjhb ja ff.checkver.1 36085998Sjhb dec %si # Next char 36185998Sjhb jnz ff.checkver 36285998Sjhb jmp ff.checklen # All numbers in name, so 36385998Sjhb # no version 36485998Sjhbff.checkver.1: movzbw DIR_NAMELEN(%bx),%cx 36585998Sjhb cmp %cx,%si # Did we find any digits? 36685998Sjhb je ff.checkdot # No 36785998Sjhb cmpb $';',DIR_NAME-1(%bx,%si) # Check for semicolon 36885998Sjhb jne ff.checkver.2 36985998Sjhb dec %si # Skip semicolon 37085998Sjhb mov %si,%cx 37185998Sjhb mov %cl,DIR_NAMELEN(%bx) # Adjust length 37285998Sjhb jmp ff.checkdot 37385998Sjhbff.checkver.2: mov %cx,%si # Restore %si to end of string 37485998Sjhbff.checkdot: cmpb $'.',DIR_NAME-1(%bx,%si) # Trailing dot? 37585998Sjhb jne ff.checklen # No 37685998Sjhb decb DIR_NAMELEN(%bx) # Adjust length 37785998Sjhbff.checklen: pop %si # Restore 37885998Sjhb movzbw name_len,%cx # Load length of name 37985998Sjhb cmp %cl,DIR_NAMELEN(%bx) # Does length match? 38085998Sjhb je ff.checkname # Yes, check name 38185998Sjhbff.nextrec: add DIR_LEN(%bx),%bl # Next record 38285998Sjhb adc $0,%bh 38385998Sjhb jmp ff.scan 38485998Sjhbff.nextblock: subl $SECTOR_SIZE,rec_size # Adjust size 38585998Sjhb jnc ff.load # If subtract ok, keep going 38685998Sjhb ret # End of file, so not found 38786001Sjhbff.checkname: lea DIR_NAME(%bx),%di # Address name in record 38885998Sjhb push %si # Save 38985998Sjhb repe cmpsb # Compare name 39085998Sjhb jcxz ff.match # We have a winner! 39185998Sjhb pop %si # Restore 39285998Sjhb jmp ff.nextrec # Keep looking. 39385998Sjhbff.match: add $2,%sp # Discard saved %si 39485998Sjhb clc # Clear carry 39585998Sjhb ret 39685998Sjhb 39785998Sjhb# 39885998Sjhb# Load DH sectors starting at LBA EAX into [EBX]. 39985998Sjhb# 40085998Sjhb# Trashes: EAX 40185998Sjhb# 40285998Sjhbread: push %si # Save 40385998Sjhb mov %eax,edd_lba # LBA to read from 40485998Sjhb mov %ebx,%eax # Convert address 40585998Sjhb shr $4,%eax # to segment 40685998Sjhb mov %ax,edd_addr+0x2 # and store 40786164Sjhbread.retry: call twiddle # Entertain the user 40885998Sjhb push %dx # Save 40985998Sjhb mov $edd_packet,%si # Address Packet 41085998Sjhb mov %dh,edd_len # Set length 41185998Sjhb mov drive,%dl # BIOS Device 41285998Sjhb mov $0x42,%ah # BIOS: Extended Read 41385998Sjhb int $0x13 # Call BIOS 41485998Sjhb pop %dx # Restore 41585998Sjhb jc read.fail # Worked? 41685998Sjhb pop %si # Restore 41785998Sjhb ret # Return 41885998Sjhbread.fail: cmp $ERROR_TIMEOUT,%ah # Timeout? 41985998Sjhb je read.retry # Yes, Retry. 42085998Sjhbread.error: mov %ah,%al # Save error 42185998Sjhb mov $hex_error,%di # Format it 42285998Sjhb call hex8 # as hex 42385998Sjhb mov $msg_badread,%si # Display Read error message 42485998Sjhb 42585998Sjhb# 42685998Sjhb# Display error message at [SI] and halt. 42785998Sjhb# 42885998Sjhberror: call putstr # Display message 42985998Sjhbhalt: hlt 43085998Sjhb jmp halt # Spin 43185998Sjhb 43285998Sjhb# 43385998Sjhb# Display a null-terminated string. 43485998Sjhb# 43585998Sjhb# Trashes: AX, SI 43685998Sjhb# 43785998Sjhbputstr: push %bx # Save 43885998Sjhbputstr.load: lodsb # load %al from %ds:(%si) 43985998Sjhb test %al,%al # stop at null 44085998Sjhb jnz putstr.putc # if the char != null, output it 44185998Sjhb pop %bx # Restore 44285998Sjhb ret # return when null is hit 44385998Sjhbputstr.putc: call putc # output char 44485998Sjhb jmp putstr.load # next char 44585998Sjhb 44685998Sjhb# 44785998Sjhb# Display a single char. 44885998Sjhb# 44986164Sjhbputc: mov $0x7,%bx # attribute for output 45085998Sjhb mov $0xe,%ah # BIOS: put_char 45156693Sjhb int $0x10 # call BIOS, print char in %al 45285998Sjhb ret # Return to caller 45356693Sjhb 45456693Sjhb# 45585998Sjhb# Output the "twiddle" 45685998Sjhb# 45785998Sjhbtwiddle: push %ax # Save 45885998Sjhb push %bx # Save 45985998Sjhb mov twiddle_index,%al # Load index 46085998Sjhb mov twiddle_chars,%bx # Address table 46185998Sjhb inc %al # Next 46285998Sjhb and $3,%al # char 46385998Sjhb xlat # Get char 46485998Sjhb call putc # Output it 46585998Sjhb mov $8,%al # Backspace 46685998Sjhb call putc # Output it 46785998Sjhb pop %bx # Restore 46885998Sjhb pop %ax # Restore 46985998Sjhb ret 47085998Sjhb 47185998Sjhb# 47256693Sjhb# Enable A20 47356693Sjhb# 47456693Sjhbseta20: cli # Disable interrupts 47585998Sjhbseta20.1: in $0x64,%al # Get status 47685998Sjhb test $0x2,%al # Busy? 47756693Sjhb jnz seta20.1 # Yes 47885998Sjhb mov $0xd1,%al # Command: Write 47985998Sjhb out %al,$0x64 # output port 48085998Sjhbseta20.2: in $0x64,%al # Get status 48185998Sjhb test $0x2,%al # Busy? 48256693Sjhb jnz seta20.2 # Yes 48385998Sjhb mov $0xdf,%al # Enable 48485998Sjhb out %al,$0x60 # A20 48556693Sjhb sti # Enable interrupts 48685998Sjhb ret # To caller 48756693Sjhb 48856693Sjhb# 48986001Sjhb# Convert AL to hex, saving the result to [EDI]. 49085998Sjhb# 49185998Sjhbhex8: pushl %eax # Save 49285998Sjhb shrb $0x4,%al # Do upper 49385998Sjhb call hex8.1 # 4 49485998Sjhb popl %eax # Restore 49585998Sjhbhex8.1: andb $0xf,%al # Get lower 4 49685998Sjhb cmpb $0xa,%al # Convert 49785998Sjhb sbbb $0x69,%al # to hex 49885998Sjhb das # digit 49985998Sjhb orb $0x20,%al # To lower case 50085998Sjhb stosb # Save char 50185998Sjhb ret # (Recursive) 50285998Sjhb 50385998Sjhb# 50458713Sjhb# BTX client to start btxldr 50556693Sjhb# 50656693Sjhb .code32 50785998Sjhbbtx_client: mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi 50856693Sjhb # %ds:(%esi) -> end 50956693Sjhb # of boot[12] args 51085998Sjhb mov $(MEM_ARG_SIZE/4),%ecx # Number of words to push 51156693Sjhb std # Go backwards 51256693Sjhbpush_arg: lodsl # Read argument 51385998Sjhb push %eax # Push it onto the stack 51456693Sjhb loop push_arg # Push all of the arguments 51556693Sjhb cld # In case anyone depends on this 51658713Sjhb pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of 51758713Sjhb # the loader 51885998Sjhb push %eax # Emulate a near call 51985998Sjhb mov $0x1,%eax # 'exec' system call 52056693Sjhb int $INT_SYS # BTX system call 52156693Sjhbbtx_client_end: 52256693Sjhb .code16 52381363Sjhb 52456693Sjhb .p2align 4 52556693Sjhb# 52656693Sjhb# Global descriptor table. 52756693Sjhb# 52856693Sjhbgdt: .word 0x0,0x0,0x0,0x0 # Null entry 52956693Sjhb .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA 53056693Sjhb .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA 53156693Sjhb .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE (32-bit) 53281363Sjhb .word 0xffff,0x0,0x9a00,0x8f # SEL_SCODE16 (16-bit) 53356693Sjhbgdt.1: 53456693Sjhb# 53556693Sjhb# Pseudo-descriptors. 53656693Sjhb# 53756693Sjhbgdtdesc: .word gdt.1-gdt-1 # Limit 53858713Sjhb .long gdt # Base 53985998Sjhb# 54085998Sjhb# EDD Packet 54185998Sjhb# 54285998Sjhbedd_packet: .byte 0x10 # Length 54385998Sjhb .byte 0 # Reserved 54485998Sjhbedd_len: .byte 0x0 # Num to read 54585998Sjhb .byte 0 # Reserved 54685998Sjhbedd_addr: .word 0x0,0x0 # Seg:Off 54785998Sjhbedd_lba: .quad 0x0 # LBA 54881363Sjhb 54985998Sjhbdrive: .byte 0 55081363Sjhb 55185998Sjhb# 55285998Sjhb# State for searching dir 55385998Sjhb# 55485998Sjhbrec_lba: .long 0x0 # LBA (adjusted for EA) 55585998Sjhbrec_size: .long 0x0 # File size 55685998Sjhbname_len: .byte 0x0 # Length of current name 55785998Sjhb 55885998Sjhbtwiddle_index: .byte 0x0 55985998Sjhb 560123476Sjhbmsg_welcome: .asciz "CD Loader 1.2\r\n\n" 56185998Sjhbmsg_bootinfo: .asciz "Building the boot loader arguments\r\n" 56285998Sjhbmsg_relocate: .asciz "Relocating the loader and the BTX\r\n" 56385998Sjhbmsg_jump: .asciz "Starting the BTX loader\r\n" 56485998Sjhbmsg_badread: .ascii "Read Error: 0x" 56585998Sjhbhex_error: .ascii "00\r\n" 56685998Sjhbmsg_novd: .asciz "Could not find Primary Volume Descriptor\r\n" 56785998Sjhbmsg_lookup: .asciz "Looking up " 56885998Sjhbmsg_lookup2: .asciz "... " 56985998Sjhbmsg_lookupok: .asciz "Found\r\n" 57085998Sjhbmsg_lookupfail: .asciz "File not found\r\n" 57185998Sjhbmsg_load2big: .asciz "File too big\r\n" 572123476Sjhbmsg_failed: .asciz "Boot failed\r\n" 57385998Sjhbtwiddle_chars: .ascii "|/-\\" 574123476Sjhbloader_paths: .asciz "/BOOT/LOADER" 575123476Sjhb .asciz "/boot/loader" 576123476Sjhb .byte 0 57785998Sjhb 578