# memory.S86 - memory access 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: memory.S86,v 1.1 2003/03/09 00:43:08 gkminix Exp $ # #==================================================================== # #include "common.i86" .file "memory.S86" .line 29 # #==================================================================== # # Define the text segment and all public entry points # \(.text) .global getext .global getmem .global movmem # #==================================================================== # # Get amount of conventional memory in kB # Input: none # Output: EAX - Amount of conventional memory # Changed registers: EAX # getmem: test byte ptr [convini],0xFF jnz getm1 # check if already initialized int 0x12 # get amount from BIOS mov [convmem],ax # save for later inc byte ptr [convini] jmp getm9 getm1: mov ax,[convmem] # load prestored value getm9: and eax,0x0000FFFF ret # #==================================================================== # # Get amount of extended memory in kB # Input: none # Output: EAX - Amount of extended memory # Changed registers: EAX # getext: test byte ptr [extini],0xFF jnz getex8 # check if already initialized # Getting the amount of extended memory is not as easy as it seems. # Different BIOS versions provide different interfaces, so we just # call one after the other. We have to use the same algorithm as the # bootrom here so that the boot rom and the boot loader agree on the # amount of extended memory installed. push ebx push ecx push edx mov ax,0xE801 # try 16-bit version int 0x15 jc getex3 mov cx,ax # some BIOS return incorrect or cx,bx # values jnz getex1 mov ax,cx mov bx,dx getex1: and eax,0x0000FFFF # clear upper word and ebx,0x0000FFFF getex2: shl ebx,6 # multiply by 64 add eax,ebx # and add to amount below 16M jmp getex7 getex3: mov ah,0x88 # try very old method clc int 0x15 # call BIOS to get amount of jnc getex4 # extended memory in kB xor ax,ax # no extended memory found getex4: and eax,0x0000FFFF getex7: mov [extmem],eax # save for later inc byte ptr [extini] pop edx pop ecx pop ebx jmp getex9 getex8: mov eax,[extmem] # load prestored value getex9: ret # #==================================================================== # # Move a memory block within memory, including high memory. # Input: EAX - Linear source address # EBX - Linear destination address # ECX - Length of memory block # Output: Carry flag set if error # Changed registers: SI # movmem: push es push ds # save all registers that might pushad # be mangled cmp eax,ebx # check if we have to copy anything je movm8 # at all jecxz movm8 mov edx,eax add edx,ecx cmp edx,0x00100000 # check if we have to copy into or jae movext # out of extended memory mov edx,ebx add edx,ecx cmp edx,0x00100000 jae movext cmp eax,ebx # we have to copy within conventional jb movtop # memory, so check if we have to move jmp movbot # from top or from bottom movm7: stc # return with error jmp movm9 movm8: clc # no error movm9: cld popad # restore all registers pop ds pop es ret # Move the memory within, into or out of extended memory. We have to use # the BIOS for this, and the BIOS always moves from bottom to top. However, # this routine moves in chunks from top to bottom. We first have to check, # that the copying areas dont overlap. movext: mov edx,eax add edx,ecx # check if the copying areas over- cmp edx,ebx # lap at all jbe movex2 mov edx,ebx add edx,ecx cmp edx,eax jbe movex2 cmp eax,ebx # if we have to move from bottom to jb movex1 # top, we can only do it if we have cmp ecx,0x00010000 # to move less than 64 kB jae movm7 jmp movex2 movex1: mov edx,ebx # if the areas overlap, we can only sub edx,eax # move if the source and destination cmp edx,0x00010000 # addresses differ by more than 64 kB jb movm7 movex2: mov dx,ds mov es,dx mov word ptr [rd_dstb],bx # enter destination address into gdt mov word ptr [rd_srcb],ax # enter source address into gdt inc ecx # int 0x15 moves words mov edx,ecx shr edx,16 shr eax,16 shr ebx,16 add ax,dx # move from the top downwards add bx,dx mov byte ptr [rd_dstb + 2],bl mov byte ptr [rd_srcb + 2],al mov byte ptr [rd_dstc],bh mov byte ptr [rd_srcc],ah shr cx,1 jcxz movex3 mov si,offset rd_gdt mov ax,0x8700 # have the BIOS move the memory int 0x15 jc movm9 # oops, something went wrong... movex3: or dx,dx jz movm8 movex4: sub byte ptr [rd_srcb + 2],1 sbb byte ptr [rd_srcc],0 # decrement source address sub byte ptr [rd_dstb + 2],1 sbb byte ptr [rd_dstc],0 # decrement destination address mov cx,0x8000 # move in chunks of 64k/2 words mov si,offset rd_gdt mov ax,0x8700 int 0x15 jc movm9 # oops, something went wrong... dec dx jnz movex4 jmp movm8 # no error # Move within conventional memory from top to bottom movtop: std mov edx,ecx # save size for later add eax,ecx sub eax,4 # convert linear source address into a mov si,ax # pointer to the highest byte to copy shr eax,4 and ax,0xF000 mov ds,ax add ebx,ecx sub ebx,4 # convert linear destination address mov di,bx # into a pointer to the highest byte shr ebx,4 # to copy and bx,0xF000 mov es,bx jmp movt5 # compute highest available offsets movt4: mov ax,si cmp si,di # we should not allow SI or DI to jbe movt1 # undeflow, so we select the smaller mov ax,di # one of these as the initial count movt1: cmp ax,cx jae movt2 # if the selected initial count exceeds mov cx,ax # the required count, set it to the movt2: # smaller value movzx32 ebx,cx shr cx,2 rep movsd32 # now copy the next chunk mov cx,bx and cx,0x0003 jz movt6 add si,3 # copy the bytes which havent been cared add di,3 # for by the dword copy rep movsb movt6: sub edx,ebx # check how many bytes left to copy jbe movm8 # nothing left movt5: mov cx,0xFFFF sub cx,si # compute by how much we can increase and cx,0xFFF0 # SI and DI without exceeding segment mov bx,0xFFFF # limits sub bx,di and bx,0xFFF0 cmp bx,cx # select the smaller of the two value jbe movt3 mov bx,cx movt3: add si,bx # now increase SI and DI by the calcu- add di,bx # lated amount shr bx,4 mov ax,ds sub ax,bx # and subtract the calculated amount mov ds,ax # from DS and ES again mov ax,es # this will care for DS:SI and ES:DI sub ax,bx # to still point to the same byte they mov es,ax # pointed before, but this time with mov ecx,edx # much higher offsets allowing more room jmp movt4 # to copy # Move from bottom to top within conventional memory movbot: cld mov edx,ecx # save size for later mov si,ax and si,0x000F # convert source and destination shr eax,4 # addresses into pointers mov ds,ax mov di,bx and di,0x000F shr ebx,4 mov es,bx jmp movb3 movb1: movzx32 ebx,cx # save count for later shr cx,2 rep movsd32 # copy next chunk mov cx,bx and cx,0x0003 jz movb2 rep movsb # move remaining bytes movb2: sub edx,ebx # check how many bytes left to copy jbe movm8 # nothing left mov ax,ds mov cx,si shr cx,4 # increase source segment add ax,cx mov ds,ax and si,0x000F mov ax,es mov cx,di shr cx,4 # increase destination segment add ax,cx mov es,ax and di,0x000F movb3: mov ecx,0x0000FFF0 cmp edx,ecx # adjust count to maximum possible jae movb1 mov cx,dx jmp movb1 # #==================================================================== # # Data definitions # \(.data) # GDT to move a memory block around using the BIOS .align 2 rd_gdt: .word 0,0,0,0 .word 0,0,0,0 rd_src: .word 0xFFFF # length rd_srcb:.byte 0,0,0 # base .byte 0x93 # typebyte .byte 0 # limit16 rd_srcc:.byte 0 # base24 rd_dst: .word 0xFFFF # length rd_dstb:.byte 0,0,0 # base .byte 0x93 # typebyte .byte 0 # limit16 rd_dstc:.byte 0 # base24 .word 0,0,0,0 # BIOS CS .word 0,0,0,0 # BIOS DS # #==================================================================== # # Define some local variables # \(.bss) .lcomm extmem,4 # amount of extended memory in kB .lcomm convmem,2 # amount of conventional memory in kB .lcomm extini,1 # flag if extmem initialized .lcomm convini,1 # flag if convmem initialized # #==================================================================== # .end