Skip to content

Commit

Permalink
[PATCH] i386: Fix the EDD code misparsing the command line
Browse files Browse the repository at this point in the history
The EDD code would scan the command line as a fixed array, without
taking account of either whitespace, null-termination, the old
command-line protocol, late overrides early, or the fact that the
command line may not be reachable from INITSEG.

This should fix those problems, and enable us to use a longer command
line.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Andi Kleen <ak@suse.de>
  • Loading branch information
H. Peter Anvin authored and Andi Kleen committed Sep 26, 2006
1 parent 53ee11a commit 575400d
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 22 deletions.
97 changes: 75 additions & 22 deletions arch/i386/boot/edd.S
Original file line number Diff line number Diff line change
Expand Up @@ -15,42 +15,95 @@
#include <asm/setup.h>

#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)

# It is assumed that %ds == INITSEG here

movb $0, (EDD_MBR_SIG_NR_BUF)
movb $0, (EDDNR)

# Check the command line for two options:
# Check the command line for options:
# edd=of disables EDD completely (edd=off)
# edd=sk skips the MBR test (edd=skipmbr)
# edd=on re-enables EDD (edd=on)

pushl %esi
cmpl $0, %cs:cmd_line_ptr
jz done_cl
movw $edd_mbr_sig_start, %di # Default to edd=on

movl %cs:(cmd_line_ptr), %esi
# ds:esi has the pointer to the command line now
movl $(COMMAND_LINE_SIZE-7), %ecx
# loop through kernel command line one byte at a time
cl_loop:
cmpl $EDD_CL_EQUALS, (%si)
andl %esi, %esi
jz old_cl # Old boot protocol?

# Convert to a real-mode pointer in fs:si
movl %esi, %eax
shrl $4, %eax
movw %ax, %fs
andw $0xf, %si
jmp have_cl_pointer

# Old-style boot protocol?
old_cl:
push %ds # aka INITSEG
pop %fs

cmpw $0xa33f, (0x20)
jne done_cl # No command line at all?
movw (0x22), %si # Pointer relative to INITSEG

# fs:si has the pointer to the command line now
have_cl_pointer:

# Loop through kernel command line one byte at a time. Just in
# case the loader is buggy and failed to null-terminate the command line
# terminate if we get close enough to the end of the segment that we
# cannot fit "edd=XX"...
cl_atspace:
cmpw $-5, %si # Watch for segment wraparound
jae done_cl
movl %fs:(%si), %eax
andb %al, %al # End of line?
jz done_cl
cmpl $EDD_CL_EQUALS, %eax
jz found_edd_equals
incl %esi
loop cl_loop
jmp done_cl
cmpb $0x20, %al # <= space consider whitespace
ja cl_skipword
incw %si
jmp cl_atspace

cl_skipword:
cmpw $-5, %si # Watch for segment wraparound
jae done_cl
movb %fs:(%si), %al # End of string?
andb %al, %al
jz done_cl
cmpb $0x20, %al
jbe cl_atspace
incw %si
jmp cl_skipword

found_edd_equals:
# only looking at first two characters after equals
addl $4, %esi
cmpw $EDD_CL_OFF, (%si) # edd=of
jz do_edd_off
cmpw $EDD_CL_SKIP, (%si) # edd=sk
jz do_edd_skipmbr
jmp done_cl
# late overrides early on the command line, so keep going after finding something
movw %fs:4(%si), %ax
cmpw $EDD_CL_OFF, %ax # edd=of
je do_edd_off
cmpw $EDD_CL_SKIP, %ax # edd=sk
je do_edd_skipmbr
cmpw $EDD_CL_ON, %ax # edd=on
je do_edd_on
jmp cl_skipword
do_edd_skipmbr:
popl %esi
jmp edd_start
movw $edd_start, %di
jmp cl_skipword
do_edd_off:
popl %esi
jmp edd_done
movw $edd_done, %di
jmp cl_skipword
do_edd_on:
movw $edd_mbr_sig_start, %di
jmp cl_skipword

done_cl:
popl %esi

jmpw *%di

# Read the first sector of each BIOS disk device and store the 4-byte signature
edd_mbr_sig_start:
Expand Down
1 change: 1 addition & 0 deletions include/linux/edd.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#define EDD_CL_EQUALS 0x3d646465 /* "edd=" */
#define EDD_CL_OFF 0x666f /* "of" for off */
#define EDD_CL_SKIP 0x6b73 /* "sk" for skipmbr */
#define EDD_CL_ON 0x6e6f /* "on" for on */

#ifndef __ASSEMBLY__

Expand Down

0 comments on commit 575400d

Please sign in to comment.