# ldrec.S86 - load record handling routines for netboot boot images # # Copyright (C) 2002-2003 Gero Kuhlmann # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # $Id: ldrec.S86,v 1.1 2003/03/09 00:43:08 gkminix Exp $ # #==================================================================== # #include "common.i86" #include "ldrec.i86" .file "ldrec.S86" .line 30 # #==================================================================== # # Define the text segment and all public entry points # \(.text) .extern strlen # define external symbols .extern getext .extern getmem .global ldrini # define global symbols .global ldrfnd .global ldradr .global ldrlen # #==================================================================== # # Initialize load record handling # Input: FS:DI - Pointer to boot image header # DX - Offset to vendor magic ID string # Output: FS:DI - Pointer to load record for this boot loader # SI - Offset to error message, zero if none # Changed registers: EAX, BX, CX, DX, SI # ldrini: mov si,offset bmerr cmp dword ptr fs:BOOT_HD_MAGIC[di],BOOT_MAGIC jne ldri9 # compare boot rom magic numbers mov word ptr [header + 0],di mov word ptr [header + 2],fs mov si,dx # determine length of vendor call strlen # magic ID string add cx,0x0003 # convert length into number of shr cx,2 # dwords movzx dx,byte ptr fs:BOOT_HD_LENGTH[di] shr dx,4 cmp cx,dx # check vendor ID size je ldri2 ldri1: mov si,offset vmerr # set error message jmp ldri9 ldri2: xor bx,bx shl cx,2 ldri3: mov al,[bx + si] # check vendor ID or al,al jz ldri4 # vendor ID ok, continue cmp al,fs:BOOT_HD_VENDOR[bx + di] jne ldri1 inc bx # continue with next byte loop ldri3 ldri4: call getext # get amount of extended memory or eax,eax # check if extended memory is jz ldri5 # available shl eax,10 add eax,0x00100000 # add amount of base memory jmp ldri6 ldri5: call getmem # get amount of base memory shl eax,10 ldri6: mov [highadr],eax # save address of last byte mov si,offset lderr mov al,LOADER_TAG call ldrfnd # find load record for this jc ldri9 # program call ldradr # get linear address of loader jc ldri9 test eax,0xFFF0000F # has to be on a lower segment jnz ldri9 # boundary shr eax,4 mov bx,cs # has to be our own segment cmp ax,bx jne ldri9 xor si,si # return without error ldri9: ret # #==================================================================== # # Find a load record in the boot header. # Input: AL - ID number of requested load record # Output: FS:DI - Pointer to load record # Carry flag set if load record not found # Changed registers: AX, DI, FS # ldrfnd: push cx mov ch,al lfs di,[header] # examine boot image header mov ax,fs or ax,di # check if initialized jz ldrf2 call ldrlen # get the pointer to first add di,ax # load record ldrf1: cmp ch,fs:BOOT_LD_TAG1[di] # is it the desired one ? je ldrf3 # check if its the last record test byte ptr fs:BOOT_LD_FLAGS[di],BOOT_FLAG_EOF jnz ldrf2 call ldrlen add di,ax jmp ldrf1 ldrf2: stc # couldnt find desired record ldrf3: pop cx ret # #==================================================================== # # Compute the length of a load record. # Input: FS:DI - Pointer to load record # Output: AX - Length of load record # Changed registers: AX # ldrlen: cmp di,word ptr [header + 0] je ldrl1 # check if boot header or load record mov al,fs:BOOT_LD_LENGTH[di] jmp ldrl2 ldrl1: mov al,fs:BOOT_HD_LENGTH[di] ldrl2: mov ah,al shr ah,4 and ax,0x0F0F # compute the total length in add al,ah # bytes from the length of the xor ah,ah # record and that of the vendor shl ax,2 # information. ret # #==================================================================== # # Return the linear address of a load segment. # Input: FS:DI - Pointer to load record # Output: EAX - Linear address of load segment # Carry flag set if error # Changed registers: EAX # ldradr: mov al,fs:BOOT_LD_FLAGS[di] test al,BOOT_FLAG_B0 # check if we can compute jnz ldra2 # the address directly test al,BOOT_FLAG_B1 jnz ldra1 mov eax,fs:BOOT_LD_ADDR[di] # get load address from load clc # record (absolute address) jmp ldra9 ldra1: mov eax,[highadr] # load record address is rela- sub eax,fs:BOOT_LD_ADDR[di] # tive to end of memory jmp ldra9 # carry flag is set on error # The load address in the load record is relative to the address of # the last record. However, the address of the last record can also # be relative to its last record. Therefore we have to go through # the whole list of records to determine each records linear address. ldra2: push ebx push ecx push edx push edi push si mov si,di # save pointer to load record movzx32 edx,word ptr [header + 2] movzx32 edi,word ptr [header + 0] shl edx,4 add edx,edi # edx contains the linear mov ebx,BOOT_SIZE # address of the last entry ldra3: call ldrlen add di,ax mov ecx,fs:BOOT_LD_MLENGTH[di] mov al,fs:BOOT_LD_FLAGS[di] test al,BOOT_FLAG_B0 # check if address is relative jz ldra5 # to last record test al,BOOT_FLAG_B1 jnz ldra4 add edx,ebx # add current address to end add edx,fs:BOOT_LD_ADDR[di] # of previous record jc ldra8 jmp ldra6 ldra4: sub edx,fs:BOOT_LD_ADDR[di] # subtract current address jc ldra8 # from start of previous jmp ldra6 # record ldra5: mov edx,fs:BOOT_LD_ADDR[di] test al,BOOT_FLAG_B1 jz ldra6 mov edx,[highadr] # subtract current address sub edx,fs:BOOT_LD_ADDR[di] # from end of memory jc ldra8 ldra6: cmp si,di # check if we found our record je ldra7 mov ebx,ecx test al,BOOT_FLAG_EOF jz ldra3 stc # if end of records reached then jmp ldra8 # our record is not in the list ldra7: mov eax,edx # return load record address ldra8: mov di,si # restore all registers pop si pop edi pop edx pop ecx pop ebx ldra9: ret # #==================================================================== # # String and constants definitions # \(.data) # Error messages bmerr: .asciz "Invalid boot header magic number" vmerr: .asciz "Invalid vendor magic ID" lderr: .asciz "Invalid load record information" # #==================================================================== # # Variable definitions # \(.bss) .global header # define global symbols .lcomm header,4 # pointer to boot header .lcomm highadr,4 # highest memory address # #==================================================================== # .end