1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* -*- linux-c -*- ------------------------------------------------------- * |
3 | * |
4 | * Copyright (C) 1991, 1992 Linus Torvalds |
5 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
6 | * |
7 | * ----------------------------------------------------------------------- */ |
8 | |
9 | /* |
10 | * Simple command-line parser for early boot. |
11 | */ |
12 | |
13 | #include "boot.h" |
14 | |
15 | static inline int myisspace(u8 c) |
16 | { |
17 | return c <= ' '; /* Close enough approximation */ |
18 | } |
19 | |
20 | /* |
21 | * Find a non-boolean option, that is, "option=argument". In accordance |
22 | * with standard Linux practice, if this option is repeated, this returns |
23 | * the last instance on the command line. |
24 | * |
25 | * Returns the length of the argument (regardless of if it was |
26 | * truncated to fit in the buffer), or -1 on not found. |
27 | */ |
28 | int __cmdline_find_option(unsigned long cmdline_ptr, const char *option, char *buffer, int bufsize) |
29 | { |
30 | addr_t cptr; |
31 | char c; |
32 | int len = -1; |
33 | const char *opptr = NULL; |
34 | char *bufptr = buffer; |
35 | enum { |
36 | st_wordstart, /* Start of word/after whitespace */ |
37 | st_wordcmp, /* Comparing this word */ |
38 | st_wordskip, /* Miscompare, skip */ |
39 | st_bufcpy /* Copying this to buffer */ |
40 | } state = st_wordstart; |
41 | |
42 | if (!cmdline_ptr) |
43 | return -1; /* No command line */ |
44 | |
45 | cptr = cmdline_ptr & 0xf; |
46 | set_fs(cmdline_ptr >> 4); |
47 | |
48 | while (cptr < 0x10000 && (c = rdfs8(addr: cptr++))) { |
49 | switch (state) { |
50 | case st_wordstart: |
51 | if (myisspace(c)) |
52 | break; |
53 | |
54 | /* else */ |
55 | state = st_wordcmp; |
56 | opptr = option; |
57 | fallthrough; |
58 | |
59 | case st_wordcmp: |
60 | if (c == '=' && !*opptr) { |
61 | len = 0; |
62 | bufptr = buffer; |
63 | state = st_bufcpy; |
64 | } else if (myisspace(c)) { |
65 | state = st_wordstart; |
66 | } else if (c != *opptr++) { |
67 | state = st_wordskip; |
68 | } |
69 | break; |
70 | |
71 | case st_wordskip: |
72 | if (myisspace(c)) |
73 | state = st_wordstart; |
74 | break; |
75 | |
76 | case st_bufcpy: |
77 | if (myisspace(c)) { |
78 | state = st_wordstart; |
79 | } else { |
80 | if (len < bufsize-1) |
81 | *bufptr++ = c; |
82 | len++; |
83 | } |
84 | break; |
85 | } |
86 | } |
87 | |
88 | if (bufsize) |
89 | *bufptr = '\0'; |
90 | |
91 | return len; |
92 | } |
93 | |
94 | /* |
95 | * Find a boolean option (like quiet,noapic,nosmp....) |
96 | * |
97 | * Returns the position of that option (starts counting with 1) |
98 | * or 0 on not found |
99 | */ |
100 | int __cmdline_find_option_bool(unsigned long cmdline_ptr, const char *option) |
101 | { |
102 | addr_t cptr; |
103 | char c; |
104 | int pos = 0, wstart = 0; |
105 | const char *opptr = NULL; |
106 | enum { |
107 | st_wordstart, /* Start of word/after whitespace */ |
108 | st_wordcmp, /* Comparing this word */ |
109 | st_wordskip, /* Miscompare, skip */ |
110 | } state = st_wordstart; |
111 | |
112 | if (!cmdline_ptr) |
113 | return -1; /* No command line */ |
114 | |
115 | cptr = cmdline_ptr & 0xf; |
116 | set_fs(cmdline_ptr >> 4); |
117 | |
118 | while (cptr < 0x10000) { |
119 | c = rdfs8(addr: cptr++); |
120 | pos++; |
121 | |
122 | switch (state) { |
123 | case st_wordstart: |
124 | if (!c) |
125 | return 0; |
126 | else if (myisspace(c)) |
127 | break; |
128 | |
129 | state = st_wordcmp; |
130 | opptr = option; |
131 | wstart = pos; |
132 | fallthrough; |
133 | |
134 | case st_wordcmp: |
135 | if (!*opptr) |
136 | if (!c || myisspace(c)) |
137 | return wstart; |
138 | else |
139 | state = st_wordskip; |
140 | else if (!c) |
141 | return 0; |
142 | else if (c != *opptr++) |
143 | state = st_wordskip; |
144 | break; |
145 | |
146 | case st_wordskip: |
147 | if (!c) |
148 | return 0; |
149 | else if (myisspace(c)) |
150 | state = st_wordstart; |
151 | break; |
152 | } |
153 | } |
154 | |
155 | return 0; /* Buffer overrun */ |
156 | } |
157 | |