From a0208c5997d850e3c8a6369f1bad8914114e4077 Mon Sep 17 00:00:00 2001 From: hpa Date: Sun, 23 Dec 2001 01:02:30 +0000 Subject: [PATCH] Code restructuring: common subroutine to load a file into high memory --- NEWS | 1 + isolinux.asm | 213 ++++++++++++++++++++++++++++++++++------------------------- ldlinux.asm | 202 ++++++++++++++++++++++++++++++++------------------------ pxelinux.asm | 213 ++++++++++++++++++++++++++++++++++------------------------- 4 files changed, 362 insertions(+), 267 deletions(-) diff --git a/NEWS b/NEWS index b5210fc..e627142 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ apply to that specific program only; other changes apply to both. Changes in 1.66: * MEMDISK: Make compile with newer versions of gcc. + * Major code restructuring. Changes in 1.65: * ISOLINUX: Support booting disk image files (to boot DOS or diff --git a/isolinux.asm b/isolinux.asm index 903e6fe..e5d867d 100644 --- a/isolinux.asm +++ b/isolinux.asm @@ -306,7 +306,6 @@ MNameBuf resb FILENAME_MAX InitRD resb FILENAME_MAX PartInfo resb 16 ; Partition table entry E820Buf resd 5 ; INT 15:E820 data buffer -InitRDat resd 1 ; Load address (linear) for initrd HiLoadAddr resd 1 ; Address pointer for high load loop HighMemSize resd 1 ; End of memory pointer (bytes) RamdiskMax resd 1 ; Highest address for a ramdisk @@ -315,7 +314,6 @@ RootDir resb dir_t_size ; Root directory CurDir resb dir_t_size ; Current directory SavedSSSP resd 1 ; Our SS:SP while running a COMBOOT image KernelClust resd 1 ; Kernel size in clusters -InitRDClust resd 1 ; Ramdisk size in clusters InitStack resd 1 ; Initial stack pointer (SS:SP) FirstSecSum resd 1 ; Checksum of bytes 64-2048 ImageDwords resd 1 ; isolinux.bin size, dwords @@ -2005,53 +2003,35 @@ read_kernel: movzx esi,word [SetupSecs] ; Setup sectors inc esi ; plus 1 boot sector shl esi,9 ; Convert to bytes - mov ecx,108000h ; 108000h = 1M + 32K - sub ecx,esi ; Adjust pointer to 2nd block - mov [HiLoadAddr],ecx - sub ecx,100000h ; Turn into a counter + mov ecx,8000h ; 32K + sub ecx,esi ; Number of bytes to copy + push ecx shr ecx,2 ; Convert to dwords add esi,(real_mode_seg << 4) ; Pointer to source mov edi,100000h ; Copy to address 100000h call bcopy ; Transfer to high memory - push word xfer_buf_seg ; Transfer buffer segment - pop es -high_load_loop: + ; On exit EDI -> where to load the rest + mov si,dot_msg ; Progress report call cwritestr call abort_check - mov ecx,[KernelClust] - and ecx,ecx - jz high_load_done ; Zero left (tiny kernel?) - cmp ecx,[ClustPerMoby] - jna high_last_moby - mov ecx,[ClustPerMoby] -high_last_moby: - sub [KernelClust],ecx - xor bx,bx ; Load at offset 0 - pop si ; Restore cluster pointer - call getfssec - push si ; Save cluster pointer - pushf ; Save EOF - xor bx,bx - mov esi,(xfer_buf_seg << 4) - mov edi,[HiLoadAddr] ; Destination address - mov ecx,4000h ; Cheating - transfer 64K - call bcopy ; Transfer to high memory - mov [HiLoadAddr],edi ; Point to next target area - popf ; Restore EOF - jc high_load_done ; If EOF we are done - cmp dword [KernelClust],byte 0 ; Are we done? - jne high_load_loop ; Apparently not + + pop ecx ; Number of bytes in the initial portion + pop si ; Restore file handle/cluster pointer + mov eax,[KernelSize] + sub eax,ecx ; Amount of kernel left over + jbe high_load_done ; Zero left (tiny kernel) + + call load_high ; Copy the file + high_load_done: - pop si ; No longer needed mov ax,real_mode_seg ; Set to real mode seg mov es,ax mov si,dot_msg call cwritestr - call crlf ; ; Now see if we have an initial RAMdisk; if so, do requisite computation ; We know we have a new kernel; the old_kernel code already will have objected @@ -2072,18 +2052,8 @@ load_initrd: call searchdir ; Look for it in directory pop es jz initrd_notthere - mov [initrd_ptr],si ; Save cluster pointer mov [es:su_ramdisklen1],ax ; Ram disk length mov [es:su_ramdisklen2],dx - movzx eax,ax - shl edx,16 - or eax,edx - xor edx,edx - div dword [ClustSize] - ; Round up... - add edx,byte -1 ; Sets CF if EDX >= 1 - adc eax,byte 0 ; Add 1 to EAX if CF set - mov [InitRDClust],eax ; Ramdisk clusters mov edx,[HighMemSize] ; End of memory dec edx mov eax,[RamdiskMax] ; Highest address allowed by kernel @@ -2094,7 +2064,7 @@ memsize_ok: inc edx sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk xor dx,dx ; Round down to 64K boundary - mov [InitRDat],edx ; Load address + mov [es:su_ramdiskat],edx ; Load address call loadinitrd ; Load initial ramdisk jmp short initrd_end @@ -2131,8 +2101,7 @@ nk_noinitrd: ; and the real mode stuff to 90000h. We assume that all bzImage kernels are ; capable of starting their setup from a different address. ; - mov bx,real_mode_seg ; Real mode segment - mov fs,bx ; FS -> real_mode_seg + ; ; Copy command line. Unfortunately, the kernel boot protocol requires ; the command line to exist in the 9xxxxh range even if the rest of the @@ -2164,8 +2133,10 @@ need_high_cmdline: shr cx,2 ; Convert to dwords fs rep movsd + push fs + pop es + test byte [LoadFlags],LOAD_HIGH - ; Note bx -> real_mode_seg still jnz in_proper_place ; If high load, we're done ; @@ -2173,8 +2144,6 @@ need_high_cmdline: ; ; Copy real_mode stuff up to 90000h ; - mov ax,real_mode_seg - mov fs,ax mov ax,9000h mov es,ax mov cx,[SetupSecs] @@ -2200,6 +2169,8 @@ need_high_cmdline: xor eax,eax rep stosd ; Clear region ; +; Copy the kernel down to the "low" location +; mov ecx,[KernelSize] add ecx,3 ; Round upwards shr ecx,2 ; Bytes -> dwords @@ -2207,13 +2178,14 @@ need_high_cmdline: mov edi,10000h call bcopy - mov bx,9000h ; Real mode segment - ; ; Now everything is where it needs to be... ; +; When we get here, es points to the final segment, either +; 9000h or real_mode_seg +; in_proper_place: - mov es,bx ; Real mode segment + ; ; If the default root device is set to FLOPPY (0000h), change to ; /dev/fd0 (0200h) @@ -2262,10 +2234,10 @@ kill_motor: %endif ; ; Set up segment registers and the Linux real-mode stack -; Note: bx == the real mode segment +; Note: es == the real mode segment ; cli - ; es is already == real mode segment + mov bx,es mov ds,bx mov fs,bx mov gs,bx @@ -2577,7 +2549,7 @@ local_boot: ; 32-bit bcopy routine for real mode ; ; We enter protected mode, set up a flat 32-bit environment, run rep movsd -; and then exit. IMPORTANT: This code assumes cs == ss == 0. +; and then exit. IMPORTANT: This code assumes cs == 0. ; ; This code is probably excessively anal-retentive in its handling of ; segments, but this stuff is painful enough as it is without having to rely @@ -2608,7 +2580,7 @@ bcopy: push eax cli call enable_a20 - o32 lgdt [bcopy_gdt] + o32 lgdt [cs:bcopy_gdt] mov eax,cr0 or al,1 mov cr0,eax ; Enter protected mode @@ -2886,53 +2858,111 @@ try_wbinvd: ; ; Load RAM disk into high memory ; +; Need to be set: +; su_ramdiskat - Where in memory to load +; su_ramdisklen - Size of file +; SI - initrd filehandle/cluster pointer +; loadinitrd: push es ; Save ES on entry - mov ax,real_mode_seg + mov ax,real_mode_seg mov es,ax - mov si,[initrd_ptr] - mov edi,[InitRDat] ; initrd load address - mov [es:su_ramdiskat],edi ; Offset for ram disk + mov edi,[es:su_ramdiskat] ; initrd load address push si - mov si,loading_msg - call cwritestr + mov si,crlfloading_msg ; Write "Loading " + call cwritestr mov si,InitRDCName ; Write ramdisk name call cwritestr mov si,dotdot_msg ; Write dots call cwritestr -rd_load_loop: - mov si,dot_msg ; Progress report - call cwritestr - pop si ; Restore cluster pointer - call abort_check - mov ecx,[InitRDClust] - cmp ecx,[ClustPerMoby] - jna rd_last_moby - mov ecx,[ClustPerMoby] -rd_last_moby: - sub [InitRDClust],ecx - xor bx,bx ; Load at offset 0 - push word xfer_buf_seg ; Bounce buffer segment - pop es - push cx - call getfssec - pop cx - push si ; Save cluster pointer - mov esi,(xfer_buf_seg << 4) - mov edi,[InitRDat] - mov ecx,4000h ; Copy 64K - call bcopy ; Does not change flags!! - jc rd_load_done ; EOF? - add dword [InitRDat],10000h ; Point to next 64K - cmp dword [InitRDClust],byte 0 ; Are we done? - jne rd_load_loop ; Apparently not -rd_load_done: - pop si ; Clean up the stack + pop si + + mov eax,[es:su_ramdisklen] + call load_high ; Load the file + call crlf + mov si,loading_msg ; Write new "Loading " for + call cwritestr ; the benefit of the kernel pop es ; Restore original ES ret ; +; load_high: loads (the remainder of) a file into high memory. +; This routine prints dots for each 64K transferred, and +; calls abort_check periodically. +; +; The xfer_buf_seg is used as a bounce buffer. +; +; The input address (EDI) should be dword aligned, and the final +; dword written is padded with zeroes if necessary. +; +; Inputs: SI = file handle/cluster pointer +; EDI = target address in high memory +; EAX = size of remaining file in bytes +; +; Outputs: SI = file handle/cluster pointer +; EDI = first untouched address (not including padding) +; +load_high: + push es + + mov bx,xfer_buf_seg + mov es,bx + +.read_loop: + push si + mov si,dot_msg + call cwritestr + pop si + call abort_check + + push eax ; Total chunk to transfer + cmp eax,(1 << 16) ; Max 64K in one transfer + jna .size_ok + mov eax,(1 << 16) +.size_ok: + cdq ; EDX <- 0 + push eax ; Bytes transferred this chunk + div dword [ClustSize] ; Convert to clusters + ; Round up... + add edx,byte -1 ; Sets CF if EDX >= 1 + adc eax,byte 0 ; Add 1 to EAX if CF set + + ; Now (e)ax contains the number of clusters to get + push edi + mov cx,ax + xor bx,bx ; ES:0 + call getfssec ; Load the data into xfer_buf_seg + pop edi + pop ecx ; Byte count this round + push ecx + push edi +.fix_slop: + test cl,3 + jz .noslop + ; The last dword fractional - pad with zeroes + ; Zero-padding is critical for multi-file initramfs. + mov bx,cx + mov byte [es:bx],0 + inc ecx + jmp short .fix_slop +.noslop: + shr ecx,2 ; Convert to dwords + push esi + mov esi,(xfer_buf_seg << 4) ; Source address + call bcopy ; Copy to high memory + pop esi + pop edi + pop ecx + pop eax + add edi,ecx + sub eax,ecx + jnz .read_loop ; More to read... + + pop es + ret + +; ; abort_check: let the user abort with or ; abort_check: @@ -4471,6 +4501,7 @@ localboot_msg db 'Booting from local disk...', CR, LF, 0 cmdline_msg db 'Command line: ', CR, LF, 0 ready_msg db ' ready.', CR, LF, 0 trying_msg db 'Trying to load: ', 0 +crlfloading_msg db CR, LF ; Fall through loading_msg db 'Loading ', 0 dotdot_msg db '.' dot_msg db '.', 0 diff --git a/ldlinux.asm b/ldlinux.asm index 20584cf..fc58af4 100644 --- a/ldlinux.asm +++ b/ldlinux.asm @@ -270,7 +270,6 @@ NumBufEnd resb 1 ; Last byte in NumBuf alignb 4 PartInfo resb 16 ; Partition table entry E820Buf resd 5 ; INT 15:E820 data buffer -InitRDat resd 1 ; Load address (linear) for initrd HiLoadAddr resd 1 ; Address pointer for high load loop HighMemSize resd 1 ; End of memory pointer (bytes) RamdiskMax resd 1 ; Highest address for a ramdisk @@ -299,7 +298,6 @@ BufSafeSec resw 1 ; = how many sectors? BufSafeBytes resw 1 ; = how many bytes? EndOfGetCBuf resw 1 ; = getcbuf+BufSafeBytes KernelClust resw 1 ; Kernel size in clusters -InitRDClust resw 1 ; Ramdisk size in clusters ClustPerMoby resw 1 ; Clusters per 64K FClust resw 1 ; Number of clusters in open/getc file FNextClust resw 1 ; Pointer to next cluster in d:o @@ -2052,15 +2050,8 @@ new_kernel: call searchdir ; Look for it in directory pop es jz initrd_notthere - mov [initrd_ptr],si ; Save cluster pointer mov [es:su_ramdisklen1],ax ; Ram disk length mov [es:su_ramdisklen2],dx - div word [ClustSize] - and dx,dx ; Round up - setnz dl - movzx dx,dl - add ax,dx - mov [InitRDClust],ax ; Ramdisk clusters mov edx,[HighMemSize] ; End of memory dec edx mov eax,[RamdiskMax] ; Highest address allowed by kernel @@ -2071,7 +2062,7 @@ memsize_ok: inc edx sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk xor dx,dx ; Round down to 64K boundary - mov [InitRDat],edx ; Load address + mov [es:su_ramdiskat],edx ; Load address call loadinitrd ; Load initial ramdisk jmp short initrd_end @@ -2114,48 +2105,31 @@ read_kernel: movzx esi,word [SetupSecs] ; Setup sectors inc esi ; plus 1 boot sector shl esi,9 ; Convert to bytes - mov ecx,108000h ; 108000h = 1M + 32K - sub ecx,esi ; Adjust pointer to 2nd block - mov [HiLoadAddr],ecx - sub ecx,100000h ; Turn into a counter + mov ecx,8000h ; 32K + sub ecx,esi ; Number of bytes to copy + push ecx shr ecx,2 ; Convert to dwords add esi,(real_mode_seg << 4) ; Pointer to source mov edi,100000h ; Copy to address 100000h call bcopy ; Transfer to high memory - push word xfer_buf_seg ; Transfer buffer segment - pop es -high_load_loop: + ; On exit EDI -> where to load the rest + mov si,dot_msg ; Progress report call cwritestr call abort_check - mov cx,[KernelClust] - and cx,cx - jz high_load_done ; Zero left (tiny kernel?) - cmp cx,[ClustPerMoby] - jna high_last_moby - mov cx,[ClustPerMoby] -high_last_moby: - sub [KernelClust],cx - xor bx,bx ; Load at offset 0 - pop si ; Restore cluster pointer - call getfssec - push si ; Save cluster pointer - pushf ; Save EOF - xor bx,bx - mov esi,(xfer_buf_seg << 4) - mov edi,[HiLoadAddr] ; Destination address - mov ecx,4000h ; Cheating - transfer 64K - call bcopy ; Transfer to high memory - mov [HiLoadAddr],edi ; Point to next target area - popf ; Restore EOF - jc high_load_done ; If EOF we are done - cmp word [KernelClust],byte 0 ; Are we done? - jne high_load_loop ; Apparently not + + pop ecx ; Number of bytes in the initial portion + pop si ; Restore file handle/cluster pointer + mov eax,[KernelSize] + sub eax,ecx ; Amount of kernel left over + jbe high_load_done ; Zero left (tiny kernel) + + call load_high ; Copy the file + high_load_done: - pop si ; No longer needed mov ax,real_mode_seg ; Set to real mode seg - mov es,ax + mov fs,ax ; FS -> real_mode_seg mov si,dot_msg call cwritestr @@ -2173,8 +2147,7 @@ high_load_done: ; and the real mode stuff to 90000h. We assume that all bzImage kernels are ; capable of starting their setup from a different address. ; - mov bx,real_mode_seg ; Real mode segment - mov fs,bx ; FS -> real_mode_seg + ; ; Copy command line. Unfortunately, the kernel boot protocol requires ; the command line to exist in the 9xxxxh range even if the rest of the @@ -2206,8 +2179,10 @@ need_high_cmdline: shr cx,2 ; Convert to dwords fs rep movsd + push fs + pop es + test byte [LoadFlags],LOAD_HIGH - ; Note bx -> real_mode_seg still jnz in_proper_place ; If high load, we're done ; @@ -2215,8 +2190,6 @@ need_high_cmdline: ; ; Copy real_mode stuff up to 90000h ; - mov ax,real_mode_seg - mov fs,ax mov ax,9000h mov es,ax mov cx,[SetupSecs] @@ -2242,6 +2215,8 @@ need_high_cmdline: xor eax,eax rep stosd ; Clear region ; +; Copy the kernel down to the "low" location +; mov ecx,[KernelSize] add ecx,3 ; Round upwards shr ecx,2 ; Bytes -> dwords @@ -2249,13 +2224,14 @@ need_high_cmdline: mov edi,10000h call bcopy - mov bx,9000h ; Real mode segment - ; ; Now everything is where it needs to be... ; +; When we get here, es points to the final segment, either +; 9000h or real_mode_seg +; in_proper_place: - mov es,bx ; Real mode segment + ; ; If the default root device is set to FLOPPY (0000h), change to ; /dev/fd0 (0200h) @@ -2304,10 +2280,10 @@ kill_motor: %endif ; ; Set up segment registers and the Linux real-mode stack -; Note: bx == the real mode segment +; Note: es == the real mode segment ; cli - ; es is already == real mode segment + mov bx,es mov ds,bx mov fs,bx mov gs,bx @@ -2527,7 +2503,7 @@ bcopy: push eax cli call enable_a20 - o32 lgdt [bcopy_gdt] + o32 lgdt [cs:bcopy_gdt] mov eax,cr0 or al,1 mov cr0,eax ; Enter protected mode @@ -2805,46 +2781,26 @@ try_wbinvd: ; ; Load RAM disk into high memory ; +; Need to be set: +; su_ramdiskat - Where in memory to load +; su_ramdisklen - Size of file +; SI - initrd filehandle/cluster pointer +; loadinitrd: push es ; Save ES on entry - mov ax,real_mode_seg + mov ax,real_mode_seg mov es,ax - mov si,[initrd_ptr] - mov edi,[InitRDat] ; initrd load address - mov [es:su_ramdiskat],edi ; Offset for ram disk + mov edi,[es:su_ramdiskat] ; initrd load address push si mov si,InitRDCName ; Write ramdisk name call cwritestr mov si,dotdot_msg ; Write dots call cwritestr -rd_load_loop: - mov si,dot_msg ; Progress report - call cwritestr - pop si ; Restore cluster pointer - call abort_check - mov cx,[InitRDClust] - cmp cx,[ClustPerMoby] - jna rd_last_moby - mov cx,[ClustPerMoby] -rd_last_moby: - sub [InitRDClust],cx - xor bx,bx ; Load at offset 0 - push word xfer_buf_seg ; Bounce buffer segment - pop es - push cx - call getfssec - pop cx - push si ; Save cluster pointer - mov esi,(xfer_buf_seg << 4) - mov edi,[InitRDat] - mov ecx,4000h ; Copy 64K - call bcopy ; Does not change flags!! - jc rd_load_done ; EOF? - add dword [InitRDat],10000h ; Point to next 64K - cmp word [InitRDClust],byte 0 ; Are we done? - jne rd_load_loop ; Apparently not -rd_load_done: - pop si ; Clean up the stack + pop si + + mov eax,[es:su_ramdisklen] + call load_high ; Load the file + call crlf mov si,loading_msg ; Write new "Loading " for call cwritestr ; the benefit of the kernel @@ -2852,6 +2808,82 @@ rd_load_done: ret ; +; load_high: loads (the remainder of) a file into high memory. +; This routine prints dots for each 64K transferred, and +; calls abort_check periodically. +; +; The xfer_buf_seg is used as a bounce buffer. +; +; The input address (EDI) should be dword aligned, and the final +; dword written is padded with zeroes if necessary. +; +; Inputs: SI = file handle/cluster pointer +; EDI = target address in high memory +; EAX = size of remaining file in bytes +; +; Outputs: SI = file handle/cluster pointer +; EDI = first untouched address (not including padding) +; +load_high: + push es + + mov bx,xfer_buf_seg + mov es,bx + +.read_loop: + push si + mov si,dot_msg + call cwritestr + pop si + call abort_check + + push eax ; Total chunk to transfer + cmp eax,(1 << 16) ; Max 64K in one transfer + jna .size_ok + mov eax,(1 << 16) +.size_ok: + cdq ; EDX <- 0 + push eax ; Bytes transferred this chunk + div dword [ClustSize] ; Convert to clusters + ; Round up... + add edx,byte -1 ; Sets CF if EDX >= 1 + adc eax,byte 0 ; Add 1 to EAX if CF set + + ; Now (e)ax contains the number of clusters to get + push edi + mov cx,ax + xor bx,bx ; ES:0 + call getfssec ; Load the data into xfer_buf_seg + pop edi + pop ecx ; Byte count this round + push ecx + push edi +.fix_slop: + test cl,3 + jz .noslop + ; The last dword fractional - pad with zeroes + ; Zero-padding is critical for multi-file initramfs. + mov bx,cx + mov byte [es:bx],0 + inc ecx + jmp short .fix_slop +.noslop: + shr ecx,2 ; Convert to dwords + push esi + mov esi,(xfer_buf_seg << 4) ; Source address + call bcopy ; Copy to high memory + pop edi + pop esi + pop ecx + pop eax + add edi,ecx + sub eax,ecx + jnz .read_loop ; More to read... + + pop es + ret + +; ; abort_check: let the user abort with or ; abort_check: diff --git a/pxelinux.asm b/pxelinux.asm index 6df269e..fcedad5 100644 --- a/pxelinux.asm +++ b/pxelinux.asm @@ -343,7 +343,6 @@ MNameBuf resb FILENAME_MAX InitRD resb FILENAME_MAX PartInfo resb 16 ; Partition table entry E820Buf resd 5 ; INT 15:E820 data buffer -InitRDat resd 1 ; Load address (linear) for initrd HiLoadAddr resd 1 ; Address pointer for high load loop HighMemSize resd 1 ; End of memory pointer (bytes) RamdiskMax resd 1 ; Highest address for a ramdisk @@ -353,7 +352,6 @@ PXEEntry resd 1 ; !PXE API entry point SavedSSSP resd 1 ; Our SS:SP while running a COMBOOT image RebootTime resd 1 ; Reboot timeout, if set by option KernelClust resd 1 ; Kernel size in clusters -InitRDClust resd 1 ; Ramdisk size in clusters FBytes equ $ ; Used by open/getc FBytes1 resw 1 FBytes2 resw 1 @@ -1884,53 +1882,35 @@ read_kernel: movzx esi,word [SetupSecs] ; Setup sectors inc esi ; plus 1 boot sector shl esi,9 ; Convert to bytes - mov ecx,108000h ; 108000h = 1M + 32K - sub ecx,esi ; Adjust pointer to 2nd block - mov [HiLoadAddr],ecx - sub ecx,100000h ; Turn into a counter + mov ecx,8000h ; 32K + sub ecx,esi ; Number of bytes to copy + push ecx shr ecx,2 ; Convert to dwords add esi,(real_mode_seg << 4) ; Pointer to source mov edi,100000h ; Copy to address 100000h call bcopy ; Transfer to high memory - push word xfer_buf_seg ; Transfer buffer segment - pop es -high_load_loop: + ; On exit EDI -> where to load the rest + mov si,dot_msg ; Progress report call cwritestr call abort_check - mov ecx,[KernelClust] - and ecx,ecx - jz high_load_done ; Zero left (tiny kernel?) - cmp ecx,[ClustPerMoby] - jna high_last_moby - mov ecx,[ClustPerMoby] -high_last_moby: - sub [KernelClust],ecx - xor bx,bx ; Load at offset 0 - pop si ; Restore cluster pointer - call getfssec - push si ; Save cluster pointer - pushf ; Save EOF - xor bx,bx - mov esi,(xfer_buf_seg << 4) - mov edi,[HiLoadAddr] ; Destination address - mov ecx,4000h ; Cheating - transfer 64K - call bcopy ; Transfer to high memory - mov [HiLoadAddr],edi ; Point to next target area - popf ; Restore EOF - jc high_load_done ; If EOF we are done - cmp dword [KernelClust],byte 0 ; Are we done? - jne high_load_loop ; Apparently not + + pop ecx ; Number of bytes in the initial portion + pop si ; Restore file handle/cluster pointer + mov eax,[KernelSize] + sub eax,ecx ; Amount of kernel left over + jbe high_load_done ; Zero left (tiny kernel) + + call load_high ; Copy the file + high_load_done: - pop si ; No longer needed mov ax,real_mode_seg ; Set to real mode seg mov es,ax mov si,dot_msg call cwritestr - call crlf ; ; Now see if we have an initial RAMdisk; if so, do requisite computation ; We know we have a new kernel; the old_kernel code already will have objected @@ -1951,18 +1931,8 @@ load_initrd: call searchdir ; Look for it in directory pop es jz initrd_notthere - mov [initrd_ptr],si ; Save cluster pointer mov [es:su_ramdisklen1],ax ; Ram disk length mov [es:su_ramdisklen2],dx - movzx eax,ax - shl edx,16 - or eax,edx - xor edx,edx - div dword [ClustSize] - ; Round up... - add edx,byte -1 ; Sets CF if EDX >= 1 - adc eax,byte 0 ; Add 1 to EAX if CF set - mov [InitRDClust],eax ; Ramdisk clusters mov edx,[HighMemSize] ; End of memory dec edx mov eax,[RamdiskMax] ; Highest address allowed by kernel @@ -1973,7 +1943,7 @@ memsize_ok: inc edx sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk xor dx,dx ; Round down to 64K boundary - mov [InitRDat],edx ; Load address + mov [es:su_ramdiskat],edx ; Load address call loadinitrd ; Load initial ramdisk jmp short initrd_end @@ -2013,8 +1983,7 @@ nk_noinitrd: ; and the real mode stuff to 90000h. We assume that all bzImage kernels are ; capable of starting their setup from a different address. ; - mov bx,real_mode_seg ; Real mode segment - mov fs,bx ; FS -> real_mode_seg + ; ; Copy command line. Unfortunately, the kernel boot protocol requires ; the command line to exist in the 9xxxxh range even if the rest of the @@ -2046,8 +2015,10 @@ need_high_cmdline: shr cx,2 ; Convert to dwords fs rep movsd + push fs + pop es + test byte [LoadFlags],LOAD_HIGH - ; Note bx -> real_mode_seg still jnz in_proper_place ; If high load, we're done ; @@ -2055,8 +2026,6 @@ need_high_cmdline: ; ; Copy real_mode stuff up to 90000h ; - mov ax,real_mode_seg - mov fs,ax mov ax,9000h mov es,ax mov cx,[SetupSecs] @@ -2082,6 +2051,8 @@ need_high_cmdline: xor eax,eax rep stosd ; Clear region ; +; Copy the kernel down to the "low" location +; mov ecx,[KernelSize] add ecx,3 ; Round upwards shr ecx,2 ; Bytes -> dwords @@ -2089,13 +2060,14 @@ need_high_cmdline: mov edi,10000h call bcopy - mov bx,9000h ; Real mode segment - ; ; Now everything is where it needs to be... ; +; When we get here, es points to the final segment, either +; 9000h or real_mode_seg +; in_proper_place: - mov es,bx ; Real mode segment + ; ; If the default root device is set to FLOPPY (0000h), change to ; /dev/fd0 (0200h) @@ -2144,10 +2116,10 @@ kill_motor: %endif ; ; Set up segment registers and the Linux real-mode stack -; Note: bx == the real mode segment +; Note: es == the real mode segment ; cli - ; es is already == real mode segment + mov bx,es mov ds,bx mov fs,bx mov gs,bx @@ -2309,7 +2281,7 @@ local_boot: ; 32-bit bcopy routine for real mode ; ; We enter protected mode, set up a flat 32-bit environment, run rep movsd -; and then exit. IMPORTANT: This code assumes cs == ss == 0. +; and then exit. IMPORTANT: This code assumes cs == 0. ; ; This code is probably excessively anal-retentive in its handling of ; segments, but this stuff is painful enough as it is without having to rely @@ -2340,7 +2312,7 @@ bcopy: push eax cli call enable_a20 - o32 lgdt [bcopy_gdt] + o32 lgdt [cs:bcopy_gdt] mov eax,cr0 or al,1 mov cr0,eax ; Enter protected mode @@ -2618,53 +2590,111 @@ try_wbinvd: ; ; Load RAM disk into high memory ; +; Need to be set: +; su_ramdiskat - Where in memory to load +; su_ramdisklen - Size of file +; SI - initrd filehandle/cluster pointer +; loadinitrd: push es ; Save ES on entry - mov ax,real_mode_seg + mov ax,real_mode_seg mov es,ax - mov si,[initrd_ptr] - mov edi,[InitRDat] ; initrd load address - mov [es:su_ramdiskat],edi ; Offset for ram disk + mov edi,[es:su_ramdiskat] ; initrd load address push si - mov si,loading_msg - call cwritestr + mov si,crlfloading_msg ; Write "Loading " + call cwritestr mov si,InitRDCName ; Write ramdisk name call cwritestr mov si,dotdot_msg ; Write dots call cwritestr -rd_load_loop: - mov si,dot_msg ; Progress report - call cwritestr - pop si ; Restore cluster pointer - call abort_check - mov ecx,[InitRDClust] - cmp ecx,[ClustPerMoby] - jna rd_last_moby - mov ecx,[ClustPerMoby] -rd_last_moby: - sub [InitRDClust],ecx - xor bx,bx ; Load at offset 0 - push word xfer_buf_seg ; Bounce buffer segment - pop es - push cx - call getfssec - pop cx - push si ; Save cluster pointer - mov esi,(xfer_buf_seg << 4) - mov edi,[InitRDat] - mov ecx,4000h ; Copy 64K - call bcopy ; Does not change flags!! - jc rd_load_done ; EOF? - add dword [InitRDat],10000h ; Point to next 64K - cmp dword [InitRDClust],byte 0 ; Are we done? - jne rd_load_loop ; Apparently not -rd_load_done: - pop si ; Clean up the stack + pop si + + mov eax,[es:su_ramdisklen] + call load_high ; Load the file + call crlf + mov si,loading_msg ; Write new "Loading " for + call cwritestr ; the benefit of the kernel pop es ; Restore original ES ret ; +; load_high: loads (the remainder of) a file into high memory. +; This routine prints dots for each 64K transferred, and +; calls abort_check periodically. +; +; The xfer_buf_seg is used as a bounce buffer. +; +; The input address (EDI) should be dword aligned, and the final +; dword written is padded with zeroes if necessary. +; +; Inputs: SI = file handle/cluster pointer +; EDI = target address in high memory +; EAX = size of remaining file in bytes +; +; Outputs: SI = file handle/cluster pointer +; EDI = first untouched address (not including padding) +; +load_high: + push es + + mov bx,xfer_buf_seg + mov es,bx + +.read_loop: + push si + mov si,dot_msg + call cwritestr + pop si + call abort_check + + push eax ; Total chunk to transfer + cmp eax,(1 << 16) ; Max 64K in one transfer + jna .size_ok + mov eax,(1 << 16) +.size_ok: + cdq ; EDX <- 0 + push eax ; Bytes transferred this chunk + div dword [ClustSize] ; Convert to clusters + ; Round up... + add edx,byte -1 ; Sets CF if EDX >= 1 + adc eax,byte 0 ; Add 1 to EAX if CF set + + ; Now (e)ax contains the number of clusters to get + push edi + mov cx,ax + xor bx,bx ; ES:0 + call getfssec ; Load the data into xfer_buf_seg + pop edi + pop ecx ; Byte count this round + push ecx + push edi +.fix_slop: + test cl,3 + jz .noslop + ; The last dword fractional - pad with zeroes + ; Zero-padding is critical for multi-file initramfs. + mov bx,cx + mov byte [es:bx],0 + inc ecx + jmp short .fix_slop +.noslop: + shr ecx,2 ; Convert to dwords + push esi + mov esi,(xfer_buf_seg << 4) ; Source address + call bcopy ; Copy to high memory + pop esi + pop edi + pop ecx + pop eax + add edi,ecx + sub eax,ecx + jnz .read_loop ; More to read... + + pop es + ret + +; ; abort_check: let the user abort with or ; abort_check: @@ -4898,6 +4928,7 @@ localboot_msg db 'Booting from local disk...', CR, LF, 0 cmdline_msg db 'Command line: ', CR, LF, 0 ready_msg db ' ready.', CR, LF, 0 trying_msg db 'Trying to load: ', 0 +crlfloading_msg db CR, LF ; Fall through loading_msg db 'Loading ', 0 dotdot_msg db '.' dot_msg db '.', 0 -- 2.7.4