1/*
2 * Copyright (c) 2000-2016 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
31typedef boolean_t (*argsep_func_t) (char c);
32
33static boolean_t isargsep( char c);
34static boolean_t israngesep( char c);
35#ifndef CONFIG_EMBEDDED
36static int argstrcpy(char *from, char *to);
37#endif
38static int argstrcpy2(char *from,char *to, unsigned maxlen);
39static int argnumcpy(long long val, void *to, unsigned maxlen);
40static int getval(char *s, long long *val, argsep_func_t issep, boolean_t skip_equal_sign);
41boolean_t get_range_bounds(char * c, int64_t * lower, int64_t * upper);
42
43extern int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize);
44
45
46struct i24 {
47 int32_t i24 : 24;
48 int32_t _pad : 8;
49};
50
51#define NUM 0
52#define STR 1
53
54#if !defined(__LP64__) && !defined(__arm__)
55boolean_t
56PE_parse_boot_arg(
57 const char *arg_string,
58 void *arg_ptr)
59{
60 int max_len = -1;
61
62#if CONFIG_EMBEDDED
63 /* Limit arg size to 4 byte when no size is given */
64 max_len = 4;
65#endif
66
67 return PE_parse_boot_argn(arg_string, arg_ptr, max_len);
68}
69#endif
70
71static boolean_t
72PE_parse_boot_argn_internal(
73 const char *arg_string,
74 void * arg_ptr,
75 int max_len,
76 boolean_t force_string)
77{
78 char *args;
79 char *cp, c;
80 uintptr_t i;
81 long long val = 0;
82 boolean_t arg_boolean;
83 boolean_t arg_found;
84
85 args = PE_boot_args();
86 if (*args == '\0') return FALSE;
87
88#ifdef CONFIG_EMBEDDED
89 if (max_len == -1) return FALSE;
90#endif
91
92 arg_found = FALSE;
93
94 while(*args && isargsep(*args)) args++;
95
96 while (*args)
97 {
98 if (*args == '-')
99 arg_boolean = TRUE;
100 else
101 arg_boolean = FALSE;
102
103 cp = args;
104 while (!isargsep (*cp) && *cp != '=')
105 cp++;
106 if (*cp != '=' && !arg_boolean)
107 goto gotit;
108
109 c = *cp;
110
111 i = cp-args;
112 if (strncmp(args, arg_string, i) ||
113 (i!=strlen(arg_string)))
114 goto gotit;
115
116 if (arg_boolean) {
117 if (!force_string) {
118 if (max_len > 0) {
119 argnumcpy(1, arg_ptr, max_len);/* max_len of 0 performs no copy at all*/
120 arg_found = TRUE;
121 }
122 else if (max_len == 0) {
123 arg_found = TRUE;
124 }
125 }
126 break;
127 } else {
128 while (*cp && isargsep (*cp))
129 cp++;
130 if (*cp == '=' && c != '=') {
131 args = cp+1;
132 goto gotit;
133 }
134 if ('_' == *arg_string) /* Force a string copy if the argument name begins with an underscore */
135 {
136 if (max_len > 0) {
137 int hacklen = 17 > max_len ? 17 : max_len;
138 argstrcpy2 (++cp, (char *)arg_ptr, hacklen - 1); /* Hack - terminate after 16 characters */
139 arg_found = TRUE;
140 }
141 else if (max_len == 0) {
142 arg_found = TRUE;
143 }
144 break;
145 }
146 switch ((force_string && *cp == '=') ? STR : getval(cp, &val, isargsep, FALSE))
147 {
148 case NUM:
149 if (max_len > 0) {
150 argnumcpy(val, arg_ptr, max_len);
151 arg_found = TRUE;
152 }
153 else if (max_len == 0) {
154 arg_found = TRUE;
155 }
156 break;
157 case STR:
158 if (max_len > 0) {
159 argstrcpy2(++cp, (char *)arg_ptr, max_len - 1);/*max_len of 0 performs no copy at all*/
160 arg_found = TRUE;
161 }
162 else if (max_len == 0) {
163 arg_found = TRUE;
164 }
165#if !CONFIG_EMBEDDED
166 else if (max_len == -1) { /* unreachable on embedded */
167 argstrcpy(++cp, (char *)arg_ptr);
168 arg_found = TRUE;
169 }
170#endif
171 break;
172 }
173 goto gotit;
174 }
175gotit:
176 /* Skip over current arg */
177 while(!isargsep(*args)) args++;
178
179 /* Skip leading white space (catch end of args) */
180 while(*args && isargsep(*args)) args++;
181 }
182
183 return(arg_found);
184}
185
186boolean_t
187PE_parse_boot_argn(
188 const char *arg_string,
189 void *arg_ptr,
190 int max_len)
191{
192 return PE_parse_boot_argn_internal(arg_string, arg_ptr, max_len, FALSE);
193}
194
195boolean_t
196PE_parse_boot_arg_str(
197 const char *arg_string,
198 char *arg_ptr,
199 int strlen)
200{
201 return PE_parse_boot_argn_internal(arg_string, arg_ptr, strlen, TRUE);
202}
203
204static boolean_t
205isargsep(char c)
206{
207 if (c == ' ' || c == '\0' || c == '\t')
208 return (TRUE);
209 else
210 return (FALSE);
211}
212
213static boolean_t
214israngesep(char c)
215{
216 if (isargsep(c) || c == '_' || c == ',')
217 return (TRUE);
218 else
219 return (FALSE);
220}
221
222#if !CONFIG_EMBEDDED
223static int
224argstrcpy(
225 char *from,
226 char *to)
227{
228 int i = 0;
229
230 while (!isargsep(*from)) {
231 i++;
232 *to++ = *from++;
233 }
234 *to = 0;
235 return(i);
236}
237#endif
238
239static int
240argstrcpy2(
241 char *from,
242 char *to,
243 unsigned maxlen)
244{
245 unsigned int i = 0;
246
247 while (!isargsep(*from) && i < maxlen) {
248 i++;
249 *to++ = *from++;
250 }
251 *to = 0;
252 return(i);
253}
254
255static int argnumcpy(long long val, void *to, unsigned maxlen)
256{
257 switch (maxlen) {
258 case 0:
259 /* No write-back, caller just wants to know if arg was found */
260 break;
261 case 1:
262 *(int8_t *)to = val;
263 break;
264 case 2:
265 *(int16_t *)to = val;
266 break;
267 case 3:
268 /* Unlikely in practice */
269 ((struct i24 *)to)->i24 = val;
270 break;
271 case 4:
272 *(int32_t *)to = val;
273 break;
274 case 8:
275 *(int64_t *)to = val;
276 break;
277 default:
278 *(int32_t *)to = val;
279 maxlen = 4;
280 break;
281 }
282
283 return (int)maxlen;
284}
285
286static int
287getval(
288 char *s,
289 long long *val,
290 argsep_func_t issep,
291 boolean_t skip_equal_sign )
292{
293 unsigned long long radix, intval;
294 unsigned char c;
295 int sign = 1;
296 boolean_t has_value = FALSE;
297
298 if (*s == '=') {
299 s++;
300 has_value = TRUE;
301 }
302
303 if (has_value || skip_equal_sign) {
304 if (*s == '-') {
305 sign = -1;
306 s++;
307 }
308 intval = *s++-'0';
309 radix = 10;
310 if (intval == 0) {
311 switch(*s) {
312
313 case 'x':
314 radix = 16;
315 s++;
316 break;
317
318 case 'b':
319 radix = 2;
320 s++;
321 break;
322
323 case '0': case '1': case '2': case '3':
324 case '4': case '5': case '6': case '7':
325 intval = *s-'0';
326 s++;
327 radix = 8;
328 break;
329
330 default:
331 if (!issep(*s))
332 return (STR);
333 }
334 } else if (intval >= radix) {
335 return (STR);
336 }
337 for(;;) {
338 c = *s++;
339 if (issep(c))
340 break;
341 if ((radix <= 10) &&
342 ((c >= '0') && (c <= ('9' - (10 - radix))))) {
343 c -= '0';
344 } else if ((radix == 16) &&
345 ((c >= '0') && (c <= '9'))) {
346 c -= '0';
347 } else if ((radix == 16) &&
348 ((c >= 'a') && (c <= 'f'))) {
349 c -= 'a' - 10;
350 } else if ((radix == 16) &&
351 ((c >= 'A') && (c <= 'F'))) {
352 c -= 'A' - 10;
353 } else if (c == 'k' || c == 'K') {
354 sign *= 1024;
355 break;
356 } else if (c == 'm' || c == 'M') {
357 sign *= 1024 * 1024;
358 break;
359 } else if (c == 'g' || c == 'G') {
360 sign *= 1024 * 1024 * 1024;
361 break;
362 } else {
363 return (STR);
364 }
365 if (c >= radix)
366 return (STR);
367 intval *= radix;
368 intval += c;
369 }
370 if (!issep(c) && !issep(*s))
371 return STR;
372 *val = intval * sign;
373 return (NUM);
374 }
375 *val = 1;
376 return (NUM);
377}
378
379boolean_t
380PE_imgsrc_mount_supported()
381{
382 return TRUE;
383}
384
385boolean_t
386PE_get_default(
387 const char *property_name,
388 void *property_ptr,
389 unsigned int max_property)
390{
391 DTEntry dte;
392 void **property_data;
393 unsigned int property_size;
394
395 /*
396 * Look for the property using the PE DT support.
397 */
398 if (kSuccess == DTLookupEntry(NULL, "/defaults", &dte)) {
399
400 /*
401 * We have a /defaults node, look for the named property.
402 */
403 if (kSuccess != DTGetProperty(dte, property_name, (void **)&property_data, &property_size))
404 return FALSE;
405
406 /*
407 * This would be a fine place to do smart argument size management for 32/64
408 * translation, but for now we'll insist that callers know how big their
409 * default values are.
410 */
411 if (property_size > max_property)
412 return FALSE;
413
414 /*
415 * Copy back the precisely-sized result.
416 */
417 memcpy(property_ptr, property_data, property_size);
418 return TRUE;
419 }
420
421 /*
422 * Look for the property using I/O Kit's DT support.
423 */
424 return IODTGetDefault(property_name, property_ptr, max_property) ? FALSE : TRUE;
425}
426
427/* function: get_range_bounds
428 * Parse a range string like "1_3,5_20" and return 1,3 as lower and upper.
429 * Note: '_' is separator for bounds integer delimiter and
430 * ',' is considered as separator for range pair.
431 * returns TRUE when both range values are found
432 */
433boolean_t
434get_range_bounds(char *c, int64_t *lower, int64_t *upper)
435{
436 if (c == NULL || lower == NULL || upper == NULL) {
437 return FALSE;
438 }
439
440 if (NUM != getval(c, lower, israngesep, TRUE)) {
441 return FALSE;
442 }
443
444 while (*c != '\0') {
445 if (*c == '_') {
446 break;
447 }
448 c++;
449 }
450
451 if (*c == '_') {
452 c++;
453 if (NUM != getval(c, upper, israngesep, TRUE)) {
454 return FALSE;
455 }
456 } else {
457 return FALSE;
458 }
459 return TRUE;
460}
461