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