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 <IOKit/IOExtensiblePaniclog.h>
30#include <IOKit/IOLib.h>
31#include <IOKit/IOBSD.h>
32#include <IOKit/IOBufferMemoryDescriptor.h>
33
34#include <libkern/c++/OSAllocation.h>
35#include <libkern/c++/OSKext.h>
36
37__BEGIN_DECLS
38#include <os/log.h>
39__END_DECLS
40
41#define super OSObject
42OSDefineMetaClassAndStructors(IOExtensiblePaniclog, OSObject)
43
44bool
45IOExtensiblePaniclog::init(void)
46{
47 extPaniclogHandle = NULL;
48
49 if (!super::init()) {
50 os_log_error(OS_LOG_DEFAULT, "EXT_PANICLOG: Super init failed\n");
51 return false;
52 }
53
54 return true;
55}
56
57bool
58IOExtensiblePaniclog::createWithUUID(uuid_t uuid, const char *data_id, uint32_t len,
59 ext_paniclog_create_options_t options, IOExtensiblePaniclog **out)
60{
61 IOExtensiblePaniclog *inst = OSTypeAlloc(IOExtensiblePaniclog);
62 if (!inst) {
63 os_log_error(OS_LOG_DEFAULT, "EXT_PANICLOG: instance is NULL\n");
64 return false;
65 }
66
67 if (!inst->init()) {
68 os_log_error(OS_LOG_DEFAULT, "EXT_PANICLOG: init failed\n");
69 OSSafeReleaseNULL(inst);
70 return false;
71 }
72
73 inst->extPaniclogHandle = ext_paniclog_handle_alloc_with_uuid(uuid, data_id,
74 max_len: len, options);
75 if (inst->extPaniclogHandle == NULL) {
76 os_log(OS_LOG_DEFAULT, "EXT_PANICLOG: Handle alloc failed\n");
77 OSSafeReleaseNULL(inst);
78 return false;
79 }
80
81 *out = inst;
82
83 return true;
84}
85
86void
87IOExtensiblePaniclog::free(void)
88{
89 if (extPaniclogHandle != NULL) {
90 ext_paniclog_handle_free(handle: extPaniclogHandle);
91 }
92
93 if (iomd != NULL) {
94 iomd->release();
95 }
96
97 super::free();
98}
99
100int
101IOExtensiblePaniclog::setActive()
102{
103 return ext_paniclog_handle_set_active(handle: extPaniclogHandle);
104}
105
106int
107IOExtensiblePaniclog::setInactive()
108{
109 return ext_paniclog_handle_set_inactive(handle: extPaniclogHandle);
110}
111
112int
113IOExtensiblePaniclog::insertData(void *addr, uint32_t len)
114{
115 return ext_paniclog_insert_data(handle: extPaniclogHandle, addr, len);
116}
117
118int
119IOExtensiblePaniclog::appendData(void *addr, uint32_t len)
120{
121 return ext_paniclog_append_data(handle: extPaniclogHandle, addr, len);
122}
123
124void *
125IOExtensiblePaniclog::claimBuffer()
126{
127 return ext_paniclog_claim_buffer(handle: extPaniclogHandle);
128}
129
130int
131IOExtensiblePaniclog::yieldBuffer(uint32_t used_len)
132{
133 return ext_paniclog_yield_buffer(handle: extPaniclogHandle, used_len);
134}
135
136int
137IOExtensiblePaniclog::setUsedLen(uint32_t used_len)
138{
139 return ext_paniclog_set_used_len(handle: extPaniclogHandle, used_len);
140}
141
142/*********************************************************************************
143* *
144* Driver Kit functions *
145* *
146*********************************************************************************/
147
148kern_return_t
149IOExtensiblePaniclog::Create_Impl(OSData *uuid, OSString *data_id, uint32_t max_len,
150 uint32_t options, IOExtensiblePaniclog **out)
151{
152 IOExtensiblePaniclog * inst = NULL;
153 uuid_t uuid_copy;
154 uint32_t mem_options = 0;
155
156 if (!IOCurrentTaskHasEntitlement(EXTPANICLOG_ENTITLEMENT)) {
157 return kIOReturnNotPrivileged;
158 }
159
160 if ((uuid == nullptr) || (uuid->getLength() > sizeof(uuid_t))) {
161 return kIOReturnBadArgument;
162 }
163
164 if ((data_id == nullptr) || (data_id->getLength() > MAX_DATA_ID_SIZE)) {
165 return kIOReturnBadArgument;
166 }
167
168 memcpy(dst: &uuid_copy, src: uuid->getBytesNoCopy(), n: uuid->getLength());
169
170 inst = OSTypeAlloc(IOExtensiblePaniclog);
171 if (!inst->init()) {
172 OSSafeReleaseNULL(inst);
173 return kIOReturnNoMemory;
174 }
175
176 mem_options = kIOMemoryKernelUserShared | kIOMemoryThreadSafe | kIODirectionInOut;
177 inst->iomd = IOBufferMemoryDescriptor::withOptions(options: mem_options, capacity: max_len);
178 if (inst->iomd == NULL) {
179 IOLog(format: "EXT_PANICLOG IOKIT: Failed to create iobmd");
180 OSSafeReleaseNULL(inst);
181 return kIOReturnNoMemory;
182 }
183
184 inst->extPaniclogHandle = ext_paniclog_handle_alloc_with_buffer(uuid: uuid_copy,
185 data_id: data_id->getCStringNoCopy(), max_len, buff: inst->iomd->getBytesNoCopy(),
186 options: (ext_paniclog_create_options_t)(options | EXT_PANICLOG_OPTIONS_WITH_BUFFER));
187 if (inst->extPaniclogHandle == NULL) {
188 OSSafeReleaseNULL(inst);
189 return kIOReturnNoMemory;
190 }
191
192 *out = inst;
193
194 return kIOReturnSuccess;
195}
196
197kern_return_t
198IOExtensiblePaniclog::SetActive_Impl()
199{
200 if (ext_paniclog_handle_set_active(handle: extPaniclogHandle) != 0) {
201 return kIOReturnBadArgument;
202 }
203
204 return kIOReturnSuccess;
205}
206
207kern_return_t
208IOExtensiblePaniclog::SetInactive_Impl()
209{
210 if (ext_paniclog_handle_set_inactive(handle: extPaniclogHandle) != 0) {
211 return kIOReturnBadArgument;
212 }
213
214 return kIOReturnSuccess;
215}
216
217kern_return_t
218IOExtensiblePaniclog::InsertData_Impl(OSData *data)
219{
220 if (data == nullptr) {
221 return kIOReturnBadArgument;
222 }
223
224 void *addr = (void *)data->getBytesNoCopy();
225
226 if (ext_paniclog_insert_data(handle: extPaniclogHandle, addr, len: data->getLength()) != 0) {
227 return kIOReturnBadArgument;
228 }
229
230 return kIOReturnSuccess;
231}
232
233kern_return_t
234IOExtensiblePaniclog::AppendData_Impl(OSData *data)
235{
236 if (data == nullptr) {
237 return kIOReturnBadArgument;
238 }
239
240 void *addr = (void *)data->getBytesNoCopy();
241
242 if (ext_paniclog_append_data(handle: extPaniclogHandle, addr, len: data->getLength()) != 0) {
243 return kIOReturnBadArgument;
244 }
245
246 return kIOReturnSuccess;
247}
248
249kern_return_t
250IOExtensiblePaniclog::CopyMemoryDescriptor_Impl(IOBufferMemoryDescriptor **mem)
251{
252 (void) ext_paniclog_claim_buffer(handle: extPaniclogHandle);
253
254 iomd->retain();
255 *mem = iomd;
256 return kIOReturnSuccess;
257}
258
259kern_return_t
260IOExtensiblePaniclog::SetUsedLen_Impl(uint32_t used_len)
261{
262 return ext_paniclog_set_used_len(handle: extPaniclogHandle, used_len);
263}
264