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 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 */ 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 */ 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