]> git.saurik.com Git - apple/xnu.git/blob - pexpert/gen/bootargs.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / pexpert / gen / bootargs.c
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
31 typedef boolean_t (*argsep_func_t) (char c);
32
33 static boolean_t isargsep( char c);
34 static boolean_t israngesep( char c);
35 #if defined(__x86_64__)
36 static int argstrcpy(char *from, char *to);
37 #endif
38 static int argstrcpy2(char *from, char *to, unsigned maxlen);
39 static int argnumcpy(long long val, void *to, unsigned maxlen);
40 static int getval(char *s, long long *val, argsep_func_t issep, boolean_t skip_equal_sign);
41 boolean_t get_range_bounds(char * c, int64_t * lower, int64_t * upper);
42
43 extern int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize);
44
45
46 struct i24 {
47 int32_t i24 : 24;
48 int32_t _pad : 8;
49 };
50
51 #define NUM 0
52 #define STR 1
53
54 static boolean_t
55 PE_parse_boot_argn_internal(
56 const char *arg_string,
57 void * arg_ptr,
58 int max_len,
59 boolean_t force_string)
60 {
61 char *args;
62 char *cp, c;
63 uintptr_t i;
64 long long val = 0;
65 boolean_t arg_boolean;
66 boolean_t arg_found;
67
68 args = PE_boot_args();
69 if (*args == '\0') {
70 return FALSE;
71 }
72
73 #if !defined(__x86_64__)
74 if (max_len == -1) {
75 return FALSE;
76 }
77 #endif
78
79 arg_found = FALSE;
80
81 while (*args && isargsep(*args)) {
82 args++;
83 }
84
85 while (*args) {
86 if (*args == '-') {
87 arg_boolean = TRUE;
88 } else {
89 arg_boolean = FALSE;
90 }
91
92 cp = args;
93 while (!isargsep(*cp) && *cp != '=') {
94 cp++;
95 }
96 if (*cp != '=' && !arg_boolean) {
97 goto gotit;
98 }
99
100 c = *cp;
101
102 i = cp - args;
103 if (strncmp(args, arg_string, i) ||
104 (i != strlen(arg_string))) {
105 goto gotit;
106 }
107
108 if (arg_boolean) {
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;
113 } else if (max_len == 0) {
114 arg_found = TRUE;
115 }
116 }
117 break;
118 } else {
119 while (*cp && isargsep(*cp)) {
120 cp++;
121 }
122 if (*cp == '=' && c != '=') {
123 args = cp + 1;
124 goto gotit;
125 }
126 if ('_' == *arg_string) { /* Force a string copy if the argument name begins with an underscore */
127 if (max_len > 0) {
128 int hacklen = 17 > max_len ? 17 : max_len;
129 argstrcpy2(++cp, (char *)arg_ptr, hacklen - 1); /* Hack - terminate after 16 characters */
130 arg_found = TRUE;
131 } else if (max_len == 0) {
132 arg_found = TRUE;
133 }
134 break;
135 }
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 }
152 #if defined(__x86_64__)
153 else if (max_len == -1) { /* unreachable on embedded */
154 argstrcpy(++cp, (char *)arg_ptr);
155 arg_found = TRUE;
156 }
157 #endif
158 break;
159 }
160 goto gotit;
161 }
162 gotit:
163 /* Skip over current arg */
164 while (!isargsep(*args)) {
165 args++;
166 }
167
168 /* Skip leading white space (catch end of args) */
169 while (*args && isargsep(*args)) {
170 args++;
171 }
172 }
173
174 return arg_found;
175 }
176
177 boolean_t
178 PE_parse_boot_argn(
179 const char *arg_string,
180 void *arg_ptr,
181 int max_len)
182 {
183 return PE_parse_boot_argn_internal(arg_string, arg_ptr, max_len, FALSE);
184 }
185
186 boolean_t
187 PE_parse_boot_arg_str(
188 const char *arg_string,
189 char *arg_ptr,
190 int strlen)
191 {
192 return PE_parse_boot_argn_internal(arg_string, arg_ptr, strlen, TRUE);
193 }
194
195 static boolean_t
196 isargsep(char c)
197 {
198 if (c == ' ' || c == '\0' || c == '\t') {
199 return TRUE;
200 } else {
201 return FALSE;
202 }
203 }
204
205 static boolean_t
206 israngesep(char c)
207 {
208 if (isargsep(c) || c == '_' || c == ',') {
209 return TRUE;
210 } else {
211 return FALSE;
212 }
213 }
214
215 #if defined(__x86_64__)
216 static int
217 argstrcpy(
218 char *from,
219 char *to)
220 {
221 int i = 0;
222
223 while (!isargsep(*from)) {
224 i++;
225 *to++ = *from++;
226 }
227 *to = 0;
228 return i;
229 }
230 #endif
231
232 static int
233 argstrcpy2(
234 char *from,
235 char *to,
236 unsigned maxlen)
237 {
238 unsigned int i = 0;
239
240 while (!isargsep(*from) && i < maxlen) {
241 i++;
242 *to++ = *from++;
243 }
244 *to = 0;
245 return i;
246 }
247
248 static int
249 argnumcpy(long long val, void *to, unsigned maxlen)
250 {
251 switch (maxlen) {
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 = (int8_t)val;
257 break;
258 case 2:
259 *(int16_t *)to = (int16_t)val;
260 break;
261 case 3:
262 /* Unlikely in practice */
263 ((struct i24 *)to)->i24 = (int32_t)val;
264 break;
265 case 4:
266 *(int32_t *)to = (int32_t)val;
267 break;
268 case 8:
269 *(int64_t *)to = (int64_t)val;
270 break;
271 default:
272 *(int32_t *)to = (int32_t)val;
273 maxlen = 4;
274 break;
275 }
276
277 return (int)maxlen;
278 }
279
280 static int
281 getval(
282 char *s,
283 long long *val,
284 argsep_func_t issep,
285 boolean_t skip_equal_sign )
286 {
287 unsigned long long radix, intval;
288 unsigned char c;
289 int sign = 1;
290 boolean_t has_value = FALSE;
291
292 if (*s == '=') {
293 s++;
294 has_value = TRUE;
295 }
296
297 if (has_value || skip_equal_sign) {
298 if (*s == '-') {
299 sign = -1;
300 s++;
301 }
302 intval = *s++ - '0';
303 radix = 10;
304 if (intval == 0) {
305 switch (*s) {
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':
318 intval = *s - '0';
319 s++;
320 radix = 8;
321 break;
322
323 default:
324 if (!issep(*s)) {
325 return STR;
326 }
327 }
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'))) {
341 c -= '0';
342 } else if ((radix == 16) &&
343 ((c >= 'a') && (c <= 'f'))) {
344 c -= 'a' - 10;
345 } else if ((radix == 16) &&
346 ((c >= 'A') && (c <= 'F'))) {
347 c -= 'A' - 10;
348 } else if (c == 'k' || c == 'K') {
349 sign *= 1024;
350 break;
351 } else if (c == 'm' || c == 'M') {
352 sign *= 1024 * 1024;
353 break;
354 } else if (c == 'g' || c == 'G') {
355 sign *= 1024 * 1024 * 1024;
356 break;
357 } else {
358 return STR;
359 }
360 if (c >= radix) {
361 return STR;
362 }
363 intval *= radix;
364 intval += c;
365 }
366 if (!issep(c) && !issep(*s)) {
367 return STR;
368 }
369 *val = intval * sign;
370 return NUM;
371 }
372 *val = 1;
373 return NUM;
374 }
375
376 boolean_t
377 PE_imgsrc_mount_supported()
378 {
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
387 return TRUE;
388 #endif
389 }
390
391 boolean_t
392 PE_get_default(
393 const char *property_name,
394 void *property_ptr,
395 unsigned int max_property)
396 {
397 DTEntry dte;
398 void const *property_data;
399 unsigned int property_size;
400
401 /*
402 * Look for the property using the PE DT support.
403 */
404 if (kSuccess == SecureDTLookupEntry(NULL, "/defaults", &dte)) {
405 /*
406 * We have a /defaults node, look for the named property.
407 */
408 if (kSuccess != SecureDTGetProperty(dte, property_name, &property_data, &property_size)) {
409 return FALSE;
410 }
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 */
417 if (property_size > max_property) {
418 return FALSE;
419 }
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 }
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 */
440 boolean_t
441 get_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 }