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