xref: /xnu-8020.140.41/pexpert/gen/bootargs.c (revision 27b03b360a988dfd3dfdf34262bb0042026747cc)
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
PE_parse_boot_argn_internal(const char * arg_string,void * arg_ptr,int max_len,boolean_t force_string)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
PE_parse_boot_argn(const char * arg_string,void * arg_ptr,int max_len)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
PE_parse_boot_arg_str(const char * arg_string,char * arg_ptr,int strlen)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
isargsep(char c)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
israngesep(char c)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
argstrcpy(char * from,char * to)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
argstrcpy2(char * from,char * to,unsigned maxlen)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
argnumcpy(long long val,void * to,unsigned maxlen)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
getval(char * s,long long * val,argsep_func_t issep,boolean_t skip_equal_sign)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
PE_imgsrc_mount_supported()377 PE_imgsrc_mount_supported()
378 {
379 	return TRUE;
380 }
381 
382 boolean_t
PE_get_default(const char * property_name,void * property_ptr,unsigned int max_property)383 PE_get_default(
384 	const char      *property_name,
385 	void            *property_ptr,
386 	unsigned int max_property)
387 {
388 	DTEntry         dte;
389 	void const      *property_data;
390 	unsigned int property_size;
391 
392 	/*
393 	 * Look for the property using the PE DT support.
394 	 */
395 	if (kSuccess == SecureDTLookupEntry(NULL, "/defaults", &dte)) {
396 		/*
397 		 * We have a /defaults node, look for the named property.
398 		 */
399 		if (kSuccess != SecureDTGetProperty(dte, property_name, &property_data, &property_size)) {
400 			return FALSE;
401 		}
402 
403 		/*
404 		 * This would be a fine place to do smart argument size management for 32/64
405 		 * translation, but for now we'll insist that callers know how big their
406 		 * default values are.
407 		 */
408 		if (property_size > max_property) {
409 			return FALSE;
410 		}
411 
412 		/*
413 		 * Copy back the precisely-sized result.
414 		 */
415 		memcpy(property_ptr, property_data, property_size);
416 		return TRUE;
417 	}
418 
419 	/*
420 	 * Look for the property using I/O Kit's DT support.
421 	 */
422 	return IODTGetDefault(property_name, property_ptr, max_property) ? FALSE : TRUE;
423 }
424 
425 /* function: get_range_bounds
426  * Parse a range string like "1_3,5_20" and return 1,3 as lower and upper.
427  * Note: '_' is separator for bounds integer delimiter and
428  *       ',' is considered as separator for range pair.
429  * returns TRUE when both range values are found
430  */
431 boolean_t
get_range_bounds(char * c,int64_t * lower,int64_t * upper)432 get_range_bounds(char *c, int64_t *lower, int64_t *upper)
433 {
434 	if (c == NULL || lower == NULL || upper == NULL) {
435 		return FALSE;
436 	}
437 
438 	if (NUM != getval(c, lower, israngesep, TRUE)) {
439 		return FALSE;
440 	}
441 
442 	while (*c != '\0') {
443 		if (*c == '_') {
444 			break;
445 		}
446 		c++;
447 	}
448 
449 	if (*c == '_') {
450 		c++;
451 		if (NUM != getval(c, upper, israngesep, TRUE)) {
452 			return FALSE;
453 		}
454 	} else {
455 		return FALSE;
456 	}
457 	return TRUE;
458 }
459