1/*
2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28#include <pexpert/pexpert.h>
29#include <pexpert/device_tree.h>
30
31static boolean_t isargsep( char c);
32static int argstrcpy(char *from, char *to);
33static int argstrcpy2(char *from,char *to, unsigned maxlen);
34static int argnumcpy(int val, void *to, unsigned maxlen);
35static int getval(char *s, int *val);
36
37extern int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize);
38
39
40struct i24 {
41	int32_t	i24 : 24;
42	int32_t _pad : 8;
43};
44
45#define	NUM	0
46#define	STR	1
47
48#if !defined(__LP64__) && !defined(__arm__)
49boolean_t
50PE_parse_boot_arg(
51	const char  *arg_string,
52	void		*arg_ptr)
53{
54	int max_len = -1;
55
56
57	return PE_parse_boot_argn(arg_string, arg_ptr, max_len);
58}
59#endif
60
61boolean_t
62PE_parse_boot_argn(
63	const char	*arg_string,
64	void		*arg_ptr,
65	int			max_len)
66{
67	char *args;
68	char *cp, c;
69	uintptr_t i;
70	int val;
71	boolean_t arg_boolean;
72	boolean_t arg_found;
73
74	args = PE_boot_args();
75	if (*args == '\0') return FALSE;
76
77
78	arg_found = FALSE;
79
80	while(*args && isargsep(*args)) args++;
81
82	while (*args)
83	{
84		if (*args == '-')
85			arg_boolean = TRUE;
86		else
87			arg_boolean = FALSE;
88
89		cp = args;
90		while (!isargsep (*cp) && *cp != '=')
91			cp++;
92		if (*cp != '=' && !arg_boolean)
93			goto gotit;
94
95		c = *cp;
96
97		i = cp-args;
98		if (strncmp(args, arg_string, i) ||
99		    (i!=strlen(arg_string)))
100			goto gotit;
101		if (arg_boolean) {
102			argnumcpy(1, arg_ptr, max_len);
103			arg_found = TRUE;
104			break;
105		} else {
106			while (*cp && isargsep (*cp))
107				cp++;
108			if (*cp == '=' && c != '=') {
109				args = cp+1;
110				goto gotit;
111			}
112			if ('_' == *arg_string) /* Force a string copy if the argument name begins with an underscore */
113			{
114				int hacklen = 17 > max_len ? 17 : max_len;
115				argstrcpy2 (++cp, (char *)arg_ptr, hacklen - 1); /* Hack - terminate after 16 characters */
116				arg_found = TRUE;
117				break;
118			}
119			switch (getval(cp, &val))
120			{
121				case NUM:
122					argnumcpy(val, arg_ptr, max_len);
123					arg_found = TRUE;
124					break;
125				case STR:
126					if(max_len > 0) //max_len of 0 performs no copy at all
127						argstrcpy2(++cp, (char *)arg_ptr, max_len - 1);
128					else if(max_len == -1) // unreachable on embedded
129						argstrcpy(++cp, (char *)arg_ptr);
130					arg_found = TRUE;
131					break;
132			}
133			goto gotit;
134		}
135gotit:
136		/* Skip over current arg */
137		while(!isargsep(*args)) args++;
138
139		/* Skip leading white space (catch end of args) */
140		while(*args && isargsep(*args)) args++;
141	}
142
143	return(arg_found);
144}
145
146static boolean_t
147isargsep(
148	char c)
149{
150	if (c == ' ' || c == '\0' || c == '\t')
151		return(TRUE);
152	else
153		return(FALSE);
154}
155
156static int
157argstrcpy(
158	char *from,
159	char *to)
160{
161	int i = 0;
162
163	while (!isargsep(*from)) {
164		i++;
165		*to++ = *from++;
166	}
167	*to = 0;
168	return(i);
169}
170
171static int
172argstrcpy2(
173	char *from,
174	char *to,
175	unsigned maxlen)
176{
177	unsigned int i = 0;
178
179	while (!isargsep(*from) && i < maxlen) {
180		i++;
181		*to++ = *from++;
182	}
183	*to = 0;
184	return(i);
185}
186
187static int argnumcpy(int val, void *to, unsigned maxlen)
188{
189	switch (maxlen) {
190		case 0:
191			/* No write-back, caller just wants to know if arg was found */
192			break;
193		case 1:
194			*(int8_t *)to = val;
195			break;
196		case 2:
197			*(int16_t *)to = val;
198			break;
199		case 3:
200			/* Unlikely in practice */
201			((struct i24 *)to)->i24 = val;
202			break;
203		case 4:
204		default:
205			*(int32_t *)to = val;
206			maxlen = 4;
207			break;
208	}
209
210	return (int)maxlen;
211}
212
213static int
214getval(
215	char *s,
216	int *val)
217{
218	unsigned int radix, intval;
219    unsigned char c;
220	int sign = 1;
221
222	if (*s == '=') {
223		s++;
224		if (*s == '-')
225			sign = -1, s++;
226		intval = *s++-'0';
227		radix = 10;
228		if (intval == 0) {
229			switch(*s) {
230
231			case 'x':
232				radix = 16;
233				s++;
234				break;
235
236			case 'b':
237				radix = 2;
238				s++;
239				break;
240
241			case '0': case '1': case '2': case '3':
242			case '4': case '5': case '6': case '7':
243				intval = *s-'0';
244				s++;
245				radix = 8;
246				break;
247
248			default:
249				if (!isargsep(*s))
250					return (STR);
251			}
252                } else if (intval >= radix) {
253                    return (STR);
254                }
255		for(;;) {
256                        c = *s++;
257                        if (isargsep(c))
258                            break;
259                        if ((radix <= 10) &&
260                            ((c >= '0') && (c <= ('9' - (10 - radix))))) {
261                                c -= '0';
262                        } else if ((radix == 16) &&
263                                   ((c >= '0') && (c <= '9'))) {
264				c -= '0';
265                        } else if ((radix == 16) &&
266                                   ((c >= 'a') && (c <= 'f'))) {
267				c -= 'a' - 10;
268                        } else if ((radix == 16) &&
269                                   ((c >= 'A') && (c <= 'F'))) {
270				c -= 'A' - 10;
271                        } else if (c == 'k' || c == 'K') {
272				sign *= 1024;
273				break;
274			} else if (c == 'm' || c == 'M') {
275				sign *= 1024 * 1024;
276                                break;
277			} else if (c == 'g' || c == 'G') {
278				sign *= 1024 * 1024 * 1024;
279                                break;
280			} else {
281				return (STR);
282                        }
283			if (c >= radix)
284				return (STR);
285			intval *= radix;
286			intval += c;
287		}
288                if (!isargsep(c) && !isargsep(*s))
289                    return STR;
290		*val = intval * sign;
291		return (NUM);
292	}
293	*val = 1;
294	return (NUM);
295}
296
297boolean_t
298PE_imgsrc_mount_supported()
299{
300	return TRUE;
301}
302
303boolean_t
304PE_get_default(
305	const char	*property_name,
306	void		*property_ptr,
307	unsigned int max_property)
308{
309	DTEntry		dte;
310	void		**property_data;
311	unsigned int property_size;
312
313	/*
314	 * Look for the property using the PE DT support.
315	 */
316	if (kSuccess == DTLookupEntry(NULL, "/defaults", &dte)) {
317
318		/*
319		 * We have a /defaults node, look for the named property.
320		 */
321		if (kSuccess != DTGetProperty(dte, property_name, (void **)&property_data, &property_size))
322			return FALSE;
323
324		/*
325		 * This would be a fine place to do smart argument size management for 32/64
326		 * translation, but for now we'll insist that callers know how big their
327		 * default values are.
328		 */
329		if (property_size > max_property)
330			return FALSE;
331
332		/*
333		 * Copy back the precisely-sized result.
334		 */
335		memcpy(property_ptr, property_data, property_size);
336		return TRUE;
337	}
338
339	/*
340	 * Look for the property using I/O Kit's DT support.
341	 */
342	return IODTGetDefault(property_name, property_ptr, max_property) ? FALSE : TRUE;
343}
344