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
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
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
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
101 IOExtensiblePaniclog::setActive()
102 {
103 	return ext_paniclog_handle_set_active(extPaniclogHandle);
104 }
105 
106 int
107 IOExtensiblePaniclog::setInactive()
108 {
109 	return ext_paniclog_handle_set_inactive(extPaniclogHandle);
110 }
111 
112 int
113 IOExtensiblePaniclog::insertData(void *addr, uint32_t len)
114 {
115 	return ext_paniclog_insert_data(extPaniclogHandle, addr, len);
116 }
117 
118 int
119 IOExtensiblePaniclog::appendData(void *addr, uint32_t len)
120 {
121 	return ext_paniclog_append_data(extPaniclogHandle, addr, len);
122 }
123 
124 void *
125 IOExtensiblePaniclog::claimBuffer()
126 {
127 	return ext_paniclog_claim_buffer(extPaniclogHandle);
128 }
129 
130 int
131 IOExtensiblePaniclog::yieldBuffer(uint32_t used_len)
132 {
133 	return ext_paniclog_yield_buffer(extPaniclogHandle, used_len);
134 }
135 
136 int
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
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
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
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
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
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
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
260 IOExtensiblePaniclog::SetUsedLen_Impl(uint32_t used_len)
261 {
262 	return ext_paniclog_set_used_len(extPaniclogHandle, used_len);
263 }
264