diff options
author | H. Peter Anvin <hpa@zytor.com> | 2006-09-26 04:52:38 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-09-26 04:52:38 -0400 |
commit | 575400d1b483fbe9e03c68758059bfaf4e4768d1 (patch) | |
tree | 9839d343d235dabfdb27e8ad2e48511ae542b015 | |
parent | 53ee11ae0d73f28029a5f0d991bc4dcd7c817e7a (diff) |
[PATCH] i386: Fix the EDD code misparsing the command line
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>
-rw-r--r-- | arch/i386/boot/edd.S | 97 | ||||
-rw-r--r-- | include/linux/edd.h | 1 |
2 files changed, 76 insertions, 22 deletions
diff --git a/arch/i386/boot/edd.S b/arch/i386/boot/edd.S index 4b84ea216f2b..34321368011a 100644 --- a/arch/i386/boot/edd.S +++ b/arch/i386/boot/edd.S | |||
@@ -15,42 +15,95 @@ | |||
15 | #include <asm/setup.h> | 15 | #include <asm/setup.h> |
16 | 16 | ||
17 | #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) | 17 | #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) |
18 | |||
19 | # It is assumed that %ds == INITSEG here | ||
20 | |||
18 | movb $0, (EDD_MBR_SIG_NR_BUF) | 21 | movb $0, (EDD_MBR_SIG_NR_BUF) |
19 | movb $0, (EDDNR) | 22 | movb $0, (EDDNR) |
20 | 23 | ||
21 | # Check the command line for two options: | 24 | # Check the command line for options: |
22 | # edd=of disables EDD completely (edd=off) | 25 | # edd=of disables EDD completely (edd=off) |
23 | # edd=sk skips the MBR test (edd=skipmbr) | 26 | # edd=sk skips the MBR test (edd=skipmbr) |
27 | # edd=on re-enables EDD (edd=on) | ||
28 | |||
24 | pushl %esi | 29 | pushl %esi |
25 | cmpl $0, %cs:cmd_line_ptr | 30 | movw $edd_mbr_sig_start, %di # Default to edd=on |
26 | jz done_cl | 31 | |
27 | movl %cs:(cmd_line_ptr), %esi | 32 | movl %cs:(cmd_line_ptr), %esi |
28 | # ds:esi has the pointer to the command line now | 33 | andl %esi, %esi |
29 | movl $(COMMAND_LINE_SIZE-7), %ecx | 34 | jz old_cl # Old boot protocol? |
30 | # loop through kernel command line one byte at a time | 35 | |
31 | cl_loop: | 36 | # Convert to a real-mode pointer in fs:si |
32 | cmpl $EDD_CL_EQUALS, (%si) | 37 | movl %esi, %eax |
38 | shrl $4, %eax | ||
39 | movw %ax, %fs | ||
40 | andw $0xf, %si | ||
41 | jmp have_cl_pointer | ||
42 | |||
43 | # Old-style boot protocol? | ||
44 | old_cl: | ||
45 | push %ds # aka INITSEG | ||
46 | pop %fs | ||
47 | |||
48 | cmpw $0xa33f, (0x20) | ||
49 | jne done_cl # No command line at all? | ||
50 | movw (0x22), %si # Pointer relative to INITSEG | ||
51 | |||
52 | # fs:si has the pointer to the command line now | ||
53 | have_cl_pointer: | ||
54 | |||
55 | # Loop through kernel command line one byte at a time. Just in | ||
56 | # case the loader is buggy and failed to null-terminate the command line | ||
57 | # terminate if we get close enough to the end of the segment that we | ||
58 | # cannot fit "edd=XX"... | ||
59 | cl_atspace: | ||
60 | cmpw $-5, %si # Watch for segment wraparound | ||
61 | jae done_cl | ||
62 | movl %fs:(%si), %eax | ||
63 | andb %al, %al # End of line? | ||
64 | jz done_cl | ||
65 | cmpl $EDD_CL_EQUALS, %eax | ||
33 | jz found_edd_equals | 66 | jz found_edd_equals |
34 | incl %esi | 67 | cmpb $0x20, %al # <= space consider whitespace |
35 | loop cl_loop | 68 | ja cl_skipword |
36 | jmp done_cl | 69 | incw %si |
70 | jmp cl_atspace | ||
71 | |||
72 | cl_skipword: | ||
73 | cmpw $-5, %si # Watch for segment wraparound | ||
74 | jae done_cl | ||
75 | movb %fs:(%si), %al # End of string? | ||
76 | andb %al, %al | ||
77 | jz done_cl | ||
78 | cmpb $0x20, %al | ||
79 | jbe cl_atspace | ||
80 | incw %si | ||
81 | jmp cl_skipword | ||
82 | |||
37 | found_edd_equals: | 83 | found_edd_equals: |
38 | # only looking at first two characters after equals | 84 | # only looking at first two characters after equals |
39 | addl $4, %esi | 85 | # late overrides early on the command line, so keep going after finding something |
40 | cmpw $EDD_CL_OFF, (%si) # edd=of | 86 | movw %fs:4(%si), %ax |
41 | jz do_edd_off | 87 | cmpw $EDD_CL_OFF, %ax # edd=of |
42 | cmpw $EDD_CL_SKIP, (%si) # edd=sk | 88 | je do_edd_off |
43 | jz do_edd_skipmbr | 89 | cmpw $EDD_CL_SKIP, %ax # edd=sk |
44 | jmp done_cl | 90 | je do_edd_skipmbr |
91 | cmpw $EDD_CL_ON, %ax # edd=on | ||
92 | je do_edd_on | ||
93 | jmp cl_skipword | ||
45 | do_edd_skipmbr: | 94 | do_edd_skipmbr: |
46 | popl %esi | 95 | movw $edd_start, %di |
47 | jmp edd_start | 96 | jmp cl_skipword |
48 | do_edd_off: | 97 | do_edd_off: |
49 | popl %esi | 98 | movw $edd_done, %di |
50 | jmp edd_done | 99 | jmp cl_skipword |
100 | do_edd_on: | ||
101 | movw $edd_mbr_sig_start, %di | ||
102 | jmp cl_skipword | ||
103 | |||
51 | done_cl: | 104 | done_cl: |
52 | popl %esi | 105 | popl %esi |
53 | 106 | jmpw *%di | |
54 | 107 | ||
55 | # Read the first sector of each BIOS disk device and store the 4-byte signature | 108 | # Read the first sector of each BIOS disk device and store the 4-byte signature |
56 | edd_mbr_sig_start: | 109 | edd_mbr_sig_start: |
diff --git a/include/linux/edd.h b/include/linux/edd.h index 162512b886f7..b2b3e68aa512 100644 --- a/include/linux/edd.h +++ b/include/linux/edd.h | |||
@@ -52,6 +52,7 @@ | |||
52 | #define EDD_CL_EQUALS 0x3d646465 /* "edd=" */ | 52 | #define EDD_CL_EQUALS 0x3d646465 /* "edd=" */ |
53 | #define EDD_CL_OFF 0x666f /* "of" for off */ | 53 | #define EDD_CL_OFF 0x666f /* "of" for off */ |
54 | #define EDD_CL_SKIP 0x6b73 /* "sk" for skipmbr */ | 54 | #define EDD_CL_SKIP 0x6b73 /* "sk" for skipmbr */ |
55 | #define EDD_CL_ON 0x6e6f /* "on" for on */ | ||
55 | 56 | ||
56 | #ifndef __ASSEMBLY__ | 57 | #ifndef __ASSEMBLY__ |
57 | 58 | ||