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