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
OSDefineMetaClassAndStructors(IOExtensiblePaniclog,OSObject)42 OSDefineMetaClassAndStructors(IOExtensiblePaniclog, OSObject)
43
44 bool
45 IOExtensiblePaniclog::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
57 bool
createWithUUID(uuid_t uuid,const char * data_id,uint32_t len,ext_paniclog_create_options_t options,IOExtensiblePaniclog ** out)58 IOExtensiblePaniclog::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 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
86 void
free(void)87 IOExtensiblePaniclog::free(void)
88 {
89 if (extPaniclogHandle != NULL) {
90 ext_paniclog_handle_free(extPaniclogHandle);
91 }
92
93 if (iomd != NULL) {
94 iomd->release();
95 }
96
97 super::free();
98 }
99
100 int
setActive()101 IOExtensiblePaniclog::setActive()
102 {
103 return ext_paniclog_handle_set_active(extPaniclogHandle);
104 }
105
106 int
setInactive()107 IOExtensiblePaniclog::setInactive()
108 {
109 return ext_paniclog_handle_set_inactive(extPaniclogHandle);
110 }
111
112 int
insertData(void * addr,uint32_t len)113 IOExtensiblePaniclog::insertData(void *addr, uint32_t len)
114 {
115 return ext_paniclog_insert_data(extPaniclogHandle, addr, len);
116 }
117
118 int
appendData(void * addr,uint32_t len)119 IOExtensiblePaniclog::appendData(void *addr, uint32_t len)
120 {
121 return ext_paniclog_append_data(extPaniclogHandle, addr, len);
122 }
123
124 void *
claimBuffer()125 IOExtensiblePaniclog::claimBuffer()
126 {
127 return ext_paniclog_claim_buffer(extPaniclogHandle);
128 }
129
130 int
yieldBuffer(uint32_t used_len)131 IOExtensiblePaniclog::yieldBuffer(uint32_t used_len)
132 {
133 return ext_paniclog_yield_buffer(extPaniclogHandle, used_len);
134 }
135
136 int
setUsedLen(uint32_t used_len)137 IOExtensiblePaniclog::setUsedLen(uint32_t used_len)
138 {
139 return ext_paniclog_set_used_len(extPaniclogHandle, used_len);
140 }
141
142 /*********************************************************************************
143 * *
144 * Driver Kit functions *
145 * *
146 *********************************************************************************/
147
148 kern_return_t
Create_Impl(OSData * uuid,OSString * data_id,uint32_t max_len,uint32_t options,IOExtensiblePaniclog ** out)149 IOExtensiblePaniclog::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(&uuid_copy, uuid->getBytesNoCopy(), 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(mem_options, max_len);
178 if (inst->iomd == NULL) {
179 IOLog("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_copy,
185 data_id->getCStringNoCopy(), max_len, inst->iomd->getBytesNoCopy(),
186 (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
197 kern_return_t
SetActive_Impl()198 IOExtensiblePaniclog::SetActive_Impl()
199 {
200 if (ext_paniclog_handle_set_active(extPaniclogHandle) != 0) {
201 return kIOReturnBadArgument;
202 }
203
204 return kIOReturnSuccess;
205 }
206
207 kern_return_t
SetInactive_Impl()208 IOExtensiblePaniclog::SetInactive_Impl()
209 {
210 if (ext_paniclog_handle_set_inactive(extPaniclogHandle) != 0) {
211 return kIOReturnBadArgument;
212 }
213
214 return kIOReturnSuccess;
215 }
216
217 kern_return_t
InsertData_Impl(OSData * data)218 IOExtensiblePaniclog::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(extPaniclogHandle, addr, data->getLength()) != 0) {
227 return kIOReturnBadArgument;
228 }
229
230 return kIOReturnSuccess;
231 }
232
233 kern_return_t
AppendData_Impl(OSData * data)234 IOExtensiblePaniclog::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(extPaniclogHandle, addr, data->getLength()) != 0) {
243 return kIOReturnBadArgument;
244 }
245
246 return kIOReturnSuccess;
247 }
248
249 kern_return_t
CopyMemoryDescriptor_Impl(IOBufferMemoryDescriptor ** mem)250 IOExtensiblePaniclog::CopyMemoryDescriptor_Impl(IOBufferMemoryDescriptor **mem)
251 {
252 (void) ext_paniclog_claim_buffer(extPaniclogHandle);
253
254 iomd->retain();
255 *mem = iomd;
256 return kIOReturnSuccess;
257 }
258
259 kern_return_t
SetUsedLen_Impl(uint32_t used_len)260 IOExtensiblePaniclog::SetUsedLen_Impl(uint32_t used_len)
261 {
262 return ext_paniclog_set_used_len(extPaniclogHandle, used_len);
263 }
264