xref: /linux/arch/x86/boot/cmdline.c (revision 24bce201d79807b668bf9d9e0aca801c5c0d5f78)
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(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(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