From 2775964e0d571f00e645e99abb446162cac53a0d Mon Sep 17 00:00:00 2001 From: hpa Date: Wed, 16 Jan 2002 01:58:11 +0000 Subject: Handle bug in the alignment of the initrd. --- NEWS | 2 +- isolinux.asm | 218 ++++++++++++++++++++++++++--------------------------------- ldlinux.asm | 207 ++++++++++++++++++++++++-------------------------------- pxelinux.asm | 218 ++++++++++++++++++++++++++--------------------------------- 4 files changed, 277 insertions(+), 368 deletions(-) diff --git a/NEWS b/NEWS index 71a6c024..0a16a697 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,7 @@ Starting with 1.47, changes marked with SYSLINUX/PXELINUX/ISOLINUX apply to that specific program only; other changes apply to both. Changes in 1.67: - * Major code restructuring. + * Handle bug in the location of initrd. Changes in 1.66: * MEMDISK: Make compile with newer versions of gcc. diff --git a/isolinux.asm b/isolinux.asm index e9803c09..0d624f3d 100644 --- a/isolinux.asm +++ b/isolinux.asm @@ -9,7 +9,7 @@ ; available. It is based on the SYSLINUX boot loader for MS-DOS ; floppies. ; -; Copyright (C) 1994-2002 H. Peter Anvin +; Copyright (C) 1994-2001 H. Peter Anvin ; ; 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 @@ -58,7 +58,7 @@ SECTORSIZE equ (1 << SECTORSIZE_LG2) ; %define version_str VERSION ; Must be 4 characters long! %define date DATE_STR ; Defined from the Makefile -%define year '2002' +%define year '2001' ; ; Debgging stuff ; @@ -306,6 +306,7 @@ 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 @@ -314,6 +315,7 @@ 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 @@ -2003,35 +2005,53 @@ read_kernel: movzx esi,word [SetupSecs] ; Setup sectors inc esi ; plus 1 boot sector shl esi,9 ; Convert to bytes - mov ecx,8000h ; 32K - sub ecx,esi ; Number of bytes to copy - push ecx + mov ecx,108000h ; 108000h = 1M + 32K + sub ecx,esi ; Adjust pointer to 2nd block + mov [HiLoadAddr],ecx + sub ecx,100000h ; Turn into a counter 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 - ; On exit EDI -> where to load the rest - + push word xfer_buf_seg ; Transfer buffer segment + pop es +high_load_loop: mov si,dot_msg ; Progress report call cwritestr call abort_check - - 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 - + 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 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 @@ -2052,8 +2072,18 @@ 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 @@ -2062,9 +2092,10 @@ load_initrd: mov edx,eax ; Adjust to fit inside limit memsize_ok: inc edx + xor dx,dx ; Round down to 64K boundary sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk xor dx,dx ; Round down to 64K boundary - mov [es:su_ramdiskat],edx ; Load address + mov [InitRDat],edx ; Load address call loadinitrd ; Load initial ramdisk jmp short initrd_end @@ -2101,7 +2132,8 @@ 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 @@ -2133,10 +2165,8 @@ 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 ; @@ -2144,6 +2174,8 @@ 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] @@ -2168,8 +2200,6 @@ need_high_cmdline: shl cx,7 ; Sectors -> dwords xor eax,eax rep stosd ; Clear region -; -; Copy the kernel down to the "low" location ; mov ecx,[KernelSize] add ecx,3 ; Round upwards @@ -2178,14 +2208,13 @@ 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) @@ -2234,10 +2263,10 @@ kill_motor: %endif ; ; Set up segment registers and the Linux real-mode stack -; Note: es == the real mode segment +; Note: bx == the real mode segment ; cli - mov bx,es + ; es is already == real mode segment mov ds,bx mov fs,bx mov gs,bx @@ -2549,7 +2578,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 == 0. +; and then exit. IMPORTANT: This code assumes cs == ss == 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 @@ -2580,7 +2609,7 @@ bcopy: push eax cli call enable_a20 - o32 lgdt [cs:bcopy_gdt] + o32 lgdt [bcopy_gdt] mov eax,cr0 or al,1 mov cr0,eax ; Enter protected mode @@ -2858,110 +2887,52 @@ 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 edi,[es:su_ramdiskat] ; initrd load address + mov si,[initrd_ptr] + mov edi,[InitRDat] ; initrd load address + mov [es:su_ramdiskat],edi ; Offset for ram disk push si - mov si,crlfloading_msg ; Write "Loading " - call cwritestr + mov si,loading_msg + call cwritestr mov si,InitRDCName ; Write ramdisk name call cwritestr mov si,dotdot_msg ; Write dots call cwritestr - pop si - - mov eax,[es:su_ramdisklen] - call load_high ; Load the file - +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 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 ; @@ -4501,7 +4472,6 @@ 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 62e8537e..f120d889 100644 --- a/ldlinux.asm +++ b/ldlinux.asm @@ -16,7 +16,7 @@ ; then the first sector (cluster, really, but we can only assume 1 sector) ; of LDLINUX.SYS at 7E00h and finally the remainder of LDLINUX.SYS at 8000h. ; -; Copyright (C) 1994-2002 H. Peter Anvin +; Copyright (C) 1994-2001 H. Peter Anvin ; ; 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 @@ -40,7 +40,7 @@ BAUD_DIVISOR equ 115200 ; Serial port parameter ; %define version_str VERSION ; Must be 4 characters long! %define date DATE_STR ; Defined from the Makefile -%define year '2002' +%define year '2001' ; ; Debgging stuff ; @@ -270,6 +270,7 @@ 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 @@ -298,6 +299,7 @@ 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 @@ -2050,8 +2052,15 @@ 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 @@ -2060,9 +2069,10 @@ new_kernel: mov edx,eax ; Adjust to fit inside limit memsize_ok: inc edx + xor dx,dx ; Round down to 64K boundary sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk xor dx,dx ; Round down to 64K boundary - mov [es:su_ramdiskat],edx ; Load address + mov [InitRDat],edx ; Load address call loadinitrd ; Load initial ramdisk jmp short initrd_end @@ -2105,31 +2115,48 @@ read_kernel: movzx esi,word [SetupSecs] ; Setup sectors inc esi ; plus 1 boot sector shl esi,9 ; Convert to bytes - mov ecx,8000h ; 32K - sub ecx,esi ; Number of bytes to copy - push ecx + mov ecx,108000h ; 108000h = 1M + 32K + sub ecx,esi ; Adjust pointer to 2nd block + mov [HiLoadAddr],ecx + sub ecx,100000h ; Turn into a counter 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 - ; On exit EDI -> where to load the rest - + push word xfer_buf_seg ; Transfer buffer segment + pop es +high_load_loop: mov si,dot_msg ; Progress report call cwritestr call abort_check - - 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 - + 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 high_load_done: + pop si ; No longer needed mov ax,real_mode_seg ; Set to real mode seg - mov fs,ax ; FS -> real_mode_seg + mov es,ax mov si,dot_msg call cwritestr @@ -2147,7 +2174,8 @@ 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 @@ -2179,10 +2207,8 @@ 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 ; @@ -2190,6 +2216,8 @@ 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] @@ -2214,8 +2242,6 @@ need_high_cmdline: shl cx,7 ; Sectors -> dwords xor eax,eax rep stosd ; Clear region -; -; Copy the kernel down to the "low" location ; mov ecx,[KernelSize] add ecx,3 ; Round upwards @@ -2224,14 +2250,13 @@ 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) @@ -2280,10 +2305,10 @@ kill_motor: %endif ; ; Set up segment registers and the Linux real-mode stack -; Note: es == the real mode segment +; Note: bx == the real mode segment ; cli - mov bx,es + ; es is already == real mode segment mov ds,bx mov fs,bx mov gs,bx @@ -2503,7 +2528,7 @@ bcopy: push eax cli call enable_a20 - o32 lgdt [cs:bcopy_gdt] + o32 lgdt [bcopy_gdt] mov eax,cr0 or al,1 mov cr0,eax ; Enter protected mode @@ -2781,108 +2806,52 @@ 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 edi,[es:su_ramdiskat] ; initrd load address + mov si,[initrd_ptr] + mov edi,[InitRDat] ; initrd load address + mov [es:su_ramdiskat],edi ; Offset for ram disk push si mov si,InitRDCName ; Write ramdisk name call cwritestr mov si,dotdot_msg ; Write dots call cwritestr - pop si - - mov eax,[es:su_ramdisklen] - call load_high ; Load the file - +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 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 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 ; diff --git a/pxelinux.asm b/pxelinux.asm index 72c0fc2a..077e618b 100644 --- a/pxelinux.asm +++ b/pxelinux.asm @@ -8,7 +8,7 @@ ; network booting API. It is based on the SYSLINUX boot loader for ; MS-DOS floppies. ; -; Copyright (C) 1994-2002 H. Peter Anvin +; Copyright (C) 1994-2001 H. Peter Anvin ; ; 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 @@ -64,7 +64,7 @@ TFTP_OACK equ htons(6) ; OACK packet ; %define version_str VERSION ; Must be 4 characters long! %define date DATE_STR ; Defined from the Makefile -%define year '2002' +%define year '2001' ; ; Debgging stuff ; @@ -343,6 +343,7 @@ 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 @@ -352,6 +353,7 @@ 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 @@ -1882,35 +1884,53 @@ read_kernel: movzx esi,word [SetupSecs] ; Setup sectors inc esi ; plus 1 boot sector shl esi,9 ; Convert to bytes - mov ecx,8000h ; 32K - sub ecx,esi ; Number of bytes to copy - push ecx + mov ecx,108000h ; 108000h = 1M + 32K + sub ecx,esi ; Adjust pointer to 2nd block + mov [HiLoadAddr],ecx + sub ecx,100000h ; Turn into a counter 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 - ; On exit EDI -> where to load the rest - + push word xfer_buf_seg ; Transfer buffer segment + pop es +high_load_loop: mov si,dot_msg ; Progress report call cwritestr call abort_check - - 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 - + 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 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 @@ -1931,8 +1951,18 @@ 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 @@ -1941,9 +1971,10 @@ load_initrd: mov edx,eax ; Adjust to fit inside limit memsize_ok: inc edx + xor dx,dx ; Round down to 64K boundary sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk xor dx,dx ; Round down to 64K boundary - mov [es:su_ramdiskat],edx ; Load address + mov [InitRDat],edx ; Load address call loadinitrd ; Load initial ramdisk jmp short initrd_end @@ -1983,7 +2014,8 @@ 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 @@ -2015,10 +2047,8 @@ 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 ; @@ -2026,6 +2056,8 @@ 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] @@ -2050,8 +2082,6 @@ need_high_cmdline: shl cx,7 ; Sectors -> dwords xor eax,eax rep stosd ; Clear region -; -; Copy the kernel down to the "low" location ; mov ecx,[KernelSize] add ecx,3 ; Round upwards @@ -2060,14 +2090,13 @@ 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) @@ -2116,10 +2145,10 @@ kill_motor: %endif ; ; Set up segment registers and the Linux real-mode stack -; Note: es == the real mode segment +; Note: bx == the real mode segment ; cli - mov bx,es + ; es is already == real mode segment mov ds,bx mov fs,bx mov gs,bx @@ -2281,7 +2310,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 == 0. +; and then exit. IMPORTANT: This code assumes cs == ss == 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 @@ -2312,7 +2341,7 @@ bcopy: push eax cli call enable_a20 - o32 lgdt [cs:bcopy_gdt] + o32 lgdt [bcopy_gdt] mov eax,cr0 or al,1 mov cr0,eax ; Enter protected mode @@ -2590,110 +2619,52 @@ 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 edi,[es:su_ramdiskat] ; initrd load address + mov si,[initrd_ptr] + mov edi,[InitRDat] ; initrd load address + mov [es:su_ramdiskat],edi ; Offset for ram disk push si - mov si,crlfloading_msg ; Write "Loading " - call cwritestr + mov si,loading_msg + call cwritestr mov si,InitRDCName ; Write ramdisk name call cwritestr mov si,dotdot_msg ; Write dots call cwritestr - pop si - - mov eax,[es:su_ramdisklen] - call load_high ; Load the file - +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 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 ; @@ -4928,7 +4899,6 @@ 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 -- cgit v1.2.1