xref: /xnu-10002.81.5/osfmk/kern/ext_paniclog.c (revision 5e3eaea39dcf651e66cb99ba7d70e32cc4a99587)
1 /*
2  * Copyright (c) 2022 Apple Computer, 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 
29 #include <kern/locks.h>
30 #include <kern/kalloc.h>
31 #include <kern/zalloc.h>
32 #include <libkern/OSAtomic.h>
33 #include <os/log.h>
34 
35 #include <kern/ext_paniclog.h>
36 #include <kern/debug.h>
37 
38 #if defined(__arm64__)
39 #include <pexpert/pexpert.h> /* For gPanicBase */
40 #endif
41 
42 #if CONFIG_EXT_PANICLOG
43 
44 static LCK_GRP_DECLARE(ext_paniclog_lck_grp, "Extensible panic log locks");
45 static LCK_MTX_DECLARE(ext_paniclog_list_lock, &ext_paniclog_lck_grp);
46 
47 // Global slot for panic_with_data
48 ext_paniclog_handle_t *panic_with_data_handle;
49 
50 // Global to keep track of number of handles
51 uint32_t ext_paniclog_handle_count = 0;
52 
53 uint8_t ext_paniclog_panic_in_progress = 0;
54 
55 uint8_t ext_paniclog_panic_write_done = 0;
56 
57 uuid_string_t panic_with_data_uuid = PANIC_WITH_DATA_UUID;
58 
59 LIST_HEAD(_ext_paniclog_handle_list, ext_paniclog_handle) ext_paniclog_handle_list;
60 
61 void
ext_paniclog_init(void)62 ext_paniclog_init(void)
63 {
64 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG: Initializing list\n");
65 	LIST_INIT(&ext_paniclog_handle_list);
66 
67 	uuid_t uuid;
68 	panic_with_data_handle = ext_paniclog_handle_alloc_with_uuid(uuid,
69 	    PANIC_WITH_DATA_DATA_ID,
70 	    PANIC_WITH_DATA_MAX_LEN, EXT_PANICLOG_OPTIONS_NONE);
71 }
72 
73 ext_paniclog_handle_t *
ext_paniclog_handle_alloc_with_uuid(uuid_t uuid,const char * data_id,uint32_t max_len,ext_paniclog_create_options_t options)74 ext_paniclog_handle_alloc_with_uuid(uuid_t uuid, const char *data_id,
75     uint32_t max_len, ext_paniclog_create_options_t options)
76 {
77 	size_t data_id_size = strnlen(data_id, MAX_DATA_ID_SIZE - 1);
78 
79 	if (max_len > (MAX_EXT_PANICLOG_SIZE - data_id_size - sizeof(ext_paniclog_header_t))) {
80 		os_log_error(OS_LOG_DEFAULT, "EXT_PANICLOG_: Input len %d greater than max allowed %d\n",
81 		    max_len, MAX_EXT_PANICLOG_SIZE);
82 		return NULL;
83 	}
84 
85 	ext_paniclog_handle_t *handle = kalloc_type(ext_paniclog_handle_t, Z_WAITOK | Z_ZERO);
86 	if (!handle) {
87 		return NULL;
88 	}
89 
90 	/* We don't alloc a buffer if the create call is from a dext.
91 	 * In the Create call for dext, we use a IOBMD to backup this handle
92 	 */
93 
94 	if (!(options & EXT_PANICLOG_OPTIONS_WITH_BUFFER)) {
95 		handle->buf_addr = kalloc_data(max_len, Z_WAITOK | Z_ZERO);
96 		if (!handle->buf_addr) {
97 			kfree_type(ext_paniclog_handle_t, handle);
98 			return NULL;
99 		}
100 	}
101 
102 	memcpy(handle->uuid, uuid, sizeof(uuid_t));
103 	memcpy(handle->data_id, data_id, data_id_size);
104 
105 	handle->options = options;
106 	handle->max_len = max_len;
107 	handle->used_len = 0;
108 	handle->active = 0;
109 
110 	return handle;
111 }
112 
113 ext_paniclog_handle_t *
ext_paniclog_handle_alloc_with_buffer(uuid_t uuid,const char * data_id,uint32_t max_len,void * buff,ext_paniclog_create_options_t options)114 ext_paniclog_handle_alloc_with_buffer(uuid_t uuid, const char *data_id,
115     uint32_t max_len, void * buff, ext_paniclog_create_options_t options)
116 {
117 	ext_paniclog_handle_t *handle = NULL;
118 
119 	handle = ext_paniclog_handle_alloc_with_uuid(uuid, data_id, max_len, options);
120 	if (handle == NULL) {
121 		return NULL;
122 	}
123 
124 	handle->buf_addr = buff;
125 
126 	return handle;
127 }
128 
129 void
ext_paniclog_handle_free(ext_paniclog_handle_t * handle)130 ext_paniclog_handle_free(ext_paniclog_handle_t *handle)
131 {
132 	if (handle == NULL) {
133 		return;
134 	}
135 
136 	ext_paniclog_handle_set_inactive(handle);
137 
138 	if (!(handle->options & EXT_PANICLOG_OPTIONS_WITH_BUFFER)) {
139 		kfree_data(handle->buf_addr, handle->max_len);
140 	}
141 
142 	kfree_type(ext_paniclog_handle_t, handle);
143 }
144 
145 int
ext_paniclog_handle_set_active(ext_paniclog_handle_t * handle)146 ext_paniclog_handle_set_active(ext_paniclog_handle_t *handle)
147 {
148 	if (handle == NULL) {
149 		return -1;
150 	}
151 
152 	if (!OSCompareAndSwap8(0, 1, &handle->active)) {
153 		return -1;
154 	}
155 
156 	lck_mtx_lock(&ext_paniclog_list_lock);
157 
158 	LIST_INSERT_HEAD(&ext_paniclog_handle_list, handle, handles);
159 	ext_paniclog_handle_count++;
160 
161 	lck_mtx_unlock(&ext_paniclog_list_lock);
162 
163 	return 0;
164 }
165 
166 int
ext_paniclog_handle_set_inactive(ext_paniclog_handle_t * handle)167 ext_paniclog_handle_set_inactive(ext_paniclog_handle_t *handle)
168 {
169 	if (handle == NULL) {
170 		return -1;
171 	}
172 
173 	if (!OSCompareAndSwap8(1, 0, &handle->active)) {
174 		return -1;
175 	}
176 
177 	lck_mtx_lock(&ext_paniclog_list_lock);
178 
179 	LIST_REMOVE(handle, handles);
180 	ext_paniclog_handle_count--;
181 
182 	lck_mtx_unlock(&ext_paniclog_list_lock);
183 
184 	return 0;
185 }
186 
187 static int
ext_paniclog_insert_data_internal(ext_paniclog_handle_t * handle,void * addr,uint32_t len,uint32_t offset)188 ext_paniclog_insert_data_internal(ext_paniclog_handle_t *handle, void *addr,
189     uint32_t len, uint32_t offset)
190 {
191 	if ((handle == NULL) || (addr == NULL)) {
192 		return -1;
193 	}
194 
195 	if (len > handle->max_len) {
196 		return -1;
197 	}
198 
199 	char *dst = (char *)handle->buf_addr + offset;
200 
201 	memcpy(dst, addr, len);
202 
203 	(void)ext_paniclog_handle_set_active(handle);
204 
205 	return 0;
206 }
207 
208 int
ext_paniclog_insert_data(ext_paniclog_handle_t * handle,void * addr,uint32_t len)209 ext_paniclog_insert_data(ext_paniclog_handle_t *handle, void *addr, uint32_t len)
210 {
211 	int ret = 0;
212 
213 	ret = ext_paniclog_insert_data_internal(handle, addr, len, 0);
214 	if (ret == 0) {
215 		handle->used_len = len;
216 	}
217 
218 	return ret;
219 }
220 
221 int
ext_paniclog_append_data(ext_paniclog_handle_t * handle,void * addr,uint32_t len)222 ext_paniclog_append_data(ext_paniclog_handle_t *handle, void *addr, uint32_t len)
223 {
224 	int ret = 0;
225 	uint32_t updt_len = 0;
226 
227 	if (os_add_overflow(len, handle->used_len, &updt_len)
228 	    || (updt_len > handle->max_len)) {
229 		return -1;
230 	}
231 
232 	ret = ext_paniclog_insert_data_internal(handle, addr, len,
233 	    handle->used_len);
234 	if (ret == 0) {
235 		handle->used_len += len;
236 	}
237 
238 	return ret;
239 }
240 
241 void *
ext_paniclog_claim_buffer(ext_paniclog_handle_t * handle)242 ext_paniclog_claim_buffer(ext_paniclog_handle_t *handle)
243 {
244 	if (handle == NULL) {
245 		return NULL;
246 	}
247 
248 	handle->used_len = handle->max_len;
249 
250 	return handle->buf_addr;
251 }
252 
253 void *
ext_paniclog_get_buffer(ext_paniclog_handle_t * handle)254 ext_paniclog_get_buffer(ext_paniclog_handle_t *handle)
255 {
256 	if (handle == NULL) {
257 		return NULL;
258 	}
259 
260 	return handle->buf_addr;
261 }
262 
263 int
ext_paniclog_set_used_len(ext_paniclog_handle_t * handle,uint32_t used_len)264 ext_paniclog_set_used_len(ext_paniclog_handle_t *handle, uint32_t used_len)
265 {
266 	if (handle == NULL) {
267 		return -1;
268 	}
269 
270 	handle->used_len = used_len;
271 
272 	return 0;
273 }
274 
275 int
ext_paniclog_yield_buffer(ext_paniclog_handle_t * handle,uint32_t used_len)276 ext_paniclog_yield_buffer(ext_paniclog_handle_t *handle, uint32_t used_len)
277 {
278 	return ext_paniclog_set_used_len(handle, used_len);
279 }
280 
281 void
ext_paniclog_panic_with_data(uuid_t uuid,void * addr,uint32_t len)282 ext_paniclog_panic_with_data(uuid_t uuid, void *addr, uint32_t len)
283 {
284 	if (!OSCompareAndSwap8(0, 1, &ext_paniclog_panic_in_progress)) {
285 		return;
286 	}
287 
288 	if (uuid_is_null(uuid)) {
289 		uuid_parse(panic_with_data_uuid, uuid);
290 	}
291 
292 	memcpy(&panic_with_data_handle->uuid[0], &uuid[0], sizeof(uuid_t));
293 
294 	ext_paniclog_insert_data(panic_with_data_handle, addr, len);
295 
296 	return;
297 }
298 
299 static uint32_t
ext_paniclog_get_size_required(void)300 ext_paniclog_get_size_required(void)
301 {
302 	uint32_t size_req = 0;
303 	ext_paniclog_handle_t *tmp;
304 
305 	LIST_FOREACH(tmp, &ext_paniclog_handle_list, handles) {
306 		size_req += (strnlen(tmp->data_id, MAX_DATA_ID_SIZE - 1) + 1) +
307 		    sizeof(ext_paniclog_header_t) + tmp->used_len;
308 	}
309 
310 	// Adding the size of handle count and ext paniclog version variable
311 	size_req += sizeof(ext_paniclog_handle_count) + sizeof(uint32_t);
312 
313 	return size_req;
314 }
315 
316 bool
is_debug_ptr_in_ext_paniclog(void)317 is_debug_ptr_in_ext_paniclog(void)
318 {
319 	bool ext_paniclog_exceeds = ((panic_info->eph_ext_paniclog_offset != 0) ?
320 	    ((uint32_t)(debug_buf_ptr - gPanicBase) >= panic_info->eph_ext_paniclog_offset) :
321 	    false);
322 
323 	return ext_paniclog_exceeds;
324 }
325 
326 /*
327  * Format of the Extensible panic log:
328  *
329  * +---------+------------+---------+------------+------------+---------+--------+-----------+------------+----------+
330  * |         |            |         |            |            |         |        |           |            |          |
331  * |Version  | No of logs | UUID 1  | Data ID 1  | Data len 1 | Data 1  | UUID 2 | Data ID 2 | Data len 2 | Data 2   |
332  * |         |            |         |            |            |         |        |           |            |          |
333  * +---------+------------+---------+------------+------------+---------+--------+-----------+------------+----------+
334  *
335  *
336  */
337 uint32_t
ext_paniclog_write_panicdata(void)338 ext_paniclog_write_panicdata(void)
339 {
340 	ext_paniclog_handle_t *tmp;
341 	char *end = (char *)(debug_buf_base + debug_buf_size);
342 	uint32_t paniclog_buf_size = (uint32_t)(end - debug_buf_ptr);
343 	uint32_t space_left = paniclog_buf_size - OTHER_LOG_REQUIRED_SIZE;
344 	size_t data_id_size = 0;
345 	uint32_t ext_paniclog_version = EXT_PANICLOG_VERSION;
346 	char *dst = NULL;
347 
348 	if (!OSCompareAndSwap8(0, 1, &ext_paniclog_panic_write_done) || (ext_paniclog_handle_count == 0)
349 	    || (paniclog_buf_size < MAX_EXT_PANICLOG_SIZE)) {
350 		return 0;
351 	}
352 
353 	uint32_t size_req = ext_paniclog_get_size_required();
354 
355 	size_req = MIN(MIN(size_req, MAX_EXT_PANICLOG_SIZE), space_left);
356 
357 	dst = (char *)(end - size_req);
358 
359 	memcpy(dst, &ext_paniclog_version, sizeof(ext_paniclog_version));
360 	dst += sizeof(ext_paniclog_version);
361 
362 	memcpy(dst, &ext_paniclog_handle_count, sizeof(ext_paniclog_handle_count));
363 	dst += sizeof(ext_paniclog_handle_count);
364 
365 	LIST_FOREACH(tmp, &ext_paniclog_handle_list, handles) {
366 		data_id_size = strnlen(tmp->data_id, MAX_DATA_ID_SIZE - 1) + 1;
367 
368 		if ((dst + tmp->used_len + data_id_size + sizeof(ext_paniclog_header_t)) > end) {
369 			break;
370 		}
371 
372 		memcpy(dst, tmp->uuid, sizeof(uuid_t));
373 		dst += sizeof(uuid_t);
374 		memcpy(dst, &tmp->data_id, data_id_size);
375 		dst += data_id_size;
376 		memcpy(dst, &tmp->used_len, sizeof(tmp->used_len));
377 		dst += sizeof(tmp->used_len);
378 		memcpy(dst, tmp->buf_addr, tmp->used_len);
379 		dst += tmp->used_len;
380 	}
381 
382 	return size_req;
383 }
384 
385 
386 #if DEVELOPMENT || DEBUG
387 
388 #pragma mark Extensible paniclog tests
389 
390 static int
ext_paniclog_create_multiple_handles(ext_paniclog_handle_t * handles[],const char * data_id[],char * data)391 ext_paniclog_create_multiple_handles(ext_paniclog_handle_t *handles[], const char *data_id[], char *data)
392 {
393 	uuid_t uuid;
394 	uuid_string_t uuid_string;
395 	ext_paniclog_handle_t *handle;
396 
397 	for (int i = 0; i < 2; i++) {
398 		uuid_generate(uuid);
399 		uuid_unparse(uuid, uuid_string);
400 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Creating handle %d with UUID: %s\n", (i + 1), uuid_string);
401 
402 		handle = ext_paniclog_handle_alloc_with_uuid(uuid, data_id[i], 1024, EXT_PANICLOG_OPTIONS_NONE);
403 		if (handle == NULL) {
404 			os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Handle %d is NULL\n", (i + 1));
405 			return -1;
406 		}
407 
408 		handles[i] = handle;
409 
410 		ext_paniclog_insert_data(handle, data, 16);
411 
412 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Used len of buffer: %d\n", handle->used_len);
413 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Data in buffer: %s\n", (char *)ext_paniclog_get_buffer(handle));
414 
415 		ext_paniclog_handle_set_active(handle);
416 	}
417 
418 	return 0;
419 }
420 
421 /*
422  * Test 6: EXT_PANICLOG_TEST_MULTIPLE_HANDLES_PANIC
423  */
424 static int
ext_paniclog_multiple_handles_panic_test(void)425 ext_paniclog_multiple_handles_panic_test(void)
426 {
427 	char data[17] = "abcdefghabcdefgh";
428 	ext_paniclog_handle_t *handles[2] = {0};
429 	const char *data_id[] = {"Test Handle 1", "Test Handle 2"};
430 	uuid_t uuid;
431 	uuid_string_t uuid_string;
432 	uuid_generate(uuid);
433 	uuid_unparse(uuid, uuid_string);
434 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: panic with data UUID: %s", uuid_string);
435 
436 	ext_paniclog_create_multiple_handles(handles, data_id, data);
437 
438 	panic_with_data(uuid, data, 16, "Extensible panic log test");
439 }
440 
441 /*
442  * Test 5: EXT_PANICLOG_TEST_MULTIPLE_HANDLES
443  */
444 static int
ext_paniclog_multiple_handles_test(void)445 ext_paniclog_multiple_handles_test(void)
446 {
447 	char data[17] = "abcdefghabcdefgh";
448 	uint32_t bytes_copied = 0;
449 	uint32_t no_of_logs;
450 	uint32_t data_len = 0;
451 	ext_paniclog_handle_t *handles[2] = {0};
452 	const char *data_id[] = {"Test Handle 1", "Test Handle 2"};
453 	char *buf_ptr;
454 	int ret = 0;
455 	uint32_t version = 0;
456 
457 	ret = ext_paniclog_create_multiple_handles(handles, data_id, data);
458 	if (ret < 0) {
459 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Create handles failed\n");
460 		return -1;
461 	}
462 
463 	bytes_copied = ext_paniclog_write_panicdata();
464 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Bytes copied: %d\n", bytes_copied);
465 
466 	buf_ptr = (debug_buf_base + debug_buf_size) - bytes_copied;
467 #if 0
468 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: *****************************************");
469 	for (int i = 0; i < 128; i++) {
470 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: %u ", buf_ptr[i]);
471 	}
472 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: *****************************************");
473 #endif
474 
475 
476 	memcpy(&version, buf_ptr, 4);
477 	if (version != EXT_PANICLOG_VERSION) {
478 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Version mismatch: %d\n", version);
479 		ret = -1;
480 		goto finish;
481 	}
482 
483 	buf_ptr += 4;
484 
485 	memcpy(&no_of_logs, buf_ptr, 4);
486 
487 	if (no_of_logs != 2) {
488 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Num logs is not equal: %d\n", no_of_logs);
489 		ret = -1;
490 		goto finish;
491 	}
492 
493 	buf_ptr = buf_ptr + 20;
494 	for (int i = 1; i >= 0; i--) {
495 		size_t data_id_len = strnlen(data_id[i], MAX_DATA_ID_SIZE);
496 
497 		if (strncmp(data_id[i], buf_ptr, data_id_len)) {
498 			os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: data id is not equal\n");
499 			ret = -1;
500 			goto finish;
501 		}
502 		buf_ptr += data_id_len + 1;
503 		memcpy(&data_len, buf_ptr, 4);
504 
505 		if (data_len != 16) {
506 			os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: data len is not equal: %d\n", data_len);
507 			ret = -1;
508 			goto finish;
509 		}
510 
511 		buf_ptr += 4;
512 
513 		if (memcmp(buf_ptr, data, data_len)) {
514 			os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Buffers don't match\n");
515 			ret = -1;
516 			goto finish;
517 		}
518 
519 		buf_ptr += data_len;
520 		buf_ptr += 16;
521 	}
522 
523 finish:
524 	for (int i = 0; i < 2; i++) {
525 		ext_paniclog_handle_free(handles[i]);
526 	}
527 
528 	return ret;
529 }
530 
531 /*
532  * Test 4: EXT_PANICLOG_TEST_WRITE_PANIC_DATA
533  */
534 static int
ext_paniclog_write_panicdata_test(void)535 ext_paniclog_write_panicdata_test(void)
536 {
537 	uuid_t uuid;
538 	uuid_generate(uuid);
539 	uuid_string_t uuid_string;
540 	uuid_unparse(uuid, uuid_string);
541 	uint32_t bytes_copied;
542 	const char data_id[] = "Test Handle";
543 	char *buf_ptr;
544 	uint32_t num_of_logs = 0;
545 	uint32_t data_len = 0;
546 	char data1[17] = "abcdefghabcdefgh";
547 	char panic_data[1024] = {0};
548 	uint32_t version = 0;
549 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Creating handle with UUID: %s\n", uuid_string);
550 
551 	ext_paniclog_handle_t *handle = ext_paniclog_handle_alloc_with_uuid(uuid, data_id, 1024, EXT_PANICLOG_OPTIONS_NONE);
552 	if (handle == NULL) {
553 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Handle is NULL\n");
554 		return -1;
555 	}
556 
557 	ext_paniclog_insert_data(handle, data1, 16);
558 
559 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Used len of buffer: %d\n", handle->used_len);
560 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Data in buffer: %s\n", (char *)ext_paniclog_get_buffer(handle));
561 
562 	ext_paniclog_handle_set_active(handle);
563 
564 	bytes_copied = ext_paniclog_write_panicdata();
565 
566 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Bytes copied: %d\n", bytes_copied);
567 
568 	buf_ptr = (debug_buf_base + debug_buf_size) - bytes_copied;
569 #if 0
570 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: *****************************************");
571 	for (int i = 0; i < 100; i++) {
572 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: %u ", panic_data[i]);
573 	}
574 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: *****************************************");
575 #endif
576 
577 	memcpy(&version, buf_ptr, 4);
578 	if (version != EXT_PANICLOG_VERSION) {
579 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Version mismatch: %d\n", version);
580 		ext_paniclog_handle_free(handle);
581 		return -1;
582 	}
583 
584 	buf_ptr += 4;
585 
586 	memcpy(&num_of_logs, buf_ptr, 4);
587 
588 	if (num_of_logs != 1) {
589 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Num logs is not equal: %d\n", num_of_logs);
590 		ext_paniclog_handle_free(handle);
591 		return -1;
592 	}
593 
594 	buf_ptr += 4;
595 
596 	char *uuid_cmp = (char *)(buf_ptr);
597 
598 	if (memcmp(uuid_cmp, uuid, 16)) {
599 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: UUID is not equal\n");
600 		ext_paniclog_handle_free(handle);
601 		return -1;
602 	}
603 
604 	buf_ptr += 16;
605 
606 	size_t data_id_len = strnlen(data_id, MAX_DATA_ID_SIZE);
607 
608 	if (strncmp(data_id, buf_ptr, data_id_len)) {
609 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: data id is not equal: %s\n", panic_data + 20);
610 		ext_paniclog_handle_free(handle);
611 		return -1;
612 	}
613 
614 	buf_ptr += data_id_len + 1;
615 	memcpy(&data_len, buf_ptr, 4);
616 
617 	if (data_len != 16) {
618 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: data len is not equal: %d\n", data_len);
619 		ext_paniclog_handle_free(handle);
620 		return -1;
621 	}
622 
623 	buf_ptr += 4;
624 	char *data_cmp = (char *)(buf_ptr);
625 
626 	if (memcmp(data_cmp, data1, data_len)) {
627 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Buffers don't match\n");
628 		ext_paniclog_handle_free(handle);
629 		return -1;
630 	}
631 
632 	ext_paniclog_handle_free(handle);
633 
634 	return 0;
635 }
636 
637 /*
638  * Test 1: EXT_PANICLOG_TEST_HANDLE_CREATE
639  */
640 static int
ext_paniclog_handle_create_test(void)641 ext_paniclog_handle_create_test(void)
642 {
643 	uint32_t max_len = 1024;
644 	uuid_t uuid;
645 	uuid_generate(uuid);
646 	uuid_string_t uuid_string;
647 	uuid_unparse(uuid, uuid_string);
648 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Creating handle with UUID: %s\n", uuid_string);
649 
650 	ext_paniclog_handle_t *handle = ext_paniclog_handle_alloc_with_uuid(uuid, "Test Handle", max_len, EXT_PANICLOG_OPTIONS_NONE);
651 	if (handle == NULL) {
652 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Handle create failed. Returned NULL\n");
653 		return -1;
654 	}
655 
656 	if ((strncmp(handle->data_id, "Test Handle", strlen(handle->data_id))) ||
657 	    (handle->max_len != 1024)) {
658 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: attribute mismatch\n");
659 		ext_paniclog_handle_free(handle);
660 		return -1;
661 	}
662 
663 	ext_paniclog_handle_free(handle);
664 
665 	return 0;
666 }
667 
668 static int
ext_paniclog_get_list_count(void)669 ext_paniclog_get_list_count(void)
670 {
671 	int cnt = 0;
672 	ext_paniclog_handle_t *tmp;
673 
674 	lck_mtx_lock(&ext_paniclog_list_lock);
675 
676 	LIST_FOREACH(tmp, &ext_paniclog_handle_list, handles) {
677 		if (tmp != NULL) {
678 			cnt++;
679 		}
680 	}
681 
682 	lck_mtx_unlock(&ext_paniclog_list_lock);
683 
684 	return cnt;
685 }
686 
687 /*
688  * Test 2: EXT_PANICLOG_TEST_SET_ACTIVE_INACTIVE
689  */
690 static int
ext_paniclog_set_active_inactive_test(void)691 ext_paniclog_set_active_inactive_test(void)
692 {
693 	uuid_t uuid;
694 	uuid_generate(uuid);
695 	uuid_string_t uuid_string;
696 	uuid_unparse(uuid, uuid_string);
697 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Creating handle with UUID: %s\n", uuid_string);
698 
699 	ext_paniclog_handle_t *handle = ext_paniclog_handle_alloc_with_uuid(uuid, "Test handle", 1024, EXT_PANICLOG_OPTIONS_NONE);
700 
701 	int cnt = 0;
702 	int initial_cnt = ext_paniclog_get_list_count();
703 
704 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Initial list count: %d\n", initial_cnt);
705 
706 	ext_paniclog_handle_set_active(handle);
707 
708 	cnt = ext_paniclog_get_list_count();
709 
710 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: List count after active: %d\n", cnt);
711 
712 	if (cnt != (initial_cnt + 1)) {
713 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: List count error after active\n");
714 		ext_paniclog_handle_free(handle);
715 		return -1;
716 	}
717 
718 	ext_paniclog_handle_set_inactive(handle);
719 
720 	cnt = ext_paniclog_get_list_count();
721 
722 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: List count after inactive: %d\n", cnt);
723 
724 	if (cnt != initial_cnt) {
725 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: List count error after inactive\n");
726 		ext_paniclog_handle_free(handle);
727 		return -1;
728 	}
729 
730 	ext_paniclog_handle_free(handle);
731 
732 	return 0;
733 }
734 
735 /*
736  * Test 3: EXT_PANICLOG_TEST_INSERT_DATA
737  */
738 static int
ext_paniclog_insert_data_test(void)739 ext_paniclog_insert_data_test(void)
740 {
741 	uuid_t uuid;
742 	uuid_generate(uuid);
743 	uuid_string_t uuid_string;
744 	uuid_unparse(uuid, uuid_string);
745 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Creating handle with UUID: %s\n", uuid_string);
746 
747 	ext_paniclog_handle_t *handle = ext_paniclog_handle_alloc_with_uuid(uuid, "Test handle", 1024, EXT_PANICLOG_OPTIONS_NONE);
748 
749 	char data1[9] = "abcdefgh";
750 
751 	ext_paniclog_insert_data(handle, data1, 8);
752 
753 	if (memcmp(handle->buf_addr, data1, 8)) {
754 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Buffers don't match\n");
755 		ext_paniclog_handle_free(handle);
756 		return -1;
757 	}
758 
759 	char data2[9] = "abcdefgh";
760 	char cmp_data[17] = "abcdefghabcdefgh";
761 
762 	ext_paniclog_append_data(handle, data2, 8);
763 
764 	if (memcmp(handle->buf_addr, cmp_data, 16)) {
765 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Buffers don't match\n");
766 		ext_paniclog_handle_free(handle);
767 		return -1;
768 	}
769 
770 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Used len of buffer: %d\n", handle->used_len);
771 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Data in buffer: %s\n", (char *)ext_paniclog_get_buffer(handle));
772 
773 	ext_paniclog_handle_free(handle);
774 
775 	return 0;
776 }
777 
778 /* Test 7 */
779 static int
ext_paniclog_insert_dummy_handles_test(void)780 ext_paniclog_insert_dummy_handles_test(void)
781 {
782 	ext_paniclog_handle_t *handle_1, *handle_2, *handle_3;
783 	char data1[18] = "Data for handle 1";
784 	char data2[18] = "Data for handle 2";
785 	char data3[18] = "Data for handle 3";
786 
787 	char uuid_string_1[] = "28245A8F-04CA-4932-8A38-E6C159FD9C92";
788 	uuid_t uuid_1;
789 	uuid_parse(uuid_string_1, uuid_1);
790 	handle_1 = ext_paniclog_handle_alloc_with_uuid(uuid_1, "Dummy handle 1", 1024, EXT_PANICLOG_OPTIONS_NONE);
791 	if (handle_1 == NULL) {
792 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Failed to create handle 1\n");
793 		return -1;
794 	}
795 
796 	handle_2 = ext_paniclog_handle_alloc_with_uuid(uuid_1, "Dummy handle 2", 1024, EXT_PANICLOG_OPTIONS_NONE);
797 	if (handle_2 == NULL) {
798 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Failed to create handle 2\n");
799 		return -1;
800 	}
801 
802 	char uuid_string_3[] = "A10F32F8-D5AF-431F-8098-FEDD0FFB794A";
803 	uuid_t uuid_3;
804 	uuid_parse(uuid_string_3, uuid_3);
805 
806 	handle_3 = ext_paniclog_handle_alloc_with_uuid(uuid_3, "Dummy handle 3", 1024, EXT_PANICLOG_OPTIONS_NONE);
807 	if (handle_3 == NULL) {
808 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Failed to create handle 3\n");
809 		return -1;
810 	}
811 
812 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Created three handles\n");
813 
814 	ext_paniclog_insert_data(handle_1, data1, 17);
815 	ext_paniclog_insert_data(handle_2, data2, 17);
816 	ext_paniclog_insert_data(handle_3, data3, 17);
817 
818 	ext_paniclog_handle_set_active(handle_1);
819 	ext_paniclog_handle_set_active(handle_2);
820 	ext_paniclog_handle_set_active(handle_3);
821 
822 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Inserted three handles\n");
823 
824 	return 0;
825 }
826 
827 /* Test 8 */
828 static int
ext_paniclog_insert_struct_handles_test(void)829 ext_paniclog_insert_struct_handles_test(void)
830 {
831 	ext_paniclog_handle_t *handle_1, *handle_2;
832 	struct _handle_1_data {
833 		uint32_t dummy_1;
834 		uint32_t dummy_2;
835 		uint32_t dummy_3;
836 	};
837 
838 	struct _handle_2_data {
839 		uint32_t dummy_1;
840 		uint32_t dummy_2;
841 	};
842 
843 	struct _handle_1_data *handle_1_data;
844 	struct _handle_2_data *handle_2_data;
845 
846 	char uuid_string_1[] = "938371FB-3B47-415E-B766-743DE6D44E6E";
847 	uuid_t uuid_1;
848 	uuid_parse(uuid_string_1, uuid_1);
849 	handle_1 = ext_paniclog_handle_alloc_with_uuid(uuid_1, "Dummy handle 1", 1024, EXT_PANICLOG_OPTIONS_NONE);
850 	if (handle_1 == NULL) {
851 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Failed to create handle 1\n");
852 		return -1;
853 	}
854 
855 	char uuid_string_2[] = "78FD5A06-1FA3-4B1C-A2F5-AF82F5D9CEFD";
856 	uuid_t uuid_2;
857 	uuid_parse(uuid_string_2, uuid_2);
858 
859 	handle_2 = ext_paniclog_handle_alloc_with_uuid(uuid_2, "Dummy handle 2", 1024, EXT_PANICLOG_OPTIONS_NONE);
860 	if (handle_2 == NULL) {
861 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Failed to create handle 3\n");
862 		return -1;
863 	}
864 
865 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Created two handles\n");
866 
867 	handle_1_data = (struct _handle_1_data *)ext_paniclog_claim_buffer(handle_1);
868 
869 	handle_2_data = (struct _handle_2_data *)ext_paniclog_claim_buffer(handle_2);
870 
871 	handle_1_data->dummy_1 = 0x1000;
872 	handle_1_data->dummy_2 = 0xFFFFFFFF;
873 	handle_1_data->dummy_3 = 0x65;
874 
875 	handle_2_data->dummy_1 = 0x10000000;
876 	handle_2_data->dummy_2 = 0xFFFF;
877 
878 	ext_paniclog_yield_buffer(handle_1, sizeof(struct _handle_1_data));
879 	ext_paniclog_yield_buffer(handle_2, sizeof(struct _handle_2_data));
880 
881 	ext_paniclog_handle_set_active(handle_1);
882 	ext_paniclog_handle_set_active(handle_2);
883 
884 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Wrote two handles\n");
885 
886 	return 0;
887 }
888 
889 int
ext_paniclog_test_hook(uint32_t option)890 ext_paniclog_test_hook(uint32_t option)
891 {
892 	int rval = 0;
893 
894 	switch (option) {
895 	case EXT_PANICLOG_TEST_HANDLE_CREATE:
896 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Create handle test\n");
897 		rval = ext_paniclog_handle_create_test();
898 		break;
899 	case EXT_PANICLOG_TEST_SET_ACTIVE_INACTIVE:
900 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Testing set active and inactive\n");
901 		rval = ext_paniclog_set_active_inactive_test();
902 		break;
903 	case EXT_PANICLOG_TEST_INSERT_DATA:
904 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Testing insert data\n");
905 		rval = ext_paniclog_insert_data_test();
906 		break;
907 	case EXT_PANICLOG_TEST_WRITE_PANIC_DATA:
908 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Testing panic data write\n");
909 		rval = ext_paniclog_write_panicdata_test();
910 		break;
911 	case EXT_PANICLOG_TEST_MULTIPLE_HANDLES:
912 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Testing multiple handles\n");
913 		rval = ext_paniclog_multiple_handles_test();
914 		break;
915 	case EXT_PANICLOG_TEST_MULTIPLE_HANDLES_PANIC:
916 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Testing multiple handles with panic\n");
917 		rval = ext_paniclog_multiple_handles_panic_test();
918 		break;
919 	case EXT_PANICLOG_TEST_INSERT_DUMMY_HANDLES:
920 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Insert dummy handles\n");
921 		rval = ext_paniclog_insert_dummy_handles_test();
922 		break;
923 	case EXT_PANICLOG_TEST_INSERT_STRUCT_HANDLES:
924 		os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Insert struct handles\n");
925 		rval = ext_paniclog_insert_struct_handles_test();
926 		break;
927 	default:
928 		os_log(OS_LOG_DEFAULT, "Not a valid option\n");
929 		break;
930 	}
931 
932 	os_log(OS_LOG_DEFAULT, "EXT_PANICLOG_TEST: Test exit: %d\n", rval);
933 	return rval;
934 }
935 #endif // DEVELOPEMNT || DEBUG
936 
937 #else // CONFIG_EXT_PANICLOG
938 
939 /*
940  * All ext paniclog functions which fail when CONFIG_EXT_PANICLOG is not
941  * enabled.
942  */
943 
944 void
ext_paniclog_init(void)945 ext_paniclog_init(void)
946 {
947 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
948 	return;
949 }
950 
951 ext_paniclog_handle_t *
ext_paniclog_handle_alloc_with_uuid(uuid_t uuid __unused,const char * data_id __unused,uint32_t max_len __unused,ext_paniclog_create_options_t options __unused)952 ext_paniclog_handle_alloc_with_uuid(uuid_t uuid __unused, const char *data_id __unused,
953     uint32_t max_len __unused, ext_paniclog_create_options_t options __unused)
954 {
955 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
956 	return NULL;
957 }
958 
959 ext_paniclog_handle_t *
ext_paniclog_handle_alloc_with_buffer(uuid_t uuid __unused,const char * data_id __unused,uint32_t max_len __unused,void * buff __unused,ext_paniclog_create_options_t options __unused)960 ext_paniclog_handle_alloc_with_buffer(uuid_t uuid __unused, const char *data_id __unused,
961     uint32_t max_len __unused, void * buff __unused, ext_paniclog_create_options_t options __unused)
962 {
963 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
964 	return NULL;
965 }
966 
967 void
ext_paniclog_handle_free(ext_paniclog_handle_t * handle __unused)968 ext_paniclog_handle_free(ext_paniclog_handle_t *handle __unused)
969 {
970 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
971 	return;
972 }
973 
974 int
ext_paniclog_handle_set_active(ext_paniclog_handle_t * handle __unused)975 ext_paniclog_handle_set_active(ext_paniclog_handle_t *handle __unused)
976 {
977 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
978 	return -1;
979 }
980 
981 int
ext_paniclog_handle_set_inactive(ext_paniclog_handle_t * handle __unused)982 ext_paniclog_handle_set_inactive(ext_paniclog_handle_t *handle __unused)
983 {
984 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
985 	return -1;
986 }
987 
988 int
ext_paniclog_insert_data(ext_paniclog_handle_t * handle __unused,void * addr __unused,uint32_t len __unused)989 ext_paniclog_insert_data(ext_paniclog_handle_t *handle __unused, void *addr __unused, uint32_t len __unused)
990 {
991 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
992 	return -1;
993 }
994 
995 int
ext_paniclog_append_data(ext_paniclog_handle_t * handle __unused,void * addr __unused,uint32_t len __unused)996 ext_paniclog_append_data(ext_paniclog_handle_t *handle __unused, void *addr __unused, uint32_t len __unused)
997 {
998 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
999 	return -1;
1000 }
1001 
1002 void *
ext_paniclog_claim_buffer(ext_paniclog_handle_t * handle __unused)1003 ext_paniclog_claim_buffer(ext_paniclog_handle_t *handle __unused)
1004 {
1005 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
1006 	return NULL;
1007 }
1008 
1009 void *
ext_paniclog_get_buffer(ext_paniclog_handle_t * handle __unused)1010 ext_paniclog_get_buffer(ext_paniclog_handle_t *handle __unused)
1011 {
1012 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
1013 	return NULL;
1014 }
1015 
1016 int
ext_paniclog_set_used_len(ext_paniclog_handle_t * handle __unused,uint32_t used_len __unused)1017 ext_paniclog_set_used_len(ext_paniclog_handle_t *handle __unused, uint32_t used_len __unused)
1018 {
1019 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
1020 	return -1;
1021 }
1022 
1023 int
ext_paniclog_yield_buffer(ext_paniclog_handle_t * handle __unused,uint32_t used_len __unused)1024 ext_paniclog_yield_buffer(ext_paniclog_handle_t *handle __unused, uint32_t used_len __unused)
1025 {
1026 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
1027 	return -1;
1028 }
1029 
1030 void
ext_paniclog_panic_with_data(uuid_t uuid __unused,void * addr __unused,uint32_t len __unused)1031 ext_paniclog_panic_with_data(uuid_t uuid __unused, void *addr __unused, uint32_t len __unused)
1032 {
1033 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
1034 	return;
1035 }
1036 
1037 bool
is_debug_ptr_in_ext_paniclog(void)1038 is_debug_ptr_in_ext_paniclog(void)
1039 {
1040 	return false;
1041 }
1042 
1043 uint32_t
ext_paniclog_write_panicdata(void)1044 ext_paniclog_write_panicdata(void)
1045 {
1046 	os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
1047 	return 0;
1048 }
1049 #endif // CONFIG_EXT_PANICLOG
1050