197873a3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
296ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
396ae6ea0SThomas Gleixner *
496ae6ea0SThomas Gleixner * Copyright (C) 1991, 1992 Linus Torvalds
596ae6ea0SThomas Gleixner * Copyright 2007 rPath, Inc. - All Rights Reserved
696ae6ea0SThomas Gleixner *
796ae6ea0SThomas Gleixner * ----------------------------------------------------------------------- */
896ae6ea0SThomas Gleixner
996ae6ea0SThomas Gleixner /*
1096ae6ea0SThomas Gleixner * Simple command-line parser for early boot.
1196ae6ea0SThomas Gleixner */
1296ae6ea0SThomas Gleixner
1396ae6ea0SThomas Gleixner #include "boot.h"
1496ae6ea0SThomas Gleixner
myisspace(u8 c)1596ae6ea0SThomas Gleixner static inline int myisspace(u8 c)
1696ae6ea0SThomas Gleixner {
1796ae6ea0SThomas Gleixner return c <= ' '; /* Close enough approximation */
1896ae6ea0SThomas Gleixner }
1996ae6ea0SThomas Gleixner
2096ae6ea0SThomas Gleixner /*
2196ae6ea0SThomas Gleixner * Find a non-boolean option, that is, "option=argument". In accordance
2296ae6ea0SThomas Gleixner * with standard Linux practice, if this option is repeated, this returns
2396ae6ea0SThomas Gleixner * the last instance on the command line.
2496ae6ea0SThomas Gleixner *
2596ae6ea0SThomas Gleixner * Returns the length of the argument (regardless of if it was
2696ae6ea0SThomas Gleixner * truncated to fit in the buffer), or -1 on not found.
2796ae6ea0SThomas Gleixner */
__cmdline_find_option(unsigned long cmdline_ptr,const char * option,char * buffer,int bufsize)283db07e70SYinghai Lu int __cmdline_find_option(unsigned long cmdline_ptr, const char *option, char *buffer, int bufsize)
2996ae6ea0SThomas Gleixner {
3096ae6ea0SThomas Gleixner addr_t cptr;
3196ae6ea0SThomas Gleixner char c;
3296ae6ea0SThomas Gleixner int len = -1;
3396ae6ea0SThomas Gleixner const char *opptr = NULL;
3496ae6ea0SThomas Gleixner char *bufptr = buffer;
3596ae6ea0SThomas Gleixner enum {
3696ae6ea0SThomas Gleixner st_wordstart, /* Start of word/after whitespace */
3796ae6ea0SThomas Gleixner st_wordcmp, /* Comparing this word */
3896ae6ea0SThomas Gleixner st_wordskip, /* Miscompare, skip */
3996ae6ea0SThomas Gleixner st_bufcpy /* Copying this to buffer */
4096ae6ea0SThomas Gleixner } state = st_wordstart;
4196ae6ea0SThomas Gleixner
4216a4baa6SYinghai Lu if (!cmdline_ptr)
4316a4baa6SYinghai Lu return -1; /* No command line */
4496ae6ea0SThomas Gleixner
4596ae6ea0SThomas Gleixner cptr = cmdline_ptr & 0xf;
4696ae6ea0SThomas Gleixner set_fs(cmdline_ptr >> 4);
4796ae6ea0SThomas Gleixner
4896ae6ea0SThomas Gleixner while (cptr < 0x10000 && (c = rdfs8(cptr++))) {
4996ae6ea0SThomas Gleixner switch (state) {
5096ae6ea0SThomas Gleixner case st_wordstart:
5196ae6ea0SThomas Gleixner if (myisspace(c))
5296ae6ea0SThomas Gleixner break;
5396ae6ea0SThomas Gleixner
5496ae6ea0SThomas Gleixner /* else */
5596ae6ea0SThomas Gleixner state = st_wordcmp;
5696ae6ea0SThomas Gleixner opptr = option;
57*df561f66SGustavo A. R. Silva fallthrough;
5896ae6ea0SThomas Gleixner
5996ae6ea0SThomas Gleixner case st_wordcmp:
6096ae6ea0SThomas Gleixner if (c == '=' && !*opptr) {
6196ae6ea0SThomas Gleixner len = 0;
6296ae6ea0SThomas Gleixner bufptr = buffer;
6396ae6ea0SThomas Gleixner state = st_bufcpy;
6496ae6ea0SThomas Gleixner } else if (myisspace(c)) {
6596ae6ea0SThomas Gleixner state = st_wordstart;
6696ae6ea0SThomas Gleixner } else if (c != *opptr++) {
6796ae6ea0SThomas Gleixner state = st_wordskip;
6896ae6ea0SThomas Gleixner }
6996ae6ea0SThomas Gleixner break;
7096ae6ea0SThomas Gleixner
7196ae6ea0SThomas Gleixner case st_wordskip:
7296ae6ea0SThomas Gleixner if (myisspace(c))
7396ae6ea0SThomas Gleixner state = st_wordstart;
7496ae6ea0SThomas Gleixner break;
7596ae6ea0SThomas Gleixner
7696ae6ea0SThomas Gleixner case st_bufcpy:
7796ae6ea0SThomas Gleixner if (myisspace(c)) {
7896ae6ea0SThomas Gleixner state = st_wordstart;
7996ae6ea0SThomas Gleixner } else {
8096ae6ea0SThomas Gleixner if (len < bufsize-1)
8196ae6ea0SThomas Gleixner *bufptr++ = c;
8296ae6ea0SThomas Gleixner len++;
8396ae6ea0SThomas Gleixner }
8496ae6ea0SThomas Gleixner break;
8596ae6ea0SThomas Gleixner }
8696ae6ea0SThomas Gleixner }
8796ae6ea0SThomas Gleixner
8896ae6ea0SThomas Gleixner if (bufsize)
8996ae6ea0SThomas Gleixner *bufptr = '\0';
9096ae6ea0SThomas Gleixner
9196ae6ea0SThomas Gleixner return len;
9296ae6ea0SThomas Gleixner }
9332d0b989Sdevzero@web.de
9432d0b989Sdevzero@web.de /*
9532d0b989Sdevzero@web.de * Find a boolean option (like quiet,noapic,nosmp....)
9632d0b989Sdevzero@web.de *
9732d0b989Sdevzero@web.de * Returns the position of that option (starts counting with 1)
9832d0b989Sdevzero@web.de * or 0 on not found
9932d0b989Sdevzero@web.de */
__cmdline_find_option_bool(unsigned long cmdline_ptr,const char * option)1003db07e70SYinghai Lu int __cmdline_find_option_bool(unsigned long cmdline_ptr, const char *option)
10132d0b989Sdevzero@web.de {
10232d0b989Sdevzero@web.de addr_t cptr;
10332d0b989Sdevzero@web.de char c;
10432d0b989Sdevzero@web.de int pos = 0, wstart = 0;
10532d0b989Sdevzero@web.de const char *opptr = NULL;
10632d0b989Sdevzero@web.de enum {
10732d0b989Sdevzero@web.de st_wordstart, /* Start of word/after whitespace */
10832d0b989Sdevzero@web.de st_wordcmp, /* Comparing this word */
10932d0b989Sdevzero@web.de st_wordskip, /* Miscompare, skip */
11032d0b989Sdevzero@web.de } state = st_wordstart;
11132d0b989Sdevzero@web.de
11216a4baa6SYinghai Lu if (!cmdline_ptr)
11316a4baa6SYinghai Lu return -1; /* No command line */
11432d0b989Sdevzero@web.de
11532d0b989Sdevzero@web.de cptr = cmdline_ptr & 0xf;
11632d0b989Sdevzero@web.de set_fs(cmdline_ptr >> 4);
11732d0b989Sdevzero@web.de
11832d0b989Sdevzero@web.de while (cptr < 0x10000) {
11932d0b989Sdevzero@web.de c = rdfs8(cptr++);
12032d0b989Sdevzero@web.de pos++;
12132d0b989Sdevzero@web.de
12232d0b989Sdevzero@web.de switch (state) {
12332d0b989Sdevzero@web.de case st_wordstart:
12432d0b989Sdevzero@web.de if (!c)
12532d0b989Sdevzero@web.de return 0;
12632d0b989Sdevzero@web.de else if (myisspace(c))
12732d0b989Sdevzero@web.de break;
12832d0b989Sdevzero@web.de
12932d0b989Sdevzero@web.de state = st_wordcmp;
13032d0b989Sdevzero@web.de opptr = option;
13132d0b989Sdevzero@web.de wstart = pos;
132*df561f66SGustavo A. R. Silva fallthrough;
13332d0b989Sdevzero@web.de
13432d0b989Sdevzero@web.de case st_wordcmp:
13532d0b989Sdevzero@web.de if (!*opptr)
13632d0b989Sdevzero@web.de if (!c || myisspace(c))
13732d0b989Sdevzero@web.de return wstart;
13832d0b989Sdevzero@web.de else
13932d0b989Sdevzero@web.de state = st_wordskip;
14032d0b989Sdevzero@web.de else if (!c)
14132d0b989Sdevzero@web.de return 0;
14232d0b989Sdevzero@web.de else if (c != *opptr++)
14332d0b989Sdevzero@web.de state = st_wordskip;
14432d0b989Sdevzero@web.de break;
14532d0b989Sdevzero@web.de
14632d0b989Sdevzero@web.de case st_wordskip:
14732d0b989Sdevzero@web.de if (!c)
14832d0b989Sdevzero@web.de return 0;
14932d0b989Sdevzero@web.de else if (myisspace(c))
15032d0b989Sdevzero@web.de state = st_wordstart;
15132d0b989Sdevzero@web.de break;
15232d0b989Sdevzero@web.de }
15332d0b989Sdevzero@web.de }
15432d0b989Sdevzero@web.de
15532d0b989Sdevzero@web.de return 0; /* Buffer overrun */
15632d0b989Sdevzero@web.de }
157