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);
32#if !CONFIG_EMBEDDED
33static int argstrcpy(char *from, char *to);
34#endif
35static int argstrcpy2(char *from,char *to, unsigned maxlen);
36static int argnumcpy(int val, void *to, unsigned maxlen);
37static int getval(char *s, int *val);
38
39extern int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize);
40
41
42struct i24 {
43	int32_t	i24 : 24;
44	int32_t _pad : 8;
45};
46
47#define	NUM	0
48#define	STR	1
49
50#if !defined(__LP64__) && !defined(__arm__)
51boolean_t
52PE_parse_boot_arg(
53	const char  *arg_string,
54	void		*arg_ptr)
55{
56	int max_len = -1;
57
58#if CONFIG_EMBEDDED
59	/* Limit arg size to 4 byte when no size is given */
60	max_len = 4;
61#endif
62
63	return PE_parse_boot_argn(arg_string, arg_ptr, max_len);
64}
65#endif
66
67boolean_t
68PE_parse_boot_argn(
69	const char	*arg_string,
70	void		*arg_ptr,
71	int			max_len)
72{
73	char *args;
74	char *cp, c;
75	uintptr_t i;
76	int val;
77	boolean_t arg_boolean;
78	boolean_t arg_found;
79
80	args = PE_boot_args();
81	if (*args == '\0') return FALSE;
82
83#if CONFIG_EMBEDDED
84	if (max_len == -1) return FALSE;
85#endif
86
87	arg_found = FALSE;
88
89	while(*args && isargsep(*args)) args++;
90
91	while (*args)
92	{
93		if (*args == '-')
94			arg_boolean = TRUE;
95		else
96			arg_boolean = FALSE;
97
98		cp = args;
99		while (!isargsep (*cp) && *cp != '=')
100			cp++;
101		if (*cp != '=' && !arg_boolean)
102			goto gotit;
103
104		c = *cp;
105
106		i = cp-args;
107		if (strncmp(args, arg_string, i) ||
108		    (i!=strlen(arg_string)))
109			goto gotit;
110		if (arg_boolean) {
111			argnumcpy(1, arg_ptr, max_len);
112			arg_found = TRUE;
113			break;
114		} else {
115			while (*cp && isargsep (*cp))
116				cp++;
117			if (*cp == '=' && c != '=') {
118				args = cp+1;
119				goto gotit;
120			}
121			if ('_' == *arg_string) /* Force a string copy if the argument name begins with an underscore */
122			{
123				int hacklen = 17 > max_len ? 17 : max_len;
124				argstrcpy2 (++cp, (char *)arg_ptr, hacklen - 1); /* Hack - terminate after 16 characters */
125				arg_found = TRUE;
126				break;
127			}
128			switch (getval(cp, &val))
129			{
130				case NUM:
131					argnumcpy(val, arg_ptr, max_len);
132					arg_found = TRUE;
133					break;
134				case STR:
135					if(max_len > 0) //max_len of 0 performs no copy at all
136						argstrcpy2(++cp, (char *)arg_ptr, max_len - 1);
137#if !CONFIG_EMBEDDED
138					else if(max_len == -1) // unreachable on embedded
139						argstrcpy(++cp, (char *)arg_ptr);
140#endif
141					arg_found = TRUE;
142					break;
143			}
144			goto gotit;
145		}
146gotit:
147		/* Skip over current arg */
148		while(!isargsep(*args)) args++;
149
150		/* Skip leading white space (catch end of args) */
151		while(*args && isargsep(*args)) args++;
152	}
153
154	return(arg_found);
155}
156
157static boolean_t
158isargsep(
159	char c)
160{
161	if (c == ' ' || c == '\0' || c == '\t')
162		return(TRUE);
163	else
164		return(FALSE);
165}
166
167#if !CONFIG_EMBEDDED
168static int
169argstrcpy(
170	char *from,
171	char *to)
172{
173	int i = 0;
174
175	while (!isargsep(*from)) {
176		i++;
177		*to++ = *from++;
178	}
179	*to = 0;
180	return(i);
181}
182#endif
183
184static int
185argstrcpy2(
186	char *from,
187	char *to,
188	unsigned maxlen)
189{
190	unsigned int i = 0;
191
192	while (!isargsep(*from) && i < maxlen) {
193		i++;
194		*to++ = *from++;
195	}
196	*to = 0;
197	return(i);
198}
199
200static int argnumcpy(int val, void *to, unsigned maxlen)
201{
202	switch (maxlen) {
203		case 0:
204			/* No write-back, caller just wants to know if arg was found */
205			break;
206		case 1:
207			*(int8_t *)to = val;
208			break;
209		case 2:
210			*(int16_t *)to = val;
211			break;
212		case 3:
213			/* Unlikely in practice */
214			((struct i24 *)to)->i24 = val;
215			break;
216		case 4:
217		default:
218			*(int32_t *)to = val;
219			maxlen = 4;
220			break;
221	}
222
223	return (int)maxlen;
224}
225
226static int
227getval(
228	char *s,
229	int *val)
230{
231	unsigned int radix, intval;
232    unsigned char c;
233	int sign = 1;
234
235	if (*s == '=') {
236		s++;
237		if (*s == '-')
238			sign = -1, s++;
239		intval = *s++-'0';
240		radix = 10;
241		if (intval == 0) {
242			switch(*s) {
243
244			case 'x':
245				radix = 16;
246				s++;
247				break;
248
249			case 'b':
250				radix = 2;
251				s++;
252				break;
253
254			case '0': case '1': case '2': case '3':
255			case '4': case '5': case '6': case '7':
256				intval = *s-'0';
257				s++;
258				radix = 8;
259				break;
260
261			default:
262				if (!isargsep(*s))
263					return (STR);
264			}
265                } else if (intval >= radix) {
266                    return (STR);
267                }
268		for(;;) {
269                        c = *s++;
270                        if (isargsep(c))
271                            break;
272                        if ((radix <= 10) &&
273                            ((c >= '0') && (c <= ('9' - (10 - radix))))) {
274                                c -= '0';
275                        } else if ((radix == 16) &&
276                                   ((c >= '0') && (c <= '9'))) {
277				c -= '0';
278                        } else if ((radix == 16) &&
279                                   ((c >= 'a') && (c <= 'f'))) {
280				c -= 'a' - 10;
281                        } else if ((radix == 16) &&
282                                   ((c >= 'A') && (c <= 'F'))) {
283				c -= 'A' - 10;
284                        } else if (c == 'k' || c == 'K') {
285				sign *= 1024;
286				break;
287			} else if (c == 'm' || c == 'M') {
288				sign *= 1024 * 1024;
289                                break;
290			} else if (c == 'g' || c == 'G') {
291				sign *= 1024 * 1024 * 1024;
292                                break;
293			} else {
294				return (STR);
295                        }
296			if (c >= radix)
297				return (STR);
298			intval *= radix;
299			intval += c;
300		}
301                if (!isargsep(c) && !isargsep(*s))
302                    return STR;
303		*val = intval * sign;
304		return (NUM);
305	}
306	*val = 1;
307	return (NUM);
308}
309
310boolean_t
311PE_imgsrc_mount_supported()
312{
313	return TRUE;
314}
315
316boolean_t
317PE_get_default(
318	const char	*property_name,
319	void		*property_ptr,
320	unsigned int max_property)
321{
322	DTEntry		dte;
323	void		**property_data;
324	unsigned int property_size;
325
326	/*
327	 * Look for the property using the PE DT support.
328	 */
329	if (kSuccess == DTLookupEntry(NULL, "/defaults", &dte)) {
330
331		/*
332		 * We have a /defaults node, look for the named property.
333		 */
334		if (kSuccess != DTGetProperty(dte, property_name, (void **)&property_data, &property_size))
335			return FALSE;
336
337		/*
338		 * This would be a fine place to do smart argument size management for 32/64
339		 * translation, but for now we'll insist that callers know how big their
340		 * default values are.
341		 */
342		if (property_size > max_property)
343			return FALSE;
344
345		/*
346		 * Copy back the precisely-sized result.
347		 */
348		memcpy(property_ptr, property_data, property_size);
349		return TRUE;
350	}
351
352	/*
353	 * Look for the property using I/O Kit's DT support.
354	 */
355	return IODTGetDefault(property_name, property_ptr, max_property) ? FALSE : TRUE;
356}
357