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
44static LCK_GRP_DECLARE(ext_paniclog_lck_grp, "Extensible panic log locks");
45static LCK_MTX_DECLARE(ext_paniclog_list_lock, &ext_paniclog_lck_grp);
46
47// Global slot for panic_with_data
48ext_paniclog_handle_t *panic_with_data_handle;
49
50// Global to keep track of number of handles
51uint32_t ext_paniclog_handle_count = 0;
52
53uint8_t ext_paniclog_panic_in_progress = 0;
54
55uint8_t ext_paniclog_panic_write_done = 0;
56
57uuid_string_t panic_with_data_uuid = PANIC_WITH_DATA_UUID;
58
59LIST_HEAD(_ext_paniclog_handle_list, ext_paniclog_handle) ext_paniclog_handle_list;
60
61void
62ext_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
73ext_paniclog_handle_t *
74ext_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
113ext_paniclog_handle_t *
114ext_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
129void
130ext_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
145int
146ext_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
166int
167ext_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
187static int
188ext_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
208int
209ext_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
221int
222ext_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
241void *
242ext_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
253void *
254ext_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
263int
264ext_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
275int
276ext_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
281void
282ext_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
299static uint32_t
300ext_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
316bool
317is_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 */
337uint32_t
338ext_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
390static int
391ext_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 */
424static int
425ext_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 */
444static int
445ext_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
523finish:
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 */
534static int
535ext_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 */
640static int
641ext_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
668static int
669ext_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 */
690static int
691ext_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 */
738static int
739ext_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 */
779static int
780ext_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 */
828static int
829ext_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
889int
890ext_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
944void
945ext_paniclog_init(void)
946{
947 os_log_error(OS_LOG_DEFAULT, "Extensible paniclog not supported");
948 return;
949}
950
951ext_paniclog_handle_t *
952ext_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
959ext_paniclog_handle_t *
960ext_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
967void
968ext_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
974int
975ext_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
981int
982ext_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
988int
989ext_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
995int
996ext_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
1002void *
1003ext_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
1009void *
1010ext_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
1016int
1017ext_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
1023int
1024ext_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
1030void
1031ext_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
1037bool
1038is_debug_ptr_in_ext_paniclog(void)
1039{
1040 return false;
1041}
1042
1043uint32_t
1044ext_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