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
15static 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 */
28int __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 */
100int __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