1e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin/* -*- linux-c -*- ------------------------------------------------------- *
2e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin *
3e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin *   Copyright (C) 1991, 1992 Linus Torvalds
4e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin *   Copyright 2007 rPath, Inc. - All Rights Reserved
5e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin *
6e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin *   This file is part of the Linux kernel, and is made available under
7e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin *   the terms of the GNU General Public License version 2.
8e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin *
9e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin * ----------------------------------------------------------------------- */
10e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
11e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin/*
12e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin * Simple command-line parser for early boot.
13e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin */
14e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
15e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin#include "boot.h"
16e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
17e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvinstatic inline int myisspace(u8 c)
18e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin{
19e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	return c <= ' ';	/* Close enough approximation */
20e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin}
21e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
22e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin/*
23e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin * Find a non-boolean option, that is, "option=argument".  In accordance
24e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin * with standard Linux practice, if this option is repeated, this returns
25e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin * the last instance on the command line.
26e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin *
27e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin * Returns the length of the argument (regardless of if it was
28e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin * truncated to fit in the buffer), or -1 on not found.
29e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin */
303db07e70f0b4742f8daeda5c4aa8fbe7aeb3799eYinghai Luint __cmdline_find_option(unsigned long cmdline_ptr, const char *option, char *buffer, int bufsize)
31e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin{
32e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	addr_t cptr;
33e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	char c;
34e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	int len = -1;
35e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	const char *opptr = NULL;
36e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	char *bufptr = buffer;
37e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	enum {
38e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin		st_wordstart,	/* Start of word/after whitespace */
39e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin		st_wordcmp,	/* Comparing this word */
40e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin		st_wordskip,	/* Miscompare, skip */
41e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin		st_bufcpy	/* Copying this to buffer */
42e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	} state = st_wordstart;
43e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
4416a4baa642cf448742aaf150c4daa093f9dbebbbYinghai Lu	if (!cmdline_ptr)
4516a4baa642cf448742aaf150c4daa093f9dbebbbYinghai Lu		return -1;      /* No command line */
46e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
47e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	cptr = cmdline_ptr & 0xf;
48e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	set_fs(cmdline_ptr >> 4);
49e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
50e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	while (cptr < 0x10000 && (c = rdfs8(cptr++))) {
51e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin		switch (state) {
52e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin		case st_wordstart:
53e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			if (myisspace(c))
54e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin				break;
55e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
56e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			/* else */
57e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			state = st_wordcmp;
58e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			opptr = option;
59e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			/* fall through */
60e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
61e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin		case st_wordcmp:
62e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			if (c == '=' && !*opptr) {
63e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin				len = 0;
64e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin				bufptr = buffer;
65e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin				state = st_bufcpy;
66e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			} else if (myisspace(c)) {
67e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin				state = st_wordstart;
68e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			} else if (c != *opptr++) {
69e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin				state = st_wordskip;
70e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			}
71e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			break;
72e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
73e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin		case st_wordskip:
74e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			if (myisspace(c))
75e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin				state = st_wordstart;
76e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			break;
77e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
78e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin		case st_bufcpy:
79e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			if (myisspace(c)) {
80e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin				state = st_wordstart;
81e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			} else {
82e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin				if (len < bufsize-1)
83e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin					*bufptr++ = c;
84e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin				len++;
85e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			}
86e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin			break;
87e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin		}
88e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	}
89e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
90e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	if (bufsize)
91e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin		*bufptr = '\0';
92e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin
93e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin	return len;
94e44c22f65f96217692e1a915032fbe7d22236751H. Peter Anvin}
9532d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de
9632d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de/*
9732d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de * Find a boolean option (like quiet,noapic,nosmp....)
9832d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de *
9932d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de * Returns the position of that option (starts counting with 1)
10032d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de * or 0 on not found
10132d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de */
1023db07e70f0b4742f8daeda5c4aa8fbe7aeb3799eYinghai Luint __cmdline_find_option_bool(unsigned long cmdline_ptr, const char *option)
10332d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de{
10432d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de	addr_t cptr;
10532d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de	char c;
10670d8abf5df857ca7befe02e5d61fde807420a54cH. Peter Anvin	int pos = 0, wstart = 0;
10732d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de	const char *opptr = NULL;
10832d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de	enum {
10932d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de		st_wordstart,	/* Start of word/after whitespace */
11032d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de		st_wordcmp,	/* Comparing this word */
11132d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de		st_wordskip,	/* Miscompare, skip */
11232d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de	} state = st_wordstart;
11332d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de
11416a4baa642cf448742aaf150c4daa093f9dbebbbYinghai Lu	if (!cmdline_ptr)
11516a4baa642cf448742aaf150c4daa093f9dbebbbYinghai Lu		return -1;      /* No command line */
11632d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de
11732d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de	cptr = cmdline_ptr & 0xf;
11832d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de	set_fs(cmdline_ptr >> 4);
11932d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de
12032d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de	while (cptr < 0x10000) {
12132d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de		c = rdfs8(cptr++);
12232d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de		pos++;
12332d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de
12432d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de		switch (state) {
12532d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de		case st_wordstart:
12632d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			if (!c)
12732d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de				return 0;
12832d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			else if (myisspace(c))
12932d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de				break;
13032d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de
13132d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			state = st_wordcmp;
13232d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			opptr = option;
13332d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			wstart = pos;
13432d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			/* fall through */
13532d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de
13632d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de		case st_wordcmp:
13732d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			if (!*opptr)
13832d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de				if (!c || myisspace(c))
13932d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de					return wstart;
14032d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de				else
14132d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de					state = st_wordskip;
14232d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			else if (!c)
14332d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de				return 0;
14432d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			else if (c != *opptr++)
14532d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de				state = st_wordskip;
14632d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			break;
14732d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de
14832d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de		case st_wordskip:
14932d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			if (!c)
15032d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de				return 0;
15132d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			else if (myisspace(c))
15232d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de				state = st_wordstart;
15332d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de			break;
15432d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de		}
15532d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de	}
15632d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de
15732d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de	return 0;	/* Buffer overrun */
15832d0b9898029b7b3c7f161d31f57c4831d9049ebdevzero@web.de}
159