cdboot.S revision 86164
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 86164 2001-11-07 01:20:33Z 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# 14285998Sjhb# Lookup the loader binary. 14385998Sjhb# 14485998Sjhb mov $loader_path,%si # File to lookup 14585998Sjhb call lookup # Try to find it 14685998Sjhb# 14785998Sjhb# Load the binary into the buffer. Due to real mode addressing limitations 14885998Sjhb# we have to read it in in 64k chunks. 14985998Sjhb# 15085998Sjhb mov DIR_SIZE(%bx),%eax # Read file length 15185998Sjhb add $SECTOR_SIZE-1,%eax # Convert length to sectors 15285998Sjhb shr $11,%eax 15385998Sjhb cmp $BUFFER_LEN,%eax 15485998Sjhb jbe load_sizeok 15585998Sjhb mov $msg_load2big,%si # Error message 15685998Sjhb call error 15785998Sjhbload_sizeok: movzbw %al,%cx # Num sectors to read 15885998Sjhb mov DIR_EXTENT(%bx),%eax # Load extent 15985998Sjhb xor %edx,%edx 16085998Sjhb mov DIR_EA_LEN(%bx),%dl 16185998Sjhb add %edx,%eax # Skip extended 16285998Sjhb mov $MEM_READ_BUFFER,%ebx # Read into the buffer 16385998Sjhbload_loop: mov %cl,%dh 16485998Sjhb cmp $MAX_READ_SEC,%cl # Truncate to max read size 16585998Sjhb jbe load_notrunc 16685998Sjhb mov $MAX_READ_SEC,%dh 16785998Sjhbload_notrunc: sub %dh,%cl # Update count 16885998Sjhb push %eax # Save 16985998Sjhb call read # Read it in 17085998Sjhb pop %eax # Restore 17185998Sjhb add $MAX_READ_SEC,%eax # Update LBA 17285998Sjhb add $MAX_READ,%ebx # Update dest addr 17385998Sjhb jcxz load_done # Done? 17485998Sjhb jmp load_loop # Keep going 17585998Sjhbload_done: 17685998Sjhb# 17756693Sjhb# Turn on the A20 address line 17856693Sjhb# 17985998Sjhb call seta20 # Turn A20 on 18056693Sjhb# 18156693Sjhb# Relocate the loader and BTX using a very lazy protected mode 18256693Sjhb# 18385998Sjhb mov $msg_relocate,%si # Display the 18485998Sjhb call putstr # relocation message 18585998Sjhb mov MEM_READ_BUFFER+AOUT_ENTRY,%edi # %edi is the destination 18685998Sjhb mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi # %esi is 18758713Sjhb # the start of the text 18858713Sjhb # segment 18985998Sjhb mov MEM_READ_BUFFER+AOUT_TEXT,%ecx # %ecx = length of the text 19058713Sjhb # segment 19185998Sjhb push %edi # Save entry point for later 19256693Sjhb lgdt gdtdesc # setup our own gdt 19356693Sjhb cli # turn off interrupts 19485998Sjhb mov %cr0,%eax # Turn on 19585998Sjhb or $0x1,%al # protected 19685998Sjhb mov %eax,%cr0 # mode 19760821Sjhb ljmp $SEL_SCODE,$pm_start # long jump to clear the 19860821Sjhb # instruction pre-fetch queue 19956693Sjhb .code32 20085998Sjhbpm_start: mov $SEL_SDATA,%ax # Initialize 20185998Sjhb mov %ax,%ds # %ds and 20285998Sjhb mov %ax,%es # %es to a flat selector 20358713Sjhb rep # Relocate the 20458713Sjhb movsb # text segment 20585998Sjhb add $(MEM_PAGE_SIZE - 1),%edi # pad %edi out to a new page 20685998Sjhb and $~(MEM_PAGE_SIZE - 1),%edi # for the data segment 20785998Sjhb mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment 20858713Sjhb rep # Relocate the 20958713Sjhb movsb # data segment 21085998Sjhb mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss 21185998Sjhb xor %eax,%eax # zero %eax 21285998Sjhb add $3,%cl # round %ecx up to 21385998Sjhb shr $2,%ecx # a multiple of 4 21458713Sjhb rep # zero the 21558713Sjhb stosl # bss 21685998Sjhb mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader 21785998Sjhb add $MEM_BTX_OFFSET,%esi # %esi -> BTX in the loader 21885998Sjhb mov $MEM_BTX_ADDRESS,%edi # %edi -> where BTX needs to go 21985998Sjhb movzwl 0xa(%esi),%ecx # %ecx -> length of BTX 22056693Sjhb rep # Relocate 22156693Sjhb movsb # BTX 22258713Sjhb ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM 22356693Sjhb .code16 22485998Sjhbpm_16: mov $SEL_RDATA,%ax # Initialize 22585998Sjhb mov %ax,%ds # %ds and 22685998Sjhb mov %ax,%es # %es to a real mode selector 22785998Sjhb mov %cr0,%eax # Turn off 22885998Sjhb and $~0x1,%al # protected 22985998Sjhb mov %eax,%cr0 # mode 23060821Sjhb ljmp $0,$pm_end # Long jump to clear the 23160821Sjhb # instruction pre-fetch queue 23256693Sjhbpm_end: sti # Turn interrupts back on now 23356693Sjhb# 23456693Sjhb# Copy the BTX client to MEM_BTX_CLIENT 23556693Sjhb# 23685998Sjhb xor %ax,%ax # zero %ax and set 23785998Sjhb mov %ax,%ds # %ds and %es 23885998Sjhb mov %ax,%es # to segment 0 23985998Sjhb mov $MEM_BTX_CLIENT,%di # Prepare to relocate 24085998Sjhb mov $btx_client,%si # the simple btx client 24185998Sjhb mov $(btx_client_end-btx_client),%cx # length of btx client 24256693Sjhb rep # Relocate the 24356693Sjhb movsb # simple BTX client 24456693Sjhb# 24556693Sjhb# Copy the boot[12] args to where the BTX client can see them 24656693Sjhb# 24785998Sjhb mov $MEM_ARG,%si # where the args are at now 24885998Sjhb mov $MEM_ARG_BTX,%di # where the args are moving to 24985998Sjhb mov $(MEM_ARG_SIZE/4),%cx # size of the arguments in longs 25056693Sjhb rep # Relocate 25156693Sjhb movsl # the words 25256693Sjhb# 25358713Sjhb# Save the entry point so the client can get to it later on 25458713Sjhb# 25585998Sjhb pop %eax # Restore saved entry point 25685998Sjhb stosl # and add it to the end of 25785998Sjhb # the arguments 25858713Sjhb# 25956693Sjhb# Now we just start up BTX and let it do the rest 26056693Sjhb# 26185998Sjhb mov $msg_jump,%si # Display the 26285998Sjhb call putstr # jump message 26360821Sjhb ljmp $0,$MEM_BTX_ENTRY # Jump to the BTX entry point 26456693Sjhb 26556693Sjhb# 26685998Sjhb# Lookup the file in the path at [SI] from the root directory. 26756693Sjhb# 26885998Sjhb# Trashes: All but BX 26985998Sjhb# Returns: BX = pointer to record 27085998Sjhb# 27185998Sjhblookup: mov $VD_ROOTDIR+MEM_VOLDESC,%bx # Root directory record 27285998Sjhb push %si 27385998Sjhb mov $msg_lookup,%si # Display lookup message 27485998Sjhb call putstr 27585998Sjhb pop %si 27685998Sjhb push %si 27785998Sjhb call putstr 27885998Sjhb mov $msg_lookup2,%si 27985998Sjhb call putstr 28085998Sjhb pop %si 28185998Sjhblookup_dir: lodsb # Get first char of path 28285998Sjhb cmp $0,%al # Are we done? 28385998Sjhb je lookup_done # Yes 28485998Sjhb cmp $'/',%al # Skip path separator. 28585998Sjhb je lookup_dir 28685998Sjhb dec %si # Undo lodsb side effect 28785998Sjhb call find_file # Lookup first path item 28885998Sjhb jnc lookup_dir # Try next component 28985998Sjhb mov $msg_lookupfail,%si # Not found. 29085998Sjhb jmp error 29185998Sjhblookup_done: mov $msg_lookupok,%si # Success message 29285998Sjhb call putstr 29385998Sjhb ret 29485998Sjhb 29585998Sjhb# 29685998Sjhb# Lookup file at [SI] in directory whose record is at [BX]. 29785998Sjhb# 29885998Sjhb# Trashes: All but returns 29985998Sjhb# Returns: CF = 0 (success), BX = pointer to record, SX = next path item 30085998Sjhb# CF = 1 (not found), SI = preserved 30185998Sjhb# 30286001Sjhbfind_file: mov DIR_EXTENT(%bx),%eax # Load extent 30385998Sjhb xor %edx,%edx 30485998Sjhb mov DIR_EA_LEN(%bx),%dl 30585998Sjhb add %edx,%eax # Skip extended attributes 30685998Sjhb mov %eax,rec_lba # Save LBA 30785998Sjhb mov DIR_SIZE(%bx),%eax # Save size 30885998Sjhb mov %eax,rec_size 30985998Sjhb xor %cl,%cl # Zero length 31085998Sjhb push %si # Save 31185998Sjhbff.namelen: inc %cl # Update length 31285998Sjhb lodsb # Read char 31385998Sjhb cmp $0,%al # Nul? 31485998Sjhb je ff.namedone # Yes 31585998Sjhb cmp $'/',%al # Path separator? 31685998Sjhb jnz ff.namelen # No, keep going 31785998Sjhbff.namedone: dec %cl # Adjust length and save 31885998Sjhb mov %cl,name_len 31985998Sjhb pop %si # Restore 32085998Sjhbff.load: mov rec_lba,%eax # Load LBA 32185998Sjhb mov $MEM_DIR,%ebx # Address buffer 32285998Sjhb mov $1,%dh # One sector 32385998Sjhb call read # Read directory block 32485998Sjhb incl rec_lba # Update LBA to next block 32585998Sjhbff.scan: mov %ebx,%edx # Check for EOF 32685998Sjhb sub $MEM_DIR,%edx 32785998Sjhb cmp %edx,rec_size 32885998Sjhb ja ff.scan.1 32985998Sjhb stc # EOF reached 33085998Sjhb ret 33185998Sjhbff.scan.1: cmpb $0,DIR_LEN(%bx) # Last record in block? 33285998Sjhb je ff.nextblock 33385998Sjhb push %si # Save 33485998Sjhb movzbw DIR_NAMELEN(%bx),%si # Find end of string 33586001Sjhbff.checkver: cmpb $'0',DIR_NAME-1(%bx,%si) # Less than '0'? 33685998Sjhb jb ff.checkver.1 33785998Sjhb cmpb $'9',DIR_NAME-1(%bx,%si) # Greater than '9'? 33885998Sjhb ja ff.checkver.1 33985998Sjhb dec %si # Next char 34085998Sjhb jnz ff.checkver 34185998Sjhb jmp ff.checklen # All numbers in name, so 34285998Sjhb # no version 34385998Sjhbff.checkver.1: movzbw DIR_NAMELEN(%bx),%cx 34485998Sjhb cmp %cx,%si # Did we find any digits? 34585998Sjhb je ff.checkdot # No 34685998Sjhb cmpb $';',DIR_NAME-1(%bx,%si) # Check for semicolon 34785998Sjhb jne ff.checkver.2 34885998Sjhb dec %si # Skip semicolon 34985998Sjhb mov %si,%cx 35085998Sjhb mov %cl,DIR_NAMELEN(%bx) # Adjust length 35185998Sjhb jmp ff.checkdot 35285998Sjhbff.checkver.2: mov %cx,%si # Restore %si to end of string 35385998Sjhbff.checkdot: cmpb $'.',DIR_NAME-1(%bx,%si) # Trailing dot? 35485998Sjhb jne ff.checklen # No 35585998Sjhb decb DIR_NAMELEN(%bx) # Adjust length 35685998Sjhbff.checklen: pop %si # Restore 35785998Sjhb movzbw name_len,%cx # Load length of name 35885998Sjhb cmp %cl,DIR_NAMELEN(%bx) # Does length match? 35985998Sjhb je ff.checkname # Yes, check name 36085998Sjhbff.nextrec: add DIR_LEN(%bx),%bl # Next record 36185998Sjhb adc $0,%bh 36285998Sjhb jmp ff.scan 36385998Sjhbff.nextblock: subl $SECTOR_SIZE,rec_size # Adjust size 36485998Sjhb jnc ff.load # If subtract ok, keep going 36585998Sjhb ret # End of file, so not found 36686001Sjhbff.checkname: lea DIR_NAME(%bx),%di # Address name in record 36785998Sjhb push %si # Save 36885998Sjhb repe cmpsb # Compare name 36985998Sjhb jcxz ff.match # We have a winner! 37085998Sjhb pop %si # Restore 37185998Sjhb jmp ff.nextrec # Keep looking. 37285998Sjhbff.match: add $2,%sp # Discard saved %si 37385998Sjhb clc # Clear carry 37485998Sjhb ret 37585998Sjhb 37685998Sjhb# 37785998Sjhb# Load DH sectors starting at LBA EAX into [EBX]. 37885998Sjhb# 37985998Sjhb# Trashes: EAX 38085998Sjhb# 38185998Sjhbread: push %si # Save 38285998Sjhb mov %eax,edd_lba # LBA to read from 38385998Sjhb mov %ebx,%eax # Convert address 38485998Sjhb shr $4,%eax # to segment 38585998Sjhb mov %ax,edd_addr+0x2 # and store 38686164Sjhbread.retry: call twiddle # Entertain the user 38785998Sjhb push %dx # Save 38885998Sjhb mov $edd_packet,%si # Address Packet 38985998Sjhb mov %dh,edd_len # Set length 39085998Sjhb mov drive,%dl # BIOS Device 39185998Sjhb mov $0x42,%ah # BIOS: Extended Read 39285998Sjhb int $0x13 # Call BIOS 39385998Sjhb pop %dx # Restore 39485998Sjhb jc read.fail # Worked? 39585998Sjhb pop %si # Restore 39685998Sjhb ret # Return 39785998Sjhbread.fail: cmp $ERROR_TIMEOUT,%ah # Timeout? 39885998Sjhb je read.retry # Yes, Retry. 39985998Sjhbread.error: mov %ah,%al # Save error 40085998Sjhb mov $hex_error,%di # Format it 40185998Sjhb call hex8 # as hex 40285998Sjhb mov $msg_badread,%si # Display Read error message 40385998Sjhb 40485998Sjhb# 40585998Sjhb# Display error message at [SI] and halt. 40685998Sjhb# 40785998Sjhberror: call putstr # Display message 40885998Sjhbhalt: hlt 40985998Sjhb jmp halt # Spin 41085998Sjhb 41185998Sjhb# 41285998Sjhb# Display a null-terminated string. 41385998Sjhb# 41485998Sjhb# Trashes: AX, SI 41585998Sjhb# 41685998Sjhbputstr: push %bx # Save 41785998Sjhbputstr.load: lodsb # load %al from %ds:(%si) 41885998Sjhb test %al,%al # stop at null 41985998Sjhb jnz putstr.putc # if the char != null, output it 42085998Sjhb pop %bx # Restore 42185998Sjhb ret # return when null is hit 42285998Sjhbputstr.putc: call putc # output char 42385998Sjhb jmp putstr.load # next char 42485998Sjhb 42585998Sjhb# 42685998Sjhb# Display a single char. 42785998Sjhb# 42886164Sjhbputc: mov $0x7,%bx # attribute for output 42985998Sjhb mov $0xe,%ah # BIOS: put_char 43056693Sjhb int $0x10 # call BIOS, print char in %al 43185998Sjhb ret # Return to caller 43256693Sjhb 43356693Sjhb# 43485998Sjhb# Output the "twiddle" 43585998Sjhb# 43685998Sjhbtwiddle: push %ax # Save 43785998Sjhb push %bx # Save 43885998Sjhb mov twiddle_index,%al # Load index 43985998Sjhb mov twiddle_chars,%bx # Address table 44085998Sjhb inc %al # Next 44185998Sjhb and $3,%al # char 44285998Sjhb xlat # Get char 44385998Sjhb call putc # Output it 44485998Sjhb mov $8,%al # Backspace 44585998Sjhb call putc # Output it 44685998Sjhb pop %bx # Restore 44785998Sjhb pop %ax # Restore 44885998Sjhb ret 44985998Sjhb 45085998Sjhb# 45156693Sjhb# Enable A20 45256693Sjhb# 45356693Sjhbseta20: cli # Disable interrupts 45485998Sjhbseta20.1: in $0x64,%al # Get status 45585998Sjhb test $0x2,%al # Busy? 45656693Sjhb jnz seta20.1 # Yes 45785998Sjhb mov $0xd1,%al # Command: Write 45885998Sjhb out %al,$0x64 # output port 45985998Sjhbseta20.2: in $0x64,%al # Get status 46085998Sjhb test $0x2,%al # Busy? 46156693Sjhb jnz seta20.2 # Yes 46285998Sjhb mov $0xdf,%al # Enable 46385998Sjhb out %al,$0x60 # A20 46456693Sjhb sti # Enable interrupts 46585998Sjhb ret # To caller 46656693Sjhb 46756693Sjhb# 46886001Sjhb# Convert AL to hex, saving the result to [EDI]. 46985998Sjhb# 47085998Sjhbhex8: pushl %eax # Save 47185998Sjhb shrb $0x4,%al # Do upper 47285998Sjhb call hex8.1 # 4 47385998Sjhb popl %eax # Restore 47485998Sjhbhex8.1: andb $0xf,%al # Get lower 4 47585998Sjhb cmpb $0xa,%al # Convert 47685998Sjhb sbbb $0x69,%al # to hex 47785998Sjhb das # digit 47885998Sjhb orb $0x20,%al # To lower case 47985998Sjhb stosb # Save char 48085998Sjhb ret # (Recursive) 48185998Sjhb 48285998Sjhb# 48358713Sjhb# BTX client to start btxldr 48456693Sjhb# 48556693Sjhb .code32 48685998Sjhbbtx_client: mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi 48756693Sjhb # %ds:(%esi) -> end 48856693Sjhb # of boot[12] args 48985998Sjhb mov $(MEM_ARG_SIZE/4),%ecx # Number of words to push 49056693Sjhb std # Go backwards 49156693Sjhbpush_arg: lodsl # Read argument 49285998Sjhb push %eax # Push it onto the stack 49356693Sjhb loop push_arg # Push all of the arguments 49456693Sjhb cld # In case anyone depends on this 49558713Sjhb pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of 49658713Sjhb # the loader 49785998Sjhb push %eax # Emulate a near call 49885998Sjhb mov $0x1,%eax # 'exec' system call 49956693Sjhb int $INT_SYS # BTX system call 50056693Sjhbbtx_client_end: 50156693Sjhb .code16 50281363Sjhb 50356693Sjhb .p2align 4 50456693Sjhb# 50556693Sjhb# Global descriptor table. 50656693Sjhb# 50756693Sjhbgdt: .word 0x0,0x0,0x0,0x0 # Null entry 50856693Sjhb .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA 50956693Sjhb .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA 51056693Sjhb .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE (32-bit) 51181363Sjhb .word 0xffff,0x0,0x9a00,0x8f # SEL_SCODE16 (16-bit) 51256693Sjhbgdt.1: 51356693Sjhb# 51456693Sjhb# Pseudo-descriptors. 51556693Sjhb# 51656693Sjhbgdtdesc: .word gdt.1-gdt-1 # Limit 51758713Sjhb .long gdt # Base 51885998Sjhb# 51985998Sjhb# EDD Packet 52085998Sjhb# 52185998Sjhbedd_packet: .byte 0x10 # Length 52285998Sjhb .byte 0 # Reserved 52385998Sjhbedd_len: .byte 0x0 # Num to read 52485998Sjhb .byte 0 # Reserved 52585998Sjhbedd_addr: .word 0x0,0x0 # Seg:Off 52685998Sjhbedd_lba: .quad 0x0 # LBA 52781363Sjhb 52885998Sjhbdrive: .byte 0 52981363Sjhb 53085998Sjhb# 53185998Sjhb# State for searching dir 53285998Sjhb# 53385998Sjhbrec_lba: .long 0x0 # LBA (adjusted for EA) 53485998Sjhbrec_size: .long 0x0 # File size 53585998Sjhbname_len: .byte 0x0 # Length of current name 53685998Sjhb 53785998Sjhbtwiddle_index: .byte 0x0 53885998Sjhb 53985998Sjhbmsg_welcome: .asciz "CD Loader 1.01\r\n\n" 54085998Sjhbmsg_bootinfo: .asciz "Building the boot loader arguments\r\n" 54185998Sjhbmsg_relocate: .asciz "Relocating the loader and the BTX\r\n" 54285998Sjhbmsg_jump: .asciz "Starting the BTX loader\r\n" 54385998Sjhbmsg_badread: .ascii "Read Error: 0x" 54485998Sjhbhex_error: .ascii "00\r\n" 54585998Sjhbmsg_novd: .asciz "Could not find Primary Volume Descriptor\r\n" 54685998Sjhbmsg_lookup: .asciz "Looking up " 54785998Sjhbmsg_lookup2: .asciz "... " 54885998Sjhbmsg_lookupok: .asciz "Found\r\n" 54985998Sjhbmsg_lookupfail: .asciz "File not found\r\n" 55085998Sjhbmsg_load2big: .asciz "File too big\r\n" 55185998Sjhbloader_path: .asciz "/BOOT/LOADER" 55285998Sjhbtwiddle_chars: .ascii "|/-\\" 55385998Sjhb 554