Commit 575400d1b483fbe9e03c68758059bfaf4e4768d1
Committed by
Andi Kleen
1 parent
53ee11ae0d
Exists in
master
and in
7 other branches
[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>
Showing 2 changed files with 76 additions and 22 deletions Side-by-side Diff
arch/i386/boot/edd.S
... | ... | @@ -15,42 +15,95 @@ |
15 | 15 | #include <asm/setup.h> |
16 | 16 | |
17 | 17 | #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) |
18 | + | |
19 | +# It is assumed that %ds == INITSEG here | |
20 | + | |
18 | 21 | movb $0, (EDD_MBR_SIG_NR_BUF) |
19 | 22 | movb $0, (EDDNR) |
20 | 23 | |
21 | -# Check the command line for two options: | |
24 | +# Check the command line for options: | |
22 | 25 | # edd=of disables EDD completely (edd=off) |
23 | 26 | # edd=sk skips the MBR test (edd=skipmbr) |
27 | +# edd=on re-enables EDD (edd=on) | |
28 | + | |
24 | 29 | pushl %esi |
25 | - cmpl $0, %cs:cmd_line_ptr | |
26 | - jz done_cl | |
30 | + movw $edd_mbr_sig_start, %di # Default to edd=on | |
31 | + | |
27 | 32 | movl %cs:(cmd_line_ptr), %esi |
28 | -# ds:esi has the pointer to the command line now | |
29 | - movl $(COMMAND_LINE_SIZE-7), %ecx | |
30 | -# loop through kernel command line one byte at a time | |
31 | -cl_loop: | |
32 | - cmpl $EDD_CL_EQUALS, (%si) | |
33 | + andl %esi, %esi | |
34 | + jz old_cl # Old boot protocol? | |
35 | + | |
36 | +# Convert to a real-mode pointer in fs: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 | 66 | jz found_edd_equals |
34 | - incl %esi | |
35 | - loop cl_loop | |
36 | - jmp done_cl | |
67 | + cmpb $0x20, %al # <= space consider whitespace | |
68 | + ja cl_skipword | |
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 | 83 | found_edd_equals: |
38 | 84 | # only looking at first two characters after equals |
39 | - addl $4, %esi | |
40 | - cmpw $EDD_CL_OFF, (%si) # edd=of | |
41 | - jz do_edd_off | |
42 | - cmpw $EDD_CL_SKIP, (%si) # edd=sk | |
43 | - jz do_edd_skipmbr | |
44 | - jmp done_cl | |
85 | +# late overrides early on the command line, so keep going after finding something | |
86 | + movw %fs:4(%si), %ax | |
87 | + cmpw $EDD_CL_OFF, %ax # edd=of | |
88 | + je do_edd_off | |
89 | + cmpw $EDD_CL_SKIP, %ax # edd=sk | |
90 | + je do_edd_skipmbr | |
91 | + cmpw $EDD_CL_ON, %ax # edd=on | |
92 | + je do_edd_on | |
93 | + jmp cl_skipword | |
45 | 94 | do_edd_skipmbr: |
46 | - popl %esi | |
47 | - jmp edd_start | |
95 | + movw $edd_start, %di | |
96 | + jmp cl_skipword | |
48 | 97 | do_edd_off: |
49 | - popl %esi | |
50 | - jmp edd_done | |
98 | + movw $edd_done, %di | |
99 | + jmp cl_skipword | |
100 | +do_edd_on: | |
101 | + movw $edd_mbr_sig_start, %di | |
102 | + jmp cl_skipword | |
103 | + | |
51 | 104 | done_cl: |
52 | 105 | popl %esi |
53 | - | |
106 | + jmpw *%di | |
54 | 107 | |
55 | 108 | # Read the first sector of each BIOS disk device and store the 4-byte signature |
56 | 109 | edd_mbr_sig_start: |
include/linux/edd.h