aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhpa <hpa>2001-12-23 01:02:30 +0000
committerhpa <hpa>2001-12-23 01:02:30 +0000
commita0208c5997d850e3c8a6369f1bad8914114e4077 (patch)
treecec68e2621c00950f879b369aa4f16396155efc8
parent61c13e1f40d68cac439a2a78061a61b71502012c (diff)
downloadsyslinux.git-a0208c5997d850e3c8a6369f1bad8914114e4077.tar.gz
syslinux.git-a0208c5997d850e3c8a6369f1bad8914114e4077.tar.xz
syslinux.git-a0208c5997d850e3c8a6369f1bad8914114e4077.zip
Code restructuring: common subroutine to load a file into high memory
-rw-r--r--NEWS1
-rw-r--r--isolinux.asm213
-rw-r--r--ldlinux.asm202
-rw-r--r--pxelinux.asm213
4 files changed, 362 insertions, 267 deletions
diff --git a/NEWS b/NEWS
index b5210fc4..e6271428 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 903e6fe7..e5d867d3 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 <ESC> or <Ctrl-C>
;
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 20584cf1..fc58af47 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 <ESC> or <Ctrl-C>
;
abort_check:
diff --git a/pxelinux.asm b/pxelinux.asm
index 6df269e6..fcedad59 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 <ESC> or <Ctrl-C>
;
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