]> git.saurik.com Git - apple/xnu.git/blame - pexpert/gen/bootargs.c
xnu-4903.241.1.tar.gz
[apple/xnu.git] / pexpert / gen / bootargs.c
CommitLineData
1c79356b 1/*
39037602 2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
3e170ce0 5 *
2d21ac55
A
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.
3e170ce0 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
3e170ce0 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
3e170ce0 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28#include <pexpert/pexpert.h>
6d2010ae 29#include <pexpert/device_tree.h>
1c79356b 30
3e170ce0
A
31typedef boolean_t (*argsep_func_t) (char c);
32
6d2010ae 33static boolean_t isargsep( char c);
3e170ce0 34static boolean_t israngesep( char c);
5ba3f43e 35#ifndef CONFIG_EMBEDDED
6d2010ae 36static int argstrcpy(char *from, char *to);
5ba3f43e 37#endif
cf7d32b8 38static int argstrcpy2(char *from,char *to, unsigned maxlen);
3e170ce0
A
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);
6d2010ae
A
42
43extern int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize);
44
316670eb 45
6d2010ae
A
46struct i24 {
47 int32_t i24 : 24;
48 int32_t _pad : 8;
49};
2d21ac55 50
1c79356b
A
51#define NUM 0
52#define STR 1
53
b0d623f7 54#if !defined(__LP64__) && !defined(__arm__)
3e170ce0 55boolean_t
1c79356b 56PE_parse_boot_arg(
91447636
A
57 const char *arg_string,
58 void *arg_ptr)
59{
2d21ac55
A
60 int max_len = -1;
61
5ba3f43e
A
62#if CONFIG_EMBEDDED
63 /* Limit arg size to 4 byte when no size is given */
64 max_len = 4;
65#endif
2d21ac55
A
66
67 return PE_parse_boot_argn(arg_string, arg_ptr, max_len);
91447636 68}
b0d623f7 69#endif
91447636 70
39037602
A
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)
1c79356b
A
77{
78 char *args;
79 char *cp, c;
316670eb 80 uintptr_t i;
39037602 81 long long val = 0;
1c79356b
A
82 boolean_t arg_boolean;
83 boolean_t arg_found;
84
85 args = PE_boot_args();
9bccf70c
A
86 if (*args == '\0') return FALSE;
87
5ba3f43e
A
88#ifdef CONFIG_EMBEDDED
89 if (max_len == -1) return FALSE;
90#endif
6d2010ae 91
1c79356b
A
92 arg_found = FALSE;
93
b0d623f7 94 while(*args && isargsep(*args)) args++;
1c79356b
A
95
96 while (*args)
97 {
3e170ce0 98 if (*args == '-')
1c79356b
A
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;
39037602 115
1c79356b 116 if (arg_boolean) {
813fb2f6
A
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 }
39037602 125 }
1c79356b
A
126 break;
127 } else {
b0d623f7 128 while (*cp && isargsep (*cp))
1c79356b
A
129 cp++;
130 if (*cp == '=' && c != '=') {
131 args = cp+1;
132 goto gotit;
133 }
55e303ae 134 if ('_' == *arg_string) /* Force a string copy if the argument name begins with an underscore */
91447636 135 {
813fb2f6
A
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 }
91447636
A
144 break;
145 }
39037602 146 switch ((force_string && *cp == '=') ? STR : getval(cp, &val, isargsep, FALSE))
1c79356b
A
147 {
148 case NUM:
813fb2f6
A
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 }
1c79356b
A
156 break;
157 case STR:
813fb2f6
A
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 }
5ba3f43e 165#if !CONFIG_EMBEDDED
813fb2f6 166 else if (max_len == -1) { /* unreachable on embedded */
91447636 167 argstrcpy(++cp, (char *)arg_ptr);
813fb2f6
A
168 arg_found = TRUE;
169 }
5ba3f43e 170#endif
1c79356b
A
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
39037602
A
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
6d2010ae 204static boolean_t
3e170ce0 205isargsep(char c)
1c79356b
A
206{
207 if (c == ' ' || c == '\0' || c == '\t')
3e170ce0 208 return (TRUE);
1c79356b 209 else
3e170ce0
A
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);
1c79356b
A
220}
221
5ba3f43e 222#if !CONFIG_EMBEDDED
6d2010ae 223static int
1c79356b 224argstrcpy(
3e170ce0 225 char *from,
1c79356b
A
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}
5ba3f43e 237#endif
1c79356b 238
cf7d32b8 239static int
55e303ae 240argstrcpy2(
3e170ce0 241 char *from,
55e303ae
A
242 char *to,
243 unsigned maxlen)
244{
2d21ac55 245 unsigned int i = 0;
55e303ae
A
246
247 while (!isargsep(*from) && i < maxlen) {
248 i++;
249 *to++ = *from++;
250 }
251 *to = 0;
252 return(i);
253}
254
3e170ce0 255static int argnumcpy(long long val, void *to, unsigned maxlen)
6d2010ae
A
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:
3e170ce0
A
272 *(int32_t *)to = val;
273 break;
274 case 8:
275 *(int64_t *)to = val;
276 break;
6d2010ae
A
277 default:
278 *(int32_t *)to = val;
279 maxlen = 4;
280 break;
281 }
282
283 return (int)maxlen;
284}
285
286static int
1c79356b 287getval(
3e170ce0
A
288 char *s,
289 long long *val,
290 argsep_func_t issep,
291 boolean_t skip_equal_sign )
1c79356b 292{
3e170ce0
A
293 unsigned long long radix, intval;
294 unsigned char c;
1c79356b 295 int sign = 1;
3e170ce0 296 boolean_t has_value = FALSE;
1c79356b
A
297
298 if (*s == '=') {
299 s++;
3e170ce0
A
300 has_value = TRUE;
301 }
302
303 if (has_value || skip_equal_sign) {
39037602
A
304 if (*s == '-') {
305 sign = -1;
306 s++;
307 }
1c79356b
A
308 intval = *s++-'0';
309 radix = 10;
0c530ab8 310 if (intval == 0) {
1c79356b
A
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:
3e170ce0 331 if (!issep(*s))
1c79356b
A
332 return (STR);
333 }
0c530ab8
A
334 } else if (intval >= radix) {
335 return (STR);
336 }
1c79356b 337 for(;;) {
0c530ab8 338 c = *s++;
3e170ce0 339 if (issep(c))
0c530ab8
A
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'))) {
1c79356b 346 c -= '0';
0c530ab8
A
347 } else if ((radix == 16) &&
348 ((c >= 'a') && (c <= 'f'))) {
1c79356b 349 c -= 'a' - 10;
0c530ab8
A
350 } else if ((radix == 16) &&
351 ((c >= 'A') && (c <= 'F'))) {
1c79356b 352 c -= 'A' - 10;
0c530ab8
A
353 } else if (c == 'k' || c == 'K') {
354 sign *= 1024;
1c79356b 355 break;
0c530ab8
A
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 {
1c79356b 363 return (STR);
0c530ab8 364 }
1c79356b
A
365 if (c >= radix)
366 return (STR);
367 intval *= radix;
368 intval += c;
369 }
3e170ce0 370 if (!issep(c) && !issep(*s))
0c530ab8 371 return STR;
1c79356b
A
372 *val = intval * sign;
373 return (NUM);
374 }
375 *val = 1;
376 return (NUM);
377}
b7266188 378
3e170ce0 379boolean_t
b7266188
A
380PE_imgsrc_mount_supported()
381{
382 return TRUE;
383}
6d2010ae
A
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}
3e170ce0
A
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}